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 get_G(self, T, units, raise_error=True, raise_warning=True, **kwargs): """Calculate the Gibbs energy Parameters ---------- T : float or (N,) `numpy.ndarray`_ Temperature(s) in K units : str Units as string. See :func:`~pMuTT.constants.R` for accepted units but omit the '/K' (e.g. J/mol). 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 ------- G : float or (N,) `numpy.ndarray`_ Gibbs energy .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.ndarray.html """ return self.get_GoRT(T=T, raise_error=raise_error, raise_warning=raise_warning, **kwargs) \ * T*c.R('{}/K'.format(units))
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_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-1.14.0/reference/generated/numpy.ndarray.html """ return self.get_CpoR(T=T) * c.R(units)
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 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 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)
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 first 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 setUp(self): self.T = c.T0('K') # Factor to convert potential energy to dimensionless number dim_factor = c.R('eV/K')*self.T self.m = 10. # BEP Slope self.c = 20. # BEP Intercept species = { 'H2': StatMech(name='H2', potentialenergy=2.*dim_factor, **presets['electronic']), 'O2': StatMech(name='O2', potentialenergy=4.*dim_factor, **presets['electronic']), 'H2O': StatMech(name='H2O', potentialenergy=3.*dim_factor, **presets['electronic']), } self.rxn_delta = Reaction.from_string( reaction_str='H2 + 0.5O2 = H2O', species=species, descriptor='delta', slope=self.m, intercept=self.c, bep=BEP) self.bep_delta = self.rxn_delta.bep rxn_rev_delta = Reaction.from_string( reaction_str='H2 + 0.5O2 = H2O', species=species, descriptor='rev_delta', slope=self.m, intercept=self.c, bep=BEP) self.bep_rev_delta = rxn_rev_delta.bep rxn_reactants = Reaction.from_string( reaction_str='H2 + 0.5O2 = H2O', species=species, descriptor='reactants', slope=self.m, intercept=self.c, bep=BEP) self.bep_reactants = rxn_reactants.bep rxn_products = Reaction.from_string( reaction_str='H2 + 0.5O2 = H2O', species=species, descriptor='products', slope=self.m, intercept=self.c, bep=BEP) self.bep_products = rxn_products.bep
def _fit_HoRT(T_ref, HoRT_ref, a): """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 Returns ------- a : (8,) `numpy.ndarray`_ Lower coefficients of Shomate polynomial .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.ndarray.html """ a[5] = (HoRT_ref - get_shomate_HoRT(T=np.array([T_ref]), a=a)) \ * c.R('kJ/mol/K')*T_ref a[7] = -get_shomate_HoRT(T=np.array([c.T0('K')]), a=a) \ * c.R('kJ/mol/K')*c.T0('K') return a
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)
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'))
def get_T(self, V=c.V0('m3'), P=c.P0('bar'), n=1.): """Calculates the temperature of an ideal 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 """ return P * V / c.R('m3 bar/mol/K') / n
def get_n(self, V=c.V0('m3'), P=c.P0('bar'), T=c.T0('K')): """Calculates the moles of an ideal gas Parameters ---------- V : float, optional Volume in m3. Default is standard volume P : float, optional Pressure in bar. Default is standard pressure T : float, optional Temperature in K. Default is standard temperature Returns ------- n : float Number of moles in mol """ return P * V / c.R('m3 bar/mol/K') / T
def get_V(self, T=c.T0('K'), P=c.P0('bar'), n=1.): """Calculates the volume of an ideal gas Parameters ---------- T : float, optional Temperature in K. Default is standard temperature P : float, optional Pressure in bar. Default is standard pressure n : float, optional Number of moles (in mol). Default is 1 mol Returns ------- V : float Volume in m3 """ return n * c.R('m3 bar/mol/K') * T / P
def get_P(self, T=c.T0('K'), V=c.V0('m3'), n=1.): """Calculates the pressure of an ideal 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 """ return n * c.R('m3 bar/mol/K') * T / V
def get_EoRT(self, T=c.T0('K'), include_ZPE=False, raise_error=True, raise_warning=True, **kwargs): """Dimensionless electronic energy Parameters ---------- T : float, optional Temperature in K. If the electronic mode is :class:`~pMuTT.statmech.elec.IdealElec`, then the output is insensitive to this input. Default is 298.15 K include_ZPE : bool, optional If True, includes the zero point energy. Default is False 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 Parameters passed to electronic mode Returns ------- EoRT : float Dimensionless electronic energy """ kwargs['T'] = T EoRT = _get_mode_quantity(mode=self.elec_model, method_name='get_UoRT', raise_error=raise_error, raise_warning=raise_warning, default_value=0., **kwargs) if include_ZPE: EoRT += _get_mode_quantity(mode=self.vib_model, method_name='get_ZPE', raise_error=raise_error, raise_warning=raise_warning, default_value=0., **kwargs) / c.R('eV/K') / T return EoRT
def get_UoRT(self, x=0., T=c.T0('K')): """Calculates the excess internal energy Parameters ---------- x : float, optional Coverage (in ML) of species j. Default is 0 T : float, optional Temperature in K. Default is 298.15 K Returns ------- UoRT : float Dimensionless internal energy """ i = np.argmax(x < np.array(self.intervals)) - 1 UoRT = (self.slopes[i] * x + self._intercepts[i]) / (c.R('kcal/mol/K') * T) return UoRT
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')
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')
def get_shomate_CpoR(a, T): """Calculates the dimensionless heat capacity using Shomate polynomial form Parameters ---------- a : (8,) `numpy.ndarray`_ Coefficients of Shomate polynomial T : iterable Temperature in K Returns ------- CpoR: float Dimensionless heat capacity .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.ndarray.html """ t = T / 1000. t_arr = np.array([[1., x, x**2, x**3, 1. / x**2, 0., 0., 0.] for x in t]) return np.dot(t_arr, a) / c.R('J/mol/K')
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)
def _fit_SoR(T_ref, SoR_ref, a): """Fit a[6] coefficient in a_low and a_high attributes given the dimensionless entropy Parameters ---------- T_ref : float Reference temperature in K SoR_ref : float Reference dimensionless entropy Returns ------- a : (8,) `numpy.ndarray`_ Lower coefficients of Shomate polynomial .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.ndarray.html """ a[6] = (SoR_ref - get_shomate_SoR(T=np.array([T_ref]), a=a)) * c.R('J/mol/K') return a
def get_shomate_HoRT(a, T): """Calculates the dimensionless enthalpy using Shomate polynomial form Parameters ---------- a : (8,) `numpy.ndarray`_ Coefficients of Shomate polynomial T : iterable Temperature in K Returns ------- HoRT : float Dimensionless enthalpy .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.ndarray.html """ t = T / 1000. t_arr = np.array( [[x, x**2 / 2., x**3 / 3., x**4 / 4., -1. / x, 1., 0., 0.] for x in t]) HoRT = np.dot(t_arr, a) / (c.R('kJ/mol/K') * T) return HoRT
def get_G(self, units, T=c.T0('K'), verbose=False, raise_error=True, raise_warning=True, **kwargs): """Calculate the Gibbs energy Parameters ---------- verbose : bool, optional If False, returns the Gibbs energy. If True, returns contribution of each mode. units : str Units as string. See :func:`~pMuTT.constants.R` for accepted units but omit the '/K' (e.g. J/mol). T : float, optional Temperature in K. Default is 298.15 K 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 Parameters passed to each mode Returns ------- G : float or (N+5,) `numpy.ndarray`_ Gibbs energy. N represents the number of mixing models. If verbose is True, contribution to each mode are as follows: [trans, vib, rot, elec, nucl, mixing_models (if any)] .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.ndarray.html """ return self.get_GoRT(verbose=verbose, raise_error=raise_error, raise_warning=raise_warning, T=T, **kwargs) \ * T*c.R('{}/K'.format(units))
def get_E(self, units, T=c.T0('K'), raise_error=True, raise_warning=True, include_ZPE=False, **kwargs): """Calculate the electronic energy Parameters ---------- units : str Units as string. See :func:`~pMuTT.constants.R` for accepted units but omit the '/K' (e.g. J/mol). T : float, optional Temperature in K. If the electronic mode is :class:`~pMuTT.statmech.elec.IdealElec`, then the output is insensitive to this input. Default is 298.15 K include_ZPE : bool, optional If True, includes the zero point energy. Default is False 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 Parameters passed to each mode Returns ------- E : float Electronic energy """ return self.get_EoRT(T=T, raise_error=raise_error, raise_warning=raise_warning, include_ZPE=include_ZPE, **kwargs) \ * T*c.R('{}/K'.format(units))
def get_S(self, units, verbose=False, raise_error=True, raise_warning=True, **kwargs): """Calculate the entropy Parameters ---------- units : str Units as string. See :func:`~pMuTT.constants.R` for accepted units. verbose : bool, optional If False, returns the entropy. If True, returns contribution of each mode. 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 Parameters passed to each mode Returns ------- S : float or (N+5,) `numpy.ndarray`_ Entropy. N represents the number of mixing models. If verbose is True, contribution to each mode are as follows: [trans, vib, rot, elec, nucl, mixing_models (if any)] .. _`numpy.ndarray`: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.ndarray.html """ return self.get_SoR(verbose=verbose, raise_error=raise_error, raise_warning=raise_warning, **kwargs) * c.R(units)
def get_GoRT_1D(self, x_name, x_values, G_units=None, **kwargs): """Calculates the Gibbs free energy for all the reactions for 1 varying parameter Parameters ---------- x_name : str Name of variable to vary x_values : iterable object x 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) `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,) `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(x_values))) for i, (reaction, norm_factor) in enumerate(zip(self.reactions, self.norm_factors)): for j, x in enumerate(x_values): kwargs[x_name] = x GoRT[i, j] = reaction.get_delta_GoRT(**kwargs)/norm_factor # Add unit corrections if G_units is not None: GoRT[i, j] *= c.R('{}/K'.format(G_units))*kwargs['T'] stable_phases = np.nanargmin(GoRT, axis=1) return (GoRT, stable_phases)
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'))