Skip to content

Commit

Permalink
Merge branch 'master' into feature/GSYE-722
Browse files Browse the repository at this point in the history
  • Loading branch information
hannesdiedrich authored May 7, 2024
2 parents 25bff30 + 14e6703 commit b3e8934
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 14 deletions.
9 changes: 9 additions & 0 deletions gsy_framework/read_user_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ class InputProfileTypes(Enum):
ENERGY_KWH = 4


class LiveProfileTypes(Enum):
"""Enum for type of live data profiles"""
NO_LIVE_DATA = 0
FORECAST = 1
MEASUREMENT = 2


def _str_to_datetime(time_string, time_format) -> DateTime:
"""
Converts time_string into a pendulum (DateTime) object that either takes the global start date
Expand Down Expand Up @@ -325,6 +332,8 @@ def read_arbitrary_profile(profile_type: InputProfileTypes,
:param current_timestamp:
:return: a mapping from time to profile values
"""
if input_profile in [{}, None]:
return {}
profile = _read_from_different_sources_todict(input_profile,
current_timestamp=current_timestamp)
profile_time_list = list(profile.keys())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@
]},
{"name": "power_profile", "type": ["null", "string"]},
{"name": "power_profile_uuid", "type": ["null", "string"]},
{"name": "power_measurement_uuid", "type": ["null", "string"]},
{"name": "capacity_kW", "type": ["null", "float"]},
{"name": "tilt", "type": ["null", "float"]},
{"name": "azimuth", "type": ["null", "float"]},
Expand Down Expand Up @@ -195,6 +196,7 @@
{"name": "energy_rate_decrease_per_update", "type": ["null", "float"]},
{"name": "power_profile", "type": ["null", "string"]},
{"name": "power_profile_uuid", "type": ["null", "string"]},
{"name": "power_measurement_uuid", "type": ["null", "string"]},
{"name": "update_interval", "type": ["null", "int"]},
{"name": "fit_to_limit", "type": ["null","boolean"]},
{"name": "capacity_kW", "type": ["null", "float"]},
Expand Down Expand Up @@ -227,6 +229,7 @@
{"name": "target_device_kpi", "type": ["null", "int"]},
{"name": "daily_load_profile", "type": ["null", "string"]},
{"name": "daily_load_profile_uuid", "type": ["null", "string"]},
{"name": "daily_load_measurement_uuid", "type": ["null", "string"]},
{"name": "use_market_maker_rate", "type": ["null", "boolean"]},
{"name": "forecast_stream_enabled", "type": ["null", "boolean"]},
{"name": "forecast_stream_id", "type": ["null", "string"]},
Expand Down Expand Up @@ -315,6 +318,7 @@
]},
{"name": "prosumption_kWh_profile", "type": ["null", "string"]},
{"name": "prosumption_kWh_profile_uuid", "type": ["null", "string"]},
{"name": "prosumption_kWh_measurement_uuid", "type": ["null", "string"]},
{"name": "use_market_maker_rate", "type": ["null", "boolean"]},
{"name": "allow_external_connection", "type": ["null", "boolean"]},
{"name": "display_type", "type": "string"},
Expand All @@ -338,6 +342,7 @@
]},
{"name": "consumption_kWh_profile", "type": ["null", "string"]},
{"name": "consumption_kWh_profile_uuid", "type": ["null", "string"]},
{"name": "consumption_kWh_measurement_uuid", "type": ["null", "string"]},
{"name": "use_market_maker_rate", "type": ["null", "boolean"]},
{"name": "allow_external_connection", "type": ["null", "boolean"]},
{"name": "display_type", "type": "string"},
Expand All @@ -363,6 +368,7 @@
]},
{"name": "smart_meter_profile", "type": ["null", "string"]},
{"name": "smart_meter_profile_uuid", "type": ["null", "string"]},
{"name": "smart_meter_measurement_uuid", "type": ["null", "string"]},
{"name": "final_buying_rate", "type": ["null", "float"]},
{"name": "initial_buying_rate", "type": ["null", "float"]},
{"name": "final_selling_rate", "type": ["null", "float"]},
Expand Down Expand Up @@ -398,9 +404,11 @@
{"name": "initial_temp_C", "type": "float"},
{"name": "external_temp_C_profile", "type": ["null", "string"]},
{"name": "external_temp_C_profile_uuid", "type": ["null", "string"]},
{"name": "external_temp_C_measurement_uuid", "type": ["null", "string"]},
{"name": "tank_volume_l", "type": "float"},
{"name": "consumption_kWh_profile", "type": ["null", "string"]},
{"name": "consumption_kWh_profile_uuid", "type": ["null", "string"]},
{"name": "consumption_kWh_measurement_uuid", "type": ["null", "string"]},
{"name": "source_type", "type": "int"},
{"name": "final_buying_rate", "type": ["null", "float"]},
{"name": "initial_buying_rate", "type": ["null", "float"]},
Expand Down
2 changes: 1 addition & 1 deletion gsy_framework/sim_results/scm/bills.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def update(self, area_result_dict, core_stats, current_market_slot):
if not area.get("children"):
continue

if "bills" not in core_stats[area["uuid"]]:
if "bills" not in core_stats[area["uuid"]] or not core_stats[area["uuid"]]["bills"]:
continue

