Example #1
0
	def fit_shomate_species(cls, symbol, T, Cp, H0, S0, T_ref = c.T0('K'), elements = None):
		"""
		Derives the shomate species from fitting the heat capacity (J/mol/K) and temperature (K) data and including the formation of enthalpy (kJ/mol) and entropy (J/mol/K).

		Paramters
		---------
			symbol - str
				Name of shomate polynomial
			T - (N,) ndarray
				Temperatures (K)
			Cp - (N,) ndarray
				Heat capacities corresponding to T (J/mol/K)
			H0 - float
				Enthalpy at reference temperature (kJ/mol)
			S0 - float
				Entropy at reference temperature (J/mol/K)
			T_ref - float
				Reference temperature (K)
			elements - dict
				Stoichiometric make up of species. Keys should be elements.
				e.g. H2O = {'H': 2, 'O': 1}
		Returns
		-------
			shomate - Shomate object
		"""
		T_low = min(T)
		T_high = max(T)
		t = np.array(T)/1000.
		[a, pcov] = curve_fit(_shomate_Cp, t, np.array(Cp))
		a = np.append(a, [0., 0., 0.])
		a[5] = H0 - _get_HoRT(T = T_ref, a = a)*c.R('kJ/mol/K')*T_ref
		a[6] = S0 - _get_SoR(T = T_ref, a = a)*c.R('J/mol/K')
		a[7] = - _get_HoRT(T = c.T0('K'), a = a)*c.R('kJ/mol/K')*c.T0('K')
		return cls(symbol = symbol, T_low = T_low, T_high = T_high, a = np.array(a), elements = elements)
Example #2
0
    def get_reverse_rate_constant(self, T, thermos, use_BEP=False):
        """
		Calculates the reverse rate constant, k_rev
		Arguments
		---------
			T - float
				Temperature (K)
			thermos - dict-like object of thermodynamic objects (e.g. Shomates)
				Container that holds the thermodynamic objects. The container should use the
				species found in stoichiometry as keys and the objects should have the methods: get_HoRT() and get_SoRT()
			use_BEP - boolean
				Whether to use BEP relationship
		Returns
		-------
			k_rev - float
				Reverse rate constant
		"""

        #Get activation energy of reverse direction
        if use_BEP:
            EoRT = self.get_EoRT_from_BEP(
                T=T, thermos=thermos) - self.get_HoRT(T=T, thermos=thermos)
        else:
            EoRT = self.EoRT - self.get_HoRT(T=T, thermos=thermos)

        #Get preexponential factor of reverse direction
        if use_sticking_coefficient:
            A_fwd = self.get_A_from_sticking_coefficient(T=T)
        else:
            A_fwd = self.A
        A_rev = A_fwd * np.exp(self.get_SoR(T=T, thermos=thermos))

        return A_rev * (T / self.T_ref)**self.beta * np.exp(
            EoRT * c.T0('K') / T)
Example #3
0
    def get_forward_rate_constant(self, T, thermos=None, use_BEP=False):
        """
		Calculates the forward rate constant, k_fwd
		Arguments
		---------
			T - float
				Temperature (K)
			thermos - dict-like object of thermodynamic objects (e.g. Shomates)
				Container that holds the thermodynamic objects. The container should use the
				species found in stoichiometry as keys and the objects should have the method: get_HoRT()
			use_BEP - boolean
				Whether to use BEP relationship
		Returns
		-------
			k_fwd - float
				Forward rate constant
		"""
        if use_BEP:
            EoRT = self.get_EoRT_from_BEP(T=T, thermos=thermos)
        else:
            EoRT = self.EoRT

        if use_sticking_coefficient:
            A_fwd = self.get_A_from_sticking_coefficient(T=T)
        else:
            A_fwd = self.A

        return self.A * (T / self.T_ref)**self.beta * np.exp(
            EoRT * c.T0('K') / T)
Example #4
0
    def _fit_SoR(self, SoR0, T0=c.T0('K')):
        """
        Calculates the a7 parameter for the NASA polynomial.
        Parameters
        ----------
            SoR0 - float
                Dimensionless entropy at reference temperature
            T0 - float
                Reference temperature (K)
        """
        T_mid = self.T_mid
        a7_low = SoR0 - self._custom_SoR(T=T0, a=self.a_low)
        a7_high = SoR0 - self._custom_SoR(T=T0, a=self.a_high)
        #Correcting for offset
        S_low_last_T = self._custom_SoR(T_mid, self.a_low) + a7_low
        S_high_first_T = self._custom_SoR(T_mid, self.a_high) + a7_high
        S_offset = S_low_last_T - S_high_first_T

        self.a_low[6] = a7_low
        self.a_high[6] = a7_high + S_offset
