Beispiel #1
0
 def __init__(self,
              A_st=None,
              atoms=None,
              symmetrynumber=None,
              inertia=None,
              geometry=None,
              vib_wavenumbers=None,
              potentialenergy=None,
              **kwargs):
     super().__init__(atoms=atoms,
                      symmetrynumber=symmetrynumber,
                      geometry=geometry,
                      vib_wavenumbers=vib_wavenumbers,
                      potentialenergy=potentialenergy,
                      **kwargs)
     self.A_st = A_st
     self.atoms = atoms
     self.geometry = geometry
     self.symmetrynumber = symmetrynumber
     self.inertia = inertia
     self.etotal = potentialenergy
     self.vib_energies = c.wavenumber_to_energy(np.array(vib_wavenumbers))
     self.theta = np.array(self.vib_energies) / c.kb('eV/K')
     self.zpe = sum(np.array(self.vib_energies)/2.) *\
         c.convert_unit(from_='eV', to='kcal')*c.Na
     if np.sum(self.vib_energies) != 0:
         self.q_vib = np.product(
             np.divide(1, (1 - np.exp(-self.theta / c.T0('K')))))
     if self.phase == 'G':
         if self.inertia is not None:
             self.I3 = self.inertia
         else:
             self.I3 = atoms.get_moments_of_inertia() *\
                     c.convert_unit(from_='A2', to='m2') *\
                     c.convert_unit(from_='amu', to='kg')
         self.T_I = c.h('J s')**2 / (8 * np.pi**2 * c.kb('J/K'))
     if self.phase == 'G':
         Irot = np.max(self.I3)
         if self.geometry == 'nonlinear':
             self.q_rot = np.sqrt(np.pi*Irot)/self.symmetrynumber *\
                                 (c.T0('K')/self.T_I)**(3./2.)
         else:
             self.q_rot = (c.T0('K') * Irot /
                           self.symmetrynumber) / self.T_I
     else:
         self.q_rot = 0.
     if self.A_st is not None:
         self.MW = mw(self.elements) * c.convert_unit(from_='g',
                                                      to='kg') / c.Na
         self.q_trans2D = self.A_st * (2 * np.pi * self.MW * c.kb('J/K') *
                                       c.T0('K')) / c.h('J s')**2
Beispiel #2
0
    def from_statmech(cls,
                      name,
                      statmech_model,
                      T_low,
                      T_high,
                      references=None,
                      elements=None,
                      **kwargs):
        """Calculates the Shomate polynomial using statistical mechanic models

        Parameters
        ----------
            name : str
                Name of the species
            statmech_model : `pMuTT.statmech.StatMech` object or class
                Statistical Mechanics model to generate data
            T_low : float
                Lower limit temerature in K
            T_high : float
                Higher limit temperature in K
            references : `pMuTT.empirical.references.References` object
                Reference to adjust enthalpy
            **kwargs : keyword arguments
                Used to initalize ``statmech_model`` or ``EmpiricalBase``
                attributes to be stored.
        Returns
        -------
            shomate : Shomate object
                Shomate object with polynomial terms fitted to data.
        """
        # Initialize the StatMech object
        if inspect.isclass(statmech_model):
            statmech_model = statmech_model(**kwargs)

        # Generate data
        T = np.linspace(T_low, T_high)
        CpoR = np.array([statmech_model.get_CpoR(T=T_i) for T_i in T])
        T_ref = c.T0('K')
        HoRT_ref = statmech_model.get_HoRT(T=T_ref)
        # Add contribution of references
        if references is not None:
            descriptor_name = references.descriptor
            if descriptor_name == 'elements':
                descriptors = elements
            else:
                descriptors = kwargs[descriptor_name]
            HoRT_ref += references.get_HoRT_offset(descriptors=descriptors,
                                                   T=T_ref)
        SoR_ref = statmech_model.get_SoR(T=T_ref)

        return cls.from_data(name=name,
                             T=T,
                             CpoR=CpoR,
                             T_ref=T_ref,
                             HoRT_ref=HoRT_ref,
                             SoR_ref=SoR_ref,
                             statmech_model=statmech_model,
                             elements=elements,
                             references=references,
                             **kwargs)
