def test_get_delta_AoRT(self): exp_sm_AoRT = self.H2O_sm.get_AoRT(T=c.T0('K')) \ - self.H2_sm.get_AoRT(T=c.T0('K')) \ - self.O2_sm.get_AoRT(T=c.T0('K'))*0.5 self.assertAlmostEqual(self.rxn_sm.get_delta_AoRT(T=c.T0('K')), exp_sm_AoRT) self.assertAlmostEqual( self.rxn_sm.get_delta_AoRT(T=c.T0('K'), rev=True), -exp_sm_AoRT)
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 setUp(self): unittest.TestCase.setUp(self) H2_thermo = BaseThermo(name='H2', phase='G', elements={'H': 2}, thermo_model=IdealGasThermo, T_ref=c.T0('K'), HoRT_ref=0., vib_energies=np.array([4306.1793]) * c.c('cm/s') * c.h('eV s'), potentialenergy=-6.7598, geometry='linear', symmetrynumber=2, spin=0, atoms=molecule('H2')) H2O_thermo = BaseThermo( name='H2O', phase='G', elements={ 'H': 2, 'O': 1 }, thermo_model=IdealGasThermo, T_ref=c.T0('K'), HoRT_ref=-241.826 / (c.R('kJ/mol/K') * c.T0('K')), vib_energies=np.array([3825.434, 3710.264, 1582.432]) * c.c('cm/s') * c.h('eV s'), potentialenergy=-14.2209, geometry='nonlinear', symmetrynumber=2, spin=0, atoms=molecule('H2O')) O2_thermo = BaseThermo(name='H2O', phase='G', elements={'O': 2}, thermo_model=IdealGasThermo, T_ref=c.T0('K'), HoRT_ref=0., vib_energies=np.array([2205.]) * c.c('cm/s') * c.h('eV s'), potentialenergy=-9.86, geometry='linear', symmetrynumber=2, spin=1, atoms=molecule('O2')) self.references = References( references=[H2_thermo, H2O_thermo, O2_thermo])
def test_get_delta_SoR(self): exp_nasa_SoR = self.H2O_nasa.get_SoR(T=c.T0('K')) \ - self.H2_nasa.get_SoR(T=c.T0('K')) \ - self.O2_nasa.get_SoR(T=c.T0('K'))*0.5 exp_sm_SoR = self.H2O_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 self.assertAlmostEqual(self.rxn_nasa.get_delta_SoR(T=c.T0('K')), exp_nasa_SoR) self.assertAlmostEqual( self.rxn_nasa.get_delta_SoR(T=c.T0('K'), rev=True), -exp_nasa_SoR) self.assertAlmostEqual(self.rxn_sm.get_delta_SoR(T=c.T0('K')), exp_sm_SoR) self.assertAlmostEqual( self.rxn_sm.get_delta_SoR(T=c.T0('K'), rev=True), -exp_sm_SoR)
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 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_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 test_get_CpoR_act(self): exp_sm_CpoR = self.H2O_TS_sm.get_CpoR(T=c.T0('K')) \ - self.H2_sm.get_CpoR(T=c.T0('K')) \ - self.O2_sm.get_CpoR(T=c.T0('K'))*0.5 exp_sm_CpoR_rev = self.H2O_TS_sm.get_CpoR(T=c.T0('K')) \ - self.H2O_sm.get_CpoR(T=c.T0('K')) self.assertAlmostEqual(self.rxn_sm.get_CpoR_act(T=c.T0('K')), exp_sm_CpoR) self.assertAlmostEqual(self.rxn_sm.get_CpoR_act(T=c.T0('K'), rev=True), exp_sm_CpoR_rev)
def test_get_GoRT_act(self): exp_sm_GoRT = self.H2O_TS_sm.get_GoRT(T=c.T0('K')) \ - self.H2_sm.get_GoRT(T=c.T0('K')) \ - self.O2_sm.get_GoRT(T=c.T0('K'))*0.5 exp_sm_GoRT_rev = self.H2O_TS_sm.get_GoRT(T=c.T0('K')) \ - self.H2O_sm.get_GoRT(T=c.T0('K')) self.assertAlmostEqual(self.rxn_sm.get_GoRT_act(T=c.T0('K')), exp_sm_GoRT) self.assertAlmostEqual(self.rxn_sm.get_GoRT_act(T=c.T0('K'), rev=True), exp_sm_GoRT_rev)
def __init__(self, T_low, T_mid, T_high, T_ref=c.T0('K'), HoRT_ref=None, SoR_ref=None, **kwargs): super().__init__(T_ref=T_ref, HoRT_ref=HoRT_ref, **kwargs) self.T_low = T_low self.T_high = T_high self.T_mid = T_mid self.fit(HoRT_dft=HoRT_ref, SoR_ref=SoR_ref)
def get_n(self, V=c.V0('m3'), P=c.P0('bar'), T=c.T0('K')): """Calculates the volume 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_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_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 setUp(self): unittest.TestCase.setUp(self) # Testing Ideal Gas Model CO2 = molecule('CO2') CO2_PyMuTT_parameters = { '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_PyMuTT_parameters['vib_wavenumbers']], 'geometry':'linear', 'symmetrynumber': 2, 'spin': 0. } self.CO2_PyMuTT = StatMech(**CO2_PyMuTT_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_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 __init__(self, T_low=None, T_mid=None, T_high=None, a_low=np.zeros(7), a_high=np.zeros(7), Ts=None, CpoR=None, T_ref=c.T0('K'), HoRT_ref=None, SoR_ref=None, **kwargs): super().__init__(T_ref=T_ref, HoRT_ref=HoRT_ref, **kwargs) self.a_low = a_low self.a_high = a_high if T_low is not None: self.T_low = T_low else: try: self.T_low = np.min(Ts) except NameError: pass if T_high is not None: self.T_high = T_high else: try: self.T_high = np.max(Ts) except NameError: pass self.T_mid = T_mid if np.array_equal(a_low, np.zeros(7)) and np.array_equal( a_high, np.zeros(7)): self.fit(T_low=self.T_low, T_high=self.T_high, Ts=Ts, CpoR=CpoR, T_ref=T_ref, HoRT_dft=HoRT_ref, SoR_ref=SoR_ref)
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 volume 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 __init__(self, name, phase=None, elements=None, thermo_model=None, T_ref=c.T0('K'), HoRT_dft=None, HoRT_ref=None, references=None, notes=None, **kwargs): self.name = name self.phase = phase self.elements = elements self.T_ref = T_ref self.references = references self.notes = notes #Assign self.thermo_model if inspect.isclass(thermo_model): #If class is passed, the required arguments will be guessed. self.thermo_model = _pass_expected_arguments( thermo_model, **kwargs) else: self.thermo_model = thermo_model #Calculate dimensionless DFT energy using thermo model if (HoRT_dft is None) and (self.thermo_model is not None): self.HoRT_dft = self.thermo_model.get_HoRT(Ts=self.T_ref) else: self.HoRT_dft = HoRT_dft if HoRT_ref is None: #Assign self.HoRT_ref if (references is None) or (self.HoRT_dft is None): self.HoRT_ref = self.HoRT_dft else: self.HoRT_ref = self.HoRT_dft + references.get_HoRT_offset( elements=elements, Ts=self.T_ref) else: self.HoRT_ref = HoRT_ref
''' #Import from excel refs_input = read_excel(io=refs_path) refs = References([BaseThermo(**ref_input) for ref_input in refs_input]) print('Reference Input:') pprint(refs_input) ''' Processing Input Species ''' #Import from excel species_data = read_excel(io=species_path) species = [ Nasa(references=refs, T_low=T_low, T_high=T_high, T_ref=c.T0('K'), **specie_data) for specie_data in species_data ] print('Species Input:') pprint(species) ''' Printing Out Results ''' write_thermdat(nasa_species=species, filename=thermdat_path, write_date=write_date) if show_plot: for specie in species: specie.plot_thermo_model_and_empirical(Cp_units='J/mol/K', H_units='kJ/mol', S_units='J/mol/K',
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 : `PyMuTT.models.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 : `PyMuTT.models.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 ``BaseThermo`` 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 try: iter(T_mid) except TypeError: 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: HoRT_ref += references.get_HoRT_offset(elements=elements, 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)
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 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 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])
def test_T0(self): self.assertEqual(c.T0('K'), 298.15) with self.assertRaises(KeyError): c.T0('arbitrary unit')