Ejemplo n.º 1
0
def isentropic(inflow, outflow, T0=675):
    r"""
    Calculate the enthalpy at the outlet after isentropic process.

    Parameters
    ----------
    inflow : list
        Inflow fluid property vector containing mass flow, pressure, enthalpy
        and fluid composition.

    outflow : list
        Outflow fluid property vector containing mass flow, pressure, enthalpy
        and fluid composition.

    Returns
    -------
    h_s : float
        Enthalpy after isentropic state change.

        .. math::

            h_\mathrm{s} = \begin{cases}
            h\left(p_{out}, s\left(p_{in}, h_{in}\right) \right) &
            \text{pure fluids}\\
            h\left(p_{out}, s\left(p_{in}, T_{in}\right) \right) &
            \text{mixtures}\\
            \end{cases}
    """
    fluid = single_fluid(inflow[3])
    if fluid is not None:
        return h_ps(outflow[1], s_ph(inflow[1], inflow[2], fluid), fluid)
    else:
        s_mix = s_mix_ph(inflow)
        return h_mix_ps(outflow, s_mix, T0=T0)
Ejemplo n.º 2
0
def h_mix_pQ(flow, Q):
    r"""
    Calculates the enthalpy from pressure and vapour mass fraction.

    Parameters
    ----------
    flow : list
        Fluid property vector containing mass flow, pressure, enthalpy and
        fluid composition.

    Q : float
        Vapour mass fraction Q / 1.

    Returns
    -------
    h : float
        Specific enthalpy h / (J/kg).

    Note
    ----
    This function works for pure fluids only!
    """
    fluid = single_fluid(flow[3])
    if not isinstance(fluid, str):
        msg = 'The function h_mix_pQ can only be used for pure fluids.'
        logging.error(msg)
        raise ValueError(msg)

    pcrit = CPPSI('Pcrit', fluid)
    if flow[1] > pcrit:
        memorise.heos[fluid].update(CP.PQ_INPUTS, pcrit * 0.95, Q)
    else:
        memorise.heos[fluid].update(CP.PQ_INPUTS, flow[1], Q)

    return memorise.heos[fluid].hmass()
Ejemplo n.º 3
0
def h_mix_pQ(flow, Q):
    r"""
    Calculate the enthalpy from pressure and vapour mass fraction.

    Parameters
    ----------
    flow : list
        Fluid property vector containing mass flow, pressure, enthalpy and
        fluid composition.

    Q : float
        Vapour mass fraction Q / 1.

    Returns
    -------
    h : float
        Specific enthalpy h / (J/kg).

    Note
    ----
    This function works for pure fluids only!
    """
    fluid = single_fluid(flow[3])
    if fluid is None:
        msg = 'The function h_mix_pQ can only be used for pure fluids.'
        logging.error(msg)
        raise ValueError(msg)

    try:
        memorise.state[fluid].update(CP.PQ_INPUTS, flow[1], Q)
    except ValueError:
        pcrit = memorise.state[fluid].trivial_keyed_output(CP.iP_critical)
        memorise.state[fluid].update(CP.PQ_INPUTS, pcrit * 0.99, Q)

    return memorise.state[fluid].hmass()
Ejemplo n.º 4
0
def T_bp_p(flow):
    r"""
    Calculate temperature from boiling point pressure.

    Parameters
    ----------
    flow : list
        Fluid property vector containing mass flow, pressure, enthalpy and
        fluid composition.

    Returns
    -------
    T : float
        Temperature at boiling point.

    Note
    ----
    This function works for pure fluids only!
    """
    fluid = single_fluid(flow[3])
    pcrit = memorise.state[fluid].trivial_keyed_output(CP.iP_critical)
    if flow[1] > pcrit:
        memorise.state[fluid].update(CP.PQ_INPUTS, pcrit * 0.99, 1)
    else:
        memorise.state[fluid].update(CP.PQ_INPUTS, flow[1], 1)
    return memorise.state[fluid].T()