Beispiel #3
0
    def get_Vm(self, T=c.T0('K'), P=c.P0('bar'), gas_phase=True):
        """Calculates the molar volume of a van der Waals gas

        Parameters
        ----------
            T : float, optional
                Temperature in K. Default is standard temperature
            P : float, optional
                Pressure in bar. Default is standard pressure
            gas_phase : bool, optional
                Relevant if system is in vapor-liquid equilibrium. If True,
                return the larger volume (gas phase). If False, returns the
                smaller volume (liquid phase).
        Returns
        -------
            Vm : float
                Volume in m3
        """
        P_SI = P * c.convert_unit(from_='bar', to='Pa')
        Vm = np.roots([
            P_SI, -(P_SI * self.b + c.R('J/mol/K') * T), self.a,
            -self.a * self.b
        ])
        real_Vm = np.real([Vm_i for Vm_i in Vm if np.isreal(Vm_i)])
        if gas_phase:
            return np.max(real_Vm)
        else:
            return np.min(real_Vm)
Beispiel #4
0
    def setUp(self):
        self.T = c.T0('K')
        # Factor to convert potential energy to dimensionless number
        dim_factor = c.R('eV/K')*self.T
        self.m = 10.  # BEP Slope
        self.c = 20.  # BEP Intercept
        species = {
            'H2': StatMech(name='H2', potentialenergy=2.*dim_factor,
                           **presets['electronic']),
            'O2': StatMech(name='O2', potentialenergy=4.*dim_factor,
                           **presets['electronic']),
            'H2O': StatMech(name='H2O', potentialenergy=3.*dim_factor,
                            **presets['electronic']),
        }
        self.rxn_delta = Reaction.from_string(
                reaction_str='H2 + 0.5O2 = H2O',
                species=species,
                descriptor='delta',
                slope=self.m,
                intercept=self.c,
                bep=BEP)
        self.bep_delta = self.rxn_delta.bep

        rxn_rev_delta = Reaction.from_string(
                reaction_str='H2 + 0.5O2 = H2O',
                species=species,
                descriptor='rev_delta',
                slope=self.m,
                intercept=self.c,
                bep=BEP)
        self.bep_rev_delta = rxn_rev_delta.bep

        rxn_reactants = Reaction.from_string(
                reaction_str='H2 + 0.5O2 = H2O',
                species=species,
                descriptor='reactants',
                slope=self.m,
                intercept=self.c,
                bep=BEP)
        self.bep_reactants = rxn_reactants.bep

        rxn_products = Reaction.from_string(
                reaction_str='H2 + 0.5O2 = H2O',
                species=species,
                descriptor='products',
                slope=self.m,
                intercept=self.c,
                bep=BEP)
        self.bep_products = rxn_products.bep
Beispiel #5
0
    def get_GoRT(self, x=0., T=c.T0('K')):
        """Calculates the excess Gibbs energy

        Parameters
        ----------
            x : float, optional
                Coverage (in ML) of species j. Default is 0
            T : float, optional
                Temperature in K. Default is 298.15 K
        Returns
        -------
            GoRT : float
                Dimensionless excess Gibbs energy
        """
        return self.get_HoRT(x=x, T=T) - self.get_SoR()
Beispiel #6
0
def _fit_HoRT(T_ref, HoRT_ref, a):
    """Fit a[5] coefficient in a_low and a_high attributes given the
    dimensionless enthalpy

    Parameters
    ----------
        T_ref : float
            Reference temperature in K
        HoRT_ref : float
            Reference dimensionless enthalpy
        T_mid : float
            Temperature to fit the offset
    Returns
    -------
        a : (8,) `numpy.ndarray`_
            Lower coefficients of Shomate polynomial

    .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.ndarray.html
    """
    a[5] = (HoRT_ref - get_shomate_HoRT(T=np.array([T_ref]), a=a)) \
        * c.R('kJ/mol/K')*T_ref
    a[7] = -get_shomate_HoRT(T=np.array([c.T0('K')]), a=a) \
        * c.R('kJ/mol/K')*c.T0('K')
    return a
Beispiel #7
0
    def get_P(self, T=c.T0('K'), V=c.V0('m3'), n=1.):
        """Calculates the pressure of an ideal gas

        Parameters
        ----------
            T : float, optional
                Temperature in K. Default is standard temperature
            V : float, optional
                Volume in m3. Default is standard volume
            n : float, optional
                Number of moles (in mol). Default is 1 mol
        Returns
        -------
            P : float
                Pressure in bar
        """
        return n * c.R('m3 bar/mol/K') * T / V
