Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/gsy_e/gsy_e_core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,11 @@ def get_market_maker_rate_from_time_slot(time_slot: Optional[DateTime]) -> float
if isinstance(GlobalConfig.market_maker_rate, dict):
if time_slot is None:
assert time_slot, "time_slot parameter is missing to get market_maker"
return get_from_profile_same_weekday_and_time(GlobalConfig.market_maker_rate, time_slot)
if GlobalConfig.is_canary_network():
return get_from_profile_same_weekday_and_time(
GlobalConfig.market_maker_rate, time_slot
)
return GlobalConfig.market_maker_rate.get(time_slot)
return GlobalConfig.market_maker_rate


Expand Down
28 changes: 16 additions & 12 deletions src/gsy_e/models/strategy/finite_power_plant.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@

from typing import Union, Optional

from gsy_framework.read_user_profile import UserProfileReader, InputProfileTypes
from gsy_framework.read_user_profile import InputProfileTypes
from gsy_framework.utils import convert_str_to_pendulum_in_dict, convert_pendulum_to_str_in_dict
from gsy_framework.utils import get_from_profile_same_weekday_and_time, convert_kW_to_kWh
from gsy_framework.utils import convert_kW_to_kWh
from gsy_framework.validators import FiniteDieselGeneratorValidator

from gsy_e.models.strategy.commercial_producer import CommercialStrategy
from gsy_e.models.strategy.strategy_profile import profile_factory, StrategyProfileBase