Ejemplo n.º 5
0
def s_mix_ph(flow, T0=300):
    r"""
    Calculate the entropy from pressure and enthalpy.

    Parameters
    ----------
    flow : list
        Fluid property vector containing mass flow, pressure, enthalpy and
        fluid composition.

    Returns
    -------
    s : float
        Specific entropy s / (J/(kgK)).

    Note
    ----
    First, check if fluid property has been memorised already.
    If this is the case, return stored value, otherwise calculate value and
    store it in the memorisation class.

    Uses CoolProp interface for pure fluids, newton algorithm for mixtures:

    .. math::

        s_{mix}\left(p,h\right) = s\left(p,T_{mix}(p,h)\right)
    """
    # check if fluid properties have been calculated before
    fl = tuple(flow[3].keys())
    memorisation = fl in memorise.s_ph.keys()
    if memorisation is True:
        a = memorise.s_ph[fl][:, :-1]
        b = np.asarray([flow[1], flow[2]] + list(flow[3].values()))
        ix = np.where(np.all(abs(a - b) <= err, axis=1))[0]
        if ix.size == 1:
            # known fluid properties
            s = memorise.s_ph[fl][ix, -1][0]
            memorise.s_ph_f[fl] += [s]
            return s

    # unknown fluid properties
    fluid = single_fluid(flow[3])
    if fluid is None:
        # calculate the fluid properties for fluid mixtures
        val = s_mix_pT(flow, T_mix_ph(flow, T0=T0))
    else:
        # calculate fluid property for pure fluids
        val = s_ph(flow[1], flow[2], fluid)

    if memorisation is True:
        # memorise the newly calculated value
        new = np.asarray([[flow[1], flow[2]] + list(flow[3].values()) + [val]])
        memorise.s_ph[fl] = np.append(memorise.s_ph[fl], new, axis=0)

    return val
Ejemplo n.º 6
0
def v_mix_ph(flow, T0=675):
    r"""
    Calculate the specific volume from pressure and enthalpy.

    Parameters
    ----------
    flow : list
        Fluid property vector containing mass flow, pressure, enthalpy and
        fluid composition.

    Returns
    -------
    v : float
        Specific volume v / (:math:`\mathrm{m}^3`/kg).

    Note
    ----
    First, check if fluid property has been memorised already.
    If this is the case, return stored value, otherwise calculate value and
    store it in the memorisation class.

    Uses CoolProp interface for pure fluids, newton algorithm for mixtures:

    .. math::

        v_{mix}\left(p,h\right) = v\left(p,T_{mix}(p,h)\right)
    """
    # check if fluid properties have been calculated before
    fl = tuple(flow[3].keys())
    memorisation = fl in Memorise.v_ph
    if memorisation:
        a = Memorise.v_ph[fl][:, :-2]
        b = np.asarray([flow[1], flow[2]] + list(flow[3].values()))
        ix = np.where(np.all(abs(a - b) <= err, axis=1))[0]
        if ix.size == 1:
            # known fluid properties
            Memorise.v_ph[fl][ix, -1] += 1
            return Memorise.v_ph[fl][ix, -2][0]

    # unknown fluid properties
    fluid = single_fluid(flow[3])
    if fluid is None:
        # calculate the fluid properties for fluid mixtures
        val = v_mix_pT(flow, T_mix_ph(flow, T0=T0))
    else:
        # calculate fluid property for pure fluids
        val = 1 / d_ph(flow[1], flow[2], fluid)

    if memorisation:
        # memorise the newly calculated value
        new = np.asarray(
            [[flow[1], flow[2]] + list(flow[3].values()) + [val, 0]])
        Memorise.v_ph[fl] = np.append(Memorise.v_ph[fl], new, axis=0)

    return val
Ejemplo n.º 7
0
def h_mix_pQ(flow, Q):
    r"""
    Calculate the enthalpy from pressure and vapour mass fraction.

    Parameters
    ----------
    flow : list
        Fluid property vector containing mass flow, pressure, enthalpy and
        fluid composition.

    Q : float
        Vapour mass fraction Q / 1.

    Returns
    -------
    h : float
        Specific enthalpy h / (J/kg).

    Note
    ----
    This function works for pure fluids only!
    """
    fluid = single_fluid(flow[3])
    if fluid is None:
        if sum(flow[3].values()) == 0:
            msg = 'The function h_mix_pQ is called without fluid information.'
            logging.error(msg)
            raise ValueError(msg)
        else:
            msg = 'The function h_mix_pQ can only be used for pure fluids.'
            logging.error(msg)
            raise ValueError(msg)

    try:
        Memorise.state[fluid].update(CP.PQ_INPUTS, flow[1], Q)
    except ValueError:
        p_crit = get_p_crit(fluid)
        Memorise.state[fluid].update(CP.PQ_INPUTS, p_crit * 0.99, Q)

    return Memorise.state[fluid].hmass()
