From bbb285ee9dc862cedf829703072b9e264be2154c Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 2 Dec 2023 11:05:32 +0100 Subject: [PATCH 1/5] Fix the mass flow and fluid topology simplification for multiprocessing --- .../heat_exchangers/desuperheater.py | 2 +- src/tespy/networks/network.py | 21 +++++++++++++-- src/tespy/tools/fluid_properties/wrappers.py | 12 ++++++++- tests/test_components/test_combustion.py | 2 -- tests/test_components/test_merge.py | 14 ---------- tests/test_components/test_reactors.py | 2 -- tutorial/advanced/optimization_example.py | 27 +++++++++++-------- 7 files changed, 47 insertions(+), 33 deletions(-) diff --git a/src/tespy/components/heat_exchangers/desuperheater.py b/src/tespy/components/heat_exchangers/desuperheater.py index dc3a60601..f69db8eb5 100644 --- a/src/tespy/components/heat_exchangers/desuperheater.py +++ b/src/tespy/components/heat_exchangers/desuperheater.py @@ -239,6 +239,6 @@ def saturated_gas_deriv(self, increment_filter, k): """ o = self.outl[0] if self.is_variable(o.p): - self.jacobian[k, o.p.J_col] = -dh_mix_dpQ(o, 1, o.fluid_data) + self.jacobian[k, o.p.J_col] = -dh_mix_dpQ(o.p.val_SI, 1, o.fluid_data) if self.is_variable(o.h): self.jacobian[k, o.h.J_col] = 1 diff --git a/src/tespy/networks/network.py b/src/tespy/networks/network.py index 405c0b2eb..3508aa4be 100644 --- a/src/tespy/networks/network.py +++ b/src/tespy/networks/network.py @@ -690,8 +690,6 @@ def check_network(self): self.check_conns() self.init_components() self.check_components() - self.create_massflow_and_fluid_branches() - self.create_fluid_wrapper_branches() # network checked self.checked = True @@ -847,6 +845,25 @@ def initialise(self): self.num_conn_vars = 0 self.variables_dict = {} + if hasattr(self, "massflow_branches"): + # in multiprocessing copies are made of all connections + # the mass flow branches and fluid branches hold references to + # connections from the original run (where network.checked is False) + # The assignment of variable spaces etc. is however made on the + # copies of the connections which do not correspond to the mass flow + # branches and fluid branches anymore. So the topology simplification + # does not actually apply to the copied network, therefore the + # branches have to be recreated for this case. We can detect that by + # checking whether a network holds a massflow branch with some + # connections and compare that with the connection object actually + # present in the network + first_conn = self.massflow_branches[0]["connections"][0] + if self.conns.loc[first_conn.label, "object"] != first_conn: + self.create_massflow_and_fluid_branches() + self.create_fluid_wrapper_branches() + else: + self.create_massflow_and_fluid_branches() + self.create_fluid_wrapper_branches() self.propagate_fluid_wrappers() self.presolve_massflow_topology() self.presolve_fluid_topology() diff --git a/src/tespy/tools/fluid_properties/wrappers.py b/src/tespy/tools/fluid_properties/wrappers.py index 97ce00647..bc2f84df7 100644 --- a/src/tespy/tools/fluid_properties/wrappers.py +++ b/src/tespy/tools/fluid_properties/wrappers.py @@ -16,6 +16,16 @@ from tespy.tools.global_vars import ERR +class SerializableAbstractState(CP.AbstractState): + + def __init__(self, back_end, fluid_name): + self.back_end = back_end + self.fluid_name = fluid_name + + def __reduce__(self): + return (self.__class__, (self.back_end, self.fluid_name)) + + class FluidPropertyWrapper: def __init__(self, fluid, back_end=None) -> None: @@ -112,7 +122,7 @@ def __init__(self, fluid, back_end=None) -> None: back_end = "HEOS" super().__init__(fluid, back_end) - self.AS = CP.CoolProp.AbstractState(self.back_end, self.fluid) + self.AS = SerializableAbstractState(self.back_end, self.fluid) self._set_constants() def _set_constants(self): diff --git a/tests/test_components/test_combustion.py b/tests/test_components/test_combustion.py index b26bcbafa..7912781fb 100644 --- a/tests/test_components/test_combustion.py +++ b/tests/test_components/test_combustion.py @@ -12,8 +12,6 @@ import shutil -import numpy as np - from tespy.components import CombustionChamber from tespy.components import CombustionEngine from tespy.components import DiabaticCombustionChamber diff --git a/tests/test_components/test_merge.py b/tests/test_components/test_merge.py index fcc6065f2..5b15783e6 100644 --- a/tests/test_components/test_merge.py +++ b/tests/test_components/test_merge.py @@ -119,17 +119,3 @@ def test_two_fluid_setup(self): target = c1.m.val_SI msg = f"Target value for mass flow at connection 3 is {target}" assert c6.m.val_SI == approx(target), msg - - -test = TestMerge() -test.setup_method() -test.test_single_fluid_at_outlet() -test.setup_method() -test.test_massflows_from_two_fluid_fractions() - - -test2 = TestCyclicMerging() -test2.setup_method() -test2.test_single_fluid_setup() -test2.setup_method() -test2.test_two_fluid_setup() diff --git a/tests/test_components/test_reactors.py b/tests/test_components/test_reactors.py index e20d1c8d0..ffdaae146 100644 --- a/tests/test_components/test_reactors.py +++ b/tests/test_components/test_reactors.py @@ -12,8 +12,6 @@ import shutil -import numpy as np - from tespy.components import Sink from tespy.components import Source from tespy.components import WaterElectrolyzer diff --git a/tutorial/advanced/optimization_example.py b/tutorial/advanced/optimization_example.py index ee1bbe336..e65314961 100644 --- a/tutorial/advanced/optimization_example.py +++ b/tutorial/advanced/optimization_example.py @@ -10,7 +10,6 @@ from tespy.components import SimpleHeatExchanger from tespy.components import Merge from tespy.components import Splitter -from tespy.components import Valve from tespy.components import Pump from tespy.components import Turbine from tespy.connections import Bus @@ -82,10 +81,7 @@ def __init__(self): c32 = Connection(fwh1, "out1", pu3, "in1", label="32") c33 = Connection(pu3, "out1", me, "in2", label="33") - self.nw.add_conns( - c21, c22, c23, c24, - c31, c32, c33 - ) + self.nw.add_conns(c21, c22, c23, c24, c31, c32, c33) # cooling water c41 = Connection(cwi, "out1", con, "in2", label="41") @@ -108,34 +104,43 @@ def __init__(self): self.nw.add_busses(self.power, self.heat) + self.set_design_values() # parametrization # components + self.nw.solve("design") + self.stable = "_stable" + self.nw.save(self.stable) + self.solved = True + self.nw.print_results() + + def set_design_values(self): + hpt, mpt, lpt = self.nw.get_comp(["high pressure turbine", "mid pressure turbine", "low pressure turbine"]) hpt.set_attr(eta_s=0.9) mpt.set_attr(eta_s=0.9) lpt.set_attr(eta_s=0.9) + pu1, pu2, pu3 = self.nw.get_comp(["feed water pump", "feed water pump 2", "feed water pump 3"]) pu1.set_attr(eta_s=0.8) pu2.set_attr(eta_s=0.8) pu3.set_attr(eta_s=0.8) + sg = self.nw.get_comp("steam generator") sg.set_attr(pr=0.92) + con, fwh1, fwh2, dsh = self.nw.get_comp(["condenser", "feed water preheater 1", "feed water preheater 2", "desuperheater"]) con.set_attr(pr1=1, pr2=0.99, ttd_u=5) fwh1.set_attr(pr1=1, pr2=0.99, ttd_u=5) fwh2.set_attr(pr1=1, pr2=0.99, ttd_u=5) dsh.set_attr(pr1=0.99, pr2=0.99) + c1, c2, c4, c41, c42 = self.nw.get_conn(["1", "2", "4", "41", "42"]) c1.set_attr(m=200, T=650, p=100, fluid={"water": 1}) c2.set_attr(p=20) c4.set_attr(p=3) - c41.set_attr(T=20, p=3, fluid={"water": 1}) - c42.set_attr(T=28) + c41.set_attr(T=20, p=3, fluid={"INCOMP::Water": 1}) + c42.set_attr(T=28, p0=3, h0=100) - self.nw.solve("design") - self.stable = "_stable" - self.nw.save(self.stable) - self.solved = True # %%[sec_2] From c0c572e8813818a914de49019c1c1679a58867ce Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 2 Dec 2023 11:11:15 +0100 Subject: [PATCH 2/5] Update What's New --- docs/whats_new.rst | 1 + docs/whats_new/v0-7-1.rst | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 docs/whats_new/v0-7-1.rst diff --git a/docs/whats_new.rst b/docs/whats_new.rst index 835278fa1..f03b829f0 100644 --- a/docs/whats_new.rst +++ b/docs/whats_new.rst @@ -3,6 +3,7 @@ What's New Discover noteable new features and improvements in each release +.. include:: whats_new/v0-7-1.rst .. include:: whats_new/v0-7-0.rst .. include:: whats_new/v0-6-3.rst .. include:: whats_new/v0-6-2.rst diff --git a/docs/whats_new/v0-7-1.rst b/docs/whats_new/v0-7-1.rst new file mode 100644 index 000000000..fa008fff8 --- /dev/null +++ b/docs/whats_new/v0-7-1.rst @@ -0,0 +1,14 @@ +v0.7.1 - Newton's Nature (December, 2, 2023) +++++++++++++++++++++++++++++++++++++++++++++ + +Bug Fixes +######### +- Several bugs introduced by the restructuring of the package in version 0.7.0 + have been fixed: + + - `PR #451 `__ + - `PR #453 `__ + +Contributors +############ +- Francesco Witte (`@fwitte `__) From cf0323065683842cd27fd93c177c4ad33cdb56f2 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 2 Dec 2023 11:12:39 +0100 Subject: [PATCH 3/5] 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 82aaf725a..eb184e992 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ exclude = ["docs/_build"] [project] name = "tespy" -version = "0.7.1" +version = "0.7.1.post1" description = "Thermal Engineering Systems in Python (TESPy)" readme = "README.rst" authors = [ diff --git a/src/tespy/__init__.py b/src/tespy/__init__.py index 049be2a61..fde368697 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.1 - Newton\'s Nature' +__version__ = '0.7.1.post1 - Newton\'s Nature' # tespy data and connections import from . import connections # noqa: F401 From 618f5df40bc8eae919083cb88eea6614edf6041c Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 2 Dec 2023 11:26:11 +0100 Subject: [PATCH 4/5] Move mass flow and fluid branch creation again --- src/tespy/networks/network.py | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/tespy/networks/network.py b/src/tespy/networks/network.py index 3508aa4be..9f699dd08 100644 --- a/src/tespy/networks/network.py +++ b/src/tespy/networks/network.py @@ -690,6 +690,8 @@ def check_network(self): self.check_conns() self.init_components() self.check_components() + self.create_massflow_and_fluid_branches() + self.create_fluid_wrapper_branches() # network checked self.checked = True @@ -845,23 +847,19 @@ def initialise(self): self.num_conn_vars = 0 self.variables_dict = {} - if hasattr(self, "massflow_branches"): - # in multiprocessing copies are made of all connections - # the mass flow branches and fluid branches hold references to - # connections from the original run (where network.checked is False) - # The assignment of variable spaces etc. is however made on the - # copies of the connections which do not correspond to the mass flow - # branches and fluid branches anymore. So the topology simplification - # does not actually apply to the copied network, therefore the - # branches have to be recreated for this case. We can detect that by - # checking whether a network holds a massflow branch with some - # connections and compare that with the connection object actually - # present in the network - first_conn = self.massflow_branches[0]["connections"][0] - if self.conns.loc[first_conn.label, "object"] != first_conn: - self.create_massflow_and_fluid_branches() - self.create_fluid_wrapper_branches() - else: + # in multiprocessing copies are made of all connections + # the mass flow branches and fluid branches hold references to + # connections from the original run (where network.checked is False) + # The assignment of variable spaces etc. is however made on the + # copies of the connections which do not correspond to the mass flow + # branches and fluid branches anymore. So the topology simplification + # does not actually apply to the copied network, therefore the + # branches have to be recreated for this case. We can detect that by + # checking whether a network holds a massflow branch with some + # connections and compare that with the connection object actually + # present in the network + first_conn = self.massflow_branches[0]["connections"][0] + if self.conns.loc[first_conn.label, "object"] != first_conn: self.create_massflow_and_fluid_branches() self.create_fluid_wrapper_branches() self.propagate_fluid_wrappers() From 1af845fa22d614597986e814c3bdb92fe004597b Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 2 Dec 2023 11:28:59 +0100 Subject: [PATCH 5/5] Revert some moving of settings --- tutorial/advanced/optimization_example.py | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/tutorial/advanced/optimization_example.py b/tutorial/advanced/optimization_example.py index e65314961..064c5a71d 100644 --- a/tutorial/advanced/optimization_example.py +++ b/tutorial/advanced/optimization_example.py @@ -104,36 +104,21 @@ def __init__(self): self.nw.add_busses(self.power, self.heat) - self.set_design_values() - # parametrization - # components - self.nw.solve("design") - self.stable = "_stable" - self.nw.save(self.stable) - self.solved = True - self.nw.print_results() - - def set_design_values(self): - hpt, mpt, lpt = self.nw.get_comp(["high pressure turbine", "mid pressure turbine", "low pressure turbine"]) hpt.set_attr(eta_s=0.9) mpt.set_attr(eta_s=0.9) lpt.set_attr(eta_s=0.9) - pu1, pu2, pu3 = self.nw.get_comp(["feed water pump", "feed water pump 2", "feed water pump 3"]) pu1.set_attr(eta_s=0.8) pu2.set_attr(eta_s=0.8) pu3.set_attr(eta_s=0.8) - sg = self.nw.get_comp("steam generator") sg.set_attr(pr=0.92) - con, fwh1, fwh2, dsh = self.nw.get_comp(["condenser", "feed water preheater 1", "feed water preheater 2", "desuperheater"]) con.set_attr(pr1=1, pr2=0.99, ttd_u=5) fwh1.set_attr(pr1=1, pr2=0.99, ttd_u=5) fwh2.set_attr(pr1=1, pr2=0.99, ttd_u=5) dsh.set_attr(pr1=0.99, pr2=0.99) - c1, c2, c4, c41, c42 = self.nw.get_conn(["1", "2", "4", "41", "42"]) c1.set_attr(m=200, T=650, p=100, fluid={"water": 1}) c2.set_attr(p=20) c4.set_attr(p=3) @@ -141,6 +126,13 @@ def set_design_values(self): c41.set_attr(T=20, p=3, fluid={"INCOMP::Water": 1}) c42.set_attr(T=28, p0=3, h0=100) + # parametrization + # components + self.nw.solve("design") + self.stable = "_stable" + self.nw.save(self.stable) + self.solved = True + self.nw.print_results() # %%[sec_2]