def calc_lhv(self):
        r"""
        Calculate the lower heating value of the combustion chambers fuel.

        Returns
        -------
        val : float
            Lower heating value of the combustion chambers fuel.

            .. math::

                LHV = \sum_{fuels} \left(-\frac{\sum_i {\Delta H_f^0}_i -
                \sum_j {\Delta H_f^0}_j }
                {M_{fuel}} \cdot x_{fuel} \right)\\
                \forall i \in \text{reation products},\\
                \forall j \in \text{reation educts},\\
                \forall fuel \in \text{fuels},\\
                \Delta H_f^0: \text{molar formation enthalpy},\\
                x_{fuel}: \text{mass fraction of fuel in fuel mixture}
        """
        hf = {}
        hf['hydrogen'] = 0
        hf['methane'] = -74.85
        hf['ethane'] = -84.68
        hf['propane'] = -103.8
        hf['butane'] = -124.51
        hf['O2'] = 0
        hf['CO2'] = -393.5
        # water (gaseous)
        hf['H2O'] = -241.8

        lhv = 0

        for f, x in self.fuel.val.items():
            molar_masses[f] = CP.PropsSI('M', f)
            fl = set(list(hf.keys())).intersection(
                    set([a.replace(' ', '') for a in CP.get_aliases(f)]))
            if len(fl) == 0:
                continue

            if list(fl)[0] in self.fuels():
                structure = fluid_structure(f)

                n = {}
                for el in ['C', 'H', 'O']:
                    if el in structure.keys():
                        n[el] = structure[el]
                    else:
                        n[el] = 0

                lhv += (-(n['H'] / 2 * hf['H2O'] + n['C'] * hf['CO2'] -
                          ((n['C'] + n['H'] / 4) * hf['O2'] +
                           hf[list(fl)[0]])) / molar_masses[f] * 1000) * x

        return lhv
def fluid_header(Fluid):
    aliases = CP.get_aliases(str(Fluid))
    aliases = ', '.join(['``' + a.strip() + '``' for a in aliases])

    BTC = BibTeXerClass()

    EOSkey = CP.get_BibTeXKey(Fluid, "EOS")
    CP0key = CP.get_BibTeXKey(Fluid, "CP0")
    SURFACE_TENSIONkey = CP.get_BibTeXKey(Fluid, "SURFACE_TENSION")
    VISCOSITYkey = CP.get_BibTeXKey(Fluid, "VISCOSITY")
    CONDUCTIVITYkey = CP.get_BibTeXKey(Fluid, "CONDUCTIVITY")
    ECS_LENNARD_JONESkey = CP.get_BibTeXKey(Fluid, "ECS_LENNARD_JONES")
    ECS_FITSkey = CP.get_BibTeXKey(Fluid, "ECS_FITS")

    BibInfo = ''
    if EOSkey:
        BibInfo += '**Equation of State**: ' + BTC.entry2rst(EOSkey) + '\n\n'
    if CP0key:
        BibInfo += '**Ideal-Gas Specific Heat**: ' + BTC.entry2rst(
            CP0key) + '\n\n'
    if SURFACE_TENSIONkey:
        BibInfo += '**Surface Tension**: ' + BTC.entry2rst(
            SURFACE_TENSIONkey) + '\n\n'
    if VISCOSITYkey:
        BibInfo += '**Viscosity**: ' + BTC.entry2rst(VISCOSITYkey) + '\n\n'
    if CONDUCTIVITYkey:
        BibInfo += '**Conductivity**: ' + BTC.entry2rst(
            CONDUCTIVITYkey) + '\n\n'
    if ECS_LENNARD_JONESkey:
        BibInfo += '**Lennard-Jones Parameters for ECS**: ' + BTC.entry2rst(
            ECS_LENNARD_JONESkey) + '\n\n'
    if ECS_FITSkey:
        BibInfo += '**ECS Correction Fit**: ' + BTC.entry2rst(
            ECS_FITSkey) + '\n\n'

    return textwrap.dedent("""
********************
{Fluid:s}
********************

Aliases
================================================================================
{Aliases:s}

Bibliographic Information
=========================
{Reference:s}
""".format(
        Fluid=Fluid,
        Aliases=aliases,
        Reference=BibInfo,
    ))
