コード例 #1
0
ファイル: test_pmutt_reaction.py プロジェクト: wittregr/pMuTT
    def test_get_A(self):
        # Testing partition function method
        exp_sm_q = self.H2O_TS_sm.get_q(T=c.T0('K'), include_ZPE=False) \
            / self.H2_sm.get_q(T=c.T0('K'), include_ZPE=False) \
            / self.O2_sm.get_q(T=c.T0('K'), include_ZPE=False)**0.5
        exp_sm_A = c.kb('J/K') * c.T0('K') / c.h('J s') * exp_sm_q
        exp_sm_q_rev = self.H2O_TS_sm.get_q(T=c.T0('K'), include_ZPE=False) \
            / self.H2O_sm.get_q(T=c.T0('K'), include_ZPE=False)
        exp_sm_A_rev = c.kb('J/K') * c.T0('K') / c.h('J s') * exp_sm_q_rev
        np.testing.assert_almost_equal(self.rxn_sm.get_A(T=c.T0('K')),
                                       exp_sm_A,
                                       decimal=0)
        np.testing.assert_almost_equal(self.rxn_sm.get_A(T=c.T0('K'),
                                                         rev=True),
                                       exp_sm_A_rev,
                                       decimal=0)

        # Testing entropy method
        exp_sm_SoR = self.H2O_TS_sm.get_SoR(T=c.T0('K')) \
            - self.H2_sm.get_SoR(T=c.T0('K')) \
            - self.O2_sm.get_SoR(T=c.T0('K'))*0.5
        exp_sm_A = c.kb('J/K') * c.T0('K') / c.h('J s') * np.exp(exp_sm_SoR)
        exp_sm_SoR_rev = self.H2O_TS_sm.get_SoR(T=c.T0('K')) \
            - self.H2O_sm.get_SoR(T=c.T0('K'))
        exp_sm_A_rev = c.kb('J/K')*c.T0('K')/c.h('J s') \
            * np.exp(exp_sm_SoR_rev)
        np.testing.assert_almost_equal(self.rxn_sm.get_A(T=c.T0('K'),
                                                         use_q=False),
                                       exp_sm_A,
                                       decimal=0)
        np.testing.assert_almost_equal(self.rxn_sm.get_A(T=c.T0('K'),
                                                         rev=True,
                                                         use_q=False),
                                       exp_sm_A_rev,
                                       decimal=0)
