Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,24 @@ def to_entity(
temperature_out = esdl_asset.get_temperature("Out", "Supply")
strategy_priority = esdl_asset.get_strategy_priority()

if esdl_asset.has_constraint():
profile = esdl_asset.get_constraint_max_profile()
resampled_profile = None
# Check if there is an optimizer out port profile or a constraint profile. If there is both,
# only the optimizer profile is used.
if esdl_asset.has_out_optimizer_profile() or esdl_asset.has_constraint():
if esdl_asset.has_out_optimizer_profile():
profile = esdl_asset.get_out_port_profile()
else:
profile = esdl_asset.get_constraint_max_profile()

self.profile_interpolator = ProfileInterpolator(
profile=profile,
sampling_method=esdl_asset.get_sampling_method(),
interpolation_method=esdl_asset.get_interpolation_method(),
timestep=timestep,
)
resampled_profile = self.profile_interpolator.get_resampled_profile()
else:

if resampled_profile is None:
resampled_profile = pd.DataFrame()

contr_producer = ControllerProducer(
Expand Down
27 changes: 27 additions & 0 deletions src/omotes_simulator_core/entities/assets/esdl_asset_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,19 @@ def get_profile(self) -> pd.DataFrame:
)
raise ValueError(f"No profile found for asset: {self.esdl_asset.name}")

def get_out_port_profile(self) -> pd.DataFrame:
"""Get the profile of the asset's out ports."""
for port in self.esdl_asset.port:
if isinstance(port, esdl.OutPort) and port.profile.items:
for profile in port.profile:
if profile.field == "Heat_flow":
return get_data_from_profile(profile)
logger.error(
f"No profile found for asset: {self.esdl_asset.name}",
extra={"esdl_object_id": self.get_id()},
)
raise ValueError(f"No profile found at out port for asset: {self.esdl_asset.name}")

def get_constraint_max_profile(self) -> pd.DataFrame:
"""Get the profile from the asset's maximum constraint."""
for constraint in self.esdl_asset.constraint:
Expand Down Expand Up @@ -211,6 +224,20 @@ def has_profile(self) -> bool:
return True
return False

def has_out_optimizer_profile(self) -> bool:
"""Checks if an asset has an optimizer profile assigned to its out port."""
for port in self.esdl_asset.port:
if isinstance(port, esdl.OutPort) and port.profile.items:
# There is a profile on the out port
for profile in port.profile:
if (
hasattr(profile, "dataSource")
and hasattr(profile.dataSource, "name")
and profile.dataSource.name == "Optimizer"
):
return True
return False

def has_constraint(self) -> bool:
"""Checks if an asset has a constraint assigned to it."""
if self.esdl_asset.constraint.items:
Expand Down
61 changes: 50 additions & 11 deletions src/omotes_simulator_core/entities/utility/influxdb_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,40 @@

"""Module to read the esdl profiles from an energy system."""
import logging
from datetime import datetime
from typing import cast

import esdl
import pandas as pd
from esdl.esdl_handler import EnergySystemHandler
from esdl.profiles.influxdbprofilemanager import InfluxDBProfileManager
from esdl.profiles.influxdbprofilemanager import ConnectionSettings, InfluxDBProfileManager
from esdl.units.conversion import ENERGY_IN_J, POWER_IN_W, convert_to_unit

logger = logging.getLogger(__name__)


def _normalize_influx_filters(filters: str | None) -> list[dict[str, str]]:
"""Parse and normalize filters to the format expected by load_influxdb.

The upstream parser may return dictionaries with a `key` field while
load_influxdb expects `tag`. This shim keeps compatibility across versions.
"""
parsed_filters = InfluxDBProfileManager._parse_esdl_profile_filters(filters)
normalized_filters: list[dict[str, str]] = []
for influx_filter in parsed_filters:
tag = influx_filter.get("tag") or influx_filter.get("key")
value = influx_filter.get("value")
if not tag or value is None:
continue
normalized_filters.append(
{
"tag": str(tag),
"value": str(value).strip().strip("\"").strip("'"),
}
)
return normalized_filters


def parse_esdl_profiles(esh: EnergySystemHandler) -> dict[str, pd.DataFrame]:
"""Method to parse the esdl profiles from an energy system.

Expand All @@ -48,33 +72,48 @@ def get_data_from_profile(esdl_profile: esdl.InfluxDBProfile) -> pd.DataFrame:
:return: pandas.DataFrame with the data
"""
influx_cred_map: dict[str, tuple[str, str]] = {}
profile_host = esdl_profile.host
profile_host = str(esdl_profile.host)
profile_port = int(esdl_profile.port)
profile_database = str(esdl_profile.database)
profile_measurement = str(esdl_profile.measurement)
profile_field = str(esdl_profile.field)
ssl_setting = False
if "https" in profile_host:
profile_host = profile_host[8:]
ssl_setting = True
elif "http" in profile_host:
profile_host = profile_host[7:]
# why is this here?
if esdl_profile.port == 443:
if profile_port == 443:
ssl_setting = True

influx_host = f"{profile_host}:{esdl_profile.port}"
influx_host = f"{profile_host}:{profile_port}"
if influx_host in influx_cred_map:
(username, password) = influx_cred_map[influx_host]
else:
username = None
password = None
time_series_data = InfluxDBProfileManager.create_esdl_influxdb_profile_manager(
esdl_profile,
username,
password,
ssl_setting,
ssl_setting,
conn_settings = ConnectionSettings(
host=profile_host,
port=profile_port,
database=profile_database,
username=username or "",
password=password or "",
ssl=ssl_setting,
verify_ssl=ssl_setting,
)
time_series_data = InfluxDBProfileManager(conn_settings)
time_series_data.load_influxdb(
measurement=profile_measurement,
fields=[profile_field],
from_datetime=cast(datetime, esdl_profile.startDate),
to_datetime=cast(datetime, esdl_profile.endDate),
filters=_normalize_influx_filters(str(esdl_profile.filters)
if esdl_profile.filters else None),
)
# Error check start and end dates of profiles

# I do not thing this is required since you set it in mapeditor.
# I do not think this is required since you set it in mapeditor.
if time_series_data.end_datetime != esdl_profile.endDate:
logger.error(
f"The user input profile end datetime: {esdl_profile.endDate} does not match the end"
Expand Down
35 changes: 35 additions & 0 deletions unit_test/entities/test_esdl_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"""Test esdl object class."""
import unittest
from pathlib import Path
from unittest.mock import MagicMock, Mock

import esdl
from pandas.testing import assert_frame_equal
Expand Down Expand Up @@ -423,6 +424,40 @@ def test_get_asset_by_id(self):
# Assert
self.assertEqual(asset.esdl_asset, producer.esdl_asset)

def test_has_out_optimizer_profile(self):
"""Test to see if the method to check for optimizer profiles works correctly."""
# Arrange
asset_with_mocked_profiles = self.esdl_object.get_all_assets_of_type("producer")[0]

non_optimizer_profile = Mock()
non_optimizer_profile.dataSource = Mock()
non_optimizer_profile.dataSource.name = "NotOptimizer"

optimizer_profile = Mock()
optimizer_profile.dataSource = Mock()
optimizer_profile.dataSource.name = "Optimizer"

mocked_profiles = MagicMock()
mocked_profiles.items = [non_optimizer_profile, optimizer_profile]
mocked_profiles.__iter__.return_value = iter([non_optimizer_profile, optimizer_profile])

mocked_out_port = Mock(spec=esdl.OutPort)
mocked_out_port.profile = mocked_profiles

mocked_esdl_asset = Mock()
mocked_esdl_asset.port = [mocked_out_port]
asset_with_mocked_profiles.esdl_asset = mocked_esdl_asset

asset_without_profile = self.esdl_object.get_all_assets_of_type("pipe")[0]

# Act
has_optimizer_profile = asset_with_mocked_profiles.has_out_optimizer_profile()
has_no_optimizer_profile = asset_without_profile.has_out_optimizer_profile()

# Assert
self.assertTrue(has_optimizer_profile)
self.assertIs(has_no_optimizer_profile, False)


class StringEsdlAssetMapperTest(unittest.TestCase):
"""Class to test conversion from esdl asset to string and back."""
Expand Down
Loading