Beispiel #8
0
    def get_n(self, V=c.V0('m3'), P=c.P0('bar'), T=c.T0('K')):
        """Calculates the moles of an ideal gas

        Parameters
        ----------
            V : float, optional
                Volume in m3. Default is standard volume
            P : float, optional
                Pressure in bar. Default is standard pressure
            T : float, optional
                Temperature in K. Default is standard temperature
        Returns
        -------
            n : float
                Number of moles in mol
        """
        return P * V / c.R('m3 bar/mol/K') / T
Beispiel #9
0
    def get_V(self, T=c.T0('K'), P=c.P0('bar'), n=1.):
        """Calculates the volume of an ideal gas

        Parameters
        ----------
            T : float, optional
                Temperature in K. Default is standard temperature
            P : float, optional
                Pressure in bar. Default is standard pressure
            n : float, optional
                Number of moles (in mol). Default is 1 mol
        Returns
        -------
            V : float
                Volume in m3
        """
        return n * c.R('m3 bar/mol/K') * T / P
Beispiel #10
0
    def get_EoRT(self,
                 T=c.T0('K'),
                 include_ZPE=False,
                 raise_error=True,
                 raise_warning=True,
                 **kwargs):
        """Dimensionless electronic energy

        Parameters
        ----------
            T : float, optional
                Temperature in K. If the electronic mode is
                :class:`~pMuTT.statmech.elec.IdealElec`, then the output is
                insensitive to this input. Default is 298.15 K
            include_ZPE : bool, optional
                If True, includes the zero point energy. Default is False
            raise_error : bool, optional
                If True, raises an error if any of the modes do not have the
                quantity of interest. Default is True
            raise_warning : bool, optional
                Only relevant if raise_error is False. Raises a warning if any
                of the modes do not have the quantity of interest. Default is
                True
            kwargs : key-word arguments
                Parameters passed to electronic mode
        Returns
        -------
            EoRT : float
                Dimensionless electronic energy
        """
        kwargs['T'] = T
        EoRT = _get_mode_quantity(mode=self.elec_model,
                                  method_name='get_UoRT',
                                  raise_error=raise_error,
                                  raise_warning=raise_warning,
                                  default_value=0.,
                                  **kwargs)
        if include_ZPE:
            EoRT += _get_mode_quantity(mode=self.vib_model,
                                       method_name='get_ZPE',
                                       raise_error=raise_error,
                                       raise_warning=raise_warning,
                                       default_value=0.,
                                       **kwargs) / c.R('eV/K') / T
        return EoRT
Beispiel #11
0
    def get_UoRT(self, x=0., T=c.T0('K')):
        """Calculates the excess internal energy

        Parameters
        ----------
            x : float, optional
                Coverage (in ML) of species j. Default is 0
            T : float, optional
                Temperature in K. Default is 298.15 K
        Returns
        -------
            UoRT : float
                Dimensionless internal energy
        """
        i = np.argmax(x < np.array(self.intervals)) - 1
        UoRT = (self.slopes[i] * x +
                self._intercepts[i]) / (c.R('kcal/mol/K') * T)
        return UoRT
Beispiel #12
0
    def get_P(self, T=c.T0('K'), V=c.V0('m3'), n=1.):
        """Calculates the pressure of a van der Waals gas

        Parameters
        ----------
            T : float, optional
                Temperature in K. Default is standard temperature
            V : float, optional
                Volume in m3. Default is standard volume
            n : float, optional
                Number of moles (in mol). Default is 1 mol
        Returns
        -------
            P : float
                Pressure in bar
        """
        Vm = V / n
        return (c.R('J/mol/K')*T/(Vm - self.b) - self.a*(1./Vm)**2) \
            * c.convert_unit(from_='Pa', to='bar')
Beispiel #13
0
    def get_V(self, T=c.T0('K'), P=c.P0('bar'), n=1., gas_phase=True):
        """Calculates the volume of a van der Waals gas

        Parameters
        ----------
            T : float, optional
                Temperature in K. Default is standard temperature
            P : float, optional
                Pressure in bar. Default is standard pressure
            n : float, optional
                Number of moles (in mol). Default is 1 mol
            gas_phase : bool, optional
                Relevant if system is in vapor-liquid equilibrium. If True,
                return the larger volume (gas phase). If False, returns the
                smaller volume (liquid phase).
        Returns
        -------
            V : float
                Volume in m3
        """
        return self.get_Vm(T=T, P=P, gas_phase=gas_phase) * n
