From 25dc5ab59f35e97e41d2fb0b4b93665908971e5c Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Sun, 7 Jan 2024 13:38:14 +0100 Subject: [PATCH 1/2] Remove ordereddicts and implement zeta calculation method --- src/tespy/components/combustion/engine.py | 8 ++-- src/tespy/components/component.py | 39 +++++++++++-------- src/tespy/components/heat_exchangers/base.py | 14 +++---- .../components/heat_exchangers/condenser.py | 2 - .../heat_exchangers/parabolic_trough.py | 6 +-- .../components/heat_exchangers/simple.py | 5 +-- .../heat_exchangers/solar_collector.py | 6 +-- src/tespy/components/piping/valve.py | 5 +-- src/tespy/components/reactors/fuel_cell.py | 10 ++--- .../components/reactors/water_electrolyzer.py | 10 ++--- src/tespy/connections/connection.py | 6 +-- src/tespy/networks/network.py | 5 +-- src/tespy/tools/data_containers.py | 14 +++---- src/tespy/tools/global_vars.py | 5 +-- src/tespy/tools/helpers.py | 22 ----------- src/tespy/tools/optimization.py | 13 ++----- 16 files changed, 64 insertions(+), 106 deletions(-) diff --git a/src/tespy/components/combustion/engine.py b/src/tespy/components/combustion/engine.py index 6f47613a3..aa4661371 100644 --- a/src/tespy/components/combustion/engine.py +++ b/src/tespy/components/combustion/engine.py @@ -1302,11 +1302,9 @@ def calc_parameters(self): self.outl[i].h.val_SI - self.inl[i].h.val_SI) self.get_attr('pr' + str(i + 1)).val = ( self.outl[i].p.val_SI / self.inl[i].p.val_SI) - self.get_attr('zeta' + str(i + 1)).val = ( - (self.inl[i].p.val_SI - self.outl[i].p.val_SI) * np.pi ** 2 / ( - 4 * self.inl[i].m.val_SI ** 2 * - (self.inl[i].vol.val_SI + self.outl[i].vol.val_SI) - )) + self.get_attr('zeta' + str(i + 1)).val = self.calc_zeta( + self.inl[i], self.outl[i] + ) self.P.val = self.calc_P() self.Qloss.val = self.calc_Qloss() diff --git a/src/tespy/components/component.py b/src/tespy/components/component.py index 8c8dec496..3d9e0f24c 100644 --- a/src/tespy/components/component.py +++ b/src/tespy/components/component.py @@ -12,8 +12,6 @@ SPDX-License-Identifier: MIT """ -from collections import OrderedDict - import numpy as np from tespy.tools import logger @@ -122,7 +120,7 @@ def __init__(self, label, **kwargs): self.fkt_group = self.label # add container for components attributes - self.parameters = OrderedDict(self.get_parameters().copy()) + self.parameters = self.get_parameters().copy() self.__dict__.update(self.parameters) self.set_attr(**kwargs) @@ -342,7 +340,7 @@ def preprocess(self, num_nw_vars): self.num_eq = 0 self.vars = {} self.num_vars = 0 - self.constraints = OrderedDict(self.get_mandatory_constraints().copy()) + self.constraints = self.get_mandatory_constraints().copy() self.prop_specifications = {} self.var_specifications = {} self.group_specifications = {} @@ -415,7 +413,7 @@ def preprocess(self, num_nw_vars): if data.is_set and data.func is not None: self.num_eq += data.num_eq - self.jacobian = OrderedDict() + self.jacobian = {} self.residual = np.zeros(self.num_eq) sum_eq = 0 @@ -813,18 +811,18 @@ def check_parameter_bounds(self): if isinstance(data, dc_cp): if data.val > data.max_val + ERR : msg = ( - 'Invalid value for ' + p + ': ' + p + ' = ' + - str(data.val) + ' above maximum value (' + - str(data.max_val) + ') at component ' + self.label + - '.') + f"Invalid value for {p}: {p} = {data.val} above " + f"maximum value ({data.max_val}) at component " + f"{self.label}." + ) logger.warning(msg) elif data.val < data.min_val - ERR : msg = ( - 'Invalid value for ' + p + ': ' + p + ' = ' + - str(data.val) + ' below minimum value (' + - str(data.min_val) + ') at component ' + self.label + - '.') + f"Invalid value for {p}: {p} = {data.val} below " + f"minimum value ({data.max_val}) at component " + f"{self.label}." + ) logger.warning(msg) elif isinstance(data, dc_cc) and data.is_set: @@ -968,7 +966,8 @@ def enthalpy_equality_func_doc(self, label): indices = str(indices[0]) latex = ( r'0=h_{\mathrm{in,}i}-h_{\mathrm{out,}i}' - r'\; \forall i \in [' + indices + r']') + r'\; \forall i \in [' + indices + r']' + ) return generate_latex_eq(self, latex, label) def enthalpy_equality_deriv(self, k): @@ -1021,8 +1020,7 @@ def pr_func(self, pr='', inconn=0, outconn=0): 0 = p_{in} \cdot pr - p_{out} """ pr = self.get_attr(pr) - return (self.inl[inconn].p.val_SI * pr.val - - self.outl[outconn].p.val_SI) + return self.inl[inconn].p.val_SI * pr.val - self.outl[outconn].p.val_SI def pr_func_doc(self, label, pr='', inconn=0, outconn=0): r""" @@ -1083,6 +1081,15 @@ def pr_deriv(self, increment_filter, k, pr='', inconn=0, outconn=0): if pr.is_var: self.jacobian[k, self.pr.J_col] = i.p.val_SI + def calc_zeta(self, i, o): + if abs(i.m.val_SI) <= 1e-4: + return 0 + else: + return ( + (i.p.val_SI - o.p.val_SI) * np.pi ** 2 + / (4 * i.m.val_SI ** 2 * (i.vol.val_SI + o.vol.val_SI)) + ) + def zeta_func(self, zeta='', inconn=0, outconn=0): r""" Calculate residual value of :math:`\zeta`-function. diff --git a/src/tespy/components/heat_exchangers/base.py b/src/tespy/components/heat_exchangers/base.py index 82830fac8..f1685f639 100644 --- a/src/tespy/components/heat_exchangers/base.py +++ b/src/tespy/components/heat_exchangers/base.py @@ -830,11 +830,9 @@ def calc_parameters(self): for i in range(2): self.get_attr('pr' + str(i + 1)).val = ( self.outl[i].p.val_SI / self.inl[i].p.val_SI) - self.get_attr('zeta' + str(i + 1)).val = ( - (self.inl[i].p.val_SI - self.outl[i].p.val_SI) * np.pi ** 2 / ( - 4 * self.inl[i].m.val_SI ** 2 * - (self.inl[i].vol.val_SI + self.outl[i].vol.val_SI) - )) + self.get_attr('zeta' + str(i + 1)).val = self.calc_zeta( + self.inl[i], self.outl[i] + ) # kA and logarithmic temperature difference if self.ttd_u.val < 0 or self.ttd_l.val < 0: @@ -842,8 +840,10 @@ def calc_parameters(self): elif self.ttd_l.val == self.ttd_u.val: self.td_log.val = self.ttd_l.val else: - self.td_log.val = ((self.ttd_l.val - self.ttd_u.val) / - np.log(self.ttd_l.val / self.ttd_u.val)) + self.td_log.val = ( + (self.ttd_l.val - self.ttd_u.val) + / np.log(self.ttd_l.val / self.ttd_u.val) + ) self.kA.val = -self.Q.val / self.td_log.val def entropy_balance(self): diff --git a/src/tespy/components/heat_exchangers/condenser.py b/src/tespy/components/heat_exchangers/condenser.py index 241a9c01b..a87316095 100644 --- a/src/tespy/components/heat_exchangers/condenser.py +++ b/src/tespy/components/heat_exchangers/condenser.py @@ -19,8 +19,6 @@ from tespy.tools.data_containers import GroupedComponentCharacteristics as dc_gcc 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 T_mix_ph -from tespy.tools.fluid_properties import T_sat_p from tespy.tools.fluid_properties import dh_mix_dpQ from tespy.tools.fluid_properties import h_mix_pQ diff --git a/src/tespy/components/heat_exchangers/parabolic_trough.py b/src/tespy/components/heat_exchangers/parabolic_trough.py index 5a41e98d1..169d164fd 100644 --- a/src/tespy/components/heat_exchangers/parabolic_trough.py +++ b/src/tespy/components/heat_exchangers/parabolic_trough.py @@ -361,10 +361,8 @@ def calc_parameters(self): self.Q.val = i.m.val_SI * (o.h.val_SI - i.h.val_SI) self.pr.val = o.p.val_SI / i.p.val_SI - self.zeta.val = ( - (i.p.val_SI - o.p.val_SI) * np.pi ** 2 - / (4 * i.m.val_SI ** 2 * (i.vol.val_SI + o.vol.val_SI)) - ) + self.zeta.val = self.calc_zeta(i, o) + if self.energy_group.is_set: self.Q_loss.val = - self.E.val * self.A.val + self.Q.val self.Q_loss.is_result = True diff --git a/src/tespy/components/heat_exchangers/simple.py b/src/tespy/components/heat_exchangers/simple.py index 29d141ea9..57623e758 100644 --- a/src/tespy/components/heat_exchangers/simple.py +++ b/src/tespy/components/heat_exchangers/simple.py @@ -884,10 +884,7 @@ def calc_parameters(self): self.Q.val = i.m.val_SI * (o.h.val_SI - i.h.val_SI) self.pr.val = o.p.val_SI / i.p.val_SI - self.zeta.val = ( - (i.p.val_SI - o.p.val_SI) * np.pi ** 2 - / (4 * i.m.val_SI ** 2 * (i.vol.val_SI + o.vol.val_SI)) - ) + self.zeta.val = self.calc_zeta(i, o) if self.Tamb.is_set: ttd_1 = i.T.val_SI - self.Tamb.val_SI diff --git a/src/tespy/components/heat_exchangers/solar_collector.py b/src/tespy/components/heat_exchangers/solar_collector.py index bce3198ce..9a940e12c 100644 --- a/src/tespy/components/heat_exchangers/solar_collector.py +++ b/src/tespy/components/heat_exchangers/solar_collector.py @@ -311,10 +311,8 @@ def calc_parameters(self): self.Q.val = i.m.val_SI * (o.h.val_SI - i.h.val_SI) self.pr.val = o.p.val_SI / i.p.val_SI - self.zeta.val = ( - (i.p.val_SI - o.p.val_SI) * np.pi ** 2 - / (4 * i.m.val_SI ** 2 * (i.vol.val_SI + o.vol.val_SI)) - ) + self.zeta.val = self.calc_zeta(i, o) + if self.energy_group.is_set: self.Q_loss.val = -(self.E.val * self.A.val - self.Q.val) self.Q_loss.is_result = True diff --git a/src/tespy/components/piping/valve.py b/src/tespy/components/piping/valve.py index 3b23aadcb..723e1d829 100644 --- a/src/tespy/components/piping/valve.py +++ b/src/tespy/components/piping/valve.py @@ -316,10 +316,7 @@ def calc_parameters(self): i = self.inl[0] o = self.outl[0] self.pr.val = o.p.val_SI / i.p.val_SI - self.zeta.val = ( - (i.p.val_SI - o.p.val_SI) * np.pi ** 2 - / (4 * i.m.val_SI ** 2 * (i.vol.val_SI + o.vol.val_SI)) - ) + self.zeta.val = self.calc_zeta(i, o) def entropy_balance(self): r""" diff --git a/src/tespy/components/reactors/fuel_cell.py b/src/tespy/components/reactors/fuel_cell.py index 088d09757..fe0198bcc 100644 --- a/src/tespy/components/reactors/fuel_cell.py +++ b/src/tespy/components/reactors/fuel_cell.py @@ -828,15 +828,13 @@ def initialise_target(self, c, key): def calc_parameters(self): r"""Postprocessing parameter calculation.""" - self.Q.val = - self.inl[0].m.val_SI * ( - self.outl[0].h.val_SI - self.inl[0].h.val_SI) + self.Q.val = -self.inl[0].m.val_SI * ( + self.outl[0].h.val_SI - self.inl[0].h.val_SI + ) self.pr.val = self.outl[0].p.val_SI / self.inl[0].p.val_SI self.e.val = self.P.val / self.inl[2].m.val_SI self.eta.val = self.e.val / self.e0 i = self.inl[0] o = self.outl[0] - self.zeta.val = ( - (i.p.val_SI - o.p.val_SI) * np.pi ** 2 - / (4 * i.m.val_SI ** 2 * (i.vol.val_SI + o.vol.val_SI)) - ) + self.zeta.val = self.calc_zeta(i, o) diff --git a/src/tespy/components/reactors/water_electrolyzer.py b/src/tespy/components/reactors/water_electrolyzer.py index 9e8e959d8..e93d87a9a 100644 --- a/src/tespy/components/reactors/water_electrolyzer.py +++ b/src/tespy/components/reactors/water_electrolyzer.py @@ -1157,18 +1157,16 @@ def initialise_target(self, c, key): def calc_parameters(self): r"""Postprocessing parameter calculation.""" - self.Q.val = - self.inl[0].m.val_SI * ( - self.outl[0].h.val_SI - self.inl[0].h.val_SI) + self.Q.val = -self.inl[0].m.val_SI * ( + self.outl[0].h.val_SI - self.inl[0].h.val_SI + ) self.pr.val = self.outl[0].p.val_SI / self.inl[0].p.val_SI self.e.val = self.P.val / self.outl[2].m.val_SI self.eta.val = self.e0 / self.e.val i = self.inl[0] o = self.outl[0] - self.zeta.val = ( - (i.p.val_SI - o.p.val_SI) * np.pi ** 2 - / (4 * i.m.val_SI ** 2 * (i.vol.val_SI + o.vol.val_SI)) - ) + self.zeta.val = self.calc_zeta(i, o) def exergy_balance(self, T0): self.E_P = ( diff --git a/src/tespy/connections/connection.py b/src/tespy/connections/connection.py index 459bcd14b..3c58eeafe 100644 --- a/src/tespy/connections/connection.py +++ b/src/tespy/connections/connection.py @@ -9,8 +9,6 @@ SPDX-License-Identifier: MIT """ -from collections import OrderedDict - import numpy as np from tespy.components.component import Component @@ -303,7 +301,7 @@ def _check_connector_id(self, component, connector_id, connecter_locations): if connector_id not in connecter_locations: msg = ( "Error creating connection. Specified connector for " - f"{component.label} ({connector_id} is not available. Choose " + f"{component.label} ({connector_id}) is not available. Choose " f"from " + ", ".join(connecter_locations) + "." ) logger.error(msg) @@ -626,7 +624,7 @@ def preprocess(self): container._solved = False self.residual = np.zeros(self.num_eq) - self.jacobian = OrderedDict() + self.jacobian = {} def simplify_specifications(self): systemvar_specs = [] diff --git a/src/tespy/networks/network.py b/src/tespy/networks/network.py index 48a4755d3..d7a11fa2c 100644 --- a/src/tespy/networks/network.py +++ b/src/tespy/networks/network.py @@ -15,7 +15,6 @@ """ import json import os -from collections import OrderedDict from time import time import numpy as np @@ -189,7 +188,7 @@ def set_defaults(self): # user defined function dictionary for fast access self.user_defined_eq = {} # bus dictionary - self.busses = OrderedDict() + self.busses = {} # results and specification dictionary self.results = {} self.specifications = {} @@ -1262,7 +1261,7 @@ def init_design(self): c.m.design = np.nan c.p.design = np.nan c.h.design = np.nan - c.fluid.design = OrderedDict() + c.fluid.design = {} c.new_design = True diff --git a/src/tespy/tools/data_containers.py b/src/tespy/tools/data_containers.py index f55447d32..a9e559626 100644 --- a/src/tespy/tools/data_containers.py +++ b/src/tespy/tools/data_containers.py @@ -354,15 +354,15 @@ def attr(): values. """ return { - 'val': collections.OrderedDict(), - 'val0': collections.OrderedDict(), + 'val': dict(), + 'val0': dict(), 'is_set': set(), - 'design': collections.OrderedDict(), - 'wrapper': collections.OrderedDict(), - 'back_end': collections.OrderedDict(), - 'engine': collections.OrderedDict(), + 'design': dict(), + 'wrapper': dict(), + 'back_end': dict(), + 'engine': dict(), "is_var": set(), - "J_col": collections.OrderedDict(), + "J_col": dict(), } def serialize(self): diff --git a/src/tespy/tools/global_vars.py b/src/tespy/tools/global_vars.py index 37a9273e5..8cd773f1a 100644 --- a/src/tespy/tools/global_vars.py +++ b/src/tespy/tools/global_vars.py @@ -8,14 +8,13 @@ SPDX-License-Identifier: MIT """ -from collections import OrderedDict ERR = 1e-6 molar_masses = {} gas_constants = {} gas_constants['uni'] = 8.314462618 -fluid_property_data = OrderedDict({ +fluid_property_data = { 'm': { 'text': 'mass flow', 'SI_unit': 'kg / s', @@ -99,6 +98,6 @@ 'latex_eq': r'0 = s_\mathrm{spec} - s\left(p, h \right)', 'documentation': {'float_fmt': '{:,.2f}'} } -}) +} combustion_gases = ['methane', 'ethane', 'propane', 'butane', 'hydrogen', 'nDodecane'] diff --git a/src/tespy/tools/helpers.py b/src/tespy/tools/helpers.py index d92ebf04e..efd5b7720 100644 --- a/src/tespy/tools/helpers.py +++ b/src/tespy/tools/helpers.py @@ -11,7 +11,6 @@ import json import os -from collections import OrderedDict from collections.abc import Mapping from copy import deepcopy @@ -65,27 +64,6 @@ def merge_dicts(dict1, dict2): return result -def nested_OrderedDict(dictionary): - """Create a nested OrderedDict from a nested dict. - - Parameters - ---------- - dictionary : dict - Nested dict. - - Returns - ------- - dictionary : collections.OrderedDict - Nested OrderedDict. - """ - dictionary = OrderedDict(dictionary) - for key, value in dictionary.items(): - if isinstance(value, dict): - dictionary[key] = nested_OrderedDict(value) - - return dictionary - - class TESPyNetworkError(Exception): """Custom message for network related errors.""" diff --git a/src/tespy/tools/optimization.py b/src/tespy/tools/optimization.py index b7a513878..4154d1a95 100644 --- a/src/tespy/tools/optimization.py +++ b/src/tespy/tools/optimization.py @@ -6,7 +6,6 @@ import pandas as pd from tespy.tools.helpers import merge_dicts -from tespy.tools.helpers import nested_OrderedDict class OptimizationProblem: @@ -70,14 +69,8 @@ def __init__(self, model, variables={}, constraints={}, objective="objective"): "upper limits": {"Connections": {}, "Components": {}} } # merge the passed values into the default dictionary structure - variables = merge_dicts(variables, default_variables) - constraints = merge_dicts(constraints, default_constraints) - - # pygmo creates a vector for the variables and constraints, which has - # to be in consistent order. Therefore use OrderedDicts instead of - # dictionaries - self.variables = nested_OrderedDict(variables) - self.constraints = nested_OrderedDict(constraints) + self.variables = merge_dicts(variables, default_variables) + self.constraints = merge_dicts(constraints, default_constraints) self.objective = objective self.variable_list = [] self.constraint_list = [] @@ -307,3 +300,5 @@ def run(self, algo, pop, num_ind, num_gen): round(pop.champion_x[i], 4) ) ) + + return pop From 7fb12658afc5b7f9be12ae79ee1d4d84014d9564 Mon Sep 17 00:00:00 2001 From: Francesco Witte Date: Mon, 8 Jan 2024 21:21:10 +0100 Subject: [PATCH 2/2] Fix link ignore --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index a8cf752fb..5d75eb094 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -148,5 +148,5 @@ r'https://doi.org/20.500.12738/6561', # 08.01.2023: does not resolve anymore r'https://doi.org/10.1021/ie4033999', # 28.02.2023: does not resolve anymore for some reason r'https://doi.org/10.1002/bbpc.19900940121', # 13.03.2023 ...? - r' http://www.coolprop.org/fluid_properties/Incompressibles.html', # 02.12.2023 ...? + r'http://www.coolprop.org/fluid_properties/Incompressibles.html', # 02.12.2023 ...? ]