if area["uuid"] not in self.bills_redis_results:
Expand Down
2 changes: 1 addition & 1 deletion gsy_framework/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def generate_market_slot_list(start_timestamp=None):
No input arguments, required input is only handled by a preconfigured GlobalConfig
@return: List with market slot datetimes
"""
time_span = (duration(days=PROFILE_EXPANSION_DAYS)
time_span = (GlobalConfig.slot_length
if GlobalConfig.is_canary_network()
else min(GlobalConfig.sim_duration, duration(days=PROFILE_EXPANSION_DAYS)))
time_span += duration(hours=ConstSettings.FutureMarketSettings.FUTURE_MARKET_DURATION_HOURS)
Expand Down
6 changes: 5 additions & 1 deletion gsy_framework/validators/profile_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ class ProfileValidator:
def __init__(
self, profile: Dict[DateTime, float], start_time: Optional[DateTime] = None,
end_time: Optional[DateTime] = None, slot_length: Optional[timedelta] = None):
assert len(profile) > 0, "profile is empty"

self.profile = OrderedDict(profile)
if not self.profile:
return
self.start_time = start_time if start_time else self._profile_start_time
self.end_time = end_time if end_time else self._profile_end_time
self.slot_length: timedelta = slot_length

def validate(self):
"""Validate if profile corresponds to the start_time, end_time and slot_length setting."""
if not self.profile:
return
if self.slot_length:
self._validate_slot_length()
else:
Expand Down
27 changes: 16 additions & 11 deletions tests/test_read_user_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import pytest
from pendulum import datetime, duration, today

from gsy_framework.constants_limits import PROFILE_EXPANSION_DAYS, TIME_ZONE, GlobalConfig
from gsy_framework.constants_limits import TIME_ZONE, GlobalConfig
from gsy_framework.enums import ConfigurationType
from gsy_framework.read_user_profile import (
InputProfileTypes, _fill_gaps_in_profile, _generate_slot_based_zero_values_dict_from_profile,
Expand Down Expand Up @@ -122,16 +122,8 @@ def test_read_profile_for_player():
def test_read_arbitrary_profile_returns_correct_profile_in_canary_network(
set_is_canary_network):
set_is_canary_network(True)
market_maker_rate = 30
GlobalConfig.sim_duration = duration(hours=3)
expected_last_time_slot = today(tz=TIME_ZONE).add(days=PROFILE_EXPANSION_DAYS - 1,
hours=23, minutes=45)
mmr = read_arbitrary_profile(InputProfileTypes.IDENTITY, market_maker_rate)
assert list(mmr.keys())[-1] == expected_last_time_slot
GlobalConfig.sim_duration = duration(hours=30)
expected_last_time_slot = today(tz=TIME_ZONE).add(days=PROFILE_EXPANSION_DAYS - 1,
hours=23, minutes=45)
mmr = read_arbitrary_profile(InputProfileTypes.IDENTITY, market_maker_rate)
expected_last_time_slot = today(tz=TIME_ZONE)
mmr = read_arbitrary_profile(InputProfileTypes.IDENTITY, 30)
assert list(mmr.keys())[-1] == expected_last_time_slot

@staticmethod
Expand Down Expand Up @@ -192,3 +184,16 @@ def test_resample_energy_profile_performs_correctly_for_equal_resolutions():
duration(hours=4),
datetime(2021, 1, 25, 0, 0))
assert result_profile == input_profile

@staticmethod
def test_read_arbitrary_profile_returns_early_for_empty_profiles():
original_slot_length = GlobalConfig.slot_length
original_sim_duration = GlobalConfig.sim_duration
GlobalConfig.slot_length = duration(hours=1)
GlobalConfig.sim_duration = duration(hours=4)
assert read_arbitrary_profile(InputProfileTypes.POWER_W, {}) == {}
assert read_arbitrary_profile(InputProfileTypes.POWER_W, None) == {}
assert len(read_arbitrary_profile(InputProfileTypes.POWER_W, 0)) == 4
assert set(read_arbitrary_profile(InputProfileTypes.POWER_W, 0).values()) == {0}
GlobalConfig.slot_length = original_slot_length
GlobalConfig.sim_duration = original_sim_duration
14 changes: 14 additions & 0 deletions tests/test_validators/test_profile_validator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from copy import copy
from unittest.mock import Mock

import pytest

Expand All @@ -8,6 +9,7 @@


class TestProfileValidator:
# pylint: disable=protected-access

@staticmethod
@pytest.mark.parametrize("input_profile, end_time", [
Expand Down Expand Up @@ -87,3 +89,15 @@ def test_profile_validator_fails_if_gap_in_profile_no_slot_length(input_profile)
del profile[gap_time]
with pytest.raises(AssertionError):
ProfileValidator(profile=profile).validate()

@staticmethod
def test_profile_validator_returns_early_if_empty_profile():
validator = ProfileValidator(profile={})
validator._validate_slot_length = Mock()
validator._get_and_validate_time_diffs = Mock()
validator._validate_start_end_date = Mock()
validator.slot_length = Mock()
assert validator.validate() is None
validator._validate_slot_length.assert_not_called()
validator._get_and_validate_time_diffs.assert_not_called()
validator._validate_start_end_date.assert_not_called()

0 comments on commit b3e8934

Please sign in to comment.