Beispiel #14
0
    def get_n(self, V=c.V0('m3'), P=c.P0('bar'), T=c.T0('K'), gas_phase=True):
        """Calculates the moles of a van der Waals gas

        Parameters
        ----------
            V : float, optional
                Volume in m3. Default is standard volume
            P : float, optional
                Pressure in bar. Default is standard pressure
            T : float, optional
                Temperature in K. Default is standard temperature
            gas_phase : bool, optional
                Relevant if system is in vapor-liquid equilibrium. If True,
                return the smaller moles (gas phase). If False, returns the
                larger moles (liquid phase).
        Returns
        -------
            n : float
                Number of moles in mol
        """
        return V / self.get_Vm(T=T, P=P, gas_phase=gas_phase)
Beispiel #15
0
    def get_G(self,
              units,
              T=c.T0('K'),
              verbose=False,
              raise_error=True,
              raise_warning=True,
              **kwargs):
        """Calculate the Gibbs energy

        Parameters
        ----------
            verbose : bool, optional
                If False, returns the Gibbs energy. If True, returns
                contribution of each mode.
            units : str
                Units as string. See :func:`~pMuTT.constants.R` for accepted
                units but omit the '/K' (e.g. J/mol).
            T : float, optional
                Temperature in K. Default is 298.15 K
            raise_error : bool, optional
                If True, raises an error if any of the modes do not have the
                quantity of interest. Default is True
            raise_warning : bool, optional
                Only relevant if raise_error is False. Raises a warning if any
                of the modes do not have the quantity of interest. Default is
                True
            kwargs : key-word arguments
                Parameters passed to each mode
        Returns
        -------
            G : float or (N+5,) `numpy.ndarray`_
                Gibbs energy. N represents the number of mixing models. If
                verbose is True, contribution to each mode are as follows:
                [trans, vib, rot, elec, nucl, mixing_models (if any)]

        .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.ndarray.html
        """
        return self.get_GoRT(verbose=verbose, raise_error=raise_error,
                             raise_warning=raise_warning, T=T, **kwargs) \
            * T*c.R('{}/K'.format(units))
Beispiel #16
0
    def setUp(self):
        unittest.TestCase.setUp(self)
        # Testing Ideal Gas Model
        CO2 = molecule('CO2')
        CO2_pMuTT_parameters = {
            'name': 'CO2',

            'trans_model': trans.IdealTrans,
            'n_degrees': 3,
            'molecular_weight': get_molecular_weight('CO2'),

            'rot_model': rot.RigidRotor,
            'rot_temperatures': rot.get_rot_temperatures_from_atoms(CO2,
                                                            geometry='linear'),
            'geometry': 'linear',
            'symmetrynumber': 2,

            'elec_model': elec.IdealElec,
            'potentialenergy': -22.994202,
            'spin': 0.,

            'vib_model': vib.HarmonicVib,
            'vib_wavenumbers': [3360., 954., 954., 1890.],
        }
        CO2_ase_parameters = {
            'atoms': CO2,
            'potentialenergy': -22.994202,
            'vib_energies': [c.wavenumber_to_energy(x)
                             for x in CO2_pMuTT_parameters['vib_wavenumbers']],
            'geometry': 'linear',
            'symmetrynumber': 2,
            'spin': 0.
        }
        self.CO2_pMuTT = StatMech(**CO2_pMuTT_parameters)
        self.CO2_ASE = IdealGasThermo(**CO2_ase_parameters)

        self.T0 = c.T0('K')  # K
        self.P0 = c.P0('Pa')
        self.V0 = c.V0('m3')
Beispiel #17
0
    def get_E(self,
              units,
              T=c.T0('K'),
              raise_error=True,
              raise_warning=True,
              include_ZPE=False,
              **kwargs):
        """Calculate the electronic energy

        Parameters
        ----------
            units : str
                Units as string. See :func:`~pMuTT.constants.R` for accepted
                units but omit the '/K' (e.g. J/mol).
            T : float, optional
                Temperature in K. If the electronic mode is
                :class:`~pMuTT.statmech.elec.IdealElec`, then the output is
                insensitive to this input. Default is 298.15 K
            include_ZPE : bool, optional
                If True, includes the zero point energy. Default is False
            raise_error : bool, optional
                If True, raises an error if any of the modes do not have the
                quantity of interest. Default is True
            raise_warning : bool, optional
                Only relevant if raise_error is False. Raises a warning if any
                of the modes do not have the quantity of interest. Default is
                True
            kwargs : key-word arguments
                Parameters passed to each mode
        Returns
        -------
            E : float
                Electronic energy
        """
        return self.get_EoRT(T=T, raise_error=raise_error,
                             raise_warning=raise_warning,
                             include_ZPE=include_ZPE, **kwargs) \
            * T*c.R('{}/K'.format(units))
