diff --git a/src/tespy/components/heat_exchangers/movingboundary.py b/src/tespy/components/heat_exchangers/movingboundary.py index a95d0db2..a9861a8d 100644 --- a/src/tespy/components/heat_exchangers/movingboundary.py +++ b/src/tespy/components/heat_exchangers/movingboundary.py @@ -193,9 +193,10 @@ class MovingBoundaryHeatExchanger(HeatExchanger): with 15 °C superheating and leaves it with 10 °C subcooling. >>> c1.set_attr(fluid={"Water": 1}, p=1, Td_bp=15, m=1) - >>> c2.set_attr(p=1, Td_bp=-15) + >>> c2.set_attr(Td_bp=-15) >>> c11.set_attr(fluid={"Air": 1}, p=1, T=15) - >>> c12.set_attr(p=1, T=25) + >>> c12.set_attr(T=25) + >>> cd.set_attr(pr1=1, pr2=1) >>> nw.solve("design") Now we can remove the pressure specifications on the air side and impose @@ -203,9 +204,7 @@ class MovingBoundaryHeatExchanger(HeatExchanger): condensation pressure. >>> c1.set_attr(p=None) - >>> c2.set_attr(p=None) - >>> c12.set_attr(p=None) - >>> cd.set_attr(td_pinch=5, pr1=1, pr2=1) + >>> cd.set_attr(td_pinch=5) >>> nw.solve("design") >>> round(c1.p.val, 3) 0.056 @@ -280,7 +279,7 @@ def get_parameters(self): ), 'td_pinch': dc_cp( min_val=0, num_eq=1, func=self.td_pinch_func, - deriv=self.td_pinch_deriv, latex=None + deriv=self.td_pinch_deriv ) }) return params @@ -303,8 +302,11 @@ def _get_h_steps(c1, c2): list Steps of enthalpy of the specified connections """ - if c1.fluid_data != c2.fluid_data: - msg = "Both connections need to utilize the same fluid data." + if c1.fluid.val != c2.fluid.val: + msg = ( + "Both connections need to utilize the same fluid data: " + f"{c1.fluid.val}, {c2.fluid.val}" + ) raise ValueError(msg) if c1.p.val_SI != c2.p.val_SI: @@ -495,12 +497,9 @@ def UA_deriv(self, increment_filter, k): """ f = self.UA_func for c in self.inl + self.outl: - if self.is_variable(c.m): - self.jacobian[k, c.m.J_col] = self.numeric_deriv(f, "m", c) - if self.is_variable(c.p): - self.jacobian[k, c.p.J_col] = self.numeric_deriv(f, 'p', c) - if self.is_variable(c.h): - self.jacobian[k, c.h.J_col] = self.numeric_deriv(f, 'h', c) + self._partial_derivative(c.m, k, f, increment_filter) + self._partial_derivative(c.p, k, f, increment_filter) + self._partial_derivative(c.h, k, f, increment_filter) def calc_td_pinch(self): """Calculate the pinch point temperature difference @@ -554,12 +553,11 @@ def td_pinch_deriv(self, increment_filter, k): """ f = self.td_pinch_func for c in self.inl + self.outl: - if self.is_variable(c.m, increment_filter): - self.jacobian[k, c.m.J_col] = self.numeric_deriv(f, 'm', c) - if self.is_variable(c.p, increment_filter): - self.jacobian[k, c.p.J_col] = self.numeric_deriv(f, 'p', c) - if self.is_variable(c.h, increment_filter): - self.jacobian[k, c.h.J_col] = self.numeric_deriv(f, 'h', c) + self._partial_derivative(c.m, k, f, increment_filter) + self._partial_derivative(c.p, k, f, increment_filter) + self._partial_derivative(c.h, k, f, increment_filter) + + logger.error(f"{self.jacobian}") def calc_parameters(self): super().calc_parameters() diff --git a/src/tespy/components/heat_exchangers/parabolic_trough.py b/src/tespy/components/heat_exchangers/parabolic_trough.py index acdc7f31..14e3583f 100644 --- a/src/tespy/components/heat_exchangers/parabolic_trough.py +++ b/src/tespy/components/heat_exchangers/parabolic_trough.py @@ -229,19 +229,25 @@ def get_parameters(self): del data[k] data.update({ - 'E': dc_cp(min_val=0), 'A': dc_cp(min_val=0), + 'E': dc_cp(min_val=0), + 'A': dc_cp(min_val=0), 'eta_opt': dc_cp(min_val=0, max_val=1), - 'c_1': dc_cp(min_val=0), 'c_2': dc_cp(min_val=0), - 'iam_1': dc_cp(), 'iam_2': dc_cp(), + 'c_1': dc_cp(min_val=0), + 'c_2': dc_cp(min_val=0), + 'iam_1': dc_cp(), + 'iam_2': dc_cp(), 'aoi': dc_cp(min_val=-90, max_val=90), 'doc': dc_cp(min_val=0, max_val=1), 'Tamb': dc_cp(), 'Q_loss': dc_cp(max_val=0, val=0), 'energy_group': dc_gcp( - elements=['E', 'eta_opt', 'aoi', 'doc', 'c_1', 'c_2', 'iam_1', - 'iam_2', 'A', 'Tamb'], num_eq=1, + elements=[ + 'E', 'eta_opt', 'aoi', 'doc', 'c_1', 'c_2', 'iam_1', + 'iam_2', 'A', 'Tamb' + ], num_eq=1, latex=self.energy_group_func_doc, - func=self.energy_group_func, deriv=self.energy_group_deriv + func=self.energy_group_func, + deriv=self.energy_group_deriv ) }) return data @@ -333,25 +339,18 @@ def energy_group_deriv(self, increment_filter, k): f = self.energy_group_func i = self.inl[0] o = self.outl[0] - if self.is_variable(i.m, increment_filter): - self.jacobian[k, i.m.J_col] = o.h.val_SI - i.h.val_SI - if self.is_variable(i.p, increment_filter): - self.jacobian[k, i.p.J_col] = self.numeric_deriv(f, 'p', i) - if self.is_variable(i.h, increment_filter): - self.jacobian[k, i.h.J_col] = self.numeric_deriv(f, 'h', i) - if self.is_variable(o.p, increment_filter): - self.jacobian[k, o.p.J_col] = self.numeric_deriv(f, 'p', o) - if self.is_variable(o.h, increment_filter): - self.jacobian[k, o.h.J_col] = self.numeric_deriv(f, 'h', o) + + self._partial_derivative(i.m, k, o.h.val_SI - i.h.val_SI, increment_filter) + self._partial_derivative(i.p, k, f, increment_filter) + self._partial_derivative(i.h, k, f, increment_filter) + self._partial_derivative(o.p, k, f, increment_filter) + self._partial_derivative(o.h, k, f, increment_filter) # custom variables for the energy-group for variable_name in self.energy_group.elements: parameter = self.get_attr(variable_name) if parameter == self.Tamb: continue - if parameter.is_var: - self.jacobian[k, parameterJ_col()] = ( - self.numeric_deriv(f, variable_name, None) - ) + self._partial_derivative(parameter, k, f, increment_filter) def calc_parameters(self): r"""Postprocessing parameter calculation.""" diff --git a/src/tespy/components/heat_exchangers/simple.py b/src/tespy/components/heat_exchangers/simple.py index 9933f62d..4cb3eb79 100644 --- a/src/tespy/components/heat_exchangers/simple.py +++ b/src/tespy/components/heat_exchangers/simple.py @@ -266,7 +266,7 @@ def outlets(): def _preprocess(self, row_idx): super()._preprocess(row_idx) - # self.Tamb.val_SI = convert_to_SI('T', self.Tamb.val, self.inl[0].T.unit) + self.Tamb.val_SI = convert_to_SI('T', self.Tamb.val, self.inl[0].T.unit) def energy_balance_func(self): r""" @@ -406,26 +406,19 @@ def darcy_deriv(self, increment_filter, k): k : int Position of derivatives in Jacobian matrix (k-th equation). """ - func = self.darcy_func + f = self.darcy_func i = self.inl[0] o = self.outl[0] - if self.is_variable(i.m, increment_filter): - self.jacobian[k, i.m.J_col] = self.numeric_deriv(func, 'm', i) - if self.is_variable(i.p, increment_filter): - self.jacobian[k, i.p.J_col] = self.numeric_deriv(func, 'p', i) - if self.is_variable(i.h, increment_filter): - self.jacobian[k, i.h.J_col] = self.numeric_deriv(func, 'h', i) - if self.is_variable(o.p, increment_filter): - self.jacobian[k, o.p.J_col] = self.numeric_deriv(func, 'p', o) - if self.is_variable(o.h, increment_filter): - self.jacobian[k, o.h.J_col] = self.numeric_deriv(func, 'h', o) + self._partial_derivative(i.m, k, f, increment_filter) + self._partial_derivative(i.p, k, f, increment_filter) + self._partial_derivative(i.h, k, f, increment_filter) + self._partial_derivative(o.p, k, f, increment_filter) + self._partial_derivative(o.h, k, f, increment_filter) + # custom variables of hydro group for variable_name in self.darcy_group.elements: parameter = self.get_attr(variable_name) - if parameter.is_var: - self.jacobian[k, parameter.J_col] = ( - self.numeric_deriv(func, variable_name, None) - ) + self._partial_derivative(parameter, k, f, increment_filter) def hazen_williams_func(self): r""" @@ -503,26 +496,19 @@ def hazen_williams_deriv(self, increment_filter, k): k : int Position of derivatives in Jacobian matrix (k-th equation). """ - func = self.hazen_williams_func + f = self.hazen_williams_func i = self.inl[0] o = self.outl[0] - if self.is_variable(i.m, increment_filter): - self.jacobian[k, i.m.J_col] = self.numeric_deriv(func, 'm', i) - if self.is_variable(i.p, increment_filter): - self.jacobian[k, i.p.J_col] = self.numeric_deriv(func, 'p', i) - if self.is_variable(i.h, increment_filter): - self.jacobian[k, i.h.J_col] = self.numeric_deriv(func, 'h', i) - if self.is_variable(o.p, increment_filter): - self.jacobian[k, o.p.J_col] = self.numeric_deriv(func, 'p', o) - if self.is_variable(o.h, increment_filter): - self.jacobian[k, o.h.J_col] = self.numeric_deriv(func, 'h', o) + self._partial_derivative(i.m, k, f, increment_filter) + self._partial_derivative(i.p, k, f, increment_filter) + self._partial_derivative(i.h, k, f, increment_filter) + self._partial_derivative(o.p, k, f, increment_filter) + self._partial_derivative(o.h, k, f, increment_filter) + # custom variables of hydro group for variable_name in self.hw_group.elements: parameter = self.get_attr(variable_name) - if parameter.is_var: - self.jacobian[k, parameter.J_col] = ( - self.numeric_deriv(func, variable_name, None) - ) + self._partial_derivative(parameter, k, f, increment_filter) def kA_group_func(self): r""" @@ -615,18 +601,14 @@ def kA_group_deriv(self, increment_filter, k): f = self.kA_group_func i = self.inl[0] o = self.outl[0] - if self.is_variable(i.m, increment_filter): - self.jacobian[k, i.m.J_col] = o.h.val_SI - i.h.val_SI - if self.is_variable(i.p, increment_filter): - self.jacobian[k, i.p.J_col] = self.numeric_deriv(f, 'p', i) - if self.is_variable(i.h, increment_filter): - self.jacobian[k, i.h.J_col] = self.numeric_deriv(f, 'h', i) - if self.is_variable(o.p, increment_filter): - self.jacobian[k, o.p.J_col] = self.numeric_deriv(f, 'p', o) - if self.is_variable(o.h, increment_filter): - self.jacobian[k, o.h.J_col] = self.numeric_deriv(f, 'h', o) - if self.kA.is_var: - self.jacobian[k, self.kAJ_col()] = self.numeric_deriv(f, self.vars[self.kA]) + + self._partial_derivative(i.m, k, o.h.val_SI - i.h.val_SI, increment_filter) + self._partial_derivative(i.p, k, f, increment_filter) + self._partial_derivative(i.h, k, f, increment_filter) + self._partial_derivative(o.p, k, f, increment_filter) + self._partial_derivative(o.h, k, f, increment_filter) + + self._partial_derivative(self.kA, k, f, increment_filter) def kA_char_group_func(self): r""" @@ -733,16 +715,12 @@ def kA_char_group_deriv(self, increment_filter, k): f = self.kA_char_group_func i = self.inl[0] o = self.outl[0] - if self.is_variable(i.m, increment_filter): - self.jacobian[k, i.m.J_col] = self.numeric_deriv(f, 'm', i) - if self.is_variable(i.p, increment_filter): - self.jacobian[k, i.p.J_col] = self.numeric_deriv(f, 'p', i) - if self.is_variable(i.h, increment_filter): - self.jacobian[k, i.h.J_col] = self.numeric_deriv(f, 'h', i) - if self.is_variable(o.p, increment_filter): - self.jacobian[k, o.p.J_col] = self.numeric_deriv(f, 'p', o) - if self.is_variable(o.h, increment_filter): - self.jacobian[k, o.h.J_col] = self.numeric_deriv(f, 'h', o) + + self._partial_derivative(i.m, k, f, increment_filter) + self._partial_derivative(i.p, k, f, increment_filter) + self._partial_derivative(i.h, k, f, increment_filter) + self._partial_derivative(o.p, k, f, increment_filter) + self._partial_derivative(o.h, k, f, increment_filter) def bus_func(self, bus): r""" diff --git a/src/tespy/connections/connection.py b/src/tespy/connections/connection.py index 9b11b3dc..c09b5371 100644 --- a/src/tespy/connections/connection.py +++ b/src/tespy/connections/connection.py @@ -774,11 +774,11 @@ def build_fluid_data(self): } for fluid in self.fluid.val } - def primary_ref_func(self, k, **kwargs): + def primary_ref_func(self, **kwargs): variable = kwargs["variable"] self.get_attr(variable) ref = self.get_attr(f"{variable}_ref").ref - self.residual[k] = ( + return ( self.get_attr(variable).val_SI - (ref.obj.get_attr(variable).val_SI * ref.factor + ref.delta_SI) ) @@ -809,8 +809,8 @@ def calc_T(self, T0=None): T0 = self.T.val_SI return T_mix_ph(self.p.val_SI, self.h.val_SI, self.fluid_data, self.mixing_rule, T0=T0) - def T_func(self, k, **kwargs): - self.residual[k] = self.calc_T() - self.T.val_SI + def T_func(self, **kwargs): + return self.calc_T() - self.T.val_SI def T_deriv(self, k, **kwargs): if _is_variable(self.p): @@ -826,11 +826,9 @@ def T_deriv(self, k, **kwargs): self.p.val_SI, self.h.val_SI, fluid, self.fluid_data, self.mixing_rule ) - def T_ref_func(self, k, **kwargs): + def T_ref_func(self, **kwargs): ref = self.T_ref.ref - self.residual[k] = ( - self.calc_T() - (ref.obj.calc_T() * ref.factor + ref.delta_SI) - ) + return self.calc_T() - (ref.obj.calc_T() * ref.factor + ref.delta_SI) def T_ref_deriv(self, k, **kwargs): # first part of sum is identical to direct temperature specification @@ -862,8 +860,8 @@ def calc_vol(self, T0=None): except NotImplementedError: return np.nan - def v_func(self, k, **kwargs): - self.residual[k] = self.calc_vol(T0=self.T.val_SI) * self.m.val_SI - self.v.val_SI + def v_func(self, **kwargs): + return self.calc_vol(T0=self.T.val_SI) * self.m.val_SI - self.v.val_SI def v_deriv(self, k, **kwargs): if _is_variable(self.m): @@ -881,9 +879,9 @@ def v_deriv(self, k, **kwargs): * self.m.val_SI ) - def v_ref_func(self, k, **kwargs): + def v_ref_func(self, **kwargs): ref = self.v_ref.ref - self.residual[k] = ( + return ( self.calc_vol(T0=self.T.val_SI) * self.m.val_SI - ( ref.obj.calc_vol(T0=ref.obj.T.val_SI) * ref.obj.m.val_SI @@ -917,9 +915,9 @@ def calc_x(self): except NotImplementedError: return np.nan - def x_func(self, k, **kwargs): + def x_func(self, **kwargs): # saturated steam fraction - self.residual[k] = ( + return ( self.h.val_SI - h_mix_pQ(self.p.val_SI, self.x.val_SI, self.fluid_data) ) @@ -942,25 +940,19 @@ def calc_Td_bp(self): except NotImplementedError: return np.nan - def Td_bp_func(self, k, **kwargs): + def Td_bp_func(self, **kwargs): # temperature difference to boiling point - self.residual[k] = self.calc_Td_bp() - self.Td_bp.val_SI + return self.calc_Td_bp() - self.Td_bp.val_SI def Td_bp_deriv(self, k, **kwargs): - if self.p.is_var: - self.jacobian[k, self.p.J_col] = ( - dT_mix_dph(self.p.val_SI, self.h.val_SI, self.fluid_data) - - dT_sat_dp(self.p.val_SI, self.fluid_data) - ) - if self.h.is_var: - self.jacobian[k, self.h.J_col] = dT_mix_pdh( - self.p.val_SI, self.h.val_SI, self.fluid_data - ) + f = self.Td_bp_func + self._partial_derivative(self.p, k, f) + self._partial_derivative(self.h, k, f) - def fluid_balance_func(self, k, **kwargs): + def fluid_balance_func(self, **kwargs): residual = 1 - sum(self.fluid.val[f] for f in self.fluid.is_set) residual -= sum(self.fluid.val[f] for f in self.fluid.is_var) - self.residual[k] = residual + return residual def fluid_balance_deriv(self, k, **kwargs): for f in self.fluid.is_var: @@ -979,7 +971,7 @@ def solve(self, increment_filter): self._increment_filter = increment_filter for k, parameter in self.equations.items(): data = self.get_attr(parameter) - data.func(k, **data.func_params) + self.residual[k] = data.func(**data.func_params) data.deriv(k, **data.func_params) def calc_results(self): diff --git a/src/tespy/networks/network.py b/src/tespy/networks/network.py index e1ca2649..a644aa71 100644 --- a/src/tespy/networks/network.py +++ b/src/tespy/networks/network.py @@ -2461,10 +2461,19 @@ def update_variables(self): increment = [float(val) for val in self.increment] # the J_cols here point to actual variables, no need to call to # get_J_col yet + if self.iter < 3: + relax = 0.25 + elif self.iter < 5: + relax = 0.5 + elif self.iter < 8: + relax = 0.75 + else: + relax = 1 + for _, data in self.variables_dict.items(): if data["variable"] in ["m", "h"]: container = data["obj"] - container._val_SI += increment[container.J_col] + container._val_SI += increment[container.J_col] * relax elif data["variable"] == "p": container = data["obj"] relax = max(