Ejemplo n.º 1
0
    def get_SoR(self, Ts, P=1., verbose=False):
        """Calculate the dimensionless entropy.

        Parameters:
            Ts : float or (N,) `numpy.ndarray`_
                Temperature(s) in K
            P : float, optional
                Pressure in atm. Default is 1 atm.
            verbose : bool
                Whether a table breaking down each contribution should be printed
        Returns:
            SoR : float or (N,) `numpy.ndarray`_
                Dimensionless entropy (S/R) at the specified temperature and pressure
        """
        try:
            iter(Ts)
        except TypeError:
            SoR = self.model.get_entropy(
                Ts,
                pressure=P * c.convert_unit(from_='atm', to='Pa'),
                verbose=verbose) / c.R('eV/K')
        else:
            SoR = np.zeros_like(Ts)
            for i, T in enumerate(Ts):
                SoR[i] = self.model.get_entropy(
                    T,
                    pressure=P * c.convert_unit(from_='atm', to='Pa'),
                    verbose=verbose) / c.R('eV/K')
        return SoR
Ejemplo n.º 2
0
    def get_GoRT(self, Ts, P=1., verbose=False):
        """Returns the dimensionless Gibbs energy at a given temperature

        Parameters:
            Ts : float or (N,) `numpy.ndarray`_
                Temperature(s) in K
            P : float, optional
                Pressure in bar. Default is 1 atm.
            verbose : bool
                Whether a table breaking down each contribution should be printed
        Returns:
            GoRT : float or (N,) `numpy.ndarray`_
                Dimensionless heat capacity (G/RT) at the specified temperature
        """
        try:
            iter(Ts)
        except TypeError:
            GoRT = self.model.get_gibbs_energy(
                Ts, pressure=P*c.convert_unit(from_='bar', to='Pa'), verbose=verbose) / \
                   (c.kb('eV/K') * Ts)
        else:
            GoRT = np.zeros_like(Ts)
            for i, T in enumerate(Ts):
                GoRT[i] = self.model.get_gibbs_energy(
                    T, pressure=P*c.convert_unit(from_='bar', to='Pa'), verbose=verbose) / \
                          (c.kb('eV/K') * T)
        return GoRT
