From 2b85dd05b03b2bff0f342116fb8fd857bcd4090d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Frei=C3=9Fmann?= Date: Mon, 29 Apr 2024 09:49:10 +0200 Subject: [PATCH 1/8] Improve writing JSON file method. --- src/tespy/networks/network.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tespy/networks/network.py b/src/tespy/networks/network.py index 7c5f22923..0120b20c4 100644 --- a/src/tespy/networks/network.py +++ b/src/tespy/networks/network.py @@ -2711,7 +2711,7 @@ def export_network(self, fn): Path/filename for the network configuration file. """ with open(fn + 'network.json', 'w') as f: - f.write(json.dumps(self._serialize(), indent=4)) + json.dump(self._serialize(), f, indent=4) logger.debug('Network information saved to %s.', fn) @@ -2758,7 +2758,7 @@ def save_busses(self, fn): bus_data[label] = self.results[label]["design value"].to_dict() fn = fn + 'busses.json' with open(fn, "w", encoding="utf-8") as f: - f.write(json.dumps(bus_data, indent=4)) + json.dump(bus_data, f, indent=4) logger.debug('Bus information saved to %s.', fn) def export_connections(self, fn): @@ -2768,7 +2768,7 @@ def export_connections(self, fn): fn = fn + "connections.json" with open(fn, "w", encoding="utf-8") as f: - f.write(json.dumps(connections, indent=4).replace("NaN", "null")) + json.dump(connections, f, indent=4) logger.debug('Connection information exported to %s.', fn) def export_components(self, fn): @@ -2779,7 +2779,7 @@ def export_components(self, fn): fname = f"{fn}{c}.json" with open(fname, "w", encoding="utf-8") as f: - f.write(json.dumps(components, indent=4).replace("NaN", "null")) + json.dump(components, f, indent=4) logger.debug('Component information exported to %s.', fname) def export_busses(self, fn): @@ -2789,5 +2789,5 @@ def export_busses(self, fn): busses.update(bus._serialize()) fn = fn + 'busses.json' with open(fn, "w", encoding="utf-8") as f: - f.write(json.dumps(busses, indent=4).replace("NaN", "null")) + json.dump(busses, f, indent=4) logger.debug('Bus information exported to %s.', fn) From f67852129465e1dbd6116bff43b4b4168b5584f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Frei=C3=9Fmann?= Date: Mon, 29 Apr 2024 14:30:12 +0200 Subject: [PATCH 2/8] Improve JSON file reads with load method. --- docs/scripts/generate_tespy_data_module.py | 2 +- src/tespy/networks/network_reader.py | 8 ++++---- src/tespy/tools/characteristics.py | 4 ++-- tests/test_tools/test_characteristics.py | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/scripts/generate_tespy_data_module.py b/docs/scripts/generate_tespy_data_module.py index 0b7b98a06..62c0aa251 100644 --- a/docs/scripts/generate_tespy_data_module.py +++ b/docs/scripts/generate_tespy_data_module.py @@ -12,7 +12,7 @@ def get_char_data(filename): path = resource_filename('tespy.data', filename + '.json') with open(path) as f: - data = json.loads(f.read()) + data = json.load(f) return data diff --git a/src/tespy/networks/network_reader.py b/src/tespy/networks/network_reader.py index ecbe2bbac..bcc22b34a 100644 --- a/src/tespy/networks/network_reader.py +++ b/src/tespy/networks/network_reader.py @@ -254,7 +254,7 @@ def load_network(path): logger.debug(msg) with open(path_comps + f, "r", encoding="utf-8") as c: - data = json.loads(c.read()) + data = json.load(c) comps.update(construct_components(component, data)) @@ -270,7 +270,7 @@ def load_network(path): logger.debug(msg) with open(fn, "r", encoding="utf-8") as c: - data = json.loads(c.read()) + data = json.load(c) conns = construct_connections(data, comps) @@ -289,7 +289,7 @@ def load_network(path): logger.debug(msg) with open(fn, "r", encoding="utf-8") as c: - data = json.loads(c.read()) + data = json.load(c) busses = construct_busses(data, comps) # add busses to network @@ -364,7 +364,7 @@ def construct_network(path): """ # read network .json-file with open(path + 'network.json', 'r') as f: - data = json.loads(f.read()) + data = json.load(f) # create network object with its properties return Network(**data) diff --git a/src/tespy/tools/characteristics.py b/src/tespy/tools/characteristics.py index 95c8bc118..29c79992e 100644 --- a/src/tespy/tools/characteristics.py +++ b/src/tespy/tools/characteristics.py @@ -503,7 +503,7 @@ def load_default_char(component, parameter, function_name, char_type): path = os.path.join(__datapath__, 'char_maps.json') with open(path) as f: - data = json.loads(f.read()) + data = json.load(f) if char_type == CharLine: x = data[component][parameter][function_name]['x'] @@ -546,7 +546,7 @@ def load_custom_char(name, char_type): if os.path.isfile(path): with open(path) as f: - data = json.loads(f.read()) + data = json.load(f) if char_type == CharLine: x = data[name]['x'] diff --git a/tests/test_tools/test_characteristics.py b/tests/test_tools/test_characteristics.py index 883f36d9c..40b2f382e 100644 --- a/tests/test_tools/test_characteristics.py +++ b/tests/test_tools/test_characteristics.py @@ -36,7 +36,7 @@ def test_custom_CharLine_import(): shutil.copy(src=path + '/' + f, dst=tmp_path) with open(data_path) as f: - raw_data = json.loads(f.read()) + raw_data = json.load(f) data = raw_data['heat exchanger']['kA_char2'] with open(os.path.join(path, 'char_lines.json'), 'w') as outfile: @@ -84,7 +84,7 @@ def test_custom_CharMap_import(): shutil.copy(src=path + '/' + f, dst=tmp_path) with open(data_path) as f: - raw_data = json.loads(f.read()) + raw_data = json.load(f) data = raw_data['compressor']['char_map_pr'] with open(os.path.join(path, 'char_maps.json'), 'w') as outfile: From 6ef925f4de6604f014f784ce52d4d4caa0353aa3 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 30 Apr 2024 06:43:10 +0200 Subject: [PATCH 3/8] Dynamically get component classes from tespy.components module level --- src/tespy/networks/network_reader.py | 100 ++++++++------------------- 1 file changed, 29 insertions(+), 71 deletions(-) diff --git a/src/tespy/networks/network_reader.py b/src/tespy/networks/network_reader.py index bcc22b34a..9aa14493d 100644 --- a/src/tespy/networks/network_reader.py +++ b/src/tespy/networks/network_reader.py @@ -12,35 +12,10 @@ SPDX-License-Identifier: MIT """ +import importlib import json import os -import pandas as pd - -from tespy.components import CombustionChamber -from tespy.components import CombustionEngine -from tespy.components import Compressor -from tespy.components import Condenser -from tespy.components import CycleCloser -from tespy.components import Desuperheater -from tespy.components import DropletSeparator -from tespy.components import Drum -from tespy.components import HeatExchanger -from tespy.components import HeatExchangerSimple -from tespy.components import Merge -from tespy.components import ParabolicTrough -from tespy.components import Pipe -from tespy.components import Pump -from tespy.components import Separator -from tespy.components import SimpleHeatExchanger -from tespy.components import Sink -from tespy.components import SolarCollector -from tespy.components import Source -from tespy.components import Splitter -from tespy.components import SubsystemInterface -from tespy.components import Turbine -from tespy.components import Valve -from tespy.components import WaterElectrolyzer from tespy.connections import Bus from tespy.connections import Connection from tespy.connections import Ref @@ -52,43 +27,14 @@ from tespy.tools.data_containers import ComponentCharacteristics as dc_cc from tespy.tools.data_containers import DataContainer as dc from tespy.tools.data_containers import FluidProperties as dc_prop -from tespy.tools.fluid_properties.wrappers import CoolPropWrapper -from tespy.tools.fluid_properties.wrappers import IAPWSWrapper -from tespy.tools.fluid_properties.wrappers import PyromatWrapper from tespy.tools.helpers import modify_path_os -COMP_TARGET_CLASSES = { - 'CycleCloser': CycleCloser, - 'Sink': Sink, - 'Source': Source, - 'SubsystemInterface': SubsystemInterface, - 'CombustionChamber': CombustionChamber, - 'CombustionEngine': CombustionEngine, - 'Condenser': Condenser, - 'Desuperheater': Desuperheater, - 'HeatExchanger': HeatExchanger, - 'HeatExchangerSimple': HeatExchangerSimple, - 'SimpleHeatExchanger': SimpleHeatExchanger, - 'SolarCollector': SolarCollector, - 'ParabolicTrough': ParabolicTrough, - 'DropletSeparator': DropletSeparator, - 'Drum': Drum, - 'Merge': Merge, - 'Separator': Separator, - 'Splitter': Splitter, - 'Pipe': Pipe, - 'Valve': Valve, - 'WaterElectrolyzer': WaterElectrolyzer, - 'Compressor': Compressor, - 'Pump': Pump, - 'Turbine': Turbine -} - -ENGINE_TARGET_CLASSES = { - "CoolPropWrapper": CoolPropWrapper, - "IAPWSWrapper": IAPWSWrapper, - "PyromatWrapper": PyromatWrapper, -} + +COMPONENTS_MODULE_NAME = "tespy.components" +COMPONENTS_MODULE = importlib.import_module(COMPONENTS_MODULE_NAME) +WRAPPER_MODULE_NAME = "tespy.tools.fluid_properties.wrappers" +WRAPPER_MODULE = importlib.import_module(WRAPPER_MODULE_NAME) + def load_network(path): r""" @@ -256,13 +202,14 @@ def load_network(path): with open(path_comps + f, "r", encoding="utf-8") as c: data = json.load(c) - comps.update(construct_components(component, data)) + target_class = _get_target_class(component, COMPONENTS_MODULE_NAME, COMPONENTS_MODULE) + comps.update(_construct_components(target_class, data)) msg = 'Created network components.' logger.info(msg) # create network - nw = construct_network(path) + nw = _construct_network(path) # load connections fn = path + 'connections.json' @@ -272,7 +219,7 @@ def load_network(path): with open(fn, "r", encoding="utf-8") as c: data = json.load(c) - conns = construct_connections(data, comps) + conns = _construct_connections(data, comps) # add connections to network for c in conns.values(): @@ -291,7 +238,7 @@ def load_network(path): with open(fn, "r", encoding="utf-8") as c: data = json.load(c) - busses = construct_busses(data, comps) + busses = _construct_busses(data, comps) # add busses to network for b in busses.values(): nw.add_busses(b) @@ -311,7 +258,18 @@ def load_network(path): return nw -def construct_components(component, data): +def _get_target_class(class_name, module_name, module): + if hasattr(module, class_name): + return getattr(module, class_name) + else: + msg = ( + f"The class {class_name} is not availble as import in the " + f"{module_name} module." + ) + logger.warning(msg) + + +def _construct_components(target_class, data): r""" Create TESPy component from class name and set parameters. @@ -328,7 +286,6 @@ def construct_components(component, data): dict Dictionary of all components of the specified type. """ - target_class = COMP_TARGET_CLASSES[component] instances = {} for cp, cp_data in data.items(): instances[cp] = target_class(cp) @@ -348,7 +305,7 @@ def construct_components(component, data): return instances -def construct_network(path): +def _construct_network(path): r""" Create TESPy network from the path provided by the user. @@ -370,7 +327,7 @@ def construct_network(path): return Network(**data) -def construct_connections(data, comps): +def _construct_connections(data, comps): r""" Create TESPy connection from data in the .json-file and its parameters. @@ -409,7 +366,8 @@ def construct_connections(data, comps): conns[label].set_attr(**{arg: conn[arg]}) for f, engine in conn["fluid"]["engine"].items(): - conn["fluid"]["engine"][f] = ENGINE_TARGET_CLASSES[engine] + target_class = _get_target_class(engine, WRAPPER_MODULE_NAME, WRAPPER_MODULE) + conn["fluid"]["engine"][f] = target_class conns[label].fluid.set_attr(**conn["fluid"]) conns[label]._create_fluid_wrapper() @@ -424,7 +382,7 @@ def construct_connections(data, comps): return conns -def construct_busses(data, comps): +def _construct_busses(data, comps): r""" Create busses of the network. From 4acedc26789d439f140dacc4d476fe74833471cb Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 30 Apr 2024 07:49:18 +0200 Subject: [PATCH 4/8] Fix styling issues --- src/tespy/networks/network_reader.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/tespy/networks/network_reader.py b/src/tespy/networks/network_reader.py index 9aa14493d..c1080ef3b 100644 --- a/src/tespy/networks/network_reader.py +++ b/src/tespy/networks/network_reader.py @@ -30,12 +30,6 @@ from tespy.tools.helpers import modify_path_os -COMPONENTS_MODULE_NAME = "tespy.components" -COMPONENTS_MODULE = importlib.import_module(COMPONENTS_MODULE_NAME) -WRAPPER_MODULE_NAME = "tespy.tools.fluid_properties.wrappers" -WRAPPER_MODULE = importlib.import_module(WRAPPER_MODULE_NAME) - - def load_network(path): r""" Load a network from a base path. @@ -191,6 +185,9 @@ def load_network(path): # load components comps = {} + module_name = "tespy.components" + module = importlib.import_module(module_name) + files = os.listdir(path_comps) for f in files: fn = path_comps + f @@ -202,7 +199,7 @@ def load_network(path): with open(path_comps + f, "r", encoding="utf-8") as c: data = json.load(c) - target_class = _get_target_class(component, COMPONENTS_MODULE_NAME, COMPONENTS_MODULE) + target_class = _get_target_class(component, module_name, module) comps.update(_construct_components(target_class, data)) msg = 'Created network components.' @@ -352,6 +349,10 @@ def _construct_connections(data, comps): and "ref" not in _ ] arglist_ref = [_ for _ in data[list(data.keys())[0]] if "ref" in _] + + module_name = "tespy.tools.fluid_properties.wrappers" + module = importlib.import_module(module_name) + for label, conn in data.items(): conns[label] = Connection( comps[conn["source"]], conn["source_id"], @@ -366,7 +367,7 @@ def _construct_connections(data, comps): conns[label].set_attr(**{arg: conn[arg]}) for f, engine in conn["fluid"]["engine"].items(): - target_class = _get_target_class(engine, WRAPPER_MODULE_NAME, WRAPPER_MODULE) + target_class = _get_target_class(engine, module_name, module) conn["fluid"]["engine"][f] = target_class conns[label].fluid.set_attr(**conn["fluid"]) @@ -376,7 +377,11 @@ def _construct_connections(data, comps): for arg in arglist_ref: if len(conn[arg]) > 0: param = arg.replace("_ref", "") - ref = Ref(conns[conn[arg]["conn"]], conn[arg]["factor"], conn[arg]["delta"]) + ref = Ref( + conns[conn[arg]["conn"]], + conn[arg]["factor"], + conn[arg]["delta"] + ) conns[label].set_attr(**{param: ref}) return conns From 245776e425a5c87d13496e8899033eb4c3c98951 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 30 Apr 2024 17:31:55 +0200 Subject: [PATCH 5/8] Use decorators to register component classes --- src/tespy/components/basics/cycle_closer.py | 4 ++-- src/tespy/components/basics/sink.py | 2 ++ src/tespy/components/basics/source.py | 2 ++ src/tespy/components/basics/subsystem_interface.py | 2 ++ src/tespy/components/combustion/base.py | 2 ++ src/tespy/components/combustion/diabatic.py | 2 ++ src/tespy/components/combustion/engine.py | 4 +++- src/tespy/components/component.py | 9 +++++++++ src/tespy/components/heat_exchangers/base.py | 2 ++ src/tespy/components/heat_exchangers/condenser.py | 2 ++ src/tespy/components/heat_exchangers/desuperheater.py | 2 ++ src/tespy/components/heat_exchangers/parabolic_trough.py | 5 ++--- src/tespy/components/heat_exchangers/simple.py | 2 ++ src/tespy/components/heat_exchangers/solar_collector.py | 5 ++--- src/tespy/components/nodes/base.py | 4 ++-- src/tespy/components/nodes/droplet_separator.py | 3 +++ src/tespy/components/nodes/drum.py | 2 ++ src/tespy/components/nodes/merge.py | 2 ++ src/tespy/components/nodes/separator.py | 4 ++-- src/tespy/components/nodes/splitter.py | 4 ++-- src/tespy/components/piping/pipe.py | 2 ++ src/tespy/components/piping/valve.py | 2 ++ src/tespy/components/reactors/fuel_cell.py | 3 ++- src/tespy/components/reactors/water_electrolyzer.py | 4 ++-- src/tespy/components/turbomachinery/base.py | 2 ++ src/tespy/components/turbomachinery/compressor.py | 2 ++ src/tespy/components/turbomachinery/pump.py | 2 ++ src/tespy/components/turbomachinery/turbine.py | 3 ++- src/tespy/networks/network_reader.py | 3 ++- 29 files changed, 67 insertions(+), 20 deletions(-) diff --git a/src/tespy/components/basics/cycle_closer.py b/src/tespy/components/basics/cycle_closer.py index 23aba26da..4d761324c 100644 --- a/src/tespy/components/basics/cycle_closer.py +++ b/src/tespy/components/basics/cycle_closer.py @@ -13,11 +13,11 @@ import numpy as np from tespy.components.component import Component +from tespy.components.component import component_registry from tespy.tools.data_containers import ComponentProperties as dc_cp -# %% - +@component_registry class CycleCloser(Component): r""" Component for closing cycles. diff --git a/src/tespy/components/basics/sink.py b/src/tespy/components/basics/sink.py index 3f3d531c9..d871698c3 100644 --- a/src/tespy/components/basics/sink.py +++ b/src/tespy/components/basics/sink.py @@ -13,8 +13,10 @@ import numpy as np from tespy.components.component import Component +from tespy.components.component import component_registry +@component_registry class Sink(Component): r""" A flow drains in a Sink. diff --git a/src/tespy/components/basics/source.py b/src/tespy/components/basics/source.py index 35719fa34..893a91ee8 100644 --- a/src/tespy/components/basics/source.py +++ b/src/tespy/components/basics/source.py @@ -15,6 +15,8 @@ from tespy.components.component import Component +from tespy.components.component import component_registry +@component_registry class Source(Component): r""" A flow originates from a Source. diff --git a/src/tespy/components/basics/subsystem_interface.py b/src/tespy/components/basics/subsystem_interface.py index be0d433ca..86a43af5d 100644 --- a/src/tespy/components/basics/subsystem_interface.py +++ b/src/tespy/components/basics/subsystem_interface.py @@ -12,9 +12,11 @@ """ from tespy.components.component import Component +from tespy.components.component import component_registry from tespy.tools.data_containers import SimpleDataContainer as dc_simple +@component_registry class SubsystemInterface(Component): r""" The subsystem interface does not change fluid properties. diff --git a/src/tespy/components/combustion/base.py b/src/tespy/components/combustion/base.py index b11151b84..baf43a83a 100644 --- a/src/tespy/components/combustion/base.py +++ b/src/tespy/components/combustion/base.py @@ -16,6 +16,7 @@ import numpy as np from tespy.components.component import Component +from tespy.components.component import component_registry from tespy.tools import logger from tespy.tools.data_containers import ComponentProperties as dc_cp from tespy.tools.document_models import generate_latex_eq @@ -27,6 +28,7 @@ from tespy.tools.helpers import fluidalias_in_list +@component_registry class CombustionChamber(Component): r""" The class CombustionChamber is parent class of all combustion components. diff --git a/src/tespy/components/combustion/diabatic.py b/src/tespy/components/combustion/diabatic.py index 5f26f6880..a7f9945f4 100644 --- a/src/tespy/components/combustion/diabatic.py +++ b/src/tespy/components/combustion/diabatic.py @@ -14,12 +14,14 @@ import numpy as np from tespy.components import CombustionChamber +from tespy.components.component import component_registry from tespy.tools import logger from tespy.tools.data_containers import ComponentProperties as dc_cp from tespy.tools.document_models import generate_latex_eq from tespy.tools.fluid_properties import h_mix_pT +@component_registry class DiabaticCombustionChamber(CombustionChamber): r""" The class CombustionChamber is parent class of all combustion components. diff --git a/src/tespy/components/combustion/engine.py b/src/tespy/components/combustion/engine.py index aa4661371..47d7d3501 100644 --- a/src/tespy/components/combustion/engine.py +++ b/src/tespy/components/combustion/engine.py @@ -10,19 +10,21 @@ SPDX-License-Identifier: MIT """ + import numpy as np from tespy.components.combustion.base import CombustionChamber +from tespy.components.component import component_registry from tespy.tools import logger from tespy.tools.data_containers import ComponentCharacteristics as dc_cc from tespy.tools.data_containers import ComponentProperties as dc_cp from tespy.tools.data_containers import SimpleDataContainer as dc_simple from tespy.tools.document_models import generate_latex_eq -from tespy.tools.fluid_properties import h_mix_pT from tespy.tools.fluid_properties import s_mix_ph from tespy.tools.fluid_properties import s_mix_pT +@component_registry class CombustionEngine(CombustionChamber): r""" An internal combustion engine supplies power and heat cogeneration. diff --git a/src/tespy/components/component.py b/src/tespy/components/component.py index 4e5937786..8f6f16ca4 100644 --- a/src/tespy/components/component.py +++ b/src/tespy/components/component.py @@ -33,6 +33,15 @@ from tespy.tools.helpers import newton_with_kwargs +def component_registry(type): + component_registry.items[type.__name__] = type + return type + + +component_registry.items = {} + + +@component_registry class Component: r""" Class Component is the base class of all TESPy components. diff --git a/src/tespy/components/heat_exchangers/base.py b/src/tespy/components/heat_exchangers/base.py index 5ad36b254..65f6adec9 100644 --- a/src/tespy/components/heat_exchangers/base.py +++ b/src/tespy/components/heat_exchangers/base.py @@ -13,6 +13,7 @@ import numpy as np from tespy.components.component import Component +from tespy.components.component import component_registry from tespy.tools.data_containers import ComponentCharacteristics as dc_cc from tespy.tools.data_containers import ComponentProperties as dc_cp from tespy.tools.data_containers import GroupedComponentCharacteristics as dc_gcc @@ -21,6 +22,7 @@ from tespy.tools.fluid_properties import s_mix_ph +@component_registry class HeatExchanger(Component): r""" Class for counter current heat exchanger. diff --git a/src/tespy/components/heat_exchangers/condenser.py b/src/tespy/components/heat_exchangers/condenser.py index 377660332..32bd77ef6 100644 --- a/src/tespy/components/heat_exchangers/condenser.py +++ b/src/tespy/components/heat_exchangers/condenser.py @@ -13,6 +13,7 @@ import numpy as np +from tespy.components.component import component_registry from tespy.components.heat_exchangers.base import HeatExchanger from tespy.tools.data_containers import ComponentCharacteristics as dc_cc from tespy.tools.data_containers import ComponentProperties as dc_cp @@ -23,6 +24,7 @@ from tespy.tools.fluid_properties import h_mix_pQ +@component_registry class Condenser(HeatExchanger): r""" A Condenser cools a fluid until it is in liquid state. diff --git a/src/tespy/components/heat_exchangers/desuperheater.py b/src/tespy/components/heat_exchangers/desuperheater.py index f69db8eb5..172adf67d 100644 --- a/src/tespy/components/heat_exchangers/desuperheater.py +++ b/src/tespy/components/heat_exchangers/desuperheater.py @@ -11,12 +11,14 @@ SPDX-License-Identifier: MIT """ +from tespy.components.component import component_registry from tespy.components.heat_exchangers.base import HeatExchanger from tespy.tools.document_models import generate_latex_eq from tespy.tools.fluid_properties import dh_mix_dpQ from tespy.tools.fluid_properties import h_mix_pQ +@component_registry class Desuperheater(HeatExchanger): r""" The Desuperheater cools a fluid to the saturated gas state. diff --git a/src/tespy/components/heat_exchangers/parabolic_trough.py b/src/tespy/components/heat_exchangers/parabolic_trough.py index 1b948ae7e..fd8c0e005 100644 --- a/src/tespy/components/heat_exchangers/parabolic_trough.py +++ b/src/tespy/components/heat_exchangers/parabolic_trough.py @@ -11,15 +11,14 @@ SPDX-License-Identifier: MIT """ -import numpy as np - +from tespy.components.component import component_registry from tespy.components.heat_exchangers.simple import SimpleHeatExchanger from tespy.tools.data_containers import ComponentProperties as dc_cp from tespy.tools.data_containers import GroupedComponentProperties as dc_gcp -from tespy.tools.data_containers import SimpleDataContainer as dc_simple from tespy.tools.document_models import generate_latex_eq +@component_registry class ParabolicTrough(SimpleHeatExchanger): r""" The ParabolicTrough calculates heat output from irradiance. diff --git a/src/tespy/components/heat_exchangers/simple.py b/src/tespy/components/heat_exchangers/simple.py index a9e555079..8615d644a 100644 --- a/src/tespy/components/heat_exchangers/simple.py +++ b/src/tespy/components/heat_exchangers/simple.py @@ -16,6 +16,7 @@ import numpy as np from tespy.components.component import Component +from tespy.components.component import component_registry from tespy.tools import logger from tespy.tools.data_containers import ComponentCharacteristics as dc_cc from tespy.tools.data_containers import ComponentProperties as dc_cp @@ -27,6 +28,7 @@ from tespy.tools.helpers import convert_to_SI +@component_registry class SimpleHeatExchanger(Component): r""" A basic heat exchanger representing a heat source or heat sink. diff --git a/src/tespy/components/heat_exchangers/solar_collector.py b/src/tespy/components/heat_exchangers/solar_collector.py index 7129bd5c6..6dc2e89bd 100644 --- a/src/tespy/components/heat_exchangers/solar_collector.py +++ b/src/tespy/components/heat_exchangers/solar_collector.py @@ -11,15 +11,14 @@ SPDX-License-Identifier: MIT """ -import numpy as np - +from tespy.components.component import component_registry from tespy.components.heat_exchangers.simple import SimpleHeatExchanger from tespy.tools.data_containers import ComponentProperties as dc_cp from tespy.tools.data_containers import GroupedComponentProperties as dc_gcp -from tespy.tools.data_containers import SimpleDataContainer as dc_simple from tespy.tools.document_models import generate_latex_eq +@component_registry class SolarCollector(SimpleHeatExchanger): r""" The solar collector calculates heat output from irradiance. diff --git a/src/tespy/components/nodes/base.py b/src/tespy/components/nodes/base.py index 55a22b82d..51e0be004 100644 --- a/src/tespy/components/nodes/base.py +++ b/src/tespy/components/nodes/base.py @@ -10,12 +10,12 @@ SPDX-License-Identifier: MIT """ -import numpy as np - from tespy.components.component import Component +from tespy.components.component import component_registry from tespy.tools.document_models import generate_latex_eq +@component_registry class NodeBase(Component): """Class NodeBase is parent class for all components of submodule nodes.""" diff --git a/src/tespy/components/nodes/droplet_separator.py b/src/tespy/components/nodes/droplet_separator.py index 9bed7a934..6307345a1 100644 --- a/src/tespy/components/nodes/droplet_separator.py +++ b/src/tespy/components/nodes/droplet_separator.py @@ -10,12 +10,15 @@ SPDX-License-Identifier: MIT """ + +from tespy.components.component import component_registry from tespy.components.nodes.base import NodeBase from tespy.tools.document_models import generate_latex_eq from tespy.tools.fluid_properties import dh_mix_dpQ from tespy.tools.fluid_properties import h_mix_pQ +@component_registry class DropletSeparator(NodeBase): r""" Separate liquid phase from gas phase of a single fluid. diff --git a/src/tespy/components/nodes/drum.py b/src/tespy/components/nodes/drum.py index dc48d5397..598fa0914 100644 --- a/src/tespy/components/nodes/drum.py +++ b/src/tespy/components/nodes/drum.py @@ -12,10 +12,12 @@ import numpy as np +from tespy.components.component import component_registry from tespy.components.nodes.droplet_separator import DropletSeparator from tespy.tools.fluid_properties import h_mix_pQ +@component_registry class Drum(DropletSeparator): r""" A drum separates saturated gas from saturated liquid. diff --git a/src/tespy/components/nodes/merge.py b/src/tespy/components/nodes/merge.py index b3b286cb2..be8570fd5 100644 --- a/src/tespy/components/nodes/merge.py +++ b/src/tespy/components/nodes/merge.py @@ -12,12 +12,14 @@ import numpy as np +from tespy.components.component import component_registry from tespy.components.nodes.base import NodeBase from tespy.tools.data_containers import SimpleDataContainer as dc_simple from tespy.tools.document_models import generate_latex_eq from tespy.tools.fluid_properties import s_mix_pT +@component_registry class Merge(NodeBase): r""" Class for merge points with multiple inflows and one outflow. diff --git a/src/tespy/components/nodes/separator.py b/src/tespy/components/nodes/separator.py index bf8a7be85..16369fa40 100644 --- a/src/tespy/components/nodes/separator.py +++ b/src/tespy/components/nodes/separator.py @@ -10,8 +10,7 @@ SPDX-License-Identifier: MIT """ -import numpy as np - +from tespy.components.component import component_registry from tespy.components.nodes.base import NodeBase from tespy.tools.data_containers import SimpleDataContainer as dc_simple from tespy.tools.document_models import generate_latex_eq @@ -21,6 +20,7 @@ # from tespy.tools.fluid_properties import dT_mix_ph_dfluid +@component_registry class Separator(NodeBase): r""" A separator separates fluid components from a mass flow. diff --git a/src/tespy/components/nodes/splitter.py b/src/tespy/components/nodes/splitter.py index ed774a076..18faa3411 100644 --- a/src/tespy/components/nodes/splitter.py +++ b/src/tespy/components/nodes/splitter.py @@ -10,13 +10,13 @@ SPDX-License-Identifier: MIT """ -import numpy as np - +from tespy.components.component import component_registry from tespy.components.nodes.base import NodeBase from tespy.tools.data_containers import SimpleDataContainer as dc_simple from tespy.tools.document_models import generate_latex_eq +@component_registry class Splitter(NodeBase): r""" Split up a mass flow in parts of identical enthalpy and fluid composition. diff --git a/src/tespy/components/piping/pipe.py b/src/tespy/components/piping/pipe.py index fb575b437..7b58f8c88 100644 --- a/src/tespy/components/piping/pipe.py +++ b/src/tespy/components/piping/pipe.py @@ -10,9 +10,11 @@ SPDX-License-Identifier: MIT """ +from tespy.components.component import component_registry from tespy.components.heat_exchangers.simple import SimpleHeatExchanger +@component_registry class Pipe(SimpleHeatExchanger): r""" The Pipe is a subclass of a SimpleHeatExchanger. diff --git a/src/tespy/components/piping/valve.py b/src/tespy/components/piping/valve.py index 723e1d829..2365d5fdd 100644 --- a/src/tespy/components/piping/valve.py +++ b/src/tespy/components/piping/valve.py @@ -13,12 +13,14 @@ import numpy as np from tespy.components.component import Component +from tespy.components.component import component_registry from tespy.tools import logger from tespy.tools.data_containers import ComponentCharacteristics as dc_cc from tespy.tools.data_containers import ComponentProperties as dc_cp from tespy.tools.document_models import generate_latex_eq +@component_registry class Valve(Component): r""" The Valve throttles a fluid without changing enthalpy. diff --git a/src/tespy/components/reactors/fuel_cell.py b/src/tespy/components/reactors/fuel_cell.py index fe0198bcc..a8cdf577d 100644 --- a/src/tespy/components/reactors/fuel_cell.py +++ b/src/tespy/components/reactors/fuel_cell.py @@ -10,15 +10,16 @@ SPDX-License-Identifier: MIT """ -import numpy as np from tespy.components.component import Component +from tespy.components.component import component_registry from tespy.tools import logger from tespy.tools.data_containers import ComponentProperties as dc_cp from tespy.tools.document_models import generate_latex_eq from tespy.tools.fluid_properties import h_mix_pT +@component_registry class FuelCell(Component): r""" The fuel cell produces power by oxidation of hydrogen. diff --git a/src/tespy/components/reactors/water_electrolyzer.py b/src/tespy/components/reactors/water_electrolyzer.py index e93d87a9a..76a83f0a9 100644 --- a/src/tespy/components/reactors/water_electrolyzer.py +++ b/src/tespy/components/reactors/water_electrolyzer.py @@ -11,9 +11,8 @@ SPDX-License-Identifier: MIT """ -import numpy as np - from tespy.components.component import Component +from tespy.components.component import component_registry from tespy.tools import logger from tespy.tools.data_containers import ComponentCharacteristics as dc_cc from tespy.tools.data_containers import ComponentProperties as dc_cp @@ -23,6 +22,7 @@ from tespy.tools.fluid_properties import h_mix_pT +@component_registry class WaterElectrolyzer(Component): r""" The water electrolyzer produces hydrogen and oxygen from water and power. diff --git a/src/tespy/components/turbomachinery/base.py b/src/tespy/components/turbomachinery/base.py index a944c8e71..03168da07 100644 --- a/src/tespy/components/turbomachinery/base.py +++ b/src/tespy/components/turbomachinery/base.py @@ -12,10 +12,12 @@ """ from tespy.components.component import Component +from tespy.components.component import component_registry from tespy.tools.data_containers import ComponentProperties as dc_cp from tespy.tools.document_models import generate_latex_eq +@component_registry class Turbomachine(Component): r""" Parent class for compressor, pump and turbine. diff --git a/src/tespy/components/turbomachinery/compressor.py b/src/tespy/components/turbomachinery/compressor.py index 5c7668d92..ede12ac80 100644 --- a/src/tespy/components/turbomachinery/compressor.py +++ b/src/tespy/components/turbomachinery/compressor.py @@ -13,6 +13,7 @@ import numpy as np +from tespy.components.component import component_registry from tespy.components.turbomachinery.base import Turbomachine from tespy.tools import logger from tespy.tools.data_containers import ComponentCharacteristicMaps as dc_cm @@ -23,6 +24,7 @@ from tespy.tools.fluid_properties import isentropic +@component_registry class Compressor(Turbomachine): r""" Class for axial or radial compressor. diff --git a/src/tespy/components/turbomachinery/pump.py b/src/tespy/components/turbomachinery/pump.py index 2fd0568f8..87b10c597 100644 --- a/src/tespy/components/turbomachinery/pump.py +++ b/src/tespy/components/turbomachinery/pump.py @@ -12,6 +12,7 @@ import numpy as np +from tespy.components.component import component_registry from tespy.components.turbomachinery.base import Turbomachine from tespy.tools import logger from tespy.tools.data_containers import ComponentCharacteristics as dc_cc @@ -20,6 +21,7 @@ from tespy.tools.fluid_properties import isentropic +@component_registry class Pump(Turbomachine): r""" Class for axial or radial pumps. diff --git a/src/tespy/components/turbomachinery/turbine.py b/src/tespy/components/turbomachinery/turbine.py index 8995e265d..be292eac7 100644 --- a/src/tespy/components/turbomachinery/turbine.py +++ b/src/tespy/components/turbomachinery/turbine.py @@ -10,9 +10,9 @@ SPDX-License-Identifier: MIT """ - import numpy as np +from tespy.components.component import component_registry from tespy.components.turbomachinery.base import Turbomachine from tespy.tools import logger from tespy.tools.data_containers import ComponentCharacteristics as dc_cc @@ -22,6 +22,7 @@ from tespy.tools.fluid_properties import isentropic +@component_registry class Turbine(Turbomachine): r""" Class for gas or steam turbines. diff --git a/src/tespy/networks/network_reader.py b/src/tespy/networks/network_reader.py index c1080ef3b..5d487f333 100644 --- a/src/tespy/networks/network_reader.py +++ b/src/tespy/networks/network_reader.py @@ -16,6 +16,7 @@ import json import os +from tespy.components.component import component_registry from tespy.connections import Bus from tespy.connections import Connection from tespy.connections import Ref @@ -199,7 +200,7 @@ def load_network(path): with open(path_comps + f, "r", encoding="utf-8") as c: data = json.load(c) - target_class = _get_target_class(component, module_name, module) + target_class = component_registry.items[component] comps.update(_construct_components(target_class, data)) msg = 'Created network components.' From 5d8e2b506f5fbbc73753c836e5662f8ebe3f0e5a Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 30 Apr 2024 17:35:31 +0200 Subject: [PATCH 6/8] Add wrapper registry --- src/tespy/components/basics/source.py | 2 +- src/tespy/networks/network_reader.py | 15 ++------------- src/tespy/tools/fluid_properties/wrappers.py | 12 ++++++++++++ 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/tespy/components/basics/source.py b/src/tespy/components/basics/source.py index 893a91ee8..56536846d 100644 --- a/src/tespy/components/basics/source.py +++ b/src/tespy/components/basics/source.py @@ -13,9 +13,9 @@ import numpy as np from tespy.components.component import Component +from tespy.components.component import component_registry -from tespy.components.component import component_registry @component_registry class Source(Component): r""" diff --git a/src/tespy/networks/network_reader.py b/src/tespy/networks/network_reader.py index 5d487f333..ea6260cc6 100644 --- a/src/tespy/networks/network_reader.py +++ b/src/tespy/networks/network_reader.py @@ -28,6 +28,7 @@ from tespy.tools.data_containers import ComponentCharacteristics as dc_cc from tespy.tools.data_containers import DataContainer as dc from tespy.tools.data_containers import FluidProperties as dc_prop +from tespy.tools.fluid_properties.wrappers import wrapper_registry from tespy.tools.helpers import modify_path_os @@ -256,17 +257,6 @@ def load_network(path): return nw -def _get_target_class(class_name, module_name, module): - if hasattr(module, class_name): - return getattr(module, class_name) - else: - msg = ( - f"The class {class_name} is not availble as import in the " - f"{module_name} module." - ) - logger.warning(msg) - - def _construct_components(target_class, data): r""" Create TESPy component from class name and set parameters. @@ -368,8 +358,7 @@ def _construct_connections(data, comps): conns[label].set_attr(**{arg: conn[arg]}) for f, engine in conn["fluid"]["engine"].items(): - target_class = _get_target_class(engine, module_name, module) - conn["fluid"]["engine"][f] = target_class + conn["fluid"]["engine"][f] = wrapper_registry.items[engine] conns[label].fluid.set_attr(**conn["fluid"]) conns[label]._create_fluid_wrapper() diff --git a/src/tespy/tools/fluid_properties/wrappers.py b/src/tespy/tools/fluid_properties/wrappers.py index 565c98bf4..6c298d54f 100644 --- a/src/tespy/tools/fluid_properties/wrappers.py +++ b/src/tespy/tools/fluid_properties/wrappers.py @@ -16,6 +16,14 @@ from tespy.tools.global_vars import ERR +def wrapper_registry(type): + wrapper_registry.items[type.__name__] = type + return type + + +wrapper_registry.items = {} + + class SerializableAbstractState(CP.AbstractState): def __init__(self, back_end, fluid_name): @@ -26,6 +34,7 @@ def __reduce__(self): return (self.__class__, (self.back_end, self.fluid_name)) +@wrapper_registry class FluidPropertyWrapper: def __init__(self, fluid, back_end=None) -> None: @@ -106,6 +115,7 @@ def s_pT(self, p, T): self._not_implemented() +@wrapper_registry class CoolPropWrapper(FluidPropertyWrapper): def __init__(self, fluid, back_end=None) -> None: @@ -248,6 +258,7 @@ def s_pT(self, p, T): return self.AS.smass() +@wrapper_registry class IAPWSWrapper(FluidPropertyWrapper): @@ -366,6 +377,7 @@ def s_pT(self, p, T): return self.AS(P=p / 1e6, T=T).s * 1e3 +@wrapper_registry class PyromatWrapper(FluidPropertyWrapper): def __init__(self, fluid, back_end=None) -> None: From 76dac6322837c3a93653b2d8506f86fb4d567b69 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 30 Apr 2024 18:03:18 +0200 Subject: [PATCH 7/8] Update What's New --- docs/whats_new.rst | 1 + docs/whats_new/v0-7-4.rst | 41 ++++++++++++++++++++++++++++ src/tespy/networks/network_reader.py | 9 +++--- 3 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 docs/whats_new/v0-7-4.rst diff --git a/docs/whats_new.rst b/docs/whats_new.rst index 32ee21fa7..5d6796f1a 100644 --- a/docs/whats_new.rst +++ b/docs/whats_new.rst @@ -3,6 +3,7 @@ What's New Discover notable new features and improvements in each release +.. include:: whats_new/v0-7-4.rst .. include:: whats_new/v0-7-3.rst .. include:: whats_new/v0-7-2.rst .. include:: whats_new/v0-7-1.rst diff --git a/docs/whats_new/v0-7-4.rst b/docs/whats_new/v0-7-4.rst new file mode 100644 index 000000000..9bb8431f9 --- /dev/null +++ b/docs/whats_new/v0-7-4.rst @@ -0,0 +1,41 @@ +v0.7.4 - Newton's Nature (April, 30, 2024) +++++++++++++++++++++++++++++++++++++++++++ + +Bug Fixes +######### +- :code:`Component` and :code:`FluidWrapper` objects are now available for the + :code:`load_network` function via the :code:`@component_registry` and + :code:`@wrapper_registry` decorators. E.g. if you are using custom components + you can decorate them with the :code:`@component_registry` and the load a + :code:`Network` with those components without needing to adjust the source + code of the :code:`load_network` function + (`PR #510 `__). + + .. code-block:: python + + >>> from tespy.components.component import component_registry + >>> from tespy.components import Source, Sink, SimpleHeatExchanger + >>> from tespy.connections import Connection + >>> from tespy.networks import Network, load_network + + >>> @component_registry + ... class MyComponent(SimpleHeatExchanger): + ... pass + + >>> c = component_registry.items["MyComponent"]("I am a component") + >>> c.label + 'I am a component' + + >>> nwk = Network() + >>> c1 = Connection(Source("source"), "out1", c, "in1", label="1") + >>> c2 = Connection(c, "out1", Sink("sink"), "in1", label="2") + >>> nwk.add_conns(c1, c2) + >>> nwk.export("exported_nwk") + >>> nwk = load_network("exported_nwk") + >>> nwk.comps.loc["I am a component", "comp_type"] + 'MyComponent' + +Contributors +############ +- Francesco Witte (`@fwitte `__) +- `@jfreissmann `__ diff --git a/src/tespy/networks/network_reader.py b/src/tespy/networks/network_reader.py index ea6260cc6..c69cb1197 100644 --- a/src/tespy/networks/network_reader.py +++ b/src/tespy/networks/network_reader.py @@ -280,10 +280,11 @@ def _construct_components(target_class, data): for param, param_data in cp_data.items(): container = instances[cp].get_attr(param) if isinstance(container, dc): - if isinstance(container, dc_cc): - param_data["char_func"] = CharLine(**param_data["char_func"]) - elif isinstance(container, dc_cm): - param_data["char_func"] = CharMap(**param_data["char_func"]) + if "char_func" in param_data: + if isinstance(container, dc_cc): + param_data["char_func"] = CharLine(**param_data["char_func"]) + elif isinstance(container, dc_cm): + param_data["char_func"] = CharMap(**param_data["char_func"]) if isinstance(container, dc_prop): param_data["val0"] = param_data["val"] container.set_attr(**param_data) From dad4f8097fa5597e6b973c0fbf90a68792060aca Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Tue, 30 Apr 2024 18:09:08 +0200 Subject: [PATCH 8/8] Bump version --- pyproject.toml | 2 +- src/tespy/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3f0de59ed..dd3340450 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ exclude = ["docs/_build"] [project] name = "tespy" -version = "0.7.3" +version = "0.7.4" description = "Thermal Engineering Systems in Python (TESPy)" readme = "README.rst" authors = [ diff --git a/src/tespy/__init__.py b/src/tespy/__init__.py index 5ba67599d..fa062803f 100644 --- a/src/tespy/__init__.py +++ b/src/tespy/__init__.py @@ -3,7 +3,7 @@ import os __datapath__ = os.path.join(importlib.resources.files("tespy"), "data") -__version__ = '0.7.3 - Newton\'s Nature' +__version__ = '0.7.4 - Newton\'s Nature' # tespy data and connections import from . import connections # noqa: F401