Ejemplo n.º 8
0
    def create_group_data(self):
        """Collect the component group exergy data."""
        for group in self.sankey_data.keys():
            E_D = 0
            for df in [self.component_data, self.bus_data]:
                E_D += df[df['group'] == group]['E_D'].sum()
            self.sankey_data[group].loc['E_D'] = [E_D, 'E_D']

        # establish connections for fuel exergy via bus balance
        for b in self.E_F:
            input_value = self.calculate_group_input_value(b.label)
            self.sankey_data['E_F'].loc[b.label] = [
                self.sankey_data[b.label]['value'].sum() - input_value, 'E_F'
            ]

        # establish connections for product exergy via bus balance
        for b in self.E_P:
            input_value = self.calculate_group_input_value(b.label)
            self.sankey_data[b.label].loc['E_P'] = [
                input_value - self.sankey_data[b.label]['value'].sum(), 'E_P'
            ]

        # establish connections for exergy loss via bus balance
        for b in self.E_L:
            input_value = self.calculate_group_input_value(b.label)
            self.sankey_data[b.label].loc['E_L'] = [
                input_value - self.sankey_data[b.label]['value'].sum(), 'E_L'
            ]

        for fkt_group, data in self.sankey_data.items():
            comps = self.component_data[self.component_data['group'] ==
                                        fkt_group].index
            for comp in comps:
                comp_obj = self.nw.get_comp(comp)
                sources = self.nw.conns[self.nw.conns['source'] == comp_obj]
                for conn in sources['object']:
                    if conn.target.label not in comps:
                        target_group = self.component_data.loc[
                            conn.target.label, 'group']
                        target_value = conn.Ex_physical
                        cat = hlp.single_fluid(conn.fluid.val)
                        if cat is None:
                            cat = 'mix'
                        if target_group in data.index:
                            self.sankey_data[fkt_group].loc[
                                target_group, 'value'] += target_value
                        else:
                            self.sankey_data[fkt_group].loc[target_group] = [
                                target_value, cat
                            ]

        # create overview of component groups
        self.group_data = pd.DataFrame(columns=['E_F', 'E_P', 'E_D'],
                                       dtype='float64')
        for fkt_group in self.component_data['group'].unique():
            self.group_data.loc[fkt_group, 'E_F'] = (
                self.calculate_group_input_value(fkt_group))
            self.group_data.loc[fkt_group, 'E_D'] = (
                self.sankey_data[fkt_group].loc['E_D', 'value'])

        # calculate missing values
        self.group_data['E_P'] = (self.group_data['E_F'] -
                                  self.group_data['E_D'])
        self.group_data['epsilon'] = (self.group_data['E_P'] /
                                      self.group_data['E_F'])
        self.group_data['y_Dk'] = (self.group_data['E_D'] /
                                   self.network_data.loc['E_F'])
        self.group_data['y*_Dk'] = (self.group_data['E_D'] /
                                    self.network_data.loc['E_D'])
Ejemplo n.º 9
0
def T_mix_ps(flow, s, T0=300):
    r"""
    Calculate the temperature from pressure and entropy.

    Parameters
    ----------
    flow : list
        Fluid property vector containing mass flow, pressure, enthalpy and
        fluid composition.

    s : float
        Entropy of flow in J / (kgK).

    Returns
    -------
    T : float
        Temperature T / K.

    Note
    ----
    First, check if fluid property has been memorised already.
    If this is the case, return stored value, otherwise calculate value and
    store it in the memorisation class.

    Uses CoolProp interface for pure fluids, newton algorithm for mixtures:

    .. math::

        T_{mix}\left(p,s\right) = T_{i}\left(p,s_{i}\right)\;
        \forall i \in \text{fluid components}\\

        s_{i} = s \left(pp_{i}, T_{mix} \right)\\
        pp: \text{partial pressure}

    """
    # check if fluid properties have been calculated before
    fl = tuple(flow[3].keys())
    memorisation = fl in memorise.T_ps.keys()
    if memorisation is True:
        a = memorise.T_ps[fl][:, :-1]
        b = np.asarray([flow[1], flow[2]] + list(flow[3].values()) + [s])
        ix = np.where(np.all(abs(a - b) <= err, axis=1))[0]
        if ix.size == 1:
            # known fluid properties
            T = memorise.T_ps[fl][ix, -1][0]
            memorise.T_ps_f[fl] += [T]
            return T

    # unknown fluid properties
    fluid = single_fluid(flow[3])
    if fluid is None:
        # calculate the fluid properties for fluid mixtures
        if memorisation is True:
            valmin = max(
                [memorise.value_range[f][2] for f in fl if flow[3][f] > err]
            ) + 0.1
            if T0 < valmin or np.isnan(T0):
                T0 = valmin * 1.1
        else:
            valmin = 70

        val = newton(s_mix_pT, ds_mix_pdT, flow, s, val0=T0,
                     valmin=valmin, valmax=3000, imax=10)
        if memorisation is True:
            new = np.asarray(
                [[flow[1], flow[2]] + list(flow[3].values()) + [s, val]])
            # memorise the newly calculated value
            memorise.T_ps[fl] = np.append(memorise.T_ps[fl], new, axis=0)

        return val
    else:
        # calculate fluid property for pure fluids
        msg = ('The calculation of temperature from pressure and entropy '
               'for pure fluids should not be required, as the '
               'calculation is always possible from pressure and '
               'enthalpy. If there is a case, where you need to calculate '
               'temperature from these properties, please inform us: '
               'https://github.com/oemof/tespy.')
        logging.error(msg)
        raise ValueError(msg)
