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
def from_statmech(cls, name, statmech_model, T_low, T_high, references=None, elements=None, **kwargs): """Calculates the Shomate polynomial using statistical mechanic models Parameters ---------- name : str Name of the species statmech_model : `pMuTT.statmech.StatMech` object or class Statistical Mechanics model to generate data T_low : float Lower limit temerature in K T_high : float Higher limit temperature in K references : `pMuTT.empirical.references.References` object Reference to adjust enthalpy **kwargs : keyword arguments Used to initalize ``statmech_model`` or ``EmpiricalBase`` attributes to be stored. Returns ------- shomate : Shomate object Shomate object with polynomial terms fitted to data. """ # Initialize the StatMech object if inspect.isclass(statmech_model): statmech_model = statmech_model(**kwargs) # Generate data T = np.linspace(T_low, T_high) CpoR = np.array([statmech_model.get_CpoR(T=T_i) for T_i in T]) T_ref = c.T0('K') HoRT_ref = statmech_model.get_HoRT(T=T_ref) # Add contribution of references if references is not None: descriptor_name = references.descriptor if descriptor_name == 'elements': descriptors = elements else: descriptors = kwargs[descriptor_name] HoRT_ref += references.get_HoRT_offset(descriptors=descriptors, T=T_ref) SoR_ref = statmech_model.get_SoR(T=T_ref) return cls.from_data(name=name, T=T, CpoR=CpoR, T_ref=T_ref, HoRT_ref=HoRT_ref, SoR_ref=SoR_ref, statmech_model=statmech_model, elements=elements, references=references, **kwargs)
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 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 get_GoRT(self, x=0., T=c.T0('K')): """Calculates the excess Gibbs 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 ------- GoRT : float Dimensionless excess Gibbs energy """ return self.get_HoRT(x=x, T=T) - self.get_SoR()
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 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_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_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_V(self, T=c.T0('K'), P=c.P0('bar'), n=1., gas_phase=True): """Calculates the 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 n : float, optional Number of moles (in mol). Default is 1 mol 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 ------- V : float Volume in m3 """ return self.get_Vm(T=T, P=P, gas_phase=gas_phase) * n
def get_n(self, V=c.V0('m3'), P=c.P0('bar'), T=c.T0('K'), gas_phase=True): """Calculates the moles 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 T : float, optional Temperature in K. Default is standard temperature gas_phase : bool, optional Relevant if system is in vapor-liquid equilibrium. If True, return the smaller moles (gas phase). If False, returns the larger moles (liquid phase). Returns ------- n : float Number of moles in mol """ return V / self.get_Vm(T=T, P=P, gas_phase=gas_phase)
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 setUp(self): unittest.TestCase.setUp(self) # Testing Ideal Gas Model CO2 = molecule('CO2') CO2_pMuTT_parameters = { 'name': 'CO2', 'trans_model': trans.IdealTrans, 'n_degrees': 3, 'molecular_weight': get_molecular_weight('CO2'), 'rot_model': rot.RigidRotor, 'rot_temperatures': rot.get_rot_temperatures_from_atoms(CO2, geometry='linear'), 'geometry': 'linear', 'symmetrynumber': 2, 'elec_model': elec.IdealElec, 'potentialenergy': -22.994202, 'spin': 0., 'vib_model': vib.HarmonicVib, 'vib_wavenumbers': [3360., 954., 954., 1890.], } CO2_ase_parameters = { 'atoms': CO2, 'potentialenergy': -22.994202, 'vib_energies': [c.wavenumber_to_energy(x) for x in CO2_pMuTT_parameters['vib_wavenumbers']], 'geometry': 'linear', 'symmetrynumber': 2, 'spin': 0. } self.CO2_pMuTT = StatMech(**CO2_pMuTT_parameters) self.CO2_ASE = IdealGasThermo(**CO2_ase_parameters) self.T0 = c.T0('K') # K self.P0 = c.P0('Pa') self.V0 = c.V0('m3')
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 test_get_P(self): self.assertAlmostEqual( self.ideal_gas.get_P(T=c.T0('K'), V=c.V0('m3'), n=1.), c.P0('bar'))
def test_get_n(self): self.assertAlmostEqual( self.ideal_gas.get_n(T=c.T0('K'), V=c.V0('m3'), P=c.P0('bar')), 1.)
def setUp(self): unittest.TestCase.setUp(self) H2_thermo = Reference(name='H2', phase='G', elements={'H': 2}, T_ref=c.T0('K'), HoRT_ref=0., statmech_model=StatMech, trans_model=trans.IdealTrans, n_degrees=3, vib_model=vib.HarmonicVib, elec_model=elec.IdealElec, rot_model=rot.RigidRotor, vib_wavenumbers=np.array([4306.1793]), potentialenergy=-6.7598, geometry='linear', symmetrynumber=2, spin=0, atoms=molecule('H2')) H2O_thermo = Reference( name='H2O', phase='G', elements={ 'H': 2, 'O': 1 }, T_ref=c.T0('K'), HoRT_ref=-241.826 / (c.R('kJ/mol/K') * c.T0('K')), statmech_model=StatMech, trans_model=trans.IdealTrans, n_degrees=3, vib_model=vib.HarmonicVib, elec_model=elec.IdealElec, rot_model=rot.RigidRotor, vib_wavenumbers=np.array([3825.434, 3710.264, 1582.432]), potentialenergy=-14.2209, geometry='nonlinear', symmetrynumber=2, spin=0, atoms=molecule('H2O')) O2_thermo = Reference(name='H2O', phase='G', elements={'O': 2}, T_ref=c.T0('K'), HoRT_ref=0., statmech_model=StatMech, trans_model=trans.IdealTrans, n_degrees=3, vib_model=vib.HarmonicVib, elec_model=elec.IdealElec, rot_model=rot.RigidRotor, vib_wavenumbers=np.array([2205.]), potentialenergy=-9.86, geometry='linear', symmetrynumber=2, spin=1, atoms=molecule('O2')) self.references = References( references=[H2_thermo, H2O_thermo, O2_thermo])
import matplotlib.pyplot as plt from pMuTT import constants as c from pMuTT.empirical.nasa import Nasa # 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 T = 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.from_data(name='CH3OH', T=T, CpoR=CpoR, T_ref=T_ref,
def write_surf(nasa_species, sden_operation='min', filename='surf.inp', T=c.T0('K'), reactions=[], species_delimiter='+', reaction_delimiter='=', act_method_name='get_E_act', act_unit='kcal/mol', float_format=' .3E', stoich_format='.0f', newline='\n', column_delimiter=' ', use_mw_correction=True, **kwargs): """Writes the surf.inp Chemkin file Parameters ---------- nasa_species : list of :class:`~pMuTT.empirical.nasa.Nasa` objects Surface used in Chemkin mechanism. If gas-phase species are present, they will be ignored filename : str, optional Filename for surf.inp file. Default is 'surf.inp' T : float, optional Temperature to calculate activation energy. Default is 298.15 K reactions : list of :class:`~pMuTT.reaction.ChemkinReaction` objects Chemkin reactions to write in surf.inp file. Purely gas-phase reactions will be ignored species_delimiter : str, optional Delimiter to separate species when writing reactions. Default is '+' reaction_delimiter : str, optional Delimiter to separate reaction sides. Default is '=' act_method_name : str, optional Name of method to use to calculate activation function act_unit : str, optional Units to calculate activation energy. Default is 'kcal/mol' float_format : str, optional String format to print floating numbers. Default is ' .3E' (i.e. scientific notation rounded to 3 decimal places with a leading space for positive numbers) stoich_format : str, optional String format to print stoichiometric coefficients. Default is '.0f' (i.e. integers) newline : str, optional Newline character. Default is the Linux newline character column_delimiter : str, optional Delimiter to separate columns. Default is ' ' use_mw_correction : bool, optional If True, uses the Motz-Wise corrections. Default is True kwargs : keyword arguments Parameters needed to calculate activation energy and preexponential factor """ # Organize species by their catalyst sites cat_adsorbates = {} unique_cat_sites = [] for specie in nasa_species: # Skip gas phase species if specie.phase.upper() == 'G': continue # Skip the bulk species if specie.cat_site.bulk_specie == specie.name: continue cat_name = specie.cat_site.name try: cat_adsorbates[cat_name].append(specie) except KeyError: cat_adsorbates[cat_name] = [specie] unique_cat_sites.append(specie.cat_site) cat_site_lines = [] for cat_site in unique_cat_sites: # Add catalyst site header cat_site_name = '{}/'.format(cat_site.name) cat_site_lines.append('SITE/{:<14}SDEN/{:.5E}/'.format( cat_site_name, cat_site.site_density)) cat_site_lines.append('') # Add species adsorbed on that site for specie in cat_adsorbates[cat_site.name]: cat_site_lines.append('{}{}/{}/'.format(column_delimiter, specie.name, specie.n_sites)) cat_site_lines.append('') # Write bulk species for cat_site in unique_cat_sites: # Add bulk line cat_site_lines.append('BULK {}/{:.1f}/'.format(cat_site.bulk_specie, cat_site.density)) # Get surface reaction lines surf_reactions = \ [reaction for reaction in reactions if not reaction.gas_phase] reaction_lines = _write_reaction_lines( reactions=surf_reactions, species_delimiter=species_delimiter, reaction_delimiter=reaction_delimiter, include_TS=False, stoich_format=stoich_format, act_method_name=act_method_name, act_unit=act_unit, float_format=float_format, column_delimiter=column_delimiter, T=T, sden_operation=sden_operation, **kwargs) # Preparing reaction line header mw_field = '{:<5}' if use_mw_correction: mw_str = mw_field.format('MWON') else: mw_str = mw_field.format('MWOFF') if 'oRT' in act_method_name: act_unit_str = '' else: act_unit_str = act_unit.upper() lines = [ _get_filestamp(), '!Surface species', '!Each catalyst site has the following format:', '!SITE/[Site name]/ SDEN/[Site density in mol/cm2]/', '![Adsorbate Name]/[# of Sites occupied]/ (for every adsorbate)', '!BULK [Bulk name]/[Bulk density in g/cm3]', ] lines.extend(cat_site_lines) lines.extend([ 'END', '', '!Gas-phase reactions.', '!The reaction line has the following format:', '!REACTIONS MW[ON/OFF] [Ea units]', '!where MW stands for Motz-Wise corrections and if the Ea', ('!units are left blank, then the activation energy should ' 'be dimensionless (i.e. E/RT)'), '!The rate constant expression is:', '!k = kb/h/site_den^(n-1) * (T)^beta * exp(-Ea/RT)', ('!where site_den is the site density and is the number ' 'of surface species (including empty sites)'), '!Each line has 4 columns:', '!- Reaction reactants and products separated by =', '!- Preexponential factor, kb/h/site_den^(n-1), or ', '! sticking coefficient if adsorption reaction', '!- Beta (power to raise T in rate constant expression)', ('!- Ea (Activation Energy or Gibbs energy of activation in ' 'specified units'), ('!Adsorption reactions can be represented using the STICK ' 'keyword'), 'REACTIONS{2}{0}{2}{1}'.format(mw_str, act_unit_str, column_delimiter) ]) lines.extend(reaction_lines) lines.append('END') # Write the file with open(filename, 'w', newline=newline) as f_ptr: f_ptr.write('\n'.join(lines))
def write_gas(nasa_species, filename='gas.inp', T=c.T0('K'), reactions=[], species_delimiter='+', reaction_delimiter='=', act_method_name='get_E_act', act_unit='kcal/mol', float_format=' .3E', stoich_format='.0f', newline='\n', column_delimiter=' ', **kwargs): """Writes the gas.inp Chemkin file. Parameters ---------- nasa_species : list of :class:`~pMuTT.empirical.nasa.Nasa` objects Surface and gas species used in Chemkin mechanism. Used to write elements section filename : str, optional File name for gas.inp file. Default is 'gas.inp' reactions : :class:`~pMuTT.reaction.Reactions` object, optional Reactions in mechanism. Reactions with only gas-phase species will be written to this file """ # Get unique elements and gas-phase species unique_elements = set() gas_species = [] for specie in nasa_species: for element in specie.elements.keys(): unique_elements.add(element) if specie.phase.upper() == 'G': gas_species.append(specie.name) unique_elements = list(unique_elements) # Get gas-phase reactions gas_reactions = [reaction for reaction in reactions if reaction.gas_phase] reaction_lines = _write_reaction_lines( reactions=gas_reactions, species_delimiter=species_delimiter, reaction_delimiter=reaction_delimiter, include_TS=False, stoich_format=stoich_format, act_method_name=act_method_name, act_unit=act_unit, float_format=float_format, column_delimiter=column_delimiter, T=T, sden_operation=None, **kwargs) # Collect all the lines into a list lines = [ _get_filestamp(), '!Elements present in gas and surface species', 'ELEMENTS' ] lines.extend(unique_elements) lines.extend(['END', '', '!Gas-phase species', 'SPECIES']) lines.extend(gas_species) lines.extend([ 'END', '', '!Gas-phase reactions. The rate constant expression is:', '!k = kb/h * (T)^beta * exp(-Ea/RT)', '!Each line has 4 columns:', '!- Reaction reactants and products separated by <=>', '!- Preexponential factor, kb/h', '!- Beta (power to raise T in rate constant expression)', ('!- Ea (Activation Energy or Gibbs energy of activation in ' 'kcal/mol'), 'REACTIONS' ]) lines.extend(reaction_lines) lines.append('END') with open(filename, 'w', newline=newline) as f_ptr: f_ptr.write('\n'.join(lines))
def test_T0(self): self.assertEqual(c.T0('K'), 298.15) with self.assertRaises(KeyError): c.T0('arbitrary unit')
def from_statmech(cls, name, statmech_model, T_low, T_high, T_mid=None, references=None, elements=None, **kwargs): """Calculates the NASA polynomials using statistical mechanic models Parameters ---------- name : str Name of the species statmech_model : `pMuTT.statmech.StatMech` object or class Statistical Mechanics model to generate data T_low : float Lower limit temerature in K T_high : float Higher limit temperature in K T_mid : float or iterable of float, optional Guess for T_mid. If float, only uses that value for T_mid. If list, finds the best fit for each element in the list. If None, a range of T_mid values are screened between the 6th lowest and 6th highest value of T. references : `pMuTT.empirical.references.References` object Reference to adjust enthalpy elements : dict Composition of the species. Keys of dictionary are elements, values are stoichiometric values in a formula unit. e.g. CH3OH can be represented as: {'C': 1, 'H': 4, 'O': 1,}. kwargs : keyword arguments Used to initalize ``statmech_model`` or ``EmpiricalBase`` attributes to be stored. Returns ------- Nasa : Nasa object Nasa object with polynomial terms fitted to data. """ # Initialize the StatMech object if inspect.isclass(statmech_model): statmech_model = statmech_model(**kwargs) # Generate data T = np.linspace(T_low, T_high) if T_mid is not None: # Check to see if specified T_mid's are in T and, if not, # insert them into T. # If a single value for T_mid is chosen, convert to a tuple if not _is_iterable(T_mid): T_mid = (T_mid, ) for x in range(0, len(T_mid)): if np.where(T == T_mid[x])[0].size == 0: # Insert T_mid's into T and save position Ts_index = np.where(T > T_mid[x])[0][0] T = np.insert(T, Ts_index, T_mid[x]) CpoR = np.array([statmech_model.get_CpoR(T=T_i) for T_i in T]) T_ref = c.T0('K') HoRT_ref = statmech_model.get_HoRT(T=T_ref) # Add contribution of references if references is not None: descriptor_name = references.descriptor if descriptor_name == 'elements': descriptors = elements else: descriptors = kwargs[descriptor_name] HoRT_ref += references.get_HoRT_offset(descriptors=descriptors, T=T_ref) SoR_ref = statmech_model.get_SoR(T=T_ref) return cls.from_data(name=name, T=T, CpoR=CpoR, T_ref=T_ref, HoRT_ref=HoRT_ref, SoR_ref=SoR_ref, T_mid=T_mid, statmech_model=statmech_model, elements=elements, references=references, **kwargs)
from pMuTT.reaction import Reaction from pMuTT.reaction.bep import BEP from pMuTT.statmech import StatMech, presets from pMuTT import constants as c from pMuTT.io_.json import pMuTTEncoder, json_to_pMuTT import os import json os.chdir(os.path.dirname(__file__)) T = c.T0('K') # Factor to convert potential energy to dimensionless number dim_factor = c.R('eV/K') * T 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']), 'H2O_TS': StatMech(name='H2O', potentialenergy=5. * dim_factor, **presets['electronic']), }