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

Feature/gsye 836 #1828

Merged
merged 4 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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: 4 additions & 2 deletions src/gsy_e/gsy_e_core/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from gsy_framework.exceptions import GSyException
from gsy_framework.settings_validators import validate_global_settings
from pendulum import today
from gsy_e.gsy_e_core.non_p2p_handler import set_non_p2p_settings

from gsy_e.gsy_e_core.simulation import run_simulation
from gsy_e.gsy_e_core.util import (
Expand Down Expand Up @@ -178,7 +179,7 @@
type=int,
default=ConstSettings.MASettings.MARKET_TYPE,
show_default=True,
help="Market type. 1 for one-sided market, 2 for two-sided market, "
help="Market type. 0 for no-market, 1 for one-sided market, 2 for two-sided market, "
"3 for coefficient-based trading.",
)
def run(
Expand Down Expand Up @@ -209,8 +210,9 @@
simulation_settings["external_connection_enabled"] = False
simulation_config = SimulationConfig(**simulation_settings)
else:
assert 1 <= market_type <= 3, "Market type should be an integer between 1 and 3."
assert 0 <= market_type <= 3, "Market type should be an integer between 0 and 3."

Check warning on line 213 in src/gsy_e/gsy_e_core/cli.py

View check run for this annotation

Codecov / codecov/patch

src/gsy_e/gsy_e_core/cli.py#L213

Added line #L213 was not covered by tests
ConstSettings.MASettings.MARKET_TYPE = market_type
set_non_p2p_settings(market_type)

Check warning on line 215 in src/gsy_e/gsy_e_core/cli.py

View check run for this annotation

Codecov / codecov/patch

src/gsy_e/gsy_e_core/cli.py#L215

Added line #L215 was not covered by tests
global_settings = {
"sim_duration": duration,
"slot_length": slot_length,
Expand Down
8 changes: 4 additions & 4 deletions src/gsy_e/gsy_e_core/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
Offer,
Trade,
)
from gsy_framework.enums import AvailableMarketTypes, BidOfferMatchAlgoEnum, SpotMarketTypeEnum
from gsy_framework.enums import AvailableMarketTypes, BidOfferMatchAlgoEnum
from gsy_framework.utils import mkdir_from_str
from pendulum import DateTime

Expand All @@ -53,7 +53,7 @@
PlotSupplyDemandCurve,
PlotUnmatchedLoads,
)
from gsy_e.gsy_e_core.util import constsettings_to_dict
from gsy_e.gsy_e_core.util import constsettings_to_dict, is_two_sided_market_simulation
from gsy_e.models.area import Area