Example #5
0
 def fit_NASA(self, T, CpoR, HoRT0, SoR0, T0=c.T0('K')):
     """
     Generate a NASA polynomial given dimensionless heat capacity as a function of temperature,
     dimensionless enthalpy of formation and dimensionless entropy of formation.
     Parameters
     ----------
         T - (N,) ndarray
             Temperatures (K) to fit the polynomial
         CpoR - (N,) ndarray
             Dimensionless heat capacities that correspond to T array
         HoRT0 - float
             Dimensionless enthalpy to be used as reference. Used to find a6. Value should correspond to T0
         SoR0 - float
             Dimensionless entropy to be used as reference. Used to find a7. Value should correspond to T0
         T0 - float
             Reference temperature used for fitting a6 and a7.
     """
     self.fit_CpoR(T=T, CpoR=CpoR)
     self._fit_HoRT(HoRT0=HoRT0, T0=T0)
     self._fit_SoR(SoR0=SoR0, T0=T0)
Example #6
0
    def _fit_HoRT(self, HoRT0, T0=c.T0('K')):
        """
        Calculates the a6 parameter for the NASA polynomial.
        Parameters
        ----------
            HoRT0 - float
                Dimensionless enthalpy at reference temperature
            T0 - float
                Reference temperature (K)
        """
        T_mid = self.T_mid
        a6_low = (HoRT0 - self._custom_HoRT(T0, self.a_low)) * T0
        a6_high = (HoRT0 - self._custom_HoRT(T0, self.a_high)) * T0

        #Correcting for offset
        H_low_last_T = self._custom_HoRT(T_mid, self.a_low) + a6_low / T_mid
        H_high_first_T = self._custom_HoRT(T_mid,
                                           self.a_high) + a6_high / T_mid
        H_offset = H_low_last_T - H_high_first_T

        self.a_low[5] = a6_low
        self.a_high[5] = T_mid * (a6_high / T_mid + H_offset)
Example #7
0
def read_ref(path, freq_cut_off=0., verbose=True, warn=True):
    """
    Read the reference file to adjust DFT energies to real energies

    Parameters
    ----------
        path - string
            Path to the .csv file that will be read
        freq_cut_off - float
            Frequency cut off. If frequencies inputted are less than this value, they are ignored
            since they are assumed to be frustrated rotational modes
        verbose - boolean
            Whether or not more detailed information should be printed
        warn - boolean
            Whether or not warnings should be printed
    Returns
    -------
        energies_fund - (N,) ndarray
            Fundamental energies of the reference species. Used as a correction factor
        fund_species_CHON - (N, 4) ndarray
            Number of carbon, hydrogen, oxygen and nitrogen in the fundamental species.
        rm_list - list
            Indices to be removed from the fund_species_CHON since the element is not
            present in any of the reference species
    """

    #Read the reference files
    species_ref = read_freq(path,
                            freq_cut_off=freq_cut_off,
                            verbose=verbose,
                            warn=warn)

    #Prepare the fundamental species
    e_list = ['C', 'H', 'O', 'N']
    rm_list = []
    fund_species_CHON = np.array([[1, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0],
                                  [0, 0, 0, 2]])

    n_s = len(species_ref)
    H0_dft = np.array([0.] * n_s)
    H0_exp = np.array([0.] * n_s)
    species_CHON = np.array([[0] * 4] * n_s)
    e_sum_list = np.array([0.] * 4)

    for i, species in enumerate(species_ref):
        #Calculate properties at T0
        H0_dft[i] = species.IdealGasThermo.get_enthalpy(c.T0('K'),
                                                        verbose=False)
        H0_exp[i] = species.H0 * c.convert_unit(
            from_='kJ/mol', to='eV/molecule')  #species.H0 from literature

        #Sets up the CHON matrix
        species_CHON[i, :] = species.CHON
        e_sum_list += species.CHON  #Used to determine if elements are not needed. e.g. O, N not needed for hydrocarbons

    #Cleans up the CHON matrix if necessary
    for i, (element,
            e_sum) in reversed(list(enumerate(zip(e_list, e_sum_list)))):
        if e_sum == 0:
            if verbose:
                print(('Element %s not needed' % element))
            species_CHON = np.delete(species_CHON, i, 1)
            fund_species_CHON = np.delete(fund_species_CHON, i, 0)
            fund_species_CHON = np.delete(fund_species_CHON, i, 1)
            rm_list.append(i)
    n_e = len(fund_species_CHON)
    if n_e != n_s and verbose:
        print((
            "Warning: Mismatch between number of elements (%d) and number of reference species."
            % (n_e, n_s)))

    #Finds the fundamental energy
    H0_fund = np.array(
        [0.] * n_e)  #Formation enthalpy for fundamental species. Usually 0
    ref_species_from_fund = np.dot(
        species_CHON, np.linalg.inv(fund_species_CHON)
    )  #Matrix to go from fundamental species --> reference species
    H0_rxn = H0_exp - np.dot(ref_species_from_fund,
                             H0_fund)  #Since H0_fund = 0, this is H0_exp
    energies_fund = np.linalg.solve(
        ref_species_from_fund,
        (H0_dft -
         H0_rxn))  #Energy of fundamental species. Used as correction factor
    return (energies_fund, fund_species_CHON, rm_list)
