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

156 refactor 2 connection point limitation to 4 connection points #160

Merged
Show file tree
Hide file tree
Changes from 14 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 @@ -25,6 +25,7 @@
from omotes_simulator_core.entities.assets.pipe import Pipe
from omotes_simulator_core.entities.assets.production_cluster import ProductionCluster
from omotes_simulator_core.entities.assets.ates_cluster import AtesCluster
from omotes_simulator_core.entities.assets.heat_pump import HeatPump

from omotes_simulator_core.entities.assets.controller.controller_producer import ControllerProducer
from omotes_simulator_core.entities.assets.controller.controller_consumer import ControllerConsumer
Expand All @@ -39,9 +40,11 @@ class EsdlAssetMapper:
esdl.Producer: ProductionCluster,
esdl.GenericProducer: ProductionCluster,
esdl.Consumer: DemandCluster,
esdl.GenericConsumer: DemandCluster,
esdl.HeatingDemand: DemandCluster,
esdl.Pipe: Pipe,
esdl.ATES: AtesCluster,
esdl.HeatPump: HeatPump,
}

def to_esdl(self, entity: AssetAbstract) -> Any:
Expand Down
146 changes: 75 additions & 71 deletions src/omotes_simulator_core/adapter/transforms/mappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from omotes_simulator_core.entities.assets.asset_abstract import AssetAbstract

from omotes_simulator_core.entities.assets.junction import Junction
from omotes_simulator_core.entities.assets.utils import Port
from omotes_simulator_core.entities.esdl_object import EsdlObject
from omotes_simulator_core.entities.heat_network import HeatNetwork
from omotes_simulator_core.entities.network_controller import NetworkController
Expand All @@ -39,34 +38,12 @@
)


def connect_connected_asset(
connected_py_assets: List[Tuple[str, Port]],
junction: Junction,
py_assets_list: List[AssetAbstract],
) -> None:
"""Method to connect assets connected to one asset to the same junction.

:param connected_py_assets: List of connected assets
:param junction: Junction to connect the assets to
:param py_assets_list: List of assets
:return: None
"""
for connected_py_asset in connected_py_assets:
index = [py_asset_temp.asset_id for py_asset_temp in py_assets_list].index(
connected_py_asset[0]
)
if connected_py_asset[1] == Port.In: # from
py_assets_list[index].set_from_junction(from_junction=junction)
else: # to
py_assets_list[index].set_to_junction(to_junction=junction)


def replace_joint_in_connected_assets(
connected_py_assets: List[Tuple[str, Port]],
py_joint_dict: Dict[str, List[Tuple[str, Port]]],
connected_py_assets: List[Tuple[str, str]],
py_joint_dict: Dict[str, List[Tuple[str, str]]],
py_asset_id: str,
iteration_limit: int = 10,
) -> List[Tuple[str, Port]]:
) -> List[Tuple[str, str]]:
"""Replace joint with assets connected to the elements.

Replace items in the connected_py_assets list that are connected to a Joint
Expand Down Expand Up @@ -131,32 +108,36 @@ def to_entity(self, network: Network) -> Tuple[List[AssetAbstract], List[Junctio
This method first converts all assets into a list of assets.
Next to this a list of Junctions is created. This is then used
to create the Heatnetwork object.
:param Network network: network to add the compenents to.
:param Network network: network to add the components to.
:return: (List[AssetAbstract], List[Junction]), tuple of list of assets and junctions.
"""
# TODO: This method requires a clean-up!
py_assets_list = []
py_joint_dict = {}
for esdl_asset in self.esdl_object.get_all_assets_of_type("asset"):
# Esdl Junctions need to be skipped for now, are added later.
if isinstance(esdl_asset.esdl_asset, esdl_junction):
py_joint_dict[esdl_asset.esdl_asset.id] = [
*self.esdl_object.get_connected_assets(esdl_asset.esdl_asset.id, Port.In),
*self.esdl_object.get_connected_assets(esdl_asset.esdl_asset.id, Port.Out),
]
else:
py_assets_list.append(EsdlAssetMapper().to_entity(esdl_asset))
py_assets_list[-1].add_physical_data(esdl_asset=esdl_asset)
network.add_existing_asset(py_assets_list[-1].solver_asset)
py_assets_list = self._convert_assets(network)
vanmeerkerk marked this conversation as resolved.
Show resolved Hide resolved
py_junction_list = self._create_junctions(network, py_assets_list)