コード例 #2
0
ファイル: zacros.py プロジェクト: paulmeza/pMuTT
 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(initial='eV', final='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(initial='A2', final='m2') *\
                     c.convert_unit(initial='amu', final='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(initial='g',
                                                      final='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
コード例 #3
0
 def test_kb(self):
     # Test kb for all units
     self.assertAlmostEqual(c.kb('J/K'), self.ans.at['test_kb', 0])
     self.assertAlmostEqual(c.kb('kJ/K'), self.ans.at['test_kb', 1])
     self.assertAlmostEqual(c.kb('eV/K'), self.ans.at['test_kb', 2])
     self.assertAlmostEqual(c.kb('cal/K'), self.ans.at['test_kb', 3])
     self.assertAlmostEqual(c.kb('kcal/K'), self.ans.at['test_kb', 4])
     self.assertAlmostEqual(c.kb('Eh/K'), self.ans.at['test_kb', 5])
     self.assertAlmostEqual(c.kb('Ha/K'), self.ans.at['test_kb', 6])
     # Test kb raises an error when an unsupported unit is passed
     with self.assertRaises(KeyError):
         c.kb('arbitrary unit')
コード例 #4
0
    def get_q(self, T, ignore_q_elec=True):
        """Calculates the partition function

        :math:`q^{elec}=1 + \\omega_i \\exp\\bigg(-\\frac{E}{RT}\\bigg)`

        Parameters
        ----------
            T : float
                Temperature in K
            ignore_q_elec : bool, optional
                Ignore contribution of electronic mode to partition function
                . Often necessary since DFT's value for potentialenergy is
                very negative causing q_elec to go to infinity. Default is True
        Returns
        -------
            q_elec : float
                Electronic partition function
        """
        if ignore_q_elec:
            return 1.
        else:
            if self.D0 is not None:
                Epsilon = self.D0 / c.kb('eV/K') / T
            else:
                Epsilon = self.get_UoRT(T=T)
            return self._degeneracy * (1 + np.exp(-Epsilon))
コード例 #5
0
ファイル: trans.py プロジェクト: wittregr/pMuTT
    def get_SoR(self, T, P=c.P0('bar')):
        """Calculates the dimensionless entropy

        :math:`\\frac{S^{trans}}{R}=1+\\frac{n_{degrees}}{2}+\\log\\bigg(\\big(
        \\frac{2\\pi mk_bT}{h^2})^\\frac{n_{degrees}}{2}\\frac{RT}{PN_a}\\bigg)`

        Parameters
        ----------
            T : float
                Temperature in K
            P : float, optional
                Pressure (bar) or pressure-like quantity.
                Default is atmospheric pressure

        Returns
        -------
            SoR_trans : float
                Translational dimensionless entropy
        """
        V = self.get_V(T=T, P=P)
        unit_mass = self.molecular_weight *\
            c.convert_unit(initial='g', final='kg')/c.Na
        return 1. + float(self.n_degrees)/2. \
            + np.log((2.*np.pi*unit_mass*c.kb('J/K')*T/c.h('J s')**2)
                     ** (float(self.n_degrees)/2.)*V/c.Na)
コード例 #6
0
    def get_A(self,
              sden_operation='min',
              include_entropy=True,
              T=c.T0('K'),
              units='molec/cm2',
              **kwargs):
        """Calculates the preexponential factor in the Cantera format

        Parameters
        ----------
        sden_operation : str, optional
            Site density operation to use. Default is 'min'
        include_entropy : bool, optional
            If True, includes the entropy of activation. Default is True
        T : float, optional
            Temperature in K. Default is 298.15 K
        units : str or :class:`~pmutt.omkm.units.Units`, optional
            Units for A. If `Units` class specified, determines the units for A.
            Default is 'molec/cm2'
        kwargs : keyword arguments
            Parameters required to calculate pre-exponential factor
        """

        if self.transition_state is None or not include_entropy:
            A = c.kb('J/K') / c.h('J s')
        else:
            A = super().get_A(T=T, **kwargs) / T

        # Uses site with highest site density
        site_dens = []
        for reactant, stoich in zip(self.reactants, self.reactants_stoich):
            # Skip species without a catalyst site
            try:
                site_den = reactant.phase.site_density
            except AttributeError:
                continue
            site_dens.extend([site_den] * int(stoich))

        # Apply the operation to the site densities
        if len(site_dens) == 0:
            err_msg = ('At least one species requires a catalytic site with '
                       'site density to calculate A.')
            raise ValueError(err_msg)
        eff_site_den = _apply_numpy_operation(quantity=site_dens,
                                              operation=sden_operation,
                                              verbose=False)
        # Convert site density to appropriate unit
        if isinstance(units, Units):
            quantity_unit = units.quantity
            area_unit = '{}2'.format(units.length)
        else:
            quantity_unit, area_unit = units.split('/')
        eff_site_den = eff_site_den\
                       *c.convert_unit(initial='mol', final=quantity_unit)\
                       /c.convert_unit(initial='cm2', final=area_unit)

        n_surf = self._get_n_surf()
        A = A / eff_site_den**(n_surf - 1)
        return A
コード例 #7
0
    def get_ZPE(self):
        """Calculates the zero point energy

        :math:`ZPE=\\frac{1}{2}k_b\\sum_i \\Theta_{V,i}`

        Returns
        -------
            zpe : float
                Zero point energy in eV
        """
        return 0.5 * c.kb('eV/K') * np.sum(self._valid_vib_temperatures)
コード例 #8
0
    def get_ZPE(self):
        """Calculates the zero point energy

        :math:`u^0_E=u+\\frac{3}{2}\\Theta_E k_B`

        Returns
        -------
            zpe : float
                Zero point energy in eV
        """
        return self.interaction_energy \
            + 1.5*self.einstein_temperature*c.kb('eV/K')
コード例 #9
0
    def get_UoRT(self, T):
        """Calculates the imensionless internal energy

        :math:`\\frac{U^{elec}}{RT}=\\frac{E}{RT}`

        Parameters
        ----------
            T : float
                Temperature in K
        Returns
        -------
            UoRT_elec : float
                Electronic dimensionless internal energy
        """
        return (self.potentialenergy) / c.kb('eV/K') / T
コード例 #10
0
    def _get_SoR_RRHO(self, T, vib_inertia):
        """Calculates the dimensionless RRHO contribution to entropy

        Parameters
        ----------
            T : float
                Temperature in K
            vib_inertia : float
                Vibrational inertia in kg m2
        Returns
        -------
            SoR_RHHO : float
                Dimensionless entropy of Rigid Rotor Harmonic Oscillator
        """
        return 0.5 + np.log(
            (8. * np.pi**3 * vib_inertia * c.kb('J/K') * T / c.h('J s')**2)**
            0.5)
コード例 #11
0
    def get_UoRT(self, T):
        """Calculates the dimensionless internal energy

        :math:`\\frac{U^{vib}}{RT}=\\frac{u^0_E}{k_BT}+3\\frac{\\Theta_E}{T}
        \\bigg(\\frac{\\exp(-\\frac{\\Theta_E}{T})}{1-\\exp(-\\frac{\\Theta_E}
        {T})}\\bigg)`

        Parameters
        ----------
            T : float
                Temperature in K
        Returns
        -------
            UoRT_vib : float
                Vibrational dimensionless internal energy
        """
        theta_E = self.einstein_temperature
        return self.get_ZPE()/c.kb('eV/K')/T \
            + 3.*theta_E/T*np.exp(-theta_E/T)/(1. - np.exp(-theta_E/T))
コード例 #12
0
    def get_q(self, T):
        """Calculates the partition function

        :math:`q^{vib}=\\exp\\bigg({\\frac{-u}{k_BT}}\\bigg)\\bigg(\\frac{
        \\exp(-\\frac{\\Theta_E}{2T})}{1-\\exp(\\frac{-\\Theta_E}{T})}\\bigg)`

        Parameters
        ----------
            T : float
                Temperature in K
        Returns
        -------
            q_vib : float
                Vibrational partition function
        """
        u = self.interaction_energy
        theta_E = self.einstein_temperature
        return np.exp(-u/c.kb('eV/K')/T) \
            * (np.exp(-theta_E/2./T)/(1. - np.exp(-theta_E/T)))
コード例 #13
0
    def get_UoRT(self, T):
        """Calculates dimensionless internal energy

        :math:`\\frac{U^{vib}}{RT} = \\frac{u_D^o}{RT} + 3F\\bigg(\\frac{
        \\Theta_D}{T}\\bigg)`

        :math:`F\\bigg(\\frac{\\Theta_D}{T}\\bigg) = 3\\bigg(\\frac{T}{
        \\Theta_D}\\bigg)^3 \\int_0^{\\frac{\\Theta_D}{T}} \\frac{x^3 e^x}
        {e^x-1} dx`

        Parameters
        ----------
            T : float
                Temperature in K
        Returns
        -------
            UoRT : float
                Dimensionless internal energy
        """
        return self.get_ZPE()/c.kb('eV/K')/T \
               + 3.*self._get_intermediate_fn(T=T, fn=self._F_integrand)
コード例 #14
0
    def get_q(self, T):
        """Calculate the partition function

        :math:`q^{vib} = \\exp\\bigg(-\\frac{u}{3k_B T} - \\frac{3}{8}
        \\frac{\\Theta_D}{T} - G\\big(\\frac{\\Theta_D}{T}\\big)\\bigg)`

        :math:`G\\bigg(\\frac{\\Theta_D}{T}\\bigg) = 3\\bigg(\\frac{T}{
        \\Theta_D}\\bigg)^3\\int_0^{\\frac{\\Theta_D}{T}}x^2 \\ln
        \\bigg(1-e^{-x}\\bigg)dx`
        
        Parameters
        ----------
            T : float
                Temperature in K
        Returns
        -------
            q : float
                Partition function
        """
        G = self._get_intermediate_fn(T=T, fn=self._G_integrand)
        return np.exp(-self.interaction_energy/3./c.kb('eV/K')/T \
                      -3./8.*self.debye_temperature/T - G)
コード例 #15
0
ファイル: trans.py プロジェクト: wittregr/pMuTT
    def get_q(self, T, P=c.P0('bar')):
        """Calculates the partition function

        :math:`q_{trans} = \\bigg(\\frac{2\\pi \\sum_{i}^{atoms}m_ikT}{h^2}
        \\bigg)^\\frac {n_{degrees}} {2}V`

        Parameters
        ----------
            T : float
                Temperature in K
            P : float, optional
                Pressure (bar) or pressure-like quantity.
                Default is atmospheric pressure
        Returns
        -------
            q_trans : float
                Translational partition function
        """
        V = self.get_V(T=T, P=P)
        unit_mass = self.molecular_weight *\
            c.convert_unit(initial='g', final='kg')/c.Na
        return V*(2*np.pi*c.kb('J/K')*T*unit_mass/c.h('J s')**2) \
            ** (float(self.n_degrees)/2.)
コード例 #16
0
 def test_kb(self):
     self.assertEqual(c.kb('J/K'), 1.38064852e-23)
     with self.assertRaises(KeyError):
         c.kb('arbitrary unit')
コード例 #17
0
 def test_get_HoRT(self):
     exp_HoRT = (self.u + 9./8.*self.theta_D*c.kb('eV/K')) \
                /c.kb('eV/K')/self.T \
                + 3.*self.F
     self.assertAlmostEqual(self.vib_Ag.get_HoRT(T=self.T), exp_HoRT, 4)
コード例 #18
0
 def test_get_ZPE(self):
     self.assertAlmostEqual(self.vib_Ag.get_ZPE(),
                            self.u + 9. / 8. * self.theta_D * c.kb('eV/K'))
コード例 #19
0
 def test_get_q(self):
     exp_q = np.exp(-self.u/3./c.kb('eV/K')/self.T \
                    -3./8.*self.theta_D/self.T \
                    -self.G)
     self.assertAlmostEqual(self.vib_Ag.get_q(T=self.T), exp_q)