Example #8
0
def dft_to_thermdat(input_path,
                    ref_path='thermdat_ref.csv',
                    T_low=300.,
                    T_high=800.,
                    write_files=True,
                    out_path='thermdat',
                    verbose=False,
                    warn=False,
                    freq_cut_off=0.,
                    pressure=1.,
                    add_gas_species=True,
                    gas_path='thermdat_gas'):
    """
    Convert DFT energies and frequencies to NASA polynomials that can be written as a thermdat file
    Attributes
    ----------
        input_path - string
            Path to .csv file that contains the DFT information of all species to be written in thermdat
        ref_path - string
            Path to .csv file that contains the gas-phase reference information
        T_low - float
            Lower temperature bound for the NASA polynomials
        T_high - float
            Higher temperature bound for the NASA polynomials
        write_files - boolean
            Whether or not the thermdat file should be written
        out_path - string
            Path where the thermdat file will be written
        verbose - boolean
            Whether or not more detailed output should be given
        warn - boolean
            Whether or not warnings should be given
        freq_cut_off - float
            Cut off frequency. If vibrational frequencies (in 1/cm) are below this value, they are ignored
            since they are assumed to be frustrated rotational or translational modes
        pressure - float
            Pressure (in atmospheres) to generate the NASA polynomials. Usually this value is left at 1 atm
        add_gas_species - boolean
            Whether or not gas-phase species from gas_path should be written to the thermdat file
        gas_path - string
            Path to thermdat file that contains the gas-phase species to add
    Returns
    -------
        thermdat - Thermdat object
            The successfully converted thermdat object
    """
    T_range = np.linspace(T_low, T_high, T_high - T_low)
    n_T = len(T_range)

    print("Opening reference file: %s" % ref_path)
    (fund_energies, fund_CHON, rm_list) = read_ref(ref_path,
                                                   verbose=verbose,
                                                   warn=warn)
    print('Fundamental energies:')
    print(fund_energies)
    print('Fund CHON')
    print(fund_CHON)

    #Read the species to be processed
    print("Opening input file: %s" % input_path)
    thermdats_dft = read_freq(input_path,
                              verbose=verbose,
                              freq_cut_off=freq_cut_off,
                              warn=warn)

    for i, thermdat_dft in enumerate(thermdats_dft):
        print("-" * 10)
        print("Processing %s..." % thermdat_dft.symbol)
        thermdat_dft.nasa = Nasa(symbol=thermdat_dft.symbol,
                                 T_low=min(T_range),
                                 T_high=max(T_range))

        print("Calculating heat capacities.")
        CpoR = thermdat_dft.get_CpoR(T_range)

        print("Calculating DFT enthalpy of formation")
        if thermdat_dft.is_gas:
            H0 = thermdat_dft.IdealGasThermo.get_enthalpy(
                temperature=c.T0('K'), verbose=verbose)
            thermo_parameters = thermdat_dft.IdealGasThermo.__dict__
        else:
            thermo_parameters = thermdat_dft.HarmonicThermo.__dict__
            if np.sum(thermdat_dft.HarmonicThermo.vib_energies) == 0:
                H0 = thermdat_dft.HarmonicThermo.potentialenergy
            else:
                H0 = thermdat_dft.HarmonicThermo.get_internal_energy(
                    temperature=c.T0('K'), verbose=verbose)
        print("Adjusting enthalpy to reference")
        CHON = np.delete(thermdat_dft.CHON, rm_list)
        TransformCHON = np.dot(CHON, np.linalg.inv(fund_CHON))
        HoRT0 = (H0 - np.dot(TransformCHON, fund_energies)) / (c.T0('K') *
                                                               c.kb('eV/K'))

        print("Calculating DFT enthalpy of formation")
        if thermdat_dft.is_gas:
            S0 = thermdat_dft.IdealGasThermo.get_entropy(
                temperature=c.T0('K'),
                pressure=pressure * c.convert_unit(from_='atm', to='Pa'),
                verbose=verbose)
        else:
            if np.sum(thermdat_dft.HarmonicThermo.vib_energies) == 0:
                S0 = 0.
            else:
                S0 = thermdat_dft.HarmonicThermo.get_entropy(
                    temperature=c.T0('K'), verbose=verbose)
        SoR0 = S0 / c.kb('eV/K')
        print('Species: {}'.format(thermdat_dft.symbol))
        print('thermo parameters: {}'.format(thermo_parameters))
        print('HoRT0 = {}'.format(HoRT0))
        print('S/R0 = {}'.format(SoR0))
        print('#')
        print("Calculating NASA polynomials")
        thermdat_dft.nasa.fit_NASA(T_range, CpoR, HoRT0, SoR0)

    #Add gas-phase species
    if add_gas_species:
        print("Opening gas phase file: {}".format(gas_path))
        thermdats_gas = Thermdats.from_thermdat(thermdat_path=gas_path,
                                                verbose=verbose,
                                                warn=warn)
        print("Attaching gas species")
        thermdats_dft.extend(thermdats_gas)

    if write_files:
        print("Writing to thermdat")
        thermdats_dft.write_thermdat(out_path, verbose=False)

    return thermdats_dft
Example #9
0
 def test_T0(self):
     self.assertEqual(c.T0('K'), 298.15)