Ejemplo n.º 10
0
def T_mix_ph(flow, T0=300):
    r"""
    Calculate the temperature from pressure and enthalpy.

    Parameters
    ----------
    flow : list
        Fluid property vector containing mass flow, pressure, enthalpy and
        fluid composition.

    Returns
    -------
    T : float
        Temperature T / K.

    Note
    ----
    First, check if fluid property has been memorised already.
    If this is the case, return stored value, otherwise calculate value and
    store it in the memorisation class.

    Uses CoolProp interface for pure fluids, newton algorithm for mixtures:

    .. math::

        T_{mix}\left(p,h\right) = T_{i}\left(p,h_{i}\right)\;
        \forall i \in \text{fluid components}\\

        h_{i} = h \left(pp_{i}, T_{mix} \right)\\
        pp: \text{partial pressure}
    """
    # check if fluid properties have been calculated before
    fl = tuple(flow[3].keys())
    memorisation = fl in memorise.T_ph.keys()
    if memorisation is True:
        a = memorise.T_ph[fl][:, :-1]
        b = np.array([flow[1], flow[2]] + list(flow[3].values()))
        ix = np.where(np.all(abs(a - b) <= err, axis=1))[0]

        if ix.size == 1:
            # known fluid properties
            T = memorise.T_ph[fl][ix, -1][0]
            memorise.T_ph_f[fl] += [T]
            return T

    # unknown fluid properties
    fluid = single_fluid(flow[3])
    if fluid is None:
        # calculate the fluid properties for fluid mixtures
        if memorisation is True:
            valmin = max(
                [memorise.value_range[f][2] for f in fl if flow[3][f] > err]
            ) + 0.1
            if T0 < valmin or np.isnan(T0):
                T0 = valmin * 1.1
        else:
            valmin = 70
        val = newton(h_mix_pT, dh_mix_pdT, flow, flow[2], val0=T0,
                     valmin=valmin, valmax=3000, imax=10)
    else:
        # calculate fluid property for pure fluids
        val = T_ph(flow[1], flow[2], fluid)

    if memorisation is True:
        # memorise the newly calculated value
        new = np.asarray([[flow[1], flow[2]] + list(flow[3].values()) + [val]])
        memorise.T_ph[fl] = np.append(memorise.T_ph[fl], new, axis=0)

    return val
Ejemplo n.º 11
0
def h_mix_pT(flow, T, force_gas=False):
    r"""
    Calculate the enthalpy from pressure and Temperature.

    Parameters
    ----------
    flow : list
        Fluid property vector containing mass flow, pressure, enthalpy and
        fluid composition.

    T : float
        Temperature of flow T / K.

    Returns
    -------
    h : float
        Enthalpy h / (J/kg).

    Note
    ----
    Calculation for fluid mixtures.

    .. math::

        h_{mix}(p,T)=\sum_{i} h(pp_{i},T,fluid_{i})\;
        \forall i \in \text{fluid components}\\
        pp: \text{partial pressure}
    """
    n = molar_mass_flow(flow[3])

    h = 0
    fluid_name = single_fluid(flow[3])
    if fluid_name is None:

        x_i = {
            fluid: y / (molar_masses[fluid] * n)
            for fluid, y in flow[3].items()
        }

        water = Memorise.water
        if (water is not None and not force_gas and flow[3][water] > err):
            y_i_gas, x_i_gas, y_water_liq, x_water_liq = (
                cond_check(flow[3], x_i, flow[1], n, T)
            )

        else:
            y_i_gas = flow[3]
            y_water_liq = 0
            x_i_gas = x_i

        for fluid, y in y_i_gas.items():
            if y > err:
                if fluid == water and y_water_liq > 0:
                    Memorise.state[fluid].update(CP.QT_INPUTS, 0, T)
                    h += Memorise.state[fluid].hmass() * y_water_liq
                    Memorise.state[fluid].update(CP.QT_INPUTS, 1, T)
                    h += Memorise.state[fluid].hmass() * y * (1 - y_water_liq)

                else:
                    h += h_pT(
                        flow[1] * x_i_gas[fluid], T, fluid, force_gas
                    ) * y * (1 - y_water_liq)

    else:
        h = h_pT(flow[1], T, fluid_name, force_gas)

    return h