Beispiel #18
0
 def test_get_P(self):
     self.assertAlmostEqual(
         self.ideal_gas.get_P(T=c.T0('K'), V=c.V0('m3'), n=1.), c.P0('bar'))
Beispiel #19
0
 def test_get_n(self):
     self.assertAlmostEqual(
         self.ideal_gas.get_n(T=c.T0('K'), V=c.V0('m3'), P=c.P0('bar')), 1.)
    def setUp(self):
        unittest.TestCase.setUp(self)

        H2_thermo = Reference(name='H2',
                              phase='G',
                              elements={'H': 2},
                              T_ref=c.T0('K'),
                              HoRT_ref=0.,
                              statmech_model=StatMech,
                              trans_model=trans.IdealTrans,
                              n_degrees=3,
                              vib_model=vib.HarmonicVib,
                              elec_model=elec.IdealElec,
                              rot_model=rot.RigidRotor,
                              vib_wavenumbers=np.array([4306.1793]),
                              potentialenergy=-6.7598,
                              geometry='linear',
                              symmetrynumber=2,
                              spin=0,
                              atoms=molecule('H2'))

        H2O_thermo = Reference(
            name='H2O',
            phase='G',
            elements={
                'H': 2,
                'O': 1
            },
            T_ref=c.T0('K'),
            HoRT_ref=-241.826 / (c.R('kJ/mol/K') * c.T0('K')),
            statmech_model=StatMech,
            trans_model=trans.IdealTrans,
            n_degrees=3,
            vib_model=vib.HarmonicVib,
            elec_model=elec.IdealElec,
            rot_model=rot.RigidRotor,
            vib_wavenumbers=np.array([3825.434, 3710.264, 1582.432]),
            potentialenergy=-14.2209,
            geometry='nonlinear',
            symmetrynumber=2,
            spin=0,
            atoms=molecule('H2O'))

        O2_thermo = Reference(name='H2O',
                              phase='G',
                              elements={'O': 2},
                              T_ref=c.T0('K'),
                              HoRT_ref=0.,
                              statmech_model=StatMech,
                              trans_model=trans.IdealTrans,
                              n_degrees=3,
                              vib_model=vib.HarmonicVib,
                              elec_model=elec.IdealElec,
                              rot_model=rot.RigidRotor,
                              vib_wavenumbers=np.array([2205.]),
                              potentialenergy=-9.86,
                              geometry='linear',
                              symmetrynumber=2,
                              spin=1,
                              atoms=molecule('O2'))
        self.references = References(
            references=[H2_thermo, H2O_thermo, O2_thermo])
Beispiel #21
0
import matplotlib.pyplot as plt
from pMuTT import constants as c
from pMuTT.empirical.nasa import Nasa

# Gas phase heat capacity data (in J/mol/K) for CH3OH from NIST
# https://webbook.nist.gov/cgi/cbook.cgi?ID=C67561&Units=SI&Mask=1#Thermo-Gas
T = np.array([50, 100, 150, 200, 273.15, 298.15, 300, 400, 500, 600, 700,
              800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1750, 2000,
              2250, 2500, 2750, 3000])
Cp = np.array([34.00, 36.95, 38.64, 39.71, 42.59, 44.06, 44.17, 51.63,
               59.7, 67.19, 73.86, 79.76, 84.95, 89.54, 93.57, 97.12,
               100.24, 102.98, 105.4, 110.2, 113.8, 116.5, 118.6, 120, 121])
CpoR = Cp/c.R('J/mol/K')

# Enthalpy of Formation for CH3OH (in kJ/mol) from NIST
T_ref = c.T0('K')
H_ref = -205.
HoRT_ref = H_ref/c.R('kJ/mol/K')/T_ref
# Standard molar entropy (in J/mol/K) from Wikipedia,
# https://en.wikipedia.org/wiki/Methanol_(data_page)
S_ref = 239.9
SoR_ref = S_ref/c.R('J/mol/K')