if TYPE_CHECKING:
Expand Down Expand Up @@ -172,7 +172,7 @@ def export(self, power_flow=None) -> None:
self.area, self.plot_dir
)
if (
ConstSettings.MASettings.MARKET_TYPE == SpotMarketTypeEnum.TWO_SIDED.value
is_two_sided_market_simulation()
and ConstSettings.MASettings.BID_OFFER_MATCH_TYPE
== BidOfferMatchAlgoEnum.PAY_AS_CLEAR.value
and ConstSettings.GeneralSettings.EXPORT_SUPPLY_DEMAND_PLOTS is True
Expand Down Expand Up @@ -353,7 +353,7 @@ def _export_area_with_children(

if area.children:
if (
ConstSettings.MASettings.MARKET_TYPE == SpotMarketTypeEnum.TWO_SIDED
is_two_sided_market_simulation()
and ConstSettings.MASettings.BID_OFFER_MATCH_TYPE
== BidOfferMatchAlgoEnum.PAY_AS_CLEAR.value
):
Expand Down
62 changes: 37 additions & 25 deletions src/gsy_e/gsy_e_core/non_p2p_handler.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
from gsy_framework.constants_limits import GlobalConfig
from gsy_framework.constants_limits import ConstSettings
from gsy_framework.enums import SpotMarketTypeEnum
from gsy_framework.exceptions import GSyException

import gsy_e.constants
from gsy_e.models.area.area import Area
from gsy_e.models.strategy.infinite_bus import InfiniteBusStrategy


def set_non_p2p_settings(spot_market_type: int):
"""Set up non-P2P settings."""
if spot_market_type == SpotMarketTypeEnum.NO_MARKET.value:
ConstSettings.MASettings.MIN_BID_AGE = gsy_e.constants.MIN_OFFER_BID_AGE_P2P_DISABLED
ConstSettings.MASettings.MIN_OFFER_AGE = gsy_e.constants.MIN_OFFER_BID_AGE_P2P_DISABLED
gsy_e.constants.RUN_IN_NON_P2P_MODE = True

Check warning on line 15 in src/gsy_e/gsy_e_core/non_p2p_handler.py

View check run for this annotation

Codecov / codecov/patch

src/gsy_e/gsy_e_core/non_p2p_handler.py#L13-L15

Added lines #L13 - L15 were not covered by tests


class NonP2PHandler:
"""Handles non-p2p case"""

def __init__(self, scenario: dict):
def __init__(self, scenario: Area):
if not gsy_e.constants.RUN_IN_NON_P2P_MODE:
return
self.non_p2p_scenario = scenario
self._energy_sell_rate = 0.0
self._energy_buy_rate = 0.0
self._get_energy_rates_from_infinite_bus(scenario)
self._handle_non_p2p_scenario(scenario)

def _get_energy_rates_from_infinite_bus(self, scenario: dict):
for child in scenario["children"]:
if child.get("type") == "InfiniteBus":
self._energy_buy_rate = child.get("energy_buy_rate", GlobalConfig.FEED_IN_TARIFF)
self._energy_sell_rate = child.get(
"energy_sell_rate", GlobalConfig.MARKET_MAKER_RATE
)
def _get_energy_rates_from_infinite_bus(self, scenario: Area):
for child in scenario.children:
if isinstance(child.strategy, InfiniteBusStrategy):
self._energy_buy_rate = child.strategy.energy_buy_rate
self._energy_sell_rate = child.strategy.energy_rate
return

raise GSyException(
Expand All @@ -27,28 +40,27 @@
)

@staticmethod
def _is_home_area(area: dict):
return area.get("children") and all(
child.get("type", None) for child in area.get("children")
)
def _is_home_area(area: Area):
return area.children and all(child.strategy is not None for child in area.children)

def _add_market_maker_to_home(self, area: dict):
if "children" not in area or not area["children"]:
def _add_market_maker_to_home(self, area: Area):
if not area.children:
return
if not self._is_home_area(area):
return
area["children"].append(
{
"name": "MarketMaker",
"type": "InfiniteBus",
"energy_buy_rate": self._energy_buy_rate,
"energy_sell_rate": self._energy_sell_rate,
}
market_maker_area = Area(
name="MarketMaker",
strategy=InfiniteBusStrategy(
energy_buy_rate=self._energy_buy_rate, energy_sell_rate=self._energy_sell_rate
),
)
market_maker_area.parent = area

area.children.append(market_maker_area)

def _handle_non_p2p_scenario(self, area: dict):
if "children" not in area or not area["children"]:
def _handle_non_p2p_scenario(self, area: Area):
if not area.children:
return
self._add_market_maker_to_home(area)
for child in area["children"]:
for child in area.children:
self._handle_non_p2p_scenario(child)
12 changes: 3 additions & 9 deletions src/gsy_e/gsy_e_core/rq_job_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
from pendulum import duration, instance, now

import gsy_e.constants
from gsy_e.gsy_e_core.non_p2p_handler import set_non_p2p_settings
from gsy_e.gsy_e_core.simulation import run_simulation
from gsy_e.gsy_e_core.util import update_advanced_settings
from gsy_e.models.config import SimulationConfig
from gsy_e.gsy_e_core.non_p2p_handler import NonP2PHandler

logging.getLogger().setLevel(logging.ERROR)
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -56,9 +56,6 @@ def launch_simulation_from_rq_job(

_configure_constants_constsettings(scenario, settings, connect_to_profiles_db)

if gsy_e.constants.RUN_IN_NON_P2P_MODE:
scenario = NonP2PHandler(scenario).non_p2p_scenario

slot_length_realtime = (
duration(seconds=settings["slot_length_realtime"].seconds)
if "slot_length_realtime" in settings
Expand Down Expand Up @@ -178,7 +175,7 @@ def _configure_constants_constsettings(
spot_market_type = settings.get("spot_market_type")
bid_offer_match_algo = settings.get("bid_offer_match_algo")

if spot_market_type:
if spot_market_type is not None:
ConstSettings.MASettings.MARKET_TYPE = spot_market_type
if bid_offer_match_algo:
ConstSettings.MASettings.BID_OFFER_MATCH_TYPE = bid_offer_match_algo
Expand All @@ -194,10 +191,7 @@ def _configure_constants_constsettings(
)
gsy_e.constants.CONNECT_TO_PROFILES_DB = connect_to_profiles_db

if spot_market_type == SpotMarketTypeEnum.NO_MARKET.value:
ConstSettings.MASettings.MIN_BID_AGE = gsy_e.constants.MIN_OFFER_BID_AGE_P2P_DISABLED
ConstSettings.MASettings.MIN_OFFER_AGE = gsy_e.constants.MIN_OFFER_BID_AGE_P2P_DISABLED
gsy_e.constants.RUN_IN_NON_P2P_MODE = True
set_non_p2p_settings(spot_market_type)

if settings.get("scm"):
ConstSettings.SCMSettings.MARKET_ALGORITHM = CoefficientAlgorithm(
Expand Down
3 changes: 2 additions & 1 deletion src/gsy_e/gsy_e_core/sim_results/file_export_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from gsy_e.constants import ROUND_TOLERANCE
from gsy_e.gsy_e_core.matching_engine_singleton import bid_offer_matcher
from gsy_e.gsy_e_core.util import is_two_sided_market_simulation
from gsy_e.models.area import Area
from gsy_e.models.strategy.load_hours import LoadHoursStrategy
from gsy_e.models.strategy.pv import PVStrategy
Expand Down Expand Up @@ -368,7 +369,7 @@ def _get_stats_from_market_data(

def _populate_plots_stats_for_supply_demand_curve(self, area: Area) -> None:
if (
ConstSettings.MASettings.MARKET_TYPE == SpotMarketTypeEnum.TWO_SIDED.value
is_two_sided_market_simulation()
and ConstSettings.MASettings.BID_OFFER_MATCH_TYPE
== BidOfferMatchAlgoEnum.PAY_AS_CLEAR.value
):
Expand Down
21 changes: 13 additions & 8 deletions src/gsy_e/gsy_e_core/simulation/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from numpy import random

from gsy_e.gsy_e_core.exceptions import SimulationException
from gsy_e.gsy_e_core.non_p2p_handler import NonP2PHandler
from gsy_e.models.config import SimulationConfig

if TYPE_CHECKING:
Expand All @@ -39,6 +40,7 @@
@dataclass
class SimulationSetup:
"""Static simulation configuration."""

seed: int = 0
enable_bc: bool = False
use_repl: bool = False
Expand All @@ -53,6 +55,7 @@
"""Load setup module and create areas that are described on the setup."""
loaded_python_module = self._import_setup_module(self.setup_module_name)
area = loaded_python_module.get_setup(self.config)
NonP2PHandler(area)
self._log_traversal_length(area)
return area

Expand All @@ -69,15 +72,18 @@
def _log_traversal_length(self, area: "Area") -> None:
no_of_levels = self._get_setup_levels(area) + 1
num_ticks_to_propagate = no_of_levels * 2
time_to_propagate_minutes = (num_ticks_to_propagate *
self.config.tick_length.seconds / 60.)
log.info("Setup has %s levels, offers/bids need at least %s minutes to propagate.",
no_of_levels, time_to_propagate_minutes)
time_to_propagate_minutes = num_ticks_to_propagate * self.config.tick_length.seconds / 60.0
log.info(
"Setup has %s levels, offers/bids need at least %s minutes to propagate.",
no_of_levels,
time_to_propagate_minutes,
)

def _get_setup_levels(self, area: "Area", level_count: int = 0) -> int:
level_count += 1
count_list = [self._get_setup_levels(child, level_count)
for child in area.children if child.children]
count_list = [
self._get_setup_levels(child, level_count) for child in area.children if child.children
]
return max(count_list) if len(count_list) > 0 else level_count

@staticmethod
Expand All @@ -89,7 +95,6 @@
return import_module(f"{setup_module_name}")
except (ModuleNotFoundError, ImportError) as ex:
log.error("Loading the simulation setup module failed: %s", str(ex))
raise SimulationException(
f"Invalid setup module '{setup_module_name}'") from ex
raise SimulationException(f"Invalid setup module '{setup_module_name}'") from ex

Check warning on line 98 in src/gsy_e/gsy_e_core/simulation/setup.py

View check run for this annotation

Codecov / codecov/patch

src/gsy_e/gsy_e_core/simulation/setup.py#L98

Added line #L98 was not covered by tests
finally:
log.debug("Using setup module '%s'", setup_module_name)
15 changes: 14 additions & 1 deletion src/gsy_e/gsy_e_core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

from click.types import ParamType
from gsy_framework.constants_limits import ConstSettings, GlobalConfig, RangeLimit, DATE_FORMAT
from gsy_framework.enums import BidOfferMatchAlgoEnum
from gsy_framework.enums import BidOfferMatchAlgoEnum, SpotMarketTypeEnum
from gsy_framework.exceptions import GSyException
from gsy_framework.utils import (
area_name_from_area_or_ma_name,
Expand Down Expand Up @@ -537,3 +537,16 @@ def get_slots_per_month(time_slot: DateTime) -> int:
return (duration(days=1) / GlobalConfig.slot_length) * monthrange(
time_slot.year, time_slot.month
)[1]


def is_two_sided_market_simulation():
"""Return if the two-sided market is set."""
return ConstSettings.MASettings.MARKET_TYPE in [
SpotMarketTypeEnum.TWO_SIDED.value,
SpotMarketTypeEnum.NO_MARKET.value,
]


def is_one_sided_market_simulation():
"""Return if the one-sided market is set."""
return ConstSettings.MASettings.MARKET_TYPE == SpotMarketTypeEnum.ONE_SIDED.value
Loading
Loading