py_junction_list = []
return py_assets_list, py_junction_list

def _create_junctions(
self,
network: Network,
py_assets_list: list[AssetAbstract],
) -> List[Junction]:
"""Method to create junctions and connect the assets with them.

:param network: network to add the junctions to.
:param py_assets_list: list of assets to connect to the junctions.
:param py_joint_dict: dictionary with all jints in the esdl.

:return: List of junctions that are created and connected to the assets.
"""
py_joint_dict = self._get_junction(network)
py_junction_list = []
# loop over assets and create junctions and connect them
vanmeerkerk marked this conversation as resolved.
Show resolved Hide resolved
for py_asset in py_assets_list:
vanmeerkerk marked this conversation as resolved.
Show resolved Hide resolved
for con_point in range(0, 2):
for con_point in range(0, py_asset.number_of_con_points):
if not py_asset.solver_asset.is_connected(con_point):
connected_py_assets = self.esdl_object.get_connected_assets(
py_asset.asset_id, Port.In if con_point == 0 else Port.Out
py_asset.asset_id, py_asset.connected_ports[con_point]
)
# Replace items in the connected_py_assets list that are connected to a Joint
# with the items that are connected to the Joint, except for the current asset.
Expand All @@ -167,35 +148,58 @@ def to_entity(self, network: Network) -> Tuple[List[AssetAbstract], List[Junctio
index = [py_asset_temp.asset_id for py_asset_temp in py_assets_list].index(
vanmeerkerk marked this conversation as resolved.
Show resolved Hide resolved
connected_py_asset
)
if connected_py_port == Port.In:
node_id = network.connect_assets(
asset1_id=py_asset.solver_asset.name,
connection_point_1=con_point,
asset2_id=py_assets_list[index].solver_asset.name,
connection_point_2=0,
)
py_junction_list.append(
Junction(network.get_node(node_id), name=str(node_id))
)
py_assets_list[index].set_to_junction(py_junction_list[-1])
else:
node_id = network.connect_assets(
asset1_id=py_asset.solver_asset.name,
connection_point_1=con_point,
asset2_id=py_assets_list[index].solver_asset.name,
connection_point_2=1,
)
py_junction_list.append(
Junction(network.get_node(node_id), name=str(node_id))
)
py_assets_list[index].set_from_junction(py_junction_list[-1])
# connect the connected assets to the junction
if con_point == 0:
py_asset.set_to_junction(py_junction_list[-1])
else:
py_asset.set_from_junction(py_junction_list[-1])
con_point_2 = py_assets_list[index].connected_ports.index(connected_py_port)

return py_assets_list, py_junction_list
node_id = network.connect_assets(
asset1_id=py_asset.solver_asset.name,
connection_point_1=con_point,
asset2_id=py_assets_list[index].solver_asset.name,
connection_point_2=con_point_2,
)
py_junction_list.append(
Junction(network.get_node(node_id), name=str(node_id))
)
return py_junction_list

def _convert_assets(self, network: Network) -> List[AssetAbstract]:
"""Method to convert all assets from the esdl to a list of pyassets.

This method loops over all assets in the esdl and converts them to pyassets.

:param Network network: network to add the components to.
:return: List of pyassets.
"""
py_assets_list = []
for esdl_asset in self.esdl_object.get_all_assets_of_type("asset"):
# Esdl Junctions need to be skipped for now, are added later.
if isinstance(esdl_asset.esdl_asset, esdl_junction):
continue
py_assets_list.append(EsdlAssetMapper().to_entity(esdl_asset))
py_assets_list[-1].add_physical_data(esdl_asset=esdl_asset)
network.add_existing_asset(py_assets_list[-1].solver_asset)
return py_assets_list

def _get_junction(self, network: Network) -> dict[str, list[tuple[str, str]]]:
vanmeerkerk marked this conversation as resolved.
Show resolved Hide resolved
"""Method to create an overview of all assets connected to a joint in the esdl.

This method creates a dictionary with the joint id as key.
The value is a list of all connected assets and the id of the port it is connected to.

:param Network network: network to get the junctions from.
:return: dict[Any, list[list[tuple[str, str]]], which is the dictionary with the connected
assets.
"""
py_joint_dict = {}
for esdl_joint in self.esdl_object.get_all_assets_of_type("joint"):
# Esdl Junctions need to be skipped for now, are added later.
temp_list = [
self.esdl_object.get_connected_assets(
asset_id=esdl_joint.esdl_asset.id, port_id=port
)
for port in esdl_joint.get_port_ids()
]
py_joint_dict[esdl_joint.get_id()] = [item for sublist in temp_list for item in sublist]
return py_joint_dict


class EsdlControllerMapper(EsdlMapperAbstract):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class StringEsdlAssetMapper:
esdl.Conversion: "conversion",
esdl.Pipe: "pipe",
esdl.Transport: "transport",
esdl.Joint: "junction",
esdl.Joint: "joint",
esdl.ATES: "storage",
}

Expand Down
25 changes: 4 additions & 21 deletions src/omotes_simulator_core/entities/assets/asset_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from pandas import DataFrame, concat

from omotes_simulator_core.entities.assets.esdl_asset_object import EsdlAssetObject
from omotes_simulator_core.entities.assets.junction import Junction
from omotes_simulator_core.solver.network.assets.base_asset import BaseAsset

from omotes_simulator_core.entities.assets.asset_defaults import (
Expand All @@ -34,12 +33,6 @@
class AssetAbstract(ABC):
"""Abstract class for Asset."""

from_junction: Junction | None
"""The junction where the asset starts."""

to_junction: Junction | None
"""The junction where the asset ends."""

name: str
"""The name of the asset."""

Expand All @@ -52,7 +45,11 @@ class AssetAbstract(ABC):
connected_ports: List[str]
"""List of ids of the connected ports."""
solver_asset: BaseAsset
vanmeerkerk marked this conversation as resolved.
Show resolved Hide resolved
"""The asset object use for the solver."""
asset_type = "asset_abstract"
"""The type of the asset."""
number_of_con_points: int = 2
"""The number of connection points of the asset."""

def __init__(self, asset_name: str, asset_id: str, connected_ports: List[str]) -> None:
"""Basic constructor for asset objects.
Expand Down Expand Up @@ -92,20 +89,6 @@ def get_setpoints(self) -> Dict[str, float]:
def add_physical_data(self, esdl_asset: EsdlAssetObject) -> None:
"""Placeholder method to add physical data to an asset."""

def set_from_junction(self, from_junction: Junction) -> None:
"""Method to set the from junction of an asset.

:param Junction from_junction: The junction where the asset starts.
"""
self.from_junction = from_junction

def set_to_junction(self, to_junction: Junction) -> None:
"""Method to set the to junction of an asset.

:param Junction to_junction: The junction where the asset ends.
"""
self.to_junction = to_junction

def write_standard_output(self) -> None:
"""Write the output of the asset to the output list.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ def __init__(self, asset: esdl.Asset) -> None:
"""
self.esdl_asset = asset

def get_id(self) -> str:
"""Get the id of the asset."""
return str(self.esdl_asset.id)

def get_property(self, esdl_property_name: str, default_value: Any) -> Tuple[Any, bool]:
"""Get property value from the esdl_asset based on the "ESDL" name.

Expand Down
51 changes: 51 additions & 0 deletions src/omotes_simulator_core/entities/assets/heat_pump.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright (c) 2024. Deltares & TNO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""This module contains the HeatPump class."""
vanmeerkerk marked this conversation as resolved.
Show resolved Hide resolved

from omotes_simulator_core.entities.assets.asset_abstract import AssetAbstract
from omotes_simulator_core.entities.assets.esdl_asset_object import EsdlAssetObject
from omotes_simulator_core.solver.network.assets.base_asset import BaseAsset


class HeatPump(AssetAbstract):
"""A HeatPump represents an asset that produces heat."""

def __init__(self, asset_name: str, asset_id: str, port_ids: list[str]):
"""Initialize a HeatPump object.

:param str asset_name: The name of the asset.
:param str asset_id: The unique identifier of the asset.
:param List[str] port_ids: List of ids of the connected ports.
"""
super().__init__(asset_name=asset_name, asset_id=asset_id, connected_ports=port_ids)
self.number_of_con_points = 4
self.solver_asset = BaseAsset(
name=self.name,
_id=self.asset_id,
number_of_unknowns=12,
number_connection_points=self.number_of_con_points,
)

def set_setpoints(self, setpoints: dict) -> None:
"""Placeholder to set the setpoints of an asset prior to a simulation."""
pass

def add_physical_data(self, esdl_asset: EsdlAssetObject) -> None:
"""Add physical data to the asset."""
pass

def write_to_output(self) -> None:
"""Write the output of the asset to the output list."""
pass
29 changes: 10 additions & 19 deletions src/omotes_simulator_core/entities/esdl_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@
import logging
from typing import List, Tuple

from esdl import InPort, OutPort
from esdl.esdl_handler import EnergySystemHandler

from omotes_simulator_core.adapter.transforms.string_to_esdl import StringEsdlAssetMapper
from omotes_simulator_core.entities.assets.esdl_asset_object import EsdlAssetObject
from omotes_simulator_core.entities.assets.utils import Port

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -60,31 +58,24 @@ def get_all_assets_of_type(self, esdl_asset_type: str) -> list[EsdlAssetObject]:
]
return output_list

def get_connected_assets(self, asset_id: str, port: Port) -> List[Tuple[str, Port]]:
def get_connected_assets(self, asset_id: str, port_id: str) -> List[Tuple[str, str]]:
"""Method to get the id's of connected assets from the esdl.

This returns a list of list with the connected asset id and the port to which it is
connected to the asset.
First it is set if the request is an in or outport. Then the connected ports to the asset
are added to a list. In the final step all assets elong to the ports are listed together
with the type of port they are connected to.
This returns a list of a tuple with the id of the connected asset and the id of the port
to which the original asset is connected.

:param str id: id of the asset for which we want to know the connected assets
:param Port port: port for which the connected assets need to be returned.
:return: List of list which the id of the connected assets and the connected port.
:param str asset_id: id of the asset for which to return the connected assets.
:param str port_id: id of the port for which to return the connected assets.
:return: List of tuple with the id of the connected assets and the connected port ids.
"""
# TODO 1. Add support for components with multiple in and outports, like heat exchanger
# TODO 2. What if it is connected to a joint?
connected_assets = []
esdl_asset = self.energy_system_handler.get_by_id(asset_id)

type_port = OutPort if port == Port.Out else InPort
connected_port_ids = []
for esdl_port in esdl_asset.port:
if isinstance(esdl_port, type_port):
if esdl_port.id == port_id:
connected_port_ids = esdl_port.connectedTo
vanmeerkerk marked this conversation as resolved.
Show resolved Hide resolved
break
for connected_port_id in connected_port_ids:
connected_port_type = Port.Out if isinstance(connected_port_id, OutPort) else Port.In
connected_assets.append((connected_port_id.energyasset.id, connected_port_type))
if not connected_port_ids:
raise ValueError(f"No connected assets found for asset: {asset_id} and port: {port_id}")
connected_assets = [(port.energyasset.id, port.id) for port in connected_port_ids]
return connected_assets
Loading
Loading