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)
def read_fund_csv(symbol, csv_path, print_graph = False): """ Reads a csv file for data that will be fed into function fit_shomate_species. Parameters ---------- symbol - str Name of the shomate polynomial csv_path - str Path to the csv file containing the values print_graph - bool Whether or not to show the thermodynamic quantities at the range of temperatures Returns shomate - Shomate object """ H0_S0_read = False T = [] Cp = [] print(("Reading from file: %s" % csv_path)) with open(csv_path, 'r') as csv_file: for line in csv_file: if line[0] != '!': #Split data and remove unnecessary characters data = line.split(',') T.append(float(data[0])) Cp.append(float(data[1])) if len(data) > 2 and not H0_S0_read: H0 = float(data[2]) S0 = float(data[3]) H0_S0_read = True shomate = Shomate.fit_shomate_species(symbol, T, Cp, H0, S0) if print_graph: T_range = np.linspace(shomate.T_low, shomate.T_high) Cp_fit = shomate.get_CpoR(T_range)*c.R('J/mol/K') H_fit = shomate.get_HoRT(T_range)*T_range*c.R('kJ/mol/K') S_fit = shomate.get_SoR(T_range)*c.R('J/mol/K') plt.figure() plt.subplot(311) plt.plot(T, Cp, 'ro', T_range, Cp_fit, 'b-') plt.legend(['NIST Data', 'Fit']) plt.xlabel('Temperature (K)') plt.ylabel('Cp (J/mol/K)') plt.subplot(312) plt.plot(T_range, H_fit) plt.xlabel('Temperature (K)') plt.ylabel('H (kJ/mol/K)') plt.subplot(313) plt.plot(T_range, S_fit) plt.xlabel('Temperature (K)') plt.ylabel('S (J/mol/K)') return shomate
def plot_thermo(self, T_low=None, T_high=None, units=None): """ Plots the heat capacity, enthalpy and entropy in the temperature range specified. Parameters ---------- T_low - float Lower bound to plot temperature (K). If not specified then the T_low attribute for the species is used. T_high - float Higher bound to plot temperatures (K). If not specified then the T_high attribute for the species is used. units - string Controls the units used based on the molar gas constant (e.g. J/mol/K, kcal/mol/K, 'eV/K'). If not specified then dimensionless units are used. """ import matplotlib.pyplot as plt if T_low == None: T_low = self.T_low if T_high == None: T_high = self.T_high T = np.linspace(T_low, T_high) Cp = self.get_CpoR(T) H = self.get_HoRT(T) S = self.get_SoR(T) if units is not None: Cp = Cp * c.R(units) H = H * c.R(units) * T S = S * c.R(units) plt.figure() plt.subplot(311) plt.plot(T, Cp, 'r-') if units is None: plt.ylabel('Cp/R') else: plt.ylabel('Cp (%s)' % units) plt.xlabel('T (K)') plt.title('Plots for %s using NASA polynomials.' % self.symbol) plt.subplot(312) plt.plot(T, H, 'b-') if units is None: plt.ylabel('H/RT') else: plt.ylabel('H (%s)' % units.replace('/K', '')) plt.xlabel('T (K)') #Entropy graph plt.subplot(313) plt.plot(T, S, 'k-') if units is None: plt.ylabel('S/R') else: plt.ylabel('S (%s)' % units) plt.xlabel('T (K)')
def get_HoRT(self, T, H_correction = False, verbose = True): """ Calculate the dimensionless enthalpy for a single temperature. Parameters ---------- T - float Temperature H_correction - bool If set to True, subtracts the enthalpy at T = 298 K. Equivalent to H parameter on NIST verbose - bool Whether or not more information should be provided Returns ------- HoRT - float Dimensionless enthalpy at a single temperature (i.e. H/RT where R is the molar gas constant) """ t = T/1000. if H_correction: T_arr = np.array([t, t ** 2 / 2, t ** 3 / 3, t ** 4 / 4, -1/t, 1., 0., 1.]) else: T_arr = np.array([t, t ** 2 / 2, t ** 3 / 3, t ** 4 / 4, -1/t, 1., 0., 0.]) if verbose: if T < self.T_low: print(("Warning. Input temperature (%f) lower than T_low (%f) for species %s" % (T, self.T_low, self.symbol))) elif T > self.T_high: print(("Warning. Input temperature (%f) higher than T_high (%f) for species %s" % (T, self.T_high, self.symbol))) return np.dot(T_arr, self.a)/(c.R('kJ/mol/K')*T)
def get_A_from_sticking_coefficient(T, thermos): #Find gas-phase reactant for species, coefficient in self.stoichiometry.items(): if coefficient < 0 and thermos[species].is_gas: #Calculate molecular weight MW = c.get_molecular_weight(thermos[species].elements) A = self.s * np.sqrt(c.R('J/mol/K') * T / (2 * np.pi * MW)) return A
def _get_SoR(T, a): """ Internal function to calculate dimensionless entropy. Parameters ---------- T - float or (N,) ndarray Temperature(s) a - (8,) ndarray Shomate parameters Returns ------- HoRT - float or (N,) ndarray Dimensionless entropy corresponding to T (i.e. S/R where R is the molar gas constant) """ t = T/1000. T_arr = np.array([np.log(t), t, t ** 2 / 2., t ** 3 / 3., -0.5 * ( 1 / t ) ** 2, 0., 1., 0.]) return np.dot(T_arr, a)/c.R('J/mol/K')
def _get_HoRT(T, a, H_correction = False): """ Internal function to calculate dimensionless enthalpy. Parameters ---------- T - float or (N,) ndarray Temperature(s) a - (8,) ndarray Shomate parameters H_correction - bool If set to True, subtracts the enthalpy at T = 298 K. Equivalent to H parameter on NIST Returns ------- HoRT - float or (N,) ndarray Dimensionless enthalpy corresponding to T (i.e. H/RT where R is the molar gas constant) """ t = T/1000. T_arr = np.array([t, t ** 2 / 2, t ** 3 / 3, t ** 4 / 4, -1/t, 1., 0., 1.]) return np.dot(T_arr, a)/(c.R('kJ/mol/K')*T)
def get_SoR(self, T, verbose = True): """ Calculates the dimensionless entropy for a single temperature. Parameters ---------- T - float or (N,) ndarray Temperature(s) verbose - bool Whether or not more information should be provided Returns ------- SoR - float Dimensionless entropy corresponding to T (i.e. S/R where R is the molar gas constant) """ t = T/1000. T_arr = np.array([np.log(t), t, t ** 2 / 2., t ** 3 / 3., -0.5 * ( 1 / t ) ** 2, 0., 1., 0.]) if verbose: if T < self.T_low: print(("Warning. Input temperature (%f) lower than T_low (%f) for species %s" % (T, self.T_low, self.symbol))) elif T > self.T_high: print(("Warning. Input temperature (%f) higher than T_high (%f) for species %s" % (T, self.T_high, self.symbol))) return np.dot(T_arr, self.a)/c.R('J/mol/K')
def get_CpoR(self, T, verbose = True): """ Calculate the dimensionless heat capacity for a single temperature. Parameters ---------- T - float Temperature verbose - bool Whether or not more information should be provided Returns ------- CpoR - float Dimensionless heat capacity at a single temperature (i.e. Cp/R where R is the molar gas constant) """ t = T/1000. T_arr = np.array([1, t, t ** 2, t ** 3, (1/t) ** 2, 0, 0, 0]) if verbose: if T < self.T_low: print(("Warning. Input temperature (%f) lower than T_low (%f) for species %s" % (T, self.T_low, self.symbol))) elif T > self.T_high: print(("Warning. Input temperature (%f) higher than T_high (%f) for species %s" % (T, self.T_high, self.symbol))) return np.dot(T_arr, self.a)/c.R('J/mol/K')
def plot_thermo(self, T_low, T_high, Cp_units = None, S_units = None, H_units = None, G_units = None, phase = None): """ Plots the heat capacity, enthalpy and entropy in the temperature range specified. The units for the plots can be specified by using R Parameters ---------- T_low - float Lower temperature bound T_high - float Higher temperature bound Cp_units - string Heat capacity units. Supported units can be found in py_box3.constants.R e.g. Use 'kJ/mol/K' to display heat capacity in kiloJoules per mol per Kelvin H_units - string Enthalpy units. Supported units can be found in py_box3.constants.R S_units - string Entropy units. Supported units can be found in py_box3.constants.R e.g. Use 'kJ/mol/K' to display entropy in kiloJoules per mol per Kelvin G_units - string Gibbs free energy units. Supported units can be found in py_box3.constants.R Returns ------- fig - matplotlib.figure.Figure object ax_Cp - meatplotlib.Axes.axes object Axes to heat capacity plot ax_H - meatplotlib.Axes.axes object Axes to enthalpy plot ax_S - meatplotlib.Axes.axes object Axes to entropy plot ax_G - meatplotlib.Axes.axes object Axes to Gibbs energy plot """ import matplotlib.pyplot as plt T = np.linspace(T_low, T_high) Cp = self.get_CpoR(T, phase = phase) H = self.get_HoRT(T, phase = phase) S = self.get_SoR(T, phase = phase) G = self.get_GoRT(T, phase = phase) #Apply units if Cp_units is not None: Cp = Cp * c.R(Cp_units) if S_units is not None: S = S * c.R(S_units) if H_units is not None: H = H * c.R('{}/K'.format(H_units)) * T if G_units is not None: G = G * c.R('{}/K'.format(G_units)) * T fig = plt.figure() ax_Cp = plt.subplot(411) plt.plot(T, Cp, 'r-') if Cp_units is None: plt.ylabel('Cp/R') else: plt.ylabel('Cp ({})'.format(Cp_units)) plt.xlabel('T (K)') plt.title('Plots for {} using shomate polynomials.'.format(self.symbol)) ax_H = plt.subplot(412) plt.plot(T, H, 'g-') if H_units is None: plt.ylabel('H/RT') else: plt.ylabel('H ({})'.format(H_units)) plt.xlabel('T (K)') #Entropy graph ax_S = plt.subplot(413) plt.plot(T, S, 'b-') if S_units is None: plt.ylabel('S/R') else: plt.ylabel('S ({})'.format(S_units)) plt.xlabel('T (K)') ax_G = plt.subplot(414) plt.plot(T, G, 'k-') if G_units is None: plt.ylabel('G/RT') else: plt.ylabel('G (%s)' % G_units) plt.xlabel('T (K)') return (fig, ax_Cp, ax_H, ax_S, ax_G)
def test_R(self): self.assertEqual(c.R('J/mol/K'), 8.3144598)