Ejemplo n.º 3
0
 def __init__(self,
              A_st=None,
              atoms=None,
              symmetrynumber=None,
              inertia=None,
              geometry=None,
              vib_energies=None,
              potentialenergy=None,
              **kwargs):
     super().__init__(atoms=atoms,
                      symmetrynumber=symmetrynumber,
                      geometry=geometry,
                      vib_energies=vib_energies,
                      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 = vib_energies
     self.theta = np.array(vib_energies) / c.kb('eV/K')
     self.zpe = sum(np.array(vib_energies)/2.) *\
         c.convert_unit(from_='eV', to='kcal')*c.Na
     if np.sum(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
Ejemplo n.º 4
0
    def get_GoRT(self, Ts, P=1., verbose=False):
        """Calculate the dimensionless Gibbs energy.

        Parameters:
            Ts : float or list
                Temperature(s) in K
            P : float
                Pressure in atm. Default is 1 atm
            verbose : bool
                Whether a table breaking down each contribution should be printed
        Returns:
            GoRT: float or (N,) `numpy.ndarray`_
                Dimensionless heat capacity (G/RT) at the specified temperature
        """
        press = P * c.convert_unit(from_='atm', to='Pa')
        try:
            iter(Ts)
        except TypeError:
            GoRT = self.model.get_helmholtz_energy(Ts, verbose=verbose) / \
                   (c.kb('eV/K') * Ts)
        else:
            GoRT = np.zeros_like(Ts)
            for i, T in enumerate(Ts):
                GoRT[i] = self.model.get_helmholtz_energy(T, verbose=verbose) / \
                          (c.kb('eV/K') * T)
        return GoRT
Ejemplo n.º 5
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)
Ejemplo n.º 6
0
    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(from_='g', to='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)
Ejemplo n.º 7
0
 def test_convert_unit(self):
     self.assertEqual(c.convert_unit(num=0., from_='C', to='K'), 273.15)
     self.assertEqual(c.convert_unit(from_='m', to='cm'), 100.)
     with self.assertRaises(ValueError):
         c.convert_unit(from_='cm', to='J')
     with self.assertRaises(ValueError):
         c.convert_unit(from_='arbitrary unit', to='J')
     with self.assertRaises(ValueError):
         c.convert_unit(from_='cm', to='arbitrary unit')
Ejemplo n.º 8
0
    def get_Pc(self):
        """Calculates the critical pressure

        Returns
        -------
            Pc : float
                Critical pressure in bar
        """
        return self.a / 27. / self.b**2 * c.convert_unit(from_='Pa', to='bar')
Ejemplo n.º 9
0
def get_rot_temperatures_from_atoms(atoms, geometry=None):
    """Calculate the rotational temperatures from ase.Atoms object

    Parameters
    ----------
        atoms : ase.Atoms object
            Atoms object
        geometry : str, optional
            Geometry of molecule. If not specified, it will be guessed from
            Atoms object.
    Returns
    -------
        rot_temperatures : list of float
            Rotational temperatures
    """
    if geometry is None:
        geometry = get_geometry_from_atoms(atoms)

    rot_temperatures = []
    for moment in atoms.get_moments_of_inertia():
        if np.isclose(0., moment):
            continue
        moment_SI = moment*c.convert_unit(from_='amu', to='kg') \
                   *c.convert_unit(from_='A2', to='m2')
        rot_temperatures.append(c.inertia_to_temp(moment_SI))

    if geometry == 'monatomic':
        # Expecting all modes to be 0
        assert np.isclose(np.sum(rot_temperatures), 0.)
        return [0.]
    elif geometry == 'linear':
        # Expecting one mode to be 0 and the other modes to be identical
        if not np.isclose(rot_temperatures[0], rot_temperatures[1]):
            warn('Expected rot_temperatures for linear specie, {}, to be '
                 'similar. Values found were:{}'.format(
                     atoms, rot_temperatures))
        return [max(rot_temperatures)]
    elif geometry == 'nonlinear':
        # Expecting 3 modes. May or may not be equal
        return rot_temperatures
    else:
        raise ValueError('Geometry, {}, not supported.'.format(geometry))
Ejemplo n.º 10
0
    def get_SoR(self, temperature, pressure=1.0, verbose=False):
        """Calculate the dimensionless entropy.

        Parameters:
            temperature (float): Temperature(s) in K
            pressure (float, optional): Pressure in atm. Default is 1 atm.
            verbose (bool): Print a table breaking down each contribution
        """
        if self.specie_type == 'ideal gas':
            entropy = self.model.get_entropy(
                temperature,
                pressure=pressure * c.convert_unit(from_='atm', to='Pa'),
                verbose=verbose)
        else:
            entropy = self.model.get_entropy(temperature, verbose=verbose)

        return entropy / c.R('eV/K')
Ejemplo n.º 11
0
    def get_V(self, T, P):
        """Calculates the molar volume of an ideal gas at T and P

        :math:`V_m=\\frac{RT}{P}`

        Parameters
        ----------
            T : float
                Temperature in K
            P : float
                Pressure in bar
        Returns
        -------
            V : float
                Molar volume in m3
        """
        return T * c.R('J/mol/K') / (P * c.convert_unit(from_='bar', to='Pa'))
Ejemplo n.º 12
0
    def get_GoRT(self, temperature, pressure=1.0, verbose=False):
        """Calculate the dimensionless Gibbs energy.

        Parameters:
            temperature (float): Temperature(s) in K
            pressure (float, optional): Pressure in atm. Default is 1 atm.
            verbose (bool): Print a table breaking down each contribution
        """
        if self.specie_type == 'ideal gas':
            G = self.model.get_gibbs_energy(
                temperature,
                pressure=pressure * c.convert_unit(from_='bar', to='Pa'),
                verbose=verbose)
        else:
            G = self.model.get_helmholtz_energy(temperature, verbose=verbose)

        return G / (c.kb('eV/K') * temperature)
Ejemplo n.º 13
0
    def from_critical(cls, Tc, Pc):
        """Creates the van der Waals object from critical temperature and 
        pressure

        Parameters
        ----------
            Tc : float
                Critical temperature in K
            Pc : float
                Critical pressure in bar
        Returns
        -------
            vanDerWaalsEOS : vanDerWaalsEOS object
        """
        Pc_SI = Pc * c.convert_unit(from_='bar', to='Pa')
        a = 27. / 64. * (c.R('J/mol/K') * Tc)**2 / Pc_SI
        b = c.R('J/mol/K') * Tc / 8. / Pc_SI
        return cls(a=a, b=b)
Ejemplo n.º 14
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')
Ejemplo n.º 15
0
    def get_T(self, V=c.V0('m3'), P=c.P0('bar'), n=1.):
        """Calculates the volume 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
            n : float, optional
                Number of moles (in mol). Default is 1 mol
        Returns
        -------
            T : float
                Temperature in K
        """
        Vm = V / n
        return (P*c.convert_unit(from_='bar', to='Pa') + self.a/Vm**2) \
               *(Vm - self.b)/c.R('J/mol/K')
Ejemplo n.º 16
0
    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(from_='g', to='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.)
Ejemplo n.º 17
0
# 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
Ts = 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(name ='CH3OH', Ts=Ts, CpoR=CpoR, T_ref=T_ref, HoRT_ref=HoRT_ref, SoR_ref=SoR_ref)

#Compare the Nasa polynomial to the input data
fig, axes = CH3OH_nasa.plot_empirical(Cp_units=Cp_units, H_units=H_units, S_units=S_units, G_units=G_units)
axes[0].plot(Ts, Cp, 'ko')
axes[1].plot(T_ref, H_ref, 'ko')
axes[2].plot(T_ref, S_ref, 'ko')
axes[3].plot(T_ref, H_ref - T_ref * S_ref * c.convert_unit(from_='J', to='kJ'), 'ko')
plt.show()