class FinitePowerPlant(CommercialStrategy):
Expand All @@ -43,24 +44,21 @@ def __init__(
FiniteDieselGeneratorValidator.validate(max_available_power_kW=max_available_power_kW)
super().__init__(energy_rate=energy_rate)
self.max_available_power_kW = max_available_power_kW
self._max_available_power_kW_profile: StrategyProfileBase = None

def event_activate(self, **kwargs):
super().event_activate()
self.max_available_power_kW = UserProfileReader().read_arbitrary_profile(
InputProfileTypes.IDENTITY, self.max_available_power_kW
)
self._init_max_power_profile(self.max_available_power_kW)

def event_offer_traded(self, *, market_id, trade):
# Disable offering more energy than the initial offer, in order to adhere to the max
# available power.
pass

def event_market_cycle(self):
power_from_profile = get_from_profile_same_weekday_and_time(
self.max_available_power_kW, self.area.spot_market.time_slot
)
self.energy_per_slot_kWh = convert_kW_to_kWh(
power_from_profile, self.simulation_config.slot_length
self._max_available_power_kW_profile.get_value(self.area.spot_market.time_slot),
self.simulation_config.slot_length,
)
if self.energy_per_slot_kWh <= 0.0:
return
Expand All @@ -69,13 +67,19 @@ def event_market_cycle(self):
def get_state(self):
return {
"energy_rate": convert_pendulum_to_str_in_dict(self._sell_energy_profile.profile),
"max_available_power_kW": convert_pendulum_to_str_in_dict(self.max_available_power_kW),
"max_available_power_kW": convert_pendulum_to_str_in_dict(
self._max_available_power_kW_profile.profile
),
}

def restore_state(self, saved_state):
self._sell_energy_profile.profile = convert_str_to_pendulum_in_dict(
saved_state["energy_rate"]
)
self.max_available_power_kW.update(
convert_str_to_pendulum_in_dict(saved_state["max_available_power_kW"])
self._init_max_power_profile(saved_state["max_available_power_kW"])

def _init_max_power_profile(self, max_available_power_kW: Union[float, dict, str]):
self._max_available_power_kW_profile = profile_factory(
input_profile=max_available_power_kW, profile_type=InputProfileTypes.IDENTITY
)
self._max_available_power_kW_profile.read_or_rotate_profiles()
50 changes: 27 additions & 23 deletions src/gsy_e/models/strategy/load_hours.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@
from gsy_framework.constants_limits import ConstSettings, FLOATING_POINT_TOLERANCE
from gsy_framework.data_classes import Offer, TraderDetails
from gsy_framework.exceptions import GSyDeviceException
from gsy_framework.read_user_profile import UserProfileReader, InputProfileTypes
from gsy_framework.read_user_profile import InputProfileTypes
from gsy_framework.utils import (
limit_float_precision,
get_from_profile_same_weekday_and_time,
is_time_slot_in_simulation_duration,
)
from gsy_framework.validators.load_validator import LoadValidator
Expand All @@ -45,6 +44,7 @@
from gsy_e.models.strategy.settlement.strategy import settlement_market_strategy_factory
from gsy_e.models.strategy.state import LoadState
from gsy_e.models.strategy.update_frequency import TemplateStrategyBidUpdater
from gsy_e.models.strategy.strategy_profile import profile_factory, StrategyProfileBase

BalancingRatio = namedtuple("BalancingRatio", ("demand", "supply"))

Expand Down Expand Up @@ -110,7 +110,6 @@ def __init__(
self._calculate_active_markets()
self._cycled_market = set()
self._simulation_start_timestamp = None
self._reader = UserProfileReader()

@property
def state(self) -> LoadState:
Expand Down Expand Up @@ -156,10 +155,14 @@ def _init_price_update(
)

def _validate_rates(
self, initial_rate, final_rate, energy_rate_change_per_update, fit_to_limit
self,
initial_rate: StrategyProfileBase,
final_rate: StrategyProfileBase,
energy_rate_change_per_update: StrategyProfileBase,
fit_to_limit: bool,
):
# all parameters have to be validated for each time slot starting from the current time
for time_slot in initial_rate.keys():
# all parameters have pvto be validated for each time slot starting from the current time
for time_slot in initial_rate.profile.keys():
if not is_time_slot_in_simulation_duration(time_slot, self.area.config):
continue

Expand All @@ -170,16 +173,12 @@ def _validate_rates(
):
continue
rate_change = (
None
if fit_to_limit
else get_from_profile_same_weekday_and_time(
energy_rate_change_per_update, time_slot
)
None if fit_to_limit else energy_rate_change_per_update.get_value(time_slot)
)
LoadValidator.validate_rate(
initial_buying_rate=initial_rate[time_slot],
initial_buying_rate=initial_rate.get_value(time_slot),
energy_rate_increase_per_update=rate_change,
final_buying_rate=get_from_profile_same_weekday_and_time(final_rate, time_slot),
final_buying_rate=final_rate.get_value(time_slot),
fit_to_limit=fit_to_limit,
)

Expand Down Expand Up @@ -232,21 +231,26 @@ def _delete_past_state(self):

def _area_reconfigure_prices(self, **kwargs):
if kwargs.get("initial_buying_rate") is not None:
initial_rate = self._reader.read_arbitrary_profile(
InputProfileTypes.IDENTITY, kwargs["initial_buying_rate"]
initial_rate = profile_factory(
profile_type=InputProfileTypes.IDENTITY,
input_profile=kwargs["initial_buying_rate"],
)
initial_rate.read_or_rotate_profiles()
else:
initial_rate = self.bid_update.initial_rate_profile_buffer
if kwargs.get("final_buying_rate") is not None:
final_rate = self._reader.read_arbitrary_profile(
InputProfileTypes.IDENTITY, kwargs["final_buying_rate"]
final_rate = profile_factory(
profile_type=InputProfileTypes.IDENTITY, input_profile=kwargs["final_buying_rate"]
)
final_rate.read_or_rotate_profiles()
else:
final_rate = self.bid_update.final_rate_profile_buffer
if kwargs.get("energy_rate_increase_per_update") is not None:
energy_rate_change_per_update = self._reader.read_arbitrary_profile(
InputProfileTypes.IDENTITY, kwargs["energy_rate_increase_per_update"]
energy_rate_change_per_update = profile_factory(
profile_type=InputProfileTypes.IDENTITY,
input_profile=kwargs["energy_rate_increase_per_update"],
)
energy_rate_change_per_update.read_or_rotate_profiles()
else:
energy_rate_change_per_update = (
self.bid_update.energy_rate_change_per_update_profile_buffer
Expand Down Expand Up @@ -276,19 +280,19 @@ def _area_reconfigure_prices(self, **kwargs):
return

self.bid_update.set_parameters(
initial_rate=initial_rate,
final_rate=final_rate,
energy_rate_change_per_update=energy_rate_change_per_update,
initial_rate=initial_rate.profile,
final_rate=final_rate.profile,
energy_rate_change_per_update=energy_rate_change_per_update.profile,
fit_to_limit=fit_to_limit,
update_interval=update_interval,
)
self.bid_update.update_and_populate_price_settings(self.area)

def area_reconfigure_event(self, *args, **kwargs):
"""Reconfigure the device properties at runtime using the provided arguments."""
self._energy_params.reset(self.area.spot_market.time_slot, **kwargs)
self._update_energy_requirement_in_state()
self._area_reconfigure_prices(**kwargs)
self.bid_update.update_and_populate_price_settings(self.area)

def event_activate_price(self):
"""Update the strategy prices upon the activation and validate them afterwards."""
Expand Down
17 changes: 10 additions & 7 deletions src/gsy_e/models/strategy/mixins.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from typing import TYPE_CHECKING

from gsy_framework.read_user_profile import InputProfileTypes, UserProfileReader
from gsy_framework.read_user_profile import InputProfileTypes

from gsy_e.gsy_e_core.util import get_market_maker_rate_from_config
from gsy_e.models.strategy.strategy_profile import profile_factory

if TYPE_CHECKING:
from gsy_e.models.area import Area
Expand All @@ -23,16 +24,18 @@ class UseMarketMakerMixin:

def _reconfigure_initial_selling_rate(self, initial_selling_rate: float):
"""validation is not needed"""
initial_selling_rate = UserProfileReader().read_arbitrary_profile(
InputProfileTypes.IDENTITY, initial_selling_rate
initial_selling_rate = profile_factory(
profile_type=InputProfileTypes.IDENTITY, input_profile=initial_selling_rate
)
self.offer_update.set_parameters(initial_rate=initial_selling_rate)
initial_selling_rate.read_or_rotate_profiles()
self.offer_update.set_parameters(initial_rate=initial_selling_rate.profile)

def _reconfigure_final_buying_rate(self, final_buying_rate: float):
final_buying_rate = UserProfileReader().read_arbitrary_profile(
InputProfileTypes.IDENTITY, final_buying_rate
final_buying_rate = profile_factory(
profile_type=InputProfileTypes.IDENTITY, input_profile=final_buying_rate
)
self.bid_update.set_parameters(final_rate=final_buying_rate)
final_buying_rate.read_or_rotate_profiles()
self.bid_update.set_parameters(final_rate=final_buying_rate.profile)

def _replace_rates_with_market_maker_rates(self):
if not self.use_market_maker_rate:
Expand Down
77 changes: 39 additions & 38 deletions src/gsy_e/models/strategy/pv.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
from gsy_framework.constants_limits import ConstSettings
from gsy_framework.data_classes import TraderDetails
from gsy_framework.exceptions import GSyException
from gsy_framework.read_user_profile import UserProfileReader, InputProfileTypes
from gsy_framework.utils import get_from_profile_same_weekday_and_time, key_in_dict_and_not_none
from gsy_framework.read_user_profile import InputProfileTypes, UserProfileReader
from gsy_framework.utils import key_in_dict_and_not_none
from gsy_framework.validators import PVValidator
from pendulum import duration

Expand All @@ -37,6 +37,7 @@
from gsy_e.models.strategy.settlement.strategy import settlement_market_strategy_factory
from gsy_e.models.strategy.state import PVState
from gsy_e.models.strategy.update_frequency import TemplateStrategyOfferUpdater
from gsy_e.models.strategy.strategy_profile import StrategyProfileBase, profile_factory

log = getLogger(__name__)

Expand Down Expand Up @@ -134,35 +135,35 @@ def _init_price_update(
def area_reconfigure_event(self, *args, **kwargs):
"""Reconfigure the device properties at runtime using the provided arguments."""
self._area_reconfigure_prices(**kwargs)
self.offer_update.update_and_populate_price_settings(self.area)
self._energy_params.reset(**kwargs)
self.set_produced_energy_forecast_in_state(reconfigure=True)

def _area_reconfigure_prices(self, **kwargs):

initial_rate = (
self._reader.read_arbitrary_profile(
InputProfileTypes.IDENTITY, kwargs["initial_selling_rate"]
if kwargs.get("initial_selling_rate") is not None:
initial_rate = profile_factory(
profile_type=InputProfileTypes.IDENTITY,
input_profile=kwargs["initial_selling_rate"],
)
if kwargs.get("initial_selling_rate") is not None
else self.offer_update.initial_rate_profile_buffer
)

final_rate = (
self._reader.read_arbitrary_profile(
InputProfileTypes.IDENTITY, kwargs["final_selling_rate"]
initial_rate.read_or_rotate_profiles()
else:
initial_rate = self.offer_update.initial_rate_profile_buffer
if kwargs.get("final_selling_rate") is not None:
final_rate = profile_factory(
profile_type=InputProfileTypes.IDENTITY, input_profile=kwargs["final_selling_rate"]
)
if kwargs.get("final_selling_rate") is not None
else self.offer_update.final_rate_profile_buffer
)

energy_rate_change_per_update = (
self._reader.read_arbitrary_profile(
InputProfileTypes.IDENTITY, kwargs["energy_rate_decrease_per_update"]
final_rate.read_or_rotate_profiles()
else:
final_rate = self.offer_update.final_rate_profile_buffer
if kwargs.get("energy_rate_increase_per_update") is not None:
energy_rate_change_per_update = profile_factory(
profile_type=InputProfileTypes.IDENTITY,
input_profile=kwargs["energy_rate_increase_per_update"],
)
energy_rate_change_per_update.read_or_rotate_profiles()
else:
energy_rate_change_per_update = (
self.offer_update.energy_rate_change_per_update_profile_buffer
)
if kwargs.get("energy_rate_decrease_per_update") is not None
else self.offer_update.energy_rate_change_per_update_profile_buffer
)

fit_to_limit = (
kwargs["fit_to_limit"]
Expand All @@ -187,41 +188,41 @@ def _area_reconfigure_prices(self, **kwargs):
)
except GSyException as e: # pylint: disable=broad-except
log.error(
"PVStrategy._area_reconfigure_prices failed. Exception: %s. " "Traceback: %s",
"PVStrategy._area_reconfigure_prices failed. Exception: %s. Traceback: %s",
e,
traceback.format_exc(),
)
return

self.offer_update.set_parameters(
initial_rate=initial_rate,
final_rate=final_rate,
energy_rate_change_per_update=energy_rate_change_per_update,
initial_rate=initial_rate.profile,
final_rate=final_rate.profile,
energy_rate_change_per_update=energy_rate_change_per_update.profile,
fit_to_limit=fit_to_limit,
update_interval=update_interval,
)
self.offer_update.update_and_populate_price_settings(self.area)

def _validate_rates(
self, initial_rate, final_rate, energy_rate_change_per_update, fit_to_limit
self,
initial_rate: StrategyProfileBase,
final_rate: StrategyProfileBase,
energy_rate_change_per_update: StrategyProfileBase,
fit_to_limit: bool,
):
# all parameters have to be validated for each time slot here
for time_slot in initial_rate.keys():
for time_slot in initial_rate.profile.keys():
if (
self.area
and self.area.current_market
and time_slot < self.area.current_market.time_slot
):
continue
rate_change = (
None
if fit_to_limit
else get_from_profile_same_weekday_and_time(
energy_rate_change_per_update, time_slot
)
None if fit_to_limit else energy_rate_change_per_update.get_value(time_slot)
)
PVValidator.validate_rate(
initial_selling_rate=initial_rate[time_slot],
final_selling_rate=get_from_profile_same_weekday_and_time(final_rate, time_slot),
initial_selling_rate=initial_rate.get_value(time_slot),
final_selling_rate=final_rate.get_value(time_slot),
energy_rate_decrease_per_update=rate_change,
fit_to_limit=fit_to_limit,
)
Expand Down
Loading
Loading