Exemple #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
Exemple #2
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)
Exemple #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)
 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')
Exemple #5
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')
Exemple #6
0
def get_rot_temperatures_from_atoms(atoms, geometry=None, degree_tol=5.):
    """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.
        degree_tol : float, optional
            Degree tolerance in degrees. Default is 5 degrees
    Returns
    -------
        rot_temperatures : list of float
            Rotational temperatures
    """
    if geometry is None:
        geometry = get_geometry_from_atoms(atoms=atoms, degree_tol=degree_tol)

    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))
Exemple #7
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'))
Exemple #8
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)
Exemple #9
0
    def get_T(self, V=c.V0('m3'), P=c.P0('bar'), n=1.):
        """Calculates the temperature 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')
Exemple #10
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')
Exemple #11
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.)
Exemple #12
0
# ## Constants
# pMuTT has a wide variety of constants to increase readability of the code. See [Constants page][0] in the documentation for supported units.
# 
# [0]: https://vlachosgroup.github.io/pMuTT/constants.html#constants

# In[1]:


from pMuTT import constants as c

print('Some constants')
print('R (J/mol/K) = {}'.format(c.R('J/mol/K')))
print("Avogadro's number = {}\n".format(c.Na))

print('Unit conversions')
print('5 kJ/mol --> {} eV/molecule'.format(c.convert_unit(num=5., from_='kJ/mol', to='eV/molecule')))
print('Frequency of 1000 Hz --> Wavenumber of {} 1/cm\n'.format(c.freq_to_wavenumber(1000.)))

print('See expected inputs, supported units of different constants')
help(c.R)
help(c.convert_unit)


# ## StatMech Objects
# Molecules show translational, vibrational, rotational, electronic, and nuclear modes.
# 
# <img src="images/statmech_modes.jpg" width=800>
# 
# The [``StatMech``][0] object allows us to specify translational, vibrational, rotational, electronic and nuclear modes independently, which gives flexibility in what behavior you would like.
# 
# [0]: https://vlachosgroup.github.io/pMuTT/statmech.html#pMuTT.statmech.StatMech
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,
                            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(T, 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()
print('S expt: {} J/mol/K'.format(S_ref))
print('S shomate: {} J/mol/K'.format(S_shomate))

# ### Compare using a plot

# In[5]:

fig, axes = CH3OH_shomate.plot_empirical(Cp_units='J/mol/K',
                                         H_units='kJ/mol',
                                         S_units='J/mol/K',
                                         G_units='kJ/mol')
# Add experimental data to plot
axes[0].plot(T, 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')

# Add legend to plot
axes[0].legend(['Shomate', 'Expt'])
axes[1].legend(['Shomate', 'Expt'])
axes[2].legend(['Shomate', 'Expt'])
axes[3].legend(['Shomate', 'Expt'])

# Adjust figure size so it's viewable
fig.set_size_inches((10, 8))

# Note that in this code's section, we showcase the ``pMuTT.constants.convert_unit`` function. Similarly to the ``c.R`` and ``c.T0`` functions shown above, this helps to increase code readability.
#
# ## Save the Shomate polynomial as a JSON file
# If we would like to save our Shomate object, we can save it in JSON format with the help of the ``pMuTT.io_.json.pMuTTEncoder``.