def test_get_U(self): np.testing.assert_almost_equal( self.CO2_pmutt.get_U(T=self.T0, V=self.V0, units='J/mol'), -875.1095022368354 * c.R('J/mol/K') * self.T0) np.testing.assert_almost_equal( self.CO2_pmutt.get_U(T=self.T0, V=self.V0, units='J/g'), -875.1095022368354 * c.R('J/mol/K') * self.T0 / self.mw)
def test_get_Cp(self): np.testing.assert_almost_equal( self.CO2_pmutt.get_Cp(T=self.T0, V=self.V0, units='J/mol/K'), 3.9422622359004853 * c.R('J/mol/K')) np.testing.assert_almost_equal( self.CO2_pmutt.get_Cp(T=self.T0, V=self.V0, units='J/g/K'), 3.9422622359004853 * c.R('J/mol/K') / self.mw)
def _fit_HoRT(T_ref, HoRT_ref, a, units): """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 units : str Units corresponding to Shomate polynomial. Units should be supported by :class:`~pmutt.constants.R`. Returns ------- a : (8,) `numpy.ndarray`_ Lower coefficients of Shomate polynomial .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html """ a[5] = (HoRT_ref \ - get_shomate_HoRT(T=np.array([T_ref]), a=a, units=units)) \ *c.R(units)*T_ref/c.prefixes['k'] a[7] = - get_shomate_HoRT(T=np.array([c.T0('K')]), a=a, units=units) \ *c.R(units)*c.T0('K')/c.prefixes['k'] return a
def test_get_F(self): np.testing.assert_almost_equal( self.CO2_pmutt.get_F(T=self.T0, V=self.V0, units='J/mol'), -900.6031596134445 * c.R('J/mol/K') * self.T0) np.testing.assert_almost_equal( self.CO2_pmutt.get_F(T=self.T0, V=self.V0, units='J/g'), -900.6031596134445 * c.R('J/mol/K') * self.T0 / self.mw)
def get_UoRT(self, T=c.T0('K'), **kwargs): """Calculates the dimensionless internal energy using the Extended LSR relationship Parameters ---------- T : float, optional Temperature in K. Default is 298.15 K kwargs : keyword arguments Parameters to calculate reference binding energy, surface energy and gas-phase energy Returns ------- UoRT : float Dimensionless internal energy """ # Check if number of surface species, gas species, and reactions are # consistent n_reactions = len(self.reactions) n_surf = len(self.surf_species) n_gas = len(self.gas_species) n_slopes = len(self.slopes) if n_reactions != n_surf \ or n_reactions != n_gas \ or n_reactions != n_slopes: warn_msg = ( 'Extended LSR can an inconsistent number of slopes {} ' 'reactions ({}), gas species ({}), and surface species ' '({}). Some contributions may be ignored.' ''.format(n_slopes, n_reactions, n_surf, n_gas)) warn(warn_msg) kwargs['T'] = T kwargs['units'] = 'kcal/mol' UoRT = 0. for slope, reaction, surf_species, gas_species in zip( self.slopes, self.reactions, self.surf_species, self.gas_species): try: deltaE_ref = reaction.get_delta_E(**kwargs) except AttributeError: deltaE_ref = reaction.get_delta_H(**kwargs) # Calculate surface energy try: E_surf = surf_species.get_E(**kwargs) except AttributeError: E_surf = surf_species.get_H(**kwargs) # Calculate gas-phase energy try: E_gas = gas_species.get_E(**kwargs) except AttributeError: E_gas = gas_species.get_H(**kwargs) UoRT += (slope * deltaE_ref + E_surf + E_gas) / c.R('kcal/mol/K') / T return UoRT + self.intercept / c.R('kcal/mol/K') / T
def test_get_FoRT(self): self.assertAlmostEqual(self.lsr_const.get_UoRT(), 4.5 / c.R('kcal/mol/K') / c.T0('K'), places=2) self.assertAlmostEqual(self.lsr_shomate.get_UoRT(), 4.5 / c.R('kcal/mol/K') / c.T0('K'), places=2) self.assertAlmostEqual(self.lsr_statmech.get_UoRT(), 4.5 / c.R('kcal/mol/K') / c.T0('K'), places=2)
def test_get_E(self): np.testing.assert_almost_equal( self.CO2_pmutt.get_E(T=self.T0, units='J/mol'), -894.97476277965 * c.R('J/mol/K') * self.T0) np.testing.assert_almost_equal(self.CO2_pmutt.get_E(T=self.T0, units='J/mol', include_ZPE=True), -877.703643641077 * c.R('J/mol/K') * self.T0, decimal=2)
def test_get_H(self): T = np.array([ 500., 525., 550., 575., 600., 625., 650., 675., 700., 725., 750., 775., 800., 825., 850., 875., 900., 925., 950., 975., 1000., 1025., 1050., 1075., 1100., 1125., 1150., 1175., 1200., 1225., 1250., 1275., 1300., 1325., 1350., 1375., 1400., 1425., 1450., 1475., 1500., 1525., 1550., 1575., 1600., 1625., 1650., 1675., 1700. ]) H_expected = np.array([ -56.50439376, -53.61125042, -50.97965343, -48.57545097, -46.37018744, -44.3399637, -42.46456033, -40.72675589, -39.11179131, -37.60694517, -36.20119391, -34.88493792, -33.64977889, -32.48833779, -31.39410484, -30.36131539, -29.38484627, -28.46012919, -27.58307762, -26.75002503, -25.9576724, -25.20304335, -24.48344574, -23.79643859, -23.13980357, -22.5115202, -21.90974438, -21.3327896, -20.77911052, -20.2472886, -19.73601934, -19.24410116, -18.7704255, -18.31396799, -17.87378072, -17.44898523, -17.03876635, -16.64236662, -16.25908132, -15.88825401, -15.52927251, -15.18156522, -14.84459794, -14.5178708, -14.20091565, -13.89329361, -13.59459279, -13.30442637, -13.02243068 ]) * c.R('J/mol/K') * T np.testing.assert_almost_equal(self.Shomate_direct.get_H( T=T[0], units='J/mol'), H_expected[0], decimal=4) np.testing.assert_array_almost_equal(self.Shomate_direct.get_H( T=T, units='J/mol'), H_expected, decimal=4)
def test_get_Cp(self): T = np.array([ 500., 525., 550., 575., 600., 625., 650., 675., 700., 725., 750., 775., 800., 825., 850., 875., 900., 925., 950., 975., 1000., 1025., 1050., 1075., 1100., 1125., 1150., 1175., 1200., 1225., 1250., 1275., 1300., 1325., 1350., 1375., 1400., 1425., 1450., 1475., 1500., 1525., 1550., 1575., 1600., 1625., 1650., 1675., 1700. ]) Cp_expected = np.array([ 4.235796744, 4.267598139, 4.300310233, 4.333821197, 4.368036178, 4.402873306, 4.438260758, 4.474134568, 4.510436977, 4.547115164, 4.584120285, 4.621406707, 4.658931423, 4.696653576, 4.734534089, 4.772535363, 4.810621034, 4.848755777, 4.886905141, 4.925035419, 4.963113539, 5.001106966, 5.038983636, 5.07671188, 5.114260381, 5.151598119, 5.18869434, 5.225518516, 5.262040323, 5.298229611, 5.334056387, 5.369490794, 5.404503098, 5.439063673, 5.47314299, 5.506711603, 5.539740144, 5.572199316, 5.604059881, 5.635292657, 5.665868512, 5.695758359, 5.724933152, 5.753363882, 5.781021572, 5.807877279, 5.833902083, 5.859067093, 5.883343439 ]) * c.R('J/mol/K') np.testing.assert_almost_equal( self.Shomate_direct.get_Cp(T=T[0], units='J/mol/K'), Cp_expected[0]) np.testing.assert_array_almost_equal( self.Shomate_direct.get_Cp(T=T, units='J/mol/K'), Cp_expected)
def get_UoRT(self, T=c.T0('K'), **kwargs): """Calculates the dimensionless internal energy using the LSR relationship Parameters ---------- T : float, optional Temperature in K. Default is 298.15 K kwargs : keyword arguments Parameters to calculate reference binding energy, surface energy and gas-phase energy Returns ------- UoRT : float Dimensionless internal energy """ kwargs['T'] = T kwargs['units'] = 'kcal/mol' # Calculate reference binding energy try: deltaE_ref = self.reaction.get_delta_E(**kwargs) except AttributeError: deltaE_ref = self.reaction.get_delta_H(**kwargs) # Calculate surface energy try: E_surf = self.surf_specie.get_E(**kwargs) except AttributeError: E_surf = self.surf_specie.get_H(**kwargs) # Calculate gas-phase energy try: E_gas = self.gas_specie.get_E(**kwargs) except AttributeError: E_gas = self.gas_specie.get_H(**kwargs) return (self.slope*deltaE_ref + self.intercept + E_surf + E_gas) \ /c.R('kcal/mol/K')/T
def get_Cp(self, T, units, raise_error=True, raise_warning=True, **kwargs): """Calculate the heat capacity Parameters ---------- T : float or (N,) `numpy.ndarray`_ Temperature(s) in K units : str Units as string. See :func:`~pmutt.constants.R` for accepted units. 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 Arguments to calculate mixture model properties, if any Returns ------- Cp : float or (N,) `numpy.ndarray`_ Heat capacity .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html """ return self.get_CpoR(T=T, raise_error=raise_error, raise_warning=raise_warning, **kwargs) * c.R(units)
def test_get_S(self): T = np.array([ 500., 525., 550., 575., 600., 625., 650., 675., 700., 725., 750., 775., 800., 825., 850., 875., 900., 925., 950., 975., 1000., 1025., 1050., 1075., 1100., 1125., 1150., 1175., 1200., 1225., 1250., 1275., 1300., 1325., 1350., 1375., 1400., 1425., 1450., 1475., 1500., 1525., 1550., 1575., 1600., 1625., 1650., 1675., 1700. ]) S_expected = np.array([ 24.84034743, 25.04777818, 25.24705859, 25.43895148, 25.62411782, 25.803134, 25.97650557, 26.14467824, 26.30804687, 26.46696281, 26.62173993, 26.77265968, 26.91997528, 27.06391529, 27.20468657, 27.34247693, 27.47745721, 27.60978326, 27.73959751, 27.86703041, 27.99220165, 28.11522125, 28.23619048, 28.35520273, 28.47234423, 28.58769466, 28.7013278, 28.81331199, 28.92371063, 29.03258257, 29.13998246, 29.24596116, 29.35056593, 29.45384082, 29.5558268, 29.6565621, 29.75608232, 29.85442065, 29.95160805, 30.04767338, 30.14264358, 30.23654374, 30.32939729, 30.42122603, 30.5120503, 30.60188904, 30.69075988, 30.77867922, 30.8656623 ]) * c.R('J/mol/K') np.testing.assert_almost_equal( self.Shomate_direct.get_S(T=T[0], units='J/mol/K'), S_expected[0]) np.testing.assert_array_almost_equal( self.Shomate_direct.get_S(T=T, units='J/mol/K'), S_expected) np.testing.assert_almost_equal( self.Shomate_direct.get_S(T=T[0], units='J/g/K'), S_expected[0] / self.mw) np.testing.assert_array_almost_equal( self.Shomate_direct.get_S(T=T, units='J/g/K'), S_expected / self.mw)
def test_get_G(self): T = np.array([ 500., 525., 550., 575., 600., 625., 650., 675., 700., 725., 750., 775., 800., 825., 850., 875., 900., 925., 950., 975., 1000., 1025., 1050., 1075., 1100., 1125., 1150., 1175., 1200., 1225., 1250., 1275., 1300., 1325., 1350., 1375., 1400., 1425., 1450., 1475., 1500., 1525., 1550., 1575., 1600., 1625., 1650., 1675., 1700. ]) G_expected = np.array([ -81.34474118, -78.6590286, -76.22671203, -74.01440245, -71.99430526, -70.14309771, -68.4410659, -66.87143413, -65.41983818, -64.07390798, -62.82293385, -61.6575976, -60.56975418, -59.55225307, -58.59879142, -57.70379231, -56.86230349, -56.06991246, -55.32267513, -54.61705544, -53.94987405, -53.31826459, -52.71963622, -52.15164133, -51.6121478, -51.09921486, -50.61107217, -50.14610159, -49.70282116, -49.27987116, -48.8760018, -48.49006232, -48.12099143, -47.76780881, -47.42960753, -47.10554734, -46.79484867, -46.49678727, -46.21068937, -45.9359274, -45.67191608, -45.41810897, -45.17399522, -44.93909682, -44.71296595, -44.49518265, -44.28535267, -44.08310559, -43.88809298 ]) * c.R('J/mol/K') * T np.testing.assert_almost_equal(self.Shomate_direct.get_G( T=T[0], units='J/mol'), G_expected[0], decimal=4) np.testing.assert_array_almost_equal(self.Shomate_direct.get_G( T=T, units='J/mol'), G_expected, decimal=4)
def get_G_act(self, units, T, P=1., rev=False, **kwargs): """Calculates the Gibbs energy of activation. If there is no transition state species, calculates the delta Gibbs energy Parameters ---------- rev : bool, optional Reverse direction. If True, uses products as initial state instead of reactants. Default is False T : float Temperature in K P : float, optional Pressure in bar. Default is 1 bar kwargs : keyword arguments Parameters required to calculate enthalpy of activation. Returns ------- HoRT_act : float Dimensionless activation enthalpy. Returns the max of the following to ensure stable MKM performance: - Difference between reactants/products and the transition state - Difference between the reactants and the products - 0 """ R_units = '{}/K'.format(units) return self.get_GoRT_act(rev=rev, T=T, P=P, **kwargs)*T*c.R(R_units)
def test_get_H(self): T = np.array([ 500., 600., 700., 800., 900., 1000., 1100., 1200., 1300., 1400., 1500., 1600., 1700., 1800., 1900., 2000., 2100., 2200 ]) H_expected = c.R('J/mol/K')*T *\ np.array([-56.49930957, -46.36612849, -39.10913137, -33.64819891, -29.38377578, -25.95653237, -23.13812007, -20.77654898, -18.76677584, -17.03389718, -15.52306522, -14.19318522, -13.01283758, -11.95756475, -11.00803153, -10.14874498, -9.367140366, -8.652916499]) np.testing.assert_almost_equal(self.Nasa_direct.get_H(T=T[0], units='J/mol'), H_expected[0], decimal=4) np.testing.assert_array_almost_equal(self.Nasa_direct.get_H( T=T, units='J/mol'), H_expected, decimal=4) np.testing.assert_almost_equal(self.Nasa_direct.get_H(T=T[0], units='J/g'), H_expected[0] / self.mw, decimal=4) np.testing.assert_array_almost_equal(self.Nasa_direct.get_H( T=T, units='J/g'), H_expected / self.mw, decimal=4)
def get_shomate_SoR(a, T, units): """Calculates the dimensionless entropy using Shomate polynomial form Parameters ---------- a : (8,) `numpy.ndarray`_ Coefficients of Shomate polynomial T : iterable Temperature in K units : str Units corresponding to Shomate polynomial. Units should be supported by :class:`~pmutt.constants.R`. Returns ------- SoR : float Dimensionless entropy .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html """ t = T / 1000. t_arr = np.array( [[np.log(x), x, x**2 / 2., x**3 / 3., -1. / 2. / x**2, 0., 1., 0.] for x in t]) SoR = np.dot(t_arr, a) / c.R(units) return SoR
def test_get_GoRT(self): expected_GoRT_CO2 = \ self.CO2_ASE.get_gibbs_energy(temperature=self.T0, pressure=self.P0, verbose=False)/c.R('eV/K')/self.T0 calc_GoRT_CO2 = self.CO2_pmutt.get_GoRT(T=self.T0, V=self.V0) np.testing.assert_almost_equal(expected_GoRT_CO2, calc_GoRT_CO2, 3)
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(initial='bar', final='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 get_Tc(self): """Calculates the critical temperature Returns ------- Tc : float Critcial temperature in K """ return 8. * self.a / 27. / self.b / c.R('J/mol/K')
def get_SoR(self): """Calculate the dimensionless entropy Returns ------- SoR : float Dimensionless entropy """ return self.S / c.R('eV/K')
def get_CpoR(self): """Calculate the dimensionless heat capacity (constant pressure) Returns ------- CpoR : float Dimensionless heat capacity (constant pressure) """ return self.Cp / c.R('eV/K')
def get_CvoR(self): """Calculate the dimensionless heat capacity (constant volume) Returns ------- CvoR : float Dimensionless heat capacity (constant volume) """ return self.Cv / c.R('eV/K')
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(initial='bar', final='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)
def units(self, val): try: c.R(val) except KeyError: err_msg = ('Units, "{}", inputted into pmutt.empirical.Shomate ' 'object are invalid. See pmutt.constants.R for ' 'supported units.'.format(val)) raise ValueError(err_msg) else: self._units = val
def get_GoRT_2D(self, x1_name, x1_values, x2_name, x2_values, G_units=None, **kwargs): """Calculates the Gibbs free energy for all the reactions for two varying parameters Parameters ---------- x1_name : str Name of first variable to vary x1_values : iterable object x1 values to use x2_name : str Name of second variable to vary x2_values : iterable object x2 values to use G_units : str, optional Units for G. If None, uses GoRT. Default is None kwargs : keyword arguments Other variables to use in the calculation Returns ------- GoRT : (M, N, O) `numpy.ndarray`_ of float GoRT values. The first index corresponds to the number of reactions. The second index corresponds to the conditions specified by x_values. stable_phases : (N, O) `numpy.ndarray`_ of int Each element of the array corresponds to the index of the most stable phase at the x_values. """ GoRT = np.zeros(shape=(len(self.reactions), len(x1_values), len(x2_values))) for i, (reaction, norm_factor) in enumerate( zip(self.reactions, self.norm_factors)): for j, x1 in enumerate(x1_values): kwargs[x1_name] = x1 for k, x2 in enumerate(x2_values): kwargs[x2_name] = x2 GoRT[i, j, k] = \ reaction.get_delta_GoRT(**kwargs)/norm_factor # Add unit corrections if G_units is not None: GoRT[i, j, k] *= c.R('{}/K'.format(G_units)) *\ kwargs['T'] # Take a transpose GoRT_T = GoRT.transpose((1, 2, 0)) stable_phases = np.zeros((len(x1_values), len(x2_values))) for i, GoRT_row in enumerate(GoRT_T): stable_phases[i, :] = np.nanargmin(GoRT_row, axis=1) return GoRT, stable_phases
def get_ZPE(self): """Calculate zero point energy :math:`u^o_D = u^o +\\frac{9}{8}R\\Theta_D` Returns ------- zpe : float Zero point energy in eV """ return self.interaction_energy \ + 9./8.*c.R('eV/K')*self.debye_temperature
def get_GoRT(self, T=c.T0('K')): """Calculate the dimensionless Gibbs energy Parameters ---------- T : float, optional Temperature in K. Default is 298.15 K Returns ------- GoRT : float Dimensionless Gibbs energy """ return self.G / c.R('eV/K') / T
def get_HoRT(self, T=c.T0('K')): """Calculate the dimensionless enthalpy Parameters ---------- T : float, optional Temperature in K. Default is 298.15 K Returns ------- HoRT : float Dimensionless enthalpy """ return self.H / c.R('eV/K') / T
def test_get_S(self): T = np.array([500., 600., 700., 800., 900., 1000., 1100., 1200., 1300., 1400., 1500., 1600., 1700., 1800., 1900., 2000., 2100., 2200]) S_expected = c.R('J/mol/K') *\ np.array([24.84583501, 25.62943045, 26.31248017, 26.92360771, 27.48073089, 27.99565652, 28.47647349, 28.92890014, 29.35709049, 29.76414079, 30.15242096, 30.52379873, 30.87979567, 31.22169282, 31.55059054, 31.86744523, 32.17309661, 32.46828858]) np.testing.assert_almost_equal(self.Nasa_direct.get_S(T=T[0], units='J/mol/K'), S_expected[0]) np.testing.assert_array_almost_equal(self.Nasa_direct.get_S(T=T, units='J/mol/K'), S_expected)
def test_get_Cp(self): T = np.array([500., 600., 700., 800., 900., 1000., 1100., 1200., 1300., 1400., 1500., 1600., 1700., 1800., 1900., 2000., 2100., 2200]) Cp_expected = c.R('J/mol/K') *\ np.array([4.238636088, 4.363835667, 4.503924733, 4.654023202, 4.809813915, 4.967542636, 5.124018051, 5.276611768, 5.423258319, 5.56245516, 5.693262665, 5.815304137, 5.928750505, 6.034087273, 6.131819121, 6.222433488, 6.306400563, 6.384173277]) np.testing.assert_almost_equal(self.Nasa_direct.get_Cp(T=T[0], units='J/mol/K'), Cp_expected[0]) np.testing.assert_array_almost_equal(self.Nasa_direct.get_Cp(T=T, units='J/mol/K'), Cp_expected)