From bbb285ee9dc862cedf829703072b9e264be2154c Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sat, 2 Dec 2023 11:05:32 +0100 Subject: [PATCH] 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]