def test_get_A(self): 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) self.assertAlmostEqual(self.rxn_sm.get_A(T=c.T0('K')), exp_sm_A) self.assertAlmostEqual(self.rxn_sm.get_A(T=c.T0('K'), rev=True), exp_sm_A_rev)
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
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)
def get_GoRT(self, Ts, verbose=False): """Calculate dimensionless Gibbs energy at a given temperature. Args: Ts (float or numpy array): Temperature(s) in K verbose (bool): Flag to print each contribution to enthalpy Returns: GoRT (float or numpy array): Dimensionless heat capacity (H/RT) """ try: iter(Ts) except TypeError: GoRT = self.model.get_helmholtz_energy(Ts, 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) / \ (c.kb('eV/K') * T) return GoRT
def get_ZPE(self): """Calculates the zero point energy :math:`ZPE=\\frac{1}{2}h\\sum_i \\Theta_{V,i}` Returns ------- zpe : float Zero point energy in eV """ return 0.5 * c.kb('eV/K') * np.sum(self._vib_temperatures)
def _get_single_CvoR_vib(vib_energies, T): """Calculate the dimensionless vibrational heat capacity Parameters: vib_energies (array of floats): Vibrational energies in eV T (float): Temperatures in K Returns: CvoR_vib (float): Dimensionless vibrational heat capacity """ dimensionless_vibs = vib_energies / c.kb('eV/K') / T CvoR_vib = np.sum((0.5 * dimensionless_vibs)**2 * (1. / np.sinh(0.5 * dimensionless_vibs))**2) return CvoR_vib
def get_CvoR_vib(vib_energies, temperature): """Calculate the dimensionless vibrational heat capacity :math:`\\frac {Cp_{vib}}{R} = \\sum_{i=1}^{n} \\bigg(\\frac {\\Theta_{V,i}}{2T}\\bigg)^2 \\frac {1}{\\big(sinh(\\frac {\\Theta_{V,i}}{2T})\\big)^2}` Parameters: vib_energies (array of floats): Vibrational energies in eV temperature (float): Temperature in K """ dimensionless_vibs = vib_energies / c.kb('eV/K') / temperature CvoR_vib = np.sum((0.5 * dimensionless_vibs)**2 * (1. / np.sinh(0.5 * dimensionless_vibs))**2) return CvoR_vib
def get_HoRT(self, Ts, verbose=False): """Calculate the dimensionless enthalpy. Parameters: Ts : float or (N,) `numpy.ndarray`_ Temperature(s) in K verbose : bool Whether a table breaking down each contribution should be printed Returns HoRT : float or (N,) `numpy.ndarray`_ Dimensionless heat capacity (H/RT) """ try: iter(Ts) except TypeError: HoRT = self.model.get_enthalpy(Ts, verbose=verbose) / \ (c.kb('eV/K') * Ts) else: HoRT = np.zeros_like(Ts) for i, T in enumerate(Ts): HoRT[i] = self.model.get_enthalpy(T, verbose=verbose) / \ (c.kb('eV/K') * T) return HoRT
def get_HoRT(self, temperature, verbose=False): """Calculate the dimensionless enthalpy. Parameters: temperature (float): Temperature in K verbose (bool): Print a table breaking down each contribution """ if self.specie_type == 'ideal gas': enthalpy = self.model.get_enthalpy(temperature, verbose=verbose) else: enthalpy = self.model.get_internal_energy(temperature, verbose=verbose) return enthalpy / (c.kb('eV/K') * temperature)
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
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)
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)
def get_A(self, T=c.T0('K'), rev=False, **kwargs): """Gets pre-exponential factor between reactants (or products) and transition state in 1/s Parameters ---------- rev : bool, optional Reverse direction. If True, uses products as initial state instead of reactants. Default is False T : float, optional Temperature in K. Default is standard temperature. kwargs : keyword arguments Parameters required to calculate pre-exponential factor Returns ------- A : float Pre-exponential factor """ return c.kb('J/K')*T/c.h('J s')\ *np.exp(-self.get_SoR_act(rev=rev, T=c.T0('K'), **kwargs))
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.)
def test_get_CvoR_vib(self): #Vibrational frequencies correspond to H2O vib_energies = np.array([5360., 5160., 2290.]) * c.kb('eV/K') self.assertAlmostEqual(heat_capacity._get_single_CvoR_vib(vib_energies=vib_energies, T=300.), 0.02824711469596) self.assertAlmostEqual(heat_capacity.get_CvoR_vib(vib_energies=vib_energies, Ts=300.), 0.02824711469596) np.testing.assert_almost_equal(heat_capacity.get_CvoR_vib(vib_energies=vib_energies, Ts=np.array([300., 400., 500.])), np.array([0.02824711469596, 0.10834772440392, 0.22564243671432]))
def test_kb(self): self.assertEqual(c.kb('J/K'), 1.38064852e-23) with self.assertRaises(KeyError): c.kb('arbitrary unit')