diff --git a/src/tespy/connections/connection.py b/src/tespy/connections/connection.py index 7572d0488..66eed5cbb 100644 --- a/src/tespy/connections/connection.py +++ b/src/tespy/connections/connection.py @@ -952,14 +952,17 @@ def get_physical_exergy(self, pamb, Tamb): E^\mathrm{M} = \dot{m} \cdot e^\mathrm{M}\\ E^\mathrm{PH} = \dot{m} \cdot e^\mathrm{PH} """ - self.ex_therm, self.ex_mech = fp.calc_physical_exergy(self, p0, T0) + self.ex_therm, self.ex_mech = fp.functions.calc_physical_exergy( + self.h.val_SI, self.s.val_SI, self.p.val_SI, pamb, Tamb, + self.fluid_data, self.mixing_rule, self.T.val_SI + ) self.Ex_therm = self.ex_therm * self.m.val_SI self.Ex_mech = self.ex_mech * self.m.val_SI self.ex_physical = self.ex_therm + self.ex_mech self.Ex_physical = self.m.val_SI * self.ex_physical - def get_chemical_exergy(self, p0, T0, Chem_Ex): + def get_chemical_exergy(self, pamb, Tamb, Chem_Ex): r""" Get the value of a connection's specific chemical exergy. @@ -983,7 +986,10 @@ def get_chemical_exergy(self, p0, T0, Chem_Ex): if Chem_Ex is None: self.ex_chemical = 0 else: - self.ex_chemical = fp.calc_chemical_exergy(self, p0, T0, Chem_Ex) + self.ex_chemical = fp.functions.calc_chemical_exergy( + pamb, Tamb, self.fluid_data, Chem_Ex, self.mixing_rule, + self.T.val_SI + ) self.Ex_chemical = self.m.val_SI * self.ex_chemical diff --git a/src/tespy/tools/fluid_properties/functions.py b/src/tespy/tools/fluid_properties/functions.py index d5cbde524..8639801ea 100644 --- a/src/tespy/tools/fluid_properties/functions.py +++ b/src/tespy/tools/fluid_properties/functions.py @@ -2,10 +2,11 @@ from .helpers import get_pure_fluid from .helpers import get_number_of_fluids from .helpers import inverse_temperature_mixture -from .mixtures import T_MIX_PH_REVERSE -from .mixtures import T_MIX_PS_REVERSE +from .mixtures import EXERGY_CHEMICAL from .mixtures import H_MIX_PT_DIRECT from .mixtures import S_MIX_PT_DIRECT +from .mixtures import T_MIX_PH_REVERSE +from .mixtures import T_MIX_PS_REVERSE from .mixtures import V_MIX_PT_DIRECT from .mixtures import VISCOSITY_MIX_PT_DIRECT @@ -20,6 +21,57 @@ def isentropic(p_1, h_1, p_2, fluid_data, mixing_rule=None, T0=None): return h_mix_pT(p_2, T_2, fluid_data, mixing_rule) +def calc_physical_exergy(h, s, p, pamb, Tamb, fluid_data, mixing_rule=None, T0=None): + r""" + Calculate specific physical exergy. + + Physical exergy is allocated to a thermal and a mechanical share according + to :cite:`Morosuk2019`. + + Parameters + ---------- + pamb : float + Ambient pressure p0 / Pa. + + Tamb : float + Ambient temperature T0 / K. + + Returns + ------- + e_ph : tuple + Specific thermal and mechanical exergy + (:math:`e^\mathrm{T}`, :math:`e^\mathrm{M}`) in J / kg. + + .. math:: + + e^\mathrm{T} = \left( h - h \left( p, T_0 \right) \right) - + T_0 \cdot \left(s - s\left(p, T_0\right)\right) + + e^\mathrm{M}=\left(h\left(p,T_0\right)-h\left(p_0,T_0\right)\right) + -T_0\cdot\left(s\left(p, T_0\right)-s\left(p_0,T_0\right)\right) + + e^\mathrm{PH} = e^\mathrm{T} + e^\mathrm{M} + """ + h_T0_p = h_mix_pT(p, Tamb, fluid_data, mixing_rule) + s_T0_p = s_mix_pT(p, Tamb, fluid_data, mixing_rule) + ex_therm = (h - h_T0_p) - T0 * (s - s_T0_p) + h0 = h_mix_pT(pamb, Tamb, fluid_data, mixing_rule) + s0 = s_mix_pT(pamb, Tamb, fluid_data, mixing_rule) + ex_mech = (h_T0_p - h0) - T0 * (s_T0_p - s0) + return ex_therm, ex_mech + + +def calc_chemical_exergy(pamb, Tamb, fluid_data, Chem_Ex, mixing_rule=None, T0=None): + if get_number_of_fluids(fluid_data) == 1: + pure_fluid = get_pure_fluid(fluid_data) + fluid_aliases = pure_fluid["wrapper"]._aliases + y = [Chem_Ex[k][Chem_Ex[k][4]] for k in fluid_aliases if k in Chem_Ex] + return y[0] / pure_fluid["wrapper"]._molar_mass * 1e3 + else: + _check_mixing_rule(mixing_rule, EXERGY_CHEMICAL, "chemical exergy") + return EXERGY_CHEMICAL[mixing_rule](pamb, Tamb, fluid_data, Chem_Ex) + + def T_mix_ph(p, h, fluid_data, mixing_rule=None, T0=None): if get_number_of_fluids(fluid_data) == 1: pure_fluid = get_pure_fluid(fluid_data) diff --git a/src/tespy/tools/fluid_properties/mixtures.py b/src/tespy/tools/fluid_properties/mixtures.py index 78fee9875..33d5fbf3e 100644 --- a/src/tespy/tools/fluid_properties/mixtures.py +++ b/src/tespy/tools/fluid_properties/mixtures.py @@ -1,11 +1,12 @@ import CoolProp as CP +import numpy as np +from tespy.tools.global_vars import gas_constants from .helpers import _is_larger_than_precision from .helpers import calc_molar_mass_mixture from .helpers import get_molar_fractions - def h_mix_pT_ideal(p=None, T=None, fluid_data=None, **kwargs): molar_fractions = get_molar_fractions(fluid_data) @@ -49,12 +50,9 @@ def h_mix_pT_forced_gas(p, T, fluid_data, **kwargs): if _is_larger_than_precision(data["mass_fraction"]): pp = p * molar_fractions[fluid] - if fluid == "H2O": - if pp >= data["wrapper"]._p_min: - if T <= data["wrapper"].T_sat(pp): - h += data["wrapper"].h_QT(1, T) * data["mass_fraction"] - else: - h += data["wrapper"].h_pT(pp, T) * data["mass_fraction"] + if fluid == "H2O" and pp >= data["wrapper"]._p_min: + if T <= data["wrapper"].T_sat(pp): + h += data["wrapper"].h_QT(1, T) * data["mass_fraction"] else: h += data["wrapper"].h_pT(pp, T) * data["mass_fraction"] else: @@ -220,6 +218,44 @@ def viscosity_mix_pT_incompressible(p=None, T=None, fluid_data=None, **kwargs): return viscosity +def exergy_chemical_ideal_cond(pamb, Tamb, fluid_data, Chem_Ex): + + molar_fractions = get_molar_fractions(fluid_data) + water_alias = _water_in_mixture(fluid_data) + if water_alias: + water_alias = next(iter(water_alias)) + _, molar_fractions_gas, _, molar_liquid = cond_check( + pamb, Tamb, fluid_data, water_alias + ) + else: + molar_fractions_gas = molar_fractions + molar_liquid = 0 + + ex_cond = 0 + ex_dry = 0 + for fluid, x in molar_fractions_gas.items(): + if x == 0: + continue + + fluid_aliases = fluid_data[fluid]["wrapper"]._aliases + + if molar_liquid > 0: + y = [ + Chem_Ex[k][2] for k in fluid_aliases if k in Chem_Ex + ] + ex_cond += molar_liquid * y[0] + + y = [Chem_Ex[k][3] for k in fluid_aliases if k in Chem_Ex] + ex_dry += x * y[0] + Tamb * gas_constants['uni'] * 1e-3 * x * np.log(x) + + ex_chemical = ex_cond + ex_dry * (1 - molar_liquid) + ex_chemical *= 1 / calc_molar_mass_mixture( + fluid_data, molar_fractions + ) + + return ex_chemical * 1e3 # Data from Chem_Ex are in kJ / mol + + def _water_in_mixture(fluid_data): water_aliases = set(CP.CoolProp.get_aliases("H2O")) return water_aliases & set([f for f in fluid_data if _is_larger_than_precision(fluid_data[f]["mass_fraction"])]) @@ -324,3 +360,7 @@ def cond_check(p, T, fluid_data, water_alias): "ideal-cond": viscosity_mix_pT_ideal, "incompressible": viscosity_mix_pT_incompressible } + +EXERGY_CHEMICAL = { + "ideal-cond": exergy_chemical_ideal_cond, +} diff --git a/src/tespy/tools/fluid_properties/wrappers.py b/src/tespy/tools/fluid_properties/wrappers.py index 483d9818d..248fae340 100644 --- a/src/tespy/tools/fluid_properties/wrappers.py +++ b/src/tespy/tools/fluid_properties/wrappers.py @@ -77,6 +77,7 @@ def __init__(self, fluid, back_end=None) -> None: def _set_constants(self): self._T_min = self.AS.trivial_keyed_output(CP.iT_min) self._T_max = self.AS.trivial_keyed_output(CP.iT_max) + self._aliases = CP.CoolProp.get_aliases(self.fluid) if self.back_end == "INCOMP": self._p_min = 1e2