def fluid_header(Fluid):
    aliases = CP.get_aliases(str(Fluid))
    aliases = ', '.join(['``'+a.strip()+'``' for a in aliases])
    
    BTC = BibTeXerClass()
    
    EOSkey = CP.get_BibTeXKey(Fluid, "EOS")
    CP0key = CP.get_BibTeXKey(Fluid, "CP0")
    SURFACE_TENSIONkey = CP.get_BibTeXKey(Fluid, "SURFACE_TENSION")
    VISCOSITYkey = CP.get_BibTeXKey(Fluid, "VISCOSITY")
    CONDUCTIVITYkey = CP.get_BibTeXKey(Fluid, "CONDUCTIVITY")
    ECS_LENNARD_JONESkey = CP.get_BibTeXKey(Fluid, "ECS_LENNARD_JONES")
    ECS_FITSkey = CP.get_BibTeXKey(Fluid, "ECS_FITS")
    
    BibInfo = ''
    if EOSkey:
        BibInfo += '**Equation of State**: ' + BTC.entry2rst(EOSkey) + '\n\n'
    if CP0key:
        BibInfo += '**Ideal-Gas Specific Heat**: ' + BTC.entry2rst(CP0key) + '\n\n'
    if SURFACE_TENSIONkey:
        BibInfo += '**Surface Tension**: ' + BTC.entry2rst(SURFACE_TENSIONkey) + '\n\n'
    if VISCOSITYkey:
        BibInfo += '**Viscosity**: ' + BTC.entry2rst(VISCOSITYkey) + '\n\n'
    if CONDUCTIVITYkey:
        BibInfo += '**Conductivity**: ' + BTC.entry2rst(CONDUCTIVITYkey) + '\n\n'
    if ECS_LENNARD_JONESkey:
        BibInfo += '**Lennard-Jones Parameters for ECS**: ' + BTC.entry2rst(ECS_LENNARD_JONESkey) + '\n\n'
    if ECS_FITSkey:
        BibInfo += '**ECS Correction Fit**: ' + BTC.entry2rst(ECS_FITSkey) + '\n\n'
    
    return textwrap.dedent(
"""
********************
{Fluid:s}
********************

Aliases
================================================================================
{Aliases:s}

Bibliographic Information
=========================
{Reference:s}
""".format(Fluid=Fluid,
           Aliases = aliases,
           Reference = BibInfo,
           )
           )
Exemple #4
0
    def calc_lhv(self, f):
        r"""
        Calculate the lower heating value of the combustion chamber's fuel.

        - Source for fluids O2, H2O and CO2: :cite:`CODATA1989`
        - Source for all other fluids: :cite:`CRCHandbook2021`

        Parameters
        ----------
        f : str
            Alias of the fuel.

        Returns
        -------
        val : float
            Lower heating value of the combustion chambers fuel.

            .. math::

                LHV = -\frac{\sum_i {\Delta H_f^0}_i -
                \sum_j {\Delta H_f^0}_j }
                {M_{fuel}}\\
                \forall i \in \text{reation products},\\
                \forall j \in \text{reation educts},\\
                \Delta H_f^0: \text{molar formation enthalpy}
        """
        hf = {}
        hf['hydrogen'] = 0
        hf['methane'] = -74.6
        hf['ethane'] = -84.0
        hf['propane'] = -103.8
        hf['butane'] = -125.7
        hf['nDodecane'] = -289.4
        hf[self.o2] = 0
        hf[self.co2] = -393.51
        # water (gaseous)
        hf[self.h2o] = -241.826

        key = set(list(hf.keys())).intersection(
            set([a.replace(' ', '') for a in CP.get_aliases(f)]))

        val = (-(self.fuels[f]['H'] / 2 * hf[self.h2o] +
                 self.fuels[f]['C'] * hf[self.co2] -
                 ((self.fuels[f]['C'] + self.fuels[f]['H'] / 4) * hf[self.o2] +
                  hf[list(key)[0]])) / molar_masses[f] * 1000)

        return val