# Units to plot the figure
Cp_units = 'J/mol/K'
H_units = 'kJ/mol'
S_units = 'J/mol/K'
G_units = 'kJ/mol'

# Input the experimental data and fitting to a NASA polynomial
CH3OH_nasa = Nasa.from_data(name='CH3OH', T=T, CpoR=CpoR, T_ref=T_ref,
Beispiel #22
0
def write_surf(nasa_species,
               sden_operation='min',
               filename='surf.inp',
               T=c.T0('K'),
               reactions=[],
               species_delimiter='+',
               reaction_delimiter='=',
               act_method_name='get_E_act',
               act_unit='kcal/mol',
               float_format=' .3E',
               stoich_format='.0f',
               newline='\n',
               column_delimiter='  ',
               use_mw_correction=True,
               **kwargs):
    """Writes the surf.inp Chemkin file

    Parameters
    ----------
        nasa_species : list of :class:`~pMuTT.empirical.nasa.Nasa` objects
            Surface used in Chemkin mechanism. If gas-phase species are
            present, they will be ignored
        filename : str, optional
            Filename for surf.inp file. Default is 'surf.inp'
        T : float, optional
            Temperature to calculate activation energy. Default is 298.15 K
        reactions : list of :class:`~pMuTT.reaction.ChemkinReaction` objects
            Chemkin reactions to write in surf.inp file. Purely gas-phase
            reactions will be ignored
        species_delimiter : str, optional
            Delimiter to separate species when writing reactions.
            Default is '+'
        reaction_delimiter : str, optional
            Delimiter to separate reaction sides. Default is '='
        act_method_name : str, optional
            Name of method to use to calculate activation function
        act_unit : str, optional
            Units to calculate activation energy. Default is 'kcal/mol'
        float_format : str, optional
            String format to print floating numbers. Default is ' .3E' (i.e.
            scientific notation rounded to 3 decimal places with a leading
            space for positive numbers)
        stoich_format : str, optional
            String format to print stoichiometric coefficients.
            Default is '.0f' (i.e. integers)
        newline : str, optional
            Newline character. Default is the Linux newline character
        column_delimiter : str, optional
            Delimiter to separate columns. Default is '  '
        use_mw_correction : bool, optional
            If True, uses the Motz-Wise corrections. Default is True
        kwargs : keyword arguments
            Parameters needed to calculate activation energy and preexponential
            factor
    """
    # Organize species by their catalyst sites
    cat_adsorbates = {}
    unique_cat_sites = []
    for specie in nasa_species:
        # Skip gas phase species
        if specie.phase.upper() == 'G':
            continue
        # Skip the bulk species
        if specie.cat_site.bulk_specie == specie.name:
            continue

        cat_name = specie.cat_site.name
        try:
            cat_adsorbates[cat_name].append(specie)
        except KeyError:
            cat_adsorbates[cat_name] = [specie]
            unique_cat_sites.append(specie.cat_site)

    cat_site_lines = []
    for cat_site in unique_cat_sites:
        # Add catalyst site header
        cat_site_name = '{}/'.format(cat_site.name)
        cat_site_lines.append('SITE/{:<14}SDEN/{:.5E}/'.format(
            cat_site_name, cat_site.site_density))
        cat_site_lines.append('')
        # Add species adsorbed on that site
        for specie in cat_adsorbates[cat_site.name]:
            cat_site_lines.append('{}{}/{}/'.format(column_delimiter,
                                                    specie.name,
                                                    specie.n_sites))
        cat_site_lines.append('')
    # Write bulk species
    for cat_site in unique_cat_sites:
        # Add bulk line
        cat_site_lines.append('BULK {}/{:.1f}/'.format(cat_site.bulk_specie,
                                                       cat_site.density))

    # Get surface reaction lines
    surf_reactions = \
        [reaction for reaction in reactions if not reaction.gas_phase]
    reaction_lines = _write_reaction_lines(
        reactions=surf_reactions,
        species_delimiter=species_delimiter,
        reaction_delimiter=reaction_delimiter,
        include_TS=False,
        stoich_format=stoich_format,
        act_method_name=act_method_name,
        act_unit=act_unit,
        float_format=float_format,
        column_delimiter=column_delimiter,
        T=T,
        sden_operation=sden_operation,
        **kwargs)

    # Preparing reaction line header
    mw_field = '{:<5}'
    if use_mw_correction:
        mw_str = mw_field.format('MWON')
    else:
        mw_str = mw_field.format('MWOFF')

    if 'oRT' in act_method_name:
        act_unit_str = ''
    else:
        act_unit_str = act_unit.upper()

    lines = [
        _get_filestamp(),
        '!Surface species',
        '!Each catalyst site has the following format:',
        '!SITE/[Site name]/      SDEN/[Site density in mol/cm2]/',
        '![Adsorbate Name]/[# of Sites occupied]/ (for every adsorbate)',
        '!BULK [Bulk name]/[Bulk density in g/cm3]',
    ]
    lines.extend(cat_site_lines)
    lines.extend([
        'END', '', '!Gas-phase reactions.',
        '!The reaction line has the following format:',
        '!REACTIONS  MW[ON/OFF]   [Ea units]',
        '!where MW stands for Motz-Wise corrections and if the Ea',
        ('!units are left blank, then the activation energy should '
         'be dimensionless (i.e. E/RT)'), '!The rate constant expression is:',
        '!k = kb/h/site_den^(n-1) * (T)^beta * exp(-Ea/RT)',
        ('!where site_den is the site density and is the number '
         'of surface species (including empty sites)'),
        '!Each line has 4 columns:',
        '!- Reaction reactants and products separated by =',
        '!- Preexponential factor, kb/h/site_den^(n-1), or ',
        '!  sticking coefficient if adsorption reaction',
        '!- Beta (power to raise T in rate constant expression)',
        ('!- Ea (Activation Energy or Gibbs energy of activation in '
         'specified units'),
        ('!Adsorption reactions can be represented using the STICK '
         'keyword'), 'REACTIONS{2}{0}{2}{1}'.format(mw_str, act_unit_str,
                                                    column_delimiter)
    ])
    lines.extend(reaction_lines)
    lines.append('END')

    # Write the file
    with open(filename, 'w', newline=newline) as f_ptr:
        f_ptr.write('\n'.join(lines))
Beispiel #23
0
def write_gas(nasa_species,
              filename='gas.inp',
              T=c.T0('K'),
              reactions=[],
              species_delimiter='+',
              reaction_delimiter='=',
              act_method_name='get_E_act',
              act_unit='kcal/mol',
              float_format=' .3E',
              stoich_format='.0f',
              newline='\n',
              column_delimiter='  ',
              **kwargs):
    """Writes the gas.inp Chemkin file.

    Parameters
    ----------
        nasa_species : list of :class:`~pMuTT.empirical.nasa.Nasa` objects
            Surface and gas species used in Chemkin mechanism. Used to write
            elements section
        filename : str, optional
            File name for gas.inp file. Default is 'gas.inp'
        reactions : :class:`~pMuTT.reaction.Reactions` object, optional
            Reactions in mechanism. Reactions with only gas-phase species will
            be written to this file
    """
    # Get unique elements and gas-phase species
    unique_elements = set()
    gas_species = []
    for specie in nasa_species:
        for element in specie.elements.keys():
            unique_elements.add(element)
        if specie.phase.upper() == 'G':
            gas_species.append(specie.name)
    unique_elements = list(unique_elements)

    # Get gas-phase reactions
    gas_reactions = [reaction for reaction in reactions if reaction.gas_phase]
    reaction_lines = _write_reaction_lines(
        reactions=gas_reactions,
        species_delimiter=species_delimiter,
        reaction_delimiter=reaction_delimiter,
        include_TS=False,
        stoich_format=stoich_format,
        act_method_name=act_method_name,
        act_unit=act_unit,
        float_format=float_format,
        column_delimiter=column_delimiter,
        T=T,
        sden_operation=None,
        **kwargs)
    # Collect all the lines into a list
    lines = [
        _get_filestamp(), '!Elements present in gas and surface species',
        'ELEMENTS'
    ]
    lines.extend(unique_elements)
    lines.extend(['END', '', '!Gas-phase species', 'SPECIES'])
    lines.extend(gas_species)
    lines.extend([
        'END', '', '!Gas-phase reactions. The rate constant expression is:',
        '!k = kb/h * (T)^beta * exp(-Ea/RT)', '!Each line has 4 columns:',
        '!- Reaction reactants and products separated by <=>',
        '!- Preexponential factor, kb/h',
        '!- Beta (power to raise T in rate constant expression)',
        ('!- Ea (Activation Energy or Gibbs energy of activation in '
         'kcal/mol'), 'REACTIONS'
    ])
    lines.extend(reaction_lines)
    lines.append('END')

    with open(filename, 'w', newline=newline) as f_ptr:
        f_ptr.write('\n'.join(lines))
Beispiel #24
0
 def test_T0(self):
     self.assertEqual(c.T0('K'), 298.15)
     with self.assertRaises(KeyError):
         c.T0('arbitrary unit')
Beispiel #25
0
    def from_statmech(cls,
                      name,
                      statmech_model,
                      T_low,
                      T_high,
                      T_mid=None,
                      references=None,
                      elements=None,
                      **kwargs):
        """Calculates the NASA polynomials using statistical mechanic models

        Parameters
        ----------
            name : str
                Name of the species
            statmech_model : `pMuTT.statmech.StatMech` object or class
                Statistical Mechanics model to generate data
            T_low : float
                Lower limit temerature in K
            T_high : float
                Higher limit temperature in K
            T_mid : float or iterable of float, optional
                Guess for T_mid. If float, only uses that value for T_mid. If
                list, finds the best fit for each element in the list. If None,
                a range of T_mid values are screened between the 6th lowest
                and 6th highest value of T.
            references : `pMuTT.empirical.references.References` object
                Reference to adjust enthalpy
            elements : dict
                Composition of the species.
                Keys of dictionary are elements, values are stoichiometric
                values in a formula unit.
                e.g. CH3OH can be represented as:
                {'C': 1, 'H': 4, 'O': 1,}.
            kwargs : keyword arguments
                Used to initalize ``statmech_model`` or ``EmpiricalBase``
                attributes to be stored.
        Returns
        -------
            Nasa : Nasa object
                Nasa object with polynomial terms fitted to data.
        """
        # Initialize the StatMech object
        if inspect.isclass(statmech_model):
            statmech_model = statmech_model(**kwargs)

        # Generate data
        T = np.linspace(T_low, T_high)
        if T_mid is not None:
            # Check to see if specified T_mid's are in T and, if not,
            # insert them into T.
            # If a single value for T_mid is chosen, convert to a tuple
            if not _is_iterable(T_mid):
                T_mid = (T_mid, )
            for x in range(0, len(T_mid)):
                if np.where(T == T_mid[x])[0].size == 0:
                    # Insert T_mid's into T and save position
                    Ts_index = np.where(T > T_mid[x])[0][0]
                    T = np.insert(T, Ts_index, T_mid[x])
        CpoR = np.array([statmech_model.get_CpoR(T=T_i) for T_i in T])
        T_ref = c.T0('K')
        HoRT_ref = statmech_model.get_HoRT(T=T_ref)
        # Add contribution of references
        if references is not None:
            descriptor_name = references.descriptor
            if descriptor_name == 'elements':
                descriptors = elements
            else:
                descriptors = kwargs[descriptor_name]
            HoRT_ref += references.get_HoRT_offset(descriptors=descriptors,
                                                   T=T_ref)
        SoR_ref = statmech_model.get_SoR(T=T_ref)

        return cls.from_data(name=name,
                             T=T,
                             CpoR=CpoR,
                             T_ref=T_ref,
                             HoRT_ref=HoRT_ref,
                             SoR_ref=SoR_ref,
                             T_mid=T_mid,
                             statmech_model=statmech_model,
                             elements=elements,
                             references=references,
                             **kwargs)
Beispiel #26
0
from pMuTT.reaction import Reaction
from pMuTT.reaction.bep import BEP
from pMuTT.statmech import StatMech, presets
from pMuTT import constants as c
from pMuTT.io_.json import pMuTTEncoder, json_to_pMuTT
import os
import json

os.chdir(os.path.dirname(__file__))
T = c.T0('K')
# Factor to convert potential energy to dimensionless number
dim_factor = c.R('eV/K') * T

species = {
    'H2':
    StatMech(name='H2',
             potentialenergy=2. * dim_factor,
             **presets['electronic']),
    'O2':
    StatMech(name='O2',
             potentialenergy=4. * dim_factor,
             **presets['electronic']),
    'H2O':
    StatMech(name='H2O',
             potentialenergy=3. * dim_factor,
             **presets['electronic']),
    'H2O_TS':
    StatMech(name='H2O',
             potentialenergy=5. * dim_factor,
             **presets['electronic']),
}