Ejemplo n.º 12
0
def T_mix_ps(flow, s, T0=675):
    r"""
    Calculate the temperature from pressure and entropy.

    Parameters
    ----------
    flow : list
        Fluid property vector containing mass flow, pressure, enthalpy and
        fluid composition.

    s : float
        Entropy of flow in J / (kgK).

    Returns
    -------
    T : float
        Temperature T / K.

    Note
    ----
    First, check if fluid property has been memorised already.
    If this is the case, return stored value, otherwise calculate value and
    store it in the memorisation class.

    Uses CoolProp interface for pure fluids, newton algorithm for mixtures:

    .. math::

        T_{mix}\left(p,s\right) = T_{i}\left(p,s_{i}\right)\;
        \forall i \in \text{fluid components}\\

        s_{i} = s \left(pp_{i}, T_{mix} \right)\\
        pp: \text{partial pressure}

    """
    # check if fluid properties have been calculated before
    fl = tuple(flow[3].keys())
    memorisation = fl in Memorise.T_ps
    if memorisation:
        a = Memorise.T_ps[fl][:, :-2]
        b = np.asarray([flow[1], flow[2]] + list(flow[3].values()) + [s])
        ix = np.where(np.all(abs(a - b) <= err, axis=1))[0]
        if ix.size == 1:
            # known fluid properties
            Memorise.T_ps[fl][ix, -1] += 1
            return Memorise.T_ps[fl][ix, -2][0]

    # unknown fluid properties
    fluid = single_fluid(flow[3])
    if fluid is None:
        # calculate the fluid properties for fluid mixtures
        valmin = max(
            [Memorise.value_range[f][2] for f in fl if flow[3][f] > err]
        ) + 0.1
        if T0 < valmin or np.isnan(T0):
            T0 = valmin * 1.1

        val = newton(s_mix_pT, ds_mix_pdT, flow, s, val0=T0,
                     valmin=valmin, valmax=3000, imax=10)

    else:
        # calculate fluid property for pure fluids
        val = T_ps(flow[1], s, fluid)

    if memorisation:
        new = np.asarray(
            [[flow[1], flow[2]] + list(flow[3].values()) + [s, val, 0]])
        # memorise the newly calculated value
        Memorise.T_ps[fl] = np.append(Memorise.T_ps[fl], new, axis=0)

    return val
Ejemplo n.º 13
0
def s_mix_pT(flow, T, force_gas=False):
    r"""
    Calculate the entropy from pressure and temperature.

    Parameters
    ----------
    flow : list
        Fluid property vector containing mass flow, pressure, enthalpy and
        fluid composition.

    T : float
        Temperature T / K.

    Returns
    -------
    s : float
        Specific entropy s / (J/(kgK)).

    Note
    ----
    Calculation for fluid mixtures.

    .. math::

        s_{mix}(p,T)=\sum_{i} x_{i} \cdot s(pp_{i},T,fluid_{i})-
        \sum_{i} x_{i} \cdot R_{i} \cdot \ln \frac{pp_{i}}{p}\;
        \forall i \in \text{fluid components}\\
        pp: \text{partial pressure}\\
        R: \text{gas constant}
    """
    n = molar_mass_flow(flow[3])
    s = 0

    fluid_name = single_fluid(flow[3])
    if fluid_name is None:

        x_i = {
            fluid: y / (molar_masses[fluid] * n)
            for fluid, y in flow[3].items()
        }

        water = Memorise.water
        if (water is not None and not force_gas and flow[3][water] > err):
            y_i_gas, x_i_gas, y_water_liq, x_water_liq = (
                cond_check(flow[3], x_i, flow[1], n, T)
            )

        else:
            y_i_gas = flow[3]
            y_water_liq = 0
            x_i_gas = x_i

        for fluid, y in y_i_gas.items():
            if y > err:
                if fluid == water and y_water_liq > 0:
                    Memorise.state[water].update(CP.QT_INPUTS, 1, T)
                    s += Memorise.state[water].smass() * y * (
                        1 - y_water_liq
                    )
                    Memorise.state[water].update(CP.QT_INPUTS, 0, T)
                    s += Memorise.state[water].smass() * y_water_liq

                else:
                    pp = flow[1] * x_i_gas[fluid]
                    s += y * (1 - y_water_liq) * s_pT(pp, T, fluid, force_gas)

    else:
        s = s_pT(flow[1], T, fluid_name, force_gas)

    return s