Exemple #5
0
    def comp_init(self, nw):

        if not self.P.is_set:
            self.set_attr(P='var')
            msg = ('The power output of cogeneration units must be set! '
                   'We are adding the power output of component ' +
                   self.label + ' as custom variable of the system.')
            logging.info(msg)

        component.comp_init(self, nw)

        o2 = [x for x in nw.fluids if x in [
            a.replace(' ', '') for a in CP.get_aliases('O2')]]
        if len(o2) == 0:
            msg = ('Missing oxygen in network fluids, component ' +
                   self.label + ' of type ' + self.component() +
                   ' requires oxygen in network fluids.')
            logging.error(msg)
            raise ValueError(msg)
        else:
            self.o2 = o2[0]

        h2o = [x for x in nw.fluids if x in [
            a.replace(' ', '') for a in CP.get_aliases('H2O')]]
        if len(h2o) == 0:
            msg = ('Missing water in network fluids, component ' +
                   self.label + ' of type ' + self.component() +
                   ' requires water in network fluids.')
            logging.error(msg)
            raise ValueError(msg)
        else:
            self.h2o = h2o[0]

        h2 = [x for x in nw.fluids if x in [
            a.replace(' ', '') for a in CP.get_aliases('H2')]]
        if len(h2) == 0:
            msg = ('Missing hydrogen in network fluids, component ' +
                   self.label + ' of type ' + self.component() +
                   ' requires hydrogen in network fluids.')
            logging.error(msg)
            raise ValueError(msg)
        else:
            self.h2 = h2[0]

        self.e0 = self.calc_e0()

        # number of mandatroy equations for
        # cooling loop fluids: num_fl
        # fluid composition at reactor inlets/outlets: 3 * num_fl
        # mass flow balances: 3
        # pressure: 2
        # energy balance: 1
        # reactor outlet temperatures: 1
        self.num_eq = self.num_nw_fluids * 4 + 7
        for var in [self.e, self.eta, self.eta_char, self.Q, self.pr_c,
                    self.zeta]:
            if var.is_set is True:
                self.num_eq += 1

        self.mat_deriv = np.zeros((
            self.num_eq,
            self.num_i + self.num_o + self.num_vars,
            self.num_nw_vars))

        self.vec_res = np.zeros(self.num_eq)
        pos = self.num_nw_fluids * 4
        self.mat_deriv[0:pos] = self.fluid_deriv()
        self.mat_deriv[pos:pos + 3] = self.mass_flow_deriv()
        self.mat_deriv[pos + 3:pos + 5] = self.pressure_deriv()
    def stoich_flue_gas(self, nw):
        r"""
        Calculate the fluid composition of the stoichiometric flue gas.

        - uses one mole of fuel as reference quantity and :math:`\lambda=1`
          for stoichiometric flue gas calculation (no oxygen in flue gas)
        - calculate molar quantities of (reactive) fuel components to determine
          water and carbondioxide mass fraction in flue gas
        - calculate required molar quantity for oxygen and required fresh
          air mass
        - calculate residual mass fractions for non reactive components of
          fresh air in the flue gas
        - calculate flue gas fluid composition
        - generate custom fluid porperties

        Reactive components in fuel

        .. math::

            m_{fuel} = \frac{1}{M_{fuel}}\\
            m_{CO_2} = \sum_{i} \frac{x_{i} \cdot m_{fuel} \cdot num_{C,i}
            \cdot M_{CO_{2}}}{M_{i}}\\
            m_{H_{2}O} = \sum_{i} \frac{x_{i} \cdot m_{fuel} \cdot
            num_{H,i} \cdot M_{H_{2}O}}{2 \cdot M_{i}}\\
            \forall i \in \text{fuels in fuel vector},\\
            num = \text{number of atoms in molecule}

        Other components of fuel vector

        .. math::

            m_{fg,j} = x_{j} \cdot m_{fuel}\\
            \forall j \in \text{non fuels in fuel vecotr, e.g. } CO_2,\\
            m_{fg,j} = \text{mass of fluid component j in flue gas}

        Non-reactive components in air

        .. math::

            n_{O_2} = \left( \frac{m_{CO_2}}{M_{CO_2}} +
            \frac{m_{H_{2}O}}
            {0,5 \cdot M_{H_{2}O}} \right) \cdot \lambda,\\
            n_{O_2} = \text{mol of oxygen required}\\
            m_{air} = \frac{n_{O_2} \cdot M_{O_2}}{x_{O_{2}, air}},\\
            m_{air} = \text{required total air mass}\\
            m_{fg,j} = x_{j, air} \cdot m_{air}\\
            m_{fg, O_2} = 0,\\
            m_{fg,j} = \text{mass of fluid component j in flue gas}

        Flue gas composition

        .. math::

            x_{fg,j} = \frac{m_{fg, j}}{m_{air} + m_{fuel}}

        Parameters
        ----------
        nw : tespy.networks.network.Network
            TESPy network to generate stoichiometric flue gas for.
        """
        lamb = 1
        n_fuel = 1
        m_fuel = 1 / molar_mass_flow(self.fuel.val) * n_fuel
        m_fuel_fg = m_fuel
        m_co2 = 0
        m_h2o = 0
        molar_masses[self.h2o] = CP.PropsSI('M', self.h2o)
        molar_masses[self.co2] = CP.PropsSI('M', self.co2)
        molar_masses[self.o2] = CP.PropsSI('M', self.o2)

        self.fg = {}
        self.fg[self.co2] = 0
        self.fg[self.h2o] = 0

        for f, x in self.fuel.val.items():
            fl = set(list(self.fuels())).intersection(
                    set([a.replace(' ', '') for a in CP.get_aliases(f)]))

            if len(fl) == 0:
                if f in self.fg.keys():
                    self.fg[f] += x * m_fuel
                else:
                    self.fg[f] = x * m_fuel
            else:
                n_fluid = x * m_fuel / molar_masses[f]
                m_fuel_fg -= n_fluid * molar_masses[f]
                structure = fluid_structure(f)
                n = {}
                for el in ['C', 'H', 'O']:
                    if el in structure.keys():
                        n[el] = structure[el]
                    else:
                        n[el] = 0

                m_co2 += n_fluid * n['C'] * molar_masses[self.co2]
                m_h2o += n_fluid * n['H'] / 2 * molar_masses[self.h2o]

        self.fg[self.co2] += m_co2
        self.fg[self.h2o] += m_h2o

        n_o2 = (m_co2 / molar_masses[self.co2] +
                0.5 * m_h2o / molar_masses[self.h2o]) * lamb
        m_air = n_o2 * molar_masses[self.o2] / self.air.val[self.o2]

        self.air_min = m_air / m_fuel

        for f, x in self.air.val.items():
            if f != self.o2:
                if f in self.fg.keys():
                    self.fg[f] += m_air * x
                else:
                    self.fg[f] = m_air * x

        m_fg = m_fuel + m_air

        for f in self.fg.keys():
            self.fg[f] /= m_fg

        if not self.path.is_set:
            self.path.val = None

        TESPyFluid(
            self.fuel_alias.val, self.fuel.val, [1000, nw.p_range_SI[1]],
            path=self.path.val)
        TESPyFluid(
            self.fuel_alias.val + '_fg', self.fg, [1000, nw.p_range_SI[1]],
            path=self.path.val)
        msg = (
            'Generated lookup table for ' + self.fuel_alias.val + ' and for '
            'stoichiometric flue gas at component ' + self.label + '.')
        logging.debug(msg)

        if self.air_alias.val not in ['Air', 'air']:
            TESPyFluid(
                self.air_alias.val, self.air.val, [1000, nw.p_range_SI[1]],
                path=self.path.val)
            msg = ('Generated lookup table for ' + self.air_alias.val +
                   ' at stoichiometric combustion chamber ' + self.label + '.')
        else:
            msg = ('Using CoolProp air at stoichiometric combustion chamber ' +
                   self.label + '.')
        logging.debug(msg)
    def comp_init(self, nw):
        if not self.fuel.is_set or not isinstance(self.fuel.val, dict):
            msg = ('You must specify the fuel composition for stoichimetric '
                   'combustion chamber ' + self.label + '.')
            logging.error(msg)
            raise TESPyComponentError(msg)

        if not self.fuel_alias.is_set:
            msg = ('You must specify a fuel alias for stoichimetric '
                   'combustion chamber ' + self.label + '.')
            logging.error(msg)
            raise TESPyComponentError(msg)

        if not self.air.is_set or not isinstance(self.air.val, dict):
            msg = ('You must specify the air composition for stoichimetric '
                   'combustion chamber ' + self.label + '.')
            logging.error(msg)
            raise TESPyComponentError(msg)

        if not self.air_alias.is_set:
            msg = ('You must specify an air alias for stoichimetric '
                   'combustion chamber ' + self.label + '.')
            logging.error(msg)
            raise TESPyComponentError(msg)

        Component.comp_init(self, nw)

        # adjust the names for required fluids according to naming in the
        # network air
        for f in list(self.air.val.keys()):
            alias = [x for x in self.nw_fluids if x in [
                a.replace(' ', '') for a in CP.get_aliases(f)]]
            if len(alias) > 0:
                self.air.val[alias[0]] = self.air.val.pop(f)

        # fuel
        for f in list(self.fuel.val.keys()):
            alias = [x for x in self.air.val.keys() if x in [
                a.replace(' ', '') for a in CP.get_aliases(f)]]
            if len(alias) > 0:
                self.fuel.val[alias[0]] = self.fuel.val.pop(f)

        # list of all fluids of air and fuel
        fluids = list(self.air.val.keys()) + list(self.fuel.val.keys())

        # oxygen
        alias = [x for x in fluids if x in [
            a.replace(' ', '') for a in CP.get_aliases('O2')]]
        if len(alias) == 0:
            msg = 'Oxygen missing in input fluids.'
            logging.error(msg)
            raise TESPyComponentError(msg)
        else:
            self.o2 = alias[0]

        # carbondioxide
        self.co2 = [x for x in self.nw_fluids if x in [
            a.replace(' ', '') for a in CP.get_aliases('CO2')]]
        if len(self.co2) == 0:
            self.co2 = 'CO2'
        else:
            self.co2 = self.co2[0]

        # water
        self.h2o = [x for x in self.nw_fluids if x in [
            a.replace(' ', '') for a in CP.get_aliases('H2O')]]
        if len(self.h2o) == 0:
            self.h2o = 'H2O'
        else:
            self.h2o = self.h2o[0]

        # calculate lower heating value of specified fuel
        self.lhv = self.calc_lhv()
        msg = ('Combustion chamber fuel (' + self.fuel_alias.val +
               ') LHV is ' + str(self.lhv) + ' for component ' +
               self.label + '.')
        logging.debug(msg)
        # generate fluid properties for stoichiometric flue gas
        self.stoich_flue_gas(nw)