Source code for tespy.components.displacementmachinery.polynomial_compressor

# -*- coding: utf-8

"""Module of class PolynomialCompressor.


This file is part of project TESPy (github.com/oemof/tespy). It's copyrighted
by the contributors recorded in the version control history of the file,
available from its original location
tespy/components/displacementmachinery/polynomial_compressor.py

SPDX-License-Identifier: MIT
"""
import warnings

import numpy as np

from tespy.components.component import component_registry
from tespy.components.displacementmachinery.base import DisplacementMachine
from tespy.tools import logger
from tespy.tools.data_containers import ComponentMandatoryConstraints as dc_cmc
from tespy.tools.data_containers import ComponentProperties as dc_cp
from tespy.tools.data_containers import GroupedComponentProperties as dc_gcp
from tespy.tools.data_containers import SimpleDataContainer as dc_simple
from tespy.tools.fluid_properties import T_sat_p
from tespy.tools.fluid_properties import isentropic
from tespy.tools.helpers import TESPyComponentError


[docs] @component_registry class PolynomialCompressor(DisplacementMachine): r""" Class for a compressor model following the EN12900 implementation of :cite:`cecchinato2010`. See the example for the intended use of the component. **Mandatory Equations** - fluid: :py:meth:`tespy.components.component.Component.variable_equality_structure_matrix` - mass flow: :py:meth:`tespy.components.component.Component.variable_equality_structure_matrix` **Optional Equations** - :py:meth:`tespy.components.component.Component.dp_structure_matrix` - :py:meth:`tespy.components.component.Component.pr_structure_matrix` - :py:meth:`tespy.components.displacementmachinery.polynomial_compressor.PolynomialCompressor.energy_balance_group_func` - :py:meth:`tespy.components.displacementmachinery.polynomial_compressor.PolynomialCompressor.eta_s_group_func` - :py:meth:`tespy.components.displacementmachinery.polynomial_compressor.PolynomialCompressor.eta_vol_group_func` Inlets/Outlets - in1 - out1 Optional inlets - power Image .. image:: /api/_images/Compressor.svg :alt: flowsheet of the compressor :align: center :class: only-light .. image:: /api/_images/Compressor_darkmode.svg :alt: flowsheet of the compressor :align: center :class: only-dark Parameters ---------- label : str The label of the component. design : list List containing design parameters (stated as String). offdesign : list List containing offdesign parameters (stated as String). design_path : str Path to the components design case. local_offdesign : boolean Treat this component in offdesign mode in a design calculation. local_design : boolean Treat this component in design mode in an offdesign calculation. char_warnings : boolean Ignore warnings on default characteristics usage for this component. printout : boolean Include this component in the network's results printout. P : float, dict Compressor power, :math:`P/\text{W}` dissipation_ratio : float, dict Relative heat loss of compressor, :math:`Q_\text{diss,rel}/1` eta_s : float, dict Isentropic efficiency, :math:`\eta_\text{s}/1` eta_s_poly : array, dict Polynomial coefficients for isentropic efficiency eta_vol : float, dict Volumetric efficiency, :math:`\eta_\text{vol}/1` eta_vol_poly : array, dict Polynomial coefficients for volumetric efficiency reference_state: dict Reference state for the polynomial and displacement. pr : float, dict Outlet to inlet pressure ratio, :math:`pr/1` dp : float, dict Inlet to outlet pressure difference, :math:`dp/\text{p}_\text{unit}` Is specified in the Network's pressure unit Example ------- The utilization of this component is intended to be done in two steps: 1. Calculate the reference state isentropic and volumetric efficiency polynomials based on the provided manufacturer data. 2. Set the resulting isentropic and volumetric efficiency polynomials. Under the assumption of isentropic and volumetric efficiency not being constant at variable compressor rpm, the outlet state will be determined with the volumetric flow at inlet. The volumetric flow at inlet scales linearly with the rpm of the compressor. >>> from tespy.components import Source, Sink, PolynomialCompressor >>> from tespy.connections import Connection >>> from tespy.networks import Network >>> import pandas as pd >>> from CoolProp.CoolProp import PropsSI >>> nw = Network(iterinfo=False) >>> nw.units.set_defaults(**{ ... "pressure": "bar", "temperature": "degC" ... }) >>> so = Source("from evaporator") >>> si = Sink("to condenser") >>> compressor = PolynomialCompressor("compressor") >>> c1 = Connection(so, "out1", compressor, "in1", label="c1") >>> c2 = Connection(compressor, "out1", si, "in1", label="c2") >>> nw.add_conns(c1, c2) Now, we can either provide - a 10-coefficient polynomial for power and cooling or - provide the respective power and cooling energy from a datasheet of a compressor manufacturer to generate such a polynomial Then we can used a precalculation method, which transforms the polynomial or the data into two polynomials, one for the isentropic efficiency and one for the volumetric efficiency, both as a function of evaporation and condensation temperature. Additionally information on a reference state have to be provided, which include - superheating at suction - subcooling after the condensation - the rpm belonging to the original data - a displacement value (kg/h) with the respective rpm for this displacement .. tip:: The compressor data or the 10-coefficient polynomials can be retrieved from manufacturers. For example, Bitzer provides such data, which can be used to retrieve a polynomial. The data for this example have been retrieved from :cite:`bitzer2025_HSK`. >>> reference_state = { ... "T_sh": 20, # superheating ... "T_sc": 0, # subcooling ... "rpm_poly": 50 * 60, # rpm belonging to the polynomial data ... "rpm_displacement": 20 * 60, # rpm belonging to the displacement ... "displacement": 214 # kg / h ... } >>> power = pd.DataFrame( ... columns=[10,7.5,5,0,-5,-10], index=[30, 40, 50], dtype=float ... ) >>> cooling = power.copy() >>> cooling.loc[30] = [465600,424100,385500,316700,257900,208000] >>> cooling.loc[40] = [418900,380400,344800,281400,227400,181600] >>> cooling.loc[50] = [365900,331300,299200,242100,193700,152900] >>> power.loc[30] = [62.0,61.8,61.8,61.8,61.7,61.3] >>> power.loc[40] = [78.0,78.0,78.0,78.0,77.7,76.8] >>> power.loc[50] = [99.2,99.2,99.2,98.9,98.1,96.5] >>> power = power * 1000 .. attention:: The data or polynomial formulations must be in SI units! We can now use the inbuilt method to determine the isentropic and volumetric efficiency polynomials. For that we need to import the respective method. Apart from this method, there is also the :py:func:`tespy.components.displacementmachinery.polynomial_compressor.generate_eta_polys_from_power_and_cooling_polys` method, that can do the same step provided a polynomial for power and one for the cooling. >>> from tespy.components.displacementmachinery.polynomial_compressor import ( ... generate_eta_polys_from_data ... ) >>> eta_s_poly, eta_vol_poly = generate_eta_polys_from_data( ... power, cooling, "R134a", reference_state ... ) >>> eta_s_poly array([ 3.44223012e-03, -3.75139140e-02, 4.39204462e-02, -9.21644870e-04, 1.68576190e-03, -8.97540501e-04, -7.54781107e-06, 1.61377008e-05, -1.53820046e-05, 5.04818089e-06]) >>> eta_vol_poly array([ 5.81192914e-03, -7.18820053e-04, 7.41463587e-02, 2.84410052e-05, 6.51372426e-05, -1.89872495e-03, 7.84206012e-07, -1.90585865e-06, 4.52695494e-07, 1.51321175e-05]) We can take these polynomials and set them on the compressor instance together with the reference state and the assumption on heat dissipation. >>> compressor.set_attr( ... eta_s_poly=eta_s_poly, eta_vol_poly=eta_vol_poly, dissipation_ratio=0.05, ... reference_state=reference_state ... ) First, we can impose the boundary conditions on "c1" that are equal to the displacement reference state. In that case, we should be able to get the same displacement value as inputted into the reference. >>> c1.set_attr(fluid={"R134a": 1}, T=0, td_dew=10) # T_evap=-10°C >>> compressor.set_attr(rpm=1200) >>> p_sat = PropsSI("P", "Q", 0, "T", 50 + 273.15, "R134a") # T_cond=50°C >>> c2.set_attr(p=p_sat / 1e5) >>> nw.solve("design") >>> round(c1.v.val * 3600 / compressor.eta_vol.val, 2) 214.0 >>> round(compressor.eta_s.val, 3) 0.5 >>> round(compressor.eta_vol.val, 3) 0.814 We can also double check our resulting isentropic and volumetric efficiency values with the evaluation of the polynomials. >>> from tespy.components.displacementmachinery.polynomial_compressor import ( ... calc_EN12900 ... ) >>> round(compressor.eta_s.val, 3) == round(calc_EN12900(eta_s_poly, -10, 50), 3) np.True_ >>> round(compressor.eta_vol.val, 3) == round(calc_EN12900(eta_vol_poly, -10, 50), 3) np.True_ .. tip:: You can also create polynomials for power and cooling from respective data. For that, import the :py:func:`tespy.components.displacementmachinery.polynomial_compressor.fit_EN12900` method and pass the respective data. We can also check the compressor power. It is higher than the power of an adiabatic compressor due to the heat dissipation. The compressor power plus heat dissipation will give the actual power required for isentropic compression. The heat dissipation is negative due to the heat leaving the component. >>> round(compressor.P.val) 38385 >>> round(compressor.Q_diss.val) -1919 >>> round(compressor.P.val + compressor.Q_diss.val) 36466 Now, let's see what happens, if evaporation or condensation temperature change: >>> c1.set_attr(T=20, td_dew=10) # T_evap=10°C >>> p_sat = PropsSI("P", "Q", 0, "T", 40 + 273.15, "R134a") # T_cond=40°C >>> c2.set_attr(p=p_sat / 1e5) >>> nw.solve("design") >>> round(compressor.eta_s.val, 3) 0.665 >>> round(compressor.eta_vol.val, 3) 0.924 It is also possible, to make the rpm a variable. This is useful, in case mass flow through the compressor is governed from external. Usually, this could be the case, if a specific heat transfer is required to be provided by the condenser or from the evaporator. In this case, we just fix the displacement to mimic that. >>> compressor.set_attr(rpm="var") >>> c1.set_attr(v=400/3600) >>> nw.solve("design") >>> round(compressor.rpm.val) 2427 As final remarks: You can also set fixed isentropic and fixed volumetric efficiencies for these components. """ def _preprocess(self, row_idx): if self.Q_diss_rel.is_set: msg = ( "The parameter Q_diss_rel has been renamed, please use " "'dissipation_ratio' instead." ) logger.warning(msg) warnings.warn(msg, FutureWarning) # this only injects to .val and not to .val_SI, the calculation # of .val_SI from .val in preprocessing already happened before # this point self.set_attr(dissipation_ratio=self.Q_diss_rel.val) self.dissipation_ratio.val_SI = self.Q_diss_rel.val_SI if not self.dissipation_ratio.is_set: msg = ( f"The component {self.label} of type {self.__class__.__name__} " "requires you to specify the relative heat dissipation " "dissipation_ratio. If you want to disregard heat dissipation set " "the value to 0.0" ) logger.error(msg) raise TESPyComponentError(msg) return super()._preprocess(row_idx)
[docs] @staticmethod def powerinlets(): return ["power"]
[docs] def get_mandatory_constraints(self): constraints = super().get_mandatory_constraints() if len(self.power_inl) > 0: constraints["energy_connector_balance"] = dc_cmc(**{ "func": self.energy_connector_balance_func, "dependents": self.energy_connector_dependents, "num_eq_sets": 1 }) return constraints
[docs] def get_parameters(self): params = super().get_parameters() params.update({ "Q_diss": dc_cp( max_val=0, val=0, is_result=True, quantity="heat", description="heat dissipation" ), "P": dc_cp( min_val=0, is_result=True, quantity="power", description="power consumption" ), "eta_vol": dc_cp( min_val=0, max_val=1, is_result=True, quantity="efficiency", description="volumetric efficiency" ), "dissipation_ratio": dc_cp( min_val=0, max_val=1, val=0, quantity="ratio", description="heat dissipation ratio relative to power consumption" ), "Q_diss_rel": dc_cp( min_val=0, max_val=1, val=0, quantity="ratio", description="heat dissipation ratio relative to power consumption(deprecated)" ), "rpm": dc_cp( min_val=0, is_result=True, _potential_var=True, description="compressor frequency" ), "reference_state": dc_simple( description="reference state definition for the scaling of displacement with compressor rpm" ), "eta_s_poly": dc_simple( description="polynomial coefficients for isentropic efficiency" ), "eta_vol_poly": dc_simple( description="polynomial coefficients for volumetric efficiency" ), "eta_vol_poly_group": dc_gcp( elements=["reference_state", "eta_vol_poly", "rpm"], func=self.eta_vol_poly_group_func, dependents=self.eta_vol_poly_group_dependents, num_eq_sets=1, description="displacement equation based on polynomial coefficients for volumetric efficiency" ), "eta_vol_group": dc_gcp( elements=["reference_state", "eta_vol", "rpm"], func=self.eta_vol_group_func, dependents=self.eta_vol_group_dependents, num_eq_sets=1, description="displacement equation based on fixed volumetric efficiency" ), "eta_s": dc_cp( min_val=0, max_val=1, is_result=True, quantity="efficiency", description="isentropic efficiency" ), "eta_s_poly_group": dc_gcp( elements=["eta_s_poly", "dissipation_ratio"], func=self.eta_s_poly_group_func, dependents=self.eta_s_group_dependents, num_eq_sets=1, description="isentropic efficiency equation based on polynomial coefficients" ), "eta_s_group": dc_gcp( elements=["eta_s", "dissipation_ratio"], func=self.eta_s_group_func, dependents=self.eta_s_group_dependents, num_eq_sets=1, description="isentropic efficiency equation with fixed efficiency" ), "energy_balance_group": dc_gcp( elements=["P", "dissipation_ratio"], func=self.energy_balance_group_func, dependents=self.energy_balance_group_dependents, num_eq_sets=1, description="energy balance equation for fixed power and dissipation ratio" ) }) return params
# this is a bit different that in other cases, because the power cannot # directly be deduced from the change in enthalpy
[docs] def energy_connector_balance_func(self): return ( self.inl[0].m.val_SI * (self.outl[0].h.val_SI - self.inl[0].h.val_SI) / (1 - self.dissipation_ratio.val_SI) - self.power_inl[0].E.val_SI )
[docs] def energy_connector_dependents(self): return [ self.power_inl[0].E, self.inl[0].m, self.inl[0].h, self.outl[0].h ]
[docs] def energy_balance_group_func(self): r"""Equation for specified power and relative heat dissipation .. math:: 0 = \dot m \cdot \frac{ h_\text{out} - h_\text{in}}{1 - \dot Q_\text{diss,rel}} - P Returns ------- float residual """ return ( self.inl[0].m.val_SI * (self.outl[0].h.val_SI - self.inl[0].h.val_SI) / (1 - self.dissipation_ratio.val_SI) - self.P.val_SI )
[docs] def energy_balance_group_dependents(self): return [self.inl[0].m, self.inl[0].h, self.outl[0].h]
[docs] def eta_s_group_func(self): r"""Isentropic efficiency function with a heat loss term .. math:: 0 = \eta_\text{s} \cdot \frac{ h_\text{out} - h_\text{in}}{1 - \dot Q_\text{diss,rel}} - \left( h_\text{out,s} - h_\text{in} \right) .. note:: For this, the actual enthalpy increase is further increased by the relative heat loss to calculate the (virtual) compression outlet enthalpy. The compressor is first considered isentropic, then the relative heat loss (relative to compression power) is subtracted from the outlet enthalpy afterwards. Returns ------- float residual value """ i = self.inl[0] o = self.outl[0] h_out_s = isentropic( i.p.val_SI, i.h.val_SI, o.p.val_SI, i.fluid_data, i.mixing_rule, T0=None ) return ( self.eta_s.val_SI * (o.h.val_SI - i.h.val_SI) / (1 - self.dissipation_ratio.val_SI) - (h_out_s - i.h.val_SI) )
[docs] def eta_s_poly_group_func(self): r"""Isentropic efficiency function with a heat loss term .. math:: 0 = \eta_\text{s} \left(T_\text{evap}, T_\text{cond}\right)\cdot \frac{ h_\text{out} - h_\text{in}}{1 - \dot Q_\text{diss,rel}} - \left( h_\text{out,s} - h_\text{in} \right) .. note:: For this, the actual enthalpy increase is further increased by the relative heat loss to calculate the (virtual) compression outlet enthalpy. The compressor is first considered isentropic, then the relative heat loss (relative to compression power) is subtracted from the outlet enthalpy afterwards. Returns ------- float residual value """ i = self.inl[0] o = self.outl[0] t_evap = T_sat_p(i.p.val_SI, i.fluid_data) t_cond = T_sat_p(o.p.val_SI, o.fluid_data) # here .val is fine, because it just holds the coefficients eta_s = _calc_EN12900_SI(self.eta_s_poly.val, t_evap, t_cond) h_out_s = isentropic( i.p.val_SI, i.h.val_SI, o.p.val_SI, i.fluid_data, i.mixing_rule, T0=None ) return ( eta_s * (o.h.val_SI - i.h.val_SI) / (1 - self.dissipation_ratio.val_SI) - (h_out_s - i.h.val_SI) )
[docs] def eta_s_group_dependents(self): return [ self.inl[0].p, self.inl[0].h, self.outl[0].p, self.outl[0].h, ]
[docs] def eta_vol_group_func(self): r"""Volumetric efficiency function. .. math:: 0 = \dot m_\text{in} - \eta_\text{vol} \cdot \frac{\dot V_\text{ref}}{3600} \cdot \frac{rpm}{rpm_\text{ref}} \cdot \frac{1}{v_\text{in}} Returns ------- float residual value """ i = self.inl[0] displacement = ( self.reference_state.val["displacement"] / 3600 * self.rpm.val_SI / self.reference_state.val["rpm_displacement"] ) return ( i.m.val_SI - self.eta_vol.val_SI * displacement / i.calc_vol() )
[docs] def eta_vol_group_dependents(self): return [ self.inl[0].m, self.inl[0].p, self.inl[0].h, self.rpm ]
[docs] def eta_vol_poly_group_func(self): r"""Volumetric efficiency function. .. math:: 0 = \dot m_\text{in} - \eta_\text{vol} \left(T_\text{evap}, T_\text{cond}\right) \cdot \frac{\dot V_\text{ref}}{3600} \cdot \frac{rpm}{rpm_\text{ref}} \cdot \frac{1}{v_\text{in}} Returns ------- float residual value """ i = self.inl[0] o = self.outl[0] t_evap = T_sat_p(i.p.val_SI, i.fluid_data) t_cond = T_sat_p(o.p.val_SI, o.fluid_data) # here .val is fine, because it just holds the coefficients eta_vol = _calc_EN12900_SI(self.eta_vol_poly.val, t_evap, t_cond) displacement = ( self.reference_state.val["displacement"] / 3600 * self.rpm.val_SI / self.reference_state.val["rpm_displacement"] ) return ( i.m.val_SI - eta_vol * displacement / i.calc_vol() )
[docs] def eta_vol_poly_group_dependents(self): return [ self.inl[0].m, self.inl[0].p, self.inl[0].h, self.outl[0].p, self.rpm ]
[docs] def calc_parameters(self): i = self.inl[0] o = self.outl[0] self.pr.val_SI = o.p.val_SI / i.p.val_SI self.dp.val_SI = i.p.val_SI - o.p.val_SI h_2 = ( (o.h.val_SI - i.h.val_SI * self.dissipation_ratio.val_SI) / (1 - self.dissipation_ratio.val_SI) ) self.P.val_SI = i.m.val_SI * (h_2 - i.h.val_SI) self.Q_diss.val_SI = i.m.val_SI * (o.h.val_SI - h_2) self.eta_s.val_SI = ( isentropic( i.p.val_SI, i.h.val_SI, o.p.val_SI, i.fluid_data, i.mixing_rule, T0=None ) - i.h.val_SI ) / ( (h_2 - i.h.val_SI) ) if self.reference_state.is_set: displacement = ( self.reference_state.val["displacement"] / 3600 * self.rpm.val_SI / self.reference_state.val["rpm_displacement"] ) self.eta_vol.val_SI = i.m.val_SI * i.calc_vol() / displacement
def _calc_etas_from_polynome(fluid: str, T_evap: float, T_cond: float, reference_state: dict, polynomes: dict) -> dict: """Calculate the isentropic and polynomial efficiency for the reference state according to the procedure in :cite:`cecchinato2010`. Parameters ---------- fluid : str Name of the fluid T_evap : float Evaporation temperature in K T_cond : float Evaporation temperature in K reference_state : dict Dictionary with reference state information, i.e. - T_sh: superheating delta T (Kelvin) - T_sc: subcooling delta T (Kelvin) - rpm_poly: reference rpm of the polynomial - displancement: displacement in m3/h - rpm_displacement: reference rpm of the displacement polynomes : dict Dictionary containing the power and the evaporator heat polynomial Returns ------- dict Dictionary with keys "eta_s" and "eta_vol" for isentropic and volumetric efficiency """ # this method will have few calls, therefore high-level interface # usage is fine from CoolProp.CoolProp import PropsSI as PSI P_comp = _calc_EN12900_SI(polynomes["power"], T_evap, T_cond) Q_evap = _calc_EN12900_SI(polynomes["cooling"], T_evap, T_cond) p_evap = PSI("P", "T", T_evap, "Q", 1, fluid) p_cond = PSI("P", "T", T_cond, "Q", 0, fluid) T_sh = reference_state["T_sh"] T_sc = reference_state["T_sc"] if T_sh > 0: h_evap_out = PSI("H", "P", p_evap, "T", T_evap + T_sh, fluid) else: h_evap_out = PSI("H", "P", p_evap, "Q", 1, fluid) if T_sc > 0: h_cond_out = PSI("H", "P", p_cond, "T", T_cond - T_sc, fluid) else: h_cond_out = PSI("H", "P", p_cond, "Q", 0, fluid) s_comp_in = PSI("S", "P", p_evap, "H", h_evap_out, fluid) h_comp_s = PSI("H", "P", p_cond, "S", s_comp_in, fluid) dot_m = Q_evap / (h_evap_out - h_cond_out) eta_s = dot_m * (h_comp_s - h_evap_out) / P_comp rpm_poly = reference_state["rpm_poly"] rpm_displacement = reference_state["rpm_displacement"] displacement = ( (reference_state["displacement"] / 3600) * (rpm_poly / rpm_displacement) ) rho_comp_in = PSI("D", "P", p_evap, "H", h_evap_out, fluid) eta_vol = dot_m / (rho_comp_in * displacement) return { "eta_s": eta_s, "eta_vol": eta_vol }
[docs] def calc_EN12900(c: list, t_evap: float, t_cond: float) -> float: """Calculate the EN12900 polynomial Parameters ---------- c : list Coefficients of the polynomial t_evap : float Reference evaporation temperature t_cond : float Reference condensation temperature Returns ------- float Result of polynomial """ return ( c[0] + c[1] * t_evap + c[2] * t_cond + c[3] * t_evap**2 + c[4] * t_evap * t_cond + c[5] * t_cond ** 2 + c[6] * t_evap**3 + c[7] * t_evap ** 2 * t_cond + c[8] * t_evap * t_cond ** 2 + c[9] * t_cond ** 3 )
def _calc_EN12900_SI(c: list, t_evap: float, t_cond: float) -> float: """Calculate the EN12900 polynomial Parameters ---------- c : list Coefficients of the polynomial t_evap : float Reference evaporation temperature t_cond : float Reference condensation temperature Returns ------- float Result of polynomial """ return calc_EN12900(c, t_evap - 273.15, t_cond - 273.15)
[docs] def fit_EN12900(t_evap: np.array, t_cond: np.array, data: np.array) -> np.array: """Fit the polynome coefficients of EN12900 polynome based on evaporation and condensation temperature and respective measurements Parameters ---------- t_evap : np.array 1-d array of evaporation temperatures t_cond : np.array 1-d array of condensation temperatures data : np.array datasheet information Returns ------- np.array 1-d array of polynome coefficients """ z = data.flatten() t_cond, t_evap = np.meshgrid(t_evap, t_cond) # needs to be inverted here x = t_cond.flatten() y = t_evap.flatten() A = np.column_stack([ np.ones_like(x), # c0 x, # c1 * t_evap y, # c2 * t_cond x ** 2, # c3 * t_evap^2 x * y, # c4 * t_evap*t_cond y ** 2, # c5 * t_cond^2 x ** 3, # c6 * t_evap^3 (x ** 2) * y, # c7 * t_evap^2*t_cond x * (y ** 2), # c8 * t_evap*t_cond^2 y ** 3 # c9 * t_cond^3 ]) c, _, _, _ = np.linalg.lstsq(A, z, rcond=None) check = calc_EN12900(c, x, y) if not np.allclose(check, z, rtol=0.02): deviation = abs((check - z) / z) location = np.argmax(deviation) T_evap = y[location] T_cond = x[location] msg = ( f"A maximum relative deviation of {deviation.max()} at " f"{T_evap=} and {T_cond=} remains when fitting the polynomial " "coefficients to the data." ) logger.warning(msg) return c
[docs] def generate_eta_polys_from_power_and_cooling_polys(power_poly: list, cooling_poly: list, t_evap: np.array, t_cond: np.array, fluid: str, reference_state: dict) -> tuple: """Generate polynomials for calculation of isentropic and volumetric efficiency of a compressor Parameters ---------- power_poly : list List of polynomial coefficients for power cooling_poly : list List of polynomial coefficients for cooling fluid : str Name of fluid reference_state : dict Dictionary with reference state information, i.e. - T_sh: superheating delta T (Kelvin) - T_sc: subcooling delta T (Kelvin) - rpm_poly: reference rpm of the polynomial - displancement: displacement in m3/h - rpm_displacement: reference rpm of the displacement Returns ------- tuple Polynomial coefficients for isentropic and volumetric efficiency as function of evaporation and condensation temperature """ columns = t_evap index = t_cond t_evap, t_cond = np.meshgrid(t_evap, t_cond) t_evap = t_evap.flatten() + 273.15 t_cond = t_cond.flatten() + 273.15 etas = _calc_etas_from_polynome( fluid, t_evap, t_cond, reference_state=reference_state, polynomes={"power": power_poly, "cooling": cooling_poly} ) for k in etas: etas[k] = etas[k].reshape(len(index), len(columns)) eta_s_poly = fit_EN12900(columns, index, etas["eta_s"]) eta_vol_poly = fit_EN12900(columns, index, etas["eta_vol"]) return eta_s_poly, eta_vol_poly
[docs] def generate_eta_polys_from_data(df_power, df_cooling, fluid: str, reference_state: dict) -> tuple: """Generate polynomials for calculation of isentropic and volumetric efficiency of a compressor Parameters ---------- df_power : pd.DataFrame Power consumption data df_cooling : pd.DataFrame Cooling data fluid : str Name of fluid reference_state : dict Dictionary with reference state information, i.e. - T_sh: superheating delta T (Kelvin) - T_sc: subcooling delta T (Kelvin) - rpm_poly: reference rpm of the polynomial - displancement: displacement in m3/h - rpm_displacement: reference rpm of the displacement Returns ------- tuple Polynomial coefficients for isentropic and volumetric efficiency as function of evaporation and condensation temperature """ same_columns = (df_cooling.columns == df_power.columns).all() same_index = (df_cooling.index == df_power.index).all() if not same_columns or not same_index: msg = ( "The dataframes provided to this method must have identical " "columns (evaporation temperature) and indices (condensation " "temperature)." ) raise ValueError(msg) t_evap = df_power.columns t_cond = df_power.index power_poly = fit_EN12900(t_evap, t_cond, df_power.values) cooling_poly = fit_EN12900(t_evap, t_cond, df_cooling.values) return generate_eta_polys_from_power_and_cooling_polys( power_poly, cooling_poly, df_power.columns, df_power.index, fluid, reference_state )