diff --git a/.gitignore b/.gitignore index 81c00a6..fa440e7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,8 @@ *.dat __pycache__* _build* +generated* +sprayPropsGCM* +mixturePropsGCM* + + diff --git a/Export4Converge.py b/Export4Converge.py new file mode 100644 index 0000000..7eb9da9 --- /dev/null +++ b/Export4Converge.py @@ -0,0 +1,359 @@ +import pandas as pd +import numpy as np +import os +import argparse +import FuelLib as fl + +""" +Script that exports mixture properties over large temperature range for use in +Converge simulations. + +This script is designed to be run from the command line and will create +a file named "mixturePropsGCM_.csv" in the specified directory. +The file contains mixture properties for the fuel, formatted for Converge. + +Usage: + python Export4Converge.py --fuel_name + +Options: + --units + --temp_min (K) + --temp_max (K) + --temp_step (K) + --export_dir +""" + + +def export_converge( + fuel, path="mixturePropsGCM", units="mks", temp_min=0, temp_max=1000, temp_step=10 +): + """ + Export mixture fuel properties to .csv for Converge simulations. + + :param fuel: An instance of the groupContribution class. + :type fuel: groupContribution object + + :param path: Directory to save the input file. + :type path: str, optional + + :param units: Units for the properties ("mks" for SI, "cgs" for CGS). + :type units: str, optional + + :param temp_min: Minimum temperature (K) for the property calculations. + :type temp_min: float, optional + + :param temp_max: Maximum temperature (K)for the property calculations. + :type temp_max: float, optional + + :param temp_step: Step size for temperature (K). + :type temp_step: float, optional + + :return: None + :rtype: None + """ + + if not os.path.exists(path): + os.makedirs(path) + + # Names of the input file + file_name = os.path.join(path, f"mixturePropsGCM_{fuel.name}.csv") + + # Unit conversion factors: + if units.lower() == "cgs": + # Convert from MKS to CGS + conv_mu = 1e2 # Pa*s to Poise + conv_surfacetension = 1e7 # N/m to dyne/cm + conv_Lv = 1e4 # J/kg to erg/g + conv_P = 1e1 # Pa to dyne/cm^2 + conv_rho = 1e3 # kg/m^3 to g/cm^3 + conv_Cl = 1e4 # J/kg/K to erg/g/K + conv_thermcond = 1e5 # W/m/K to erg/cm/s/K + else: + conv_mu = 1 + conv_surfacetension = 1 + conv_Lv = 1 + conv_P = 1 + conv_rho = 1 + conv_Cl = 1 + conv_thermcond = 1 + + # Assume droplet of 50 microns to account for compositional changes with temp + drop_r = 50 * 1e-6 # initial droplet radius (m) + + # Vector of evenly space temperatures + nT = int((temp_max - temp_min) / temp_step) + 1 + T = np.linspace(temp_min, temp_max, nT) + + # Round to nearest multiple of temp_step + def nearest_temp(x, base=temp_step): + return base * round(x / base) + + def nearest_floor(array, value): + """ + Find the largest value in the array that is less than or equal to the given value. + """ + if np.any(array <= value): + return array[array <= value].max() + else: + raise ValueError( + f"No temperature in the array is less than or equal to the critical point {value}. Choose a lower temp_min" + ) + + def nearest_ceil(array, value): + """ + Find the smallest value in the array that is greater than or equal to the given value. + """ + if np.any(array >= value): + return array[array >= value].min() + else: + # Report an error if no value is found + raise ValueError( + f"No temperature in the array is greater than or equal the freezing point {value}. Choose a higher temp_max" + ) + + # Estimate freezing point and critical temp of mixture + T_freeze = fl.mixing_rule(fuel.Tm, fuel.Y2X(fuel.Y_0)) + T_crit = fl.mixing_rule(fuel.Tc, fuel.Y2X(fuel.Y_0)) + T_min_allowed = nearest_temp(T_freeze) + T_max_allowed = min(fuel.Tc) + + print(f"\nEstimated mixture freezing temp: {T_freeze:.2f} K") + print(f"Min freezing temp min(Tm_i): {min(fuel.Tm):.2f} K") + print(f"Max freezing temp max(Tm_i): {max(fuel.Tm):.2f} K") + if np.any(T < T_min_allowed): + T_min_allowed = nearest_ceil(T, T_min_allowed) + # Set T_min_allowed to be the next temperature above T_min_allowed in T + print( + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + ) + print( + f" Warning: Some compounds have freezing temperatures above the estimated\n" + f" freezing temperature of the mixture ({T_freeze:.2f} K). All properties calculated\n" + f" below {T_min_allowed} will be set using a temperature of {T_min_allowed} K." + ) + print( + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + ) + + print(f"\nEstimated mixture critical temp: {T_crit:.2f} K") + print(f"Min critical temp min(Tc_i): {min(fuel.Tc):.2f} K") + print(f"Max critical temp max(Tc_i): {max(fuel.Tc):.2f} K") + if np.any(T > T_max_allowed): + T_max_allowed = nearest_floor(T, T_max_allowed) + print( + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + ) + print( + f" Warning: Some compounds have critical temperatures below the estimated\n" + f" critical temperature of the mixture ({T_crit:.2f} K). All properties calculated\n" + f" above {T_max_allowed} will be set using a temperature of {T_max_allowed} K." + ) + print( + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + ) + + mu = np.zeros_like(T) # Dynamic viscosity + surface_tension = np.zeros_like(T) # Surface tension + Lv = np.zeros_like(T) # Latent heat of vaporization + pv = np.zeros_like(T) # vapor pressure + rho = np.zeros_like(T) # density + Cl = np.zeros_like(T) # Specific heat + thermal_conductivity = np.zeros_like(T) # Thermal conductivity + + # Calculate GCM properties for a range of temperatures + print( + f"\nCalculating properties over {len(T)} temperatures from {temp_min} K to {temp_max} K..." + ) + for k in range(len(T)): + if T[k] <= T_min_allowed: + Temp = T_min_allowed + elif T[k] >= T_max_allowed: + Temp = T_max_allowed + else: + Temp = T[k] + + # Correct droplet mass (GCxGC at standard temperature) + mass = fl.droplet_mass(fuel, drop_r, fuel.Y_0, Temp) + Y_li = fuel.mass2Y(mass) + X_li = fuel.Y2X(Y_li) + + # Standard mixing rules for properties + rho[k] = fuel.mixture_density(Y_li, Temp) # kg/m^3 + mu[k] = fuel.mixture_dynamic_viscosity(Y_li, Temp) # Pa*s + pv[k] = fuel.mixture_vapor_pressure(Y_li, Temp) # Pa + surface_tension[k] = fuel.mixture_surface_tension(Y_li, Temp) # N/m + thermal_conductivity[k] = fuel.mixture_thermal_conductivity(Y_li, Temp) + + # Generic mixing rules for latent heat and specific heat + Lv[k] = fl.mixing_rule(fuel.latent_heat_vaporization(Temp), X_li) # J/kg + Cl[k] = fl.mixing_rule(fuel.Cl(Temp), X_li) # J/kg/K + + if units.lower() == "cgs": + # Convert properties to CGS units + data = pd.DataFrame( + { + "Temperature (K)": T, + "Critical Temperature (K)": T_crit + np.zeros_like(T), + "Viscosity (Poise)": mu * conv_mu, + "Surface Tension (dyne/cm)": surface_tension * conv_surfacetension, + "Heat of Vaporization (erg/g)": Lv * conv_Lv, + "Vapor Pressure (dyne/cm^2)": pv * conv_P, + "Density (g/cm^3)": rho * conv_rho, + "Specific Heat (erg/g/K)": Cl * conv_Cl, + "Thermal Conductivity (erg/cm/s/K)": thermal_conductivity + * conv_thermcond, + } + ) + else: + # MKS units + data = pd.DataFrame( + { + "Temperature (K)": T, + "Critical Temperature (K)": T_crit + np.zeros_like(T), + "Viscosity (Pa*s)": mu, + "Surface Tension (N/m)": surface_tension, + "Heat of Vaporization (J/kg)": Lv, + "Vapor Pressure (Pa)": pv, + "Density (kg/m^3)": rho, + "Specific Heat (J/kg/K)": Cl, + "Thermal Conductivity (W/m/K)": thermal_conductivity, + } + ) + + # Write the properties to the input file + print(f"\nWriting mixture properties to {file_name}") + if os.path.exists(file_name): + os.remove(file_name) + df = pd.DataFrame(data) + df.to_csv(file_name, index=False) + + +def main(): + """ + Main function to execute the export process. + + :param --fuel_name: Name of the fuel (mandatory). + :type --fuel_name: str + + :param --units: Units for critical properties. Options are "mks" (default) or "cgs". + :type --units: str, optional + + :param --temp_min: Minimum temperature (K) for the property calculations (optional, default: 0). + :type --temp_min: float, optional + + :param --temp_max: Maximum temperature (K) for the property calculations (optional, default: 1000). + :type --temp_max: float, optional + + :param --temp_step: Step size for temperature (K) (optional, default: 10). + :type --temp_step: float, optional + + :param --export_dir: Directory to export the properties. Default is "sprayPropsGCM". + :type --export_dir: str, optional + + :raises FileNotFoundError: If required files for the specified fuel are not found. + """ + + # Set up argument parser + parser = argparse.ArgumentParser( + description="Export mixture fuel properties for Converge simulations." + ) + + # Mandatory argument for fuel name + parser.add_argument( + "--fuel_name", + required=True, + help="Name of the fuel (mandatory).", + ) + + # Optional argument for units + # Default is 'mks', but can be set to 'cgs' + parser.add_argument( + "--units", + default="mks", + help="Units for critical properties: mks or cgs (optional, default: mks).", + ) + + # Optional argument for minimum temperature + parser.add_argument( + "--temp_min", + type=float, + default=0, + help="Minimum temperature (K) for the property calculations (optional, default: 0).", + ) + + # Optional argument for maximum temperature + parser.add_argument( + "--temp_max", + type=float, + default=1000, + help="Maximum temperature (K) for the property calculations (optional, default: 1000).", + ) + + # Optional argument for temperature step size + parser.add_argument( + "--temp_step", + type=int, + default=10, + help="Step size for temperature (K) (optional, default: 10).", + ) + + # Optional argument for export directory + parser.add_argument( + "--export_dir", + default="mixturePropsGCM", + help="Directory to export the properties (optional, default: mixturePropsGCM).", + ) + + # Parse arguments + args = parser.parse_args() + fuel_name = args.fuel_name + units = args.units.lower() + temp_min = args.temp_min + temp_max = args.temp_max + temp_step = args.temp_step + export_dir = args.export_dir + + # Print the parsed arguments + print(f"Preparing to export mixture properties:") + print(f" Fuel name: {fuel_name}") + print(f" Units: {units}") + print(f" Minimum temperature: {temp_min} K") + print(f" Maximum temperature: {temp_max} K") + print(f" Temperature step size: {temp_step} K") + print(f" Export directory: {export_dir}") + + # Check if necessary files exist in the fuelData directory + print("\nChecking for required files...") + decomp_dir = os.path.join( + fl.groupContribution.fuelDataDir, "groupDecompositionData" + ) + gcxgc_dir = os.path.join(fl.groupContribution.fuelDataDir, "gcData") + gcxgc_file = os.path.join(gcxgc_dir, f"{fuel_name}_init.csv") + decomp_file = os.path.join(decomp_dir, f"{fuel_name}.csv") + if not os.path.exists(gcxgc_file): + raise FileNotFoundError( + f"GCXGC file for {fuel_name} not found in {gcxgc_dir}. gxcgc_file = {gcxgc_file}" + ) + if not os.path.exists(decomp_file): + raise FileNotFoundError( + f"Decomposition file for {fuel_name} not found in {decomp_dir}." + ) + print("All required files found.") + + # Create the groupContribution object for the specified fuel + fuel = fl.groupContribution(fuel_name) + + # Export properties for Pele + export_converge( + fuel, + path=export_dir, + units=units, + temp_min=temp_min, + temp_max=temp_max, + ) + + print("\nExport completed successfully!") + + +if __name__ == "__main__": + main() diff --git a/Export4Pele.py b/Export4Pele.py new file mode 100644 index 0000000..6e84e4a --- /dev/null +++ b/Export4Pele.py @@ -0,0 +1,300 @@ +import pandas as pd +import numpy as np +import os +import argparse +import FuelLib as fl + +""" +Script that exports critical properties and initial mass fraction data +for use in Pele simulations. + +This script is designed to be run from the command line and will create +a file named "sprayPropsfl.inp" in the specified directory. +The file contains properties for each compound in the fuel, formatted for Pele. + +Usage: + python Export4Pele.py --fuel_name + +Options: + --units + --dep_fuel_names + --max_dep_fuels + --export_dir +""" + + +def vec_to_str(vec): + """ + Convert a list or numpy array to a string representation. + + :param vec: List or numpy array to convert. + :return: String representation of the vector. + """ + + # If strings return string[0] string[1] ... string[n] + if isinstance(vec, list): + return " ".join(f"{v}" for v in vec) + # Else if numbers, format with spaces between no commas or [] + elif isinstance(vec, (pd.Series, pd.DataFrame)): + return " ".join(f"{v}" for v in vec.values) + + +def export_pele( + fuel, path="sprayPropsGCM", units="mks", dep_fuel_names=None, max_dep_fuels=30 +): + """ + Export fuel properties to input file for Pele simulations. + + :param fuel: An instance of the groupContribution class. + :type fuel: groupContribution object + + :param path: Directory to save the input file. + :type path: str, optional + + :param units: Units for the properties ("mks" for SI, "cgs" for CGS). + :type units: str, optional + + :param dep_fuel_names: List or single fuel that each compound deposits to. + :type dep_fuel_names: str, optional + + :param max_dep_fuels: Maximum number of deposition fuels to consider. + :type max_dep_fuels: int, optional + + :return: None + :rtype: None + """ + + if not os.path.exists(path): + os.makedirs(path) + + # Names of the input file + file_name = os.path.join(path, "sprayPropsfl.inp") + + # If dep_fuel_names is not provided, use fuel.compounds + if dep_fuel_names is None: + if len(fuel.compounds) <= max_dep_fuels: + # If no deposition fuel names are provided, use the compounds as deposition fuels + dep_fuel_names = fuel.compounds + else: + # If more than max_dep_fuels, deposit all compoudns to fuel.name.upper() + # This assumes a POSF fuel with a single deposition fuel + dep_fuel_names = [fuel.name.upper()] * len(fuel.compounds) + elif len(dep_fuel_names) == 1: + # If a single deposition fuel name is provided, use it for all compounds + dep_fuel_names = [dep_fuel_names[0]] * len(fuel.compounds) + elif len(dep_fuel_names) != len(fuel.compounds): + raise ValueError( + "Length of dep_fuel_names must be one or match the number of compounds in the fuel." + ) + + # Unit conversion factors: + if units.lower() == "cgs": + # Convert from MKS to CGS + conv_MW = 1e3 # kg/mol to g/mol + conv_Cp = 1e4 # J/kg/K to erg/g/K + conv_Vm = 1e6 # m^3/mol to cm^3/mol + conv_Lv = 1e4 # J/kg to erg/g + conv_P = 1e1 # Pa to dyne/cm^2 + else: + conv_MW = 1.0 + conv_Cp = 1.0 + conv_Vm = 1.0 + conv_Lv = 1.0 + conv_P = 1.0 + + # Terms for liquid specific heat capacity in (J/kg/K) or (erg/g/K) + # Cp(T) = Cp_stp + Cp_B * theta + Cp_C * theta^2 + # where theta = (T - 298.15) / 700 + Cp_stp = fuel.Cp_stp / fuel.MW + Cp_B = fuel.Cp_B / fuel.MW + Cp_C = fuel.Cp_C / fuel.MW + + # Dataframe of all properties with unit conversions to be exported + print("\nCalculating GCM properties at standard conditions...") + df = pd.DataFrame( + { + "Compound": fuel.compounds, + "Y_0": fuel.Y_0, + "MW": fuel.MW * conv_MW, + "Tc": fuel.Tc, + "Pc": fuel.Pc * conv_P, + "Vc": fuel.Vc * conv_Vm, + "Tb": fuel.Tb, + "omega": fuel.omega, + "Vm_stp": fuel.Vm_stp * conv_Vm, + "Cp_stp": Cp_stp * conv_Cp, + "Cp_B": Cp_B * conv_Cp, + "Cp_C": Cp_C * conv_Cp, + "Lv_stp": fuel.Lv_stp * conv_Lv, + } + ) + # Get the property names + prop_names = ["MW", "Tc", "Pc", "Vc", "Tb", "omega", "Vm_stp", "Cp_stp", "Lv_stp"] + + formatted_names = { + "MW": ("molar_weight", ["kg/mol", "g/mol"]), + "Tc": ("crit_temp", ["K", "K"]), + "Pc": ("crit_press", ["Pa", "dyne/cm^2"]), + "Vc": ("crit_vol", ["m^3/mol", "cm^3/mol"]), + "Tb": ("boil_temp", ["K", "K"]), + "omega": ("acentric_factor", ["-", "-"]), + "Vm_stp": ("molar_vol", ["m^3/mol", "cm^3/mol"]), + "Cp_stp": ("cp", ["J/kg/K", "erg/g/K"]), + "Lv_stp": ("latent", ["J/kg", "erg/g"]), + } + + # Write the properties to the input file + print(f"Writing properties to {file_name}...") + if os.path.exists(file_name): + os.remove(file_name) + with open(file_name, "a") as f: + f.write(f"particles.spray_fuel_num = {len(fuel.compounds)}\n") + f.write(f"particles.fuel_species = {vec_to_str(df['Compound'].tolist())}\n") + f.write(f"particles.Y_0 = {vec_to_str(df['Y_0'].tolist())}\n") + f.write(f"particles.dep_fuel_names = {vec_to_str(dep_fuel_names)}\n") + + for comp_name in fuel.compounds: + f.write(f"\n# Properties for {comp_name} in {units.upper()}\n") + for prop in prop_names: + if prop in formatted_names: + if prop == "Cp_stp": + value = np.array( + [ + df.loc[df["Compound"] == comp_name, prop].values[0], + df.loc[df["Compound"] == comp_name, "Cp_B"].values[0], + df.loc[df["Compound"] == comp_name, "Cp_C"].values[0], + ] + ) + else: + value = df.loc[df["Compound"] == comp_name, prop].values[0] + prop_name, unit_txt = formatted_names[prop] + if units.lower() == "cgs": + unit_txt = unit_txt[1] + else: + unit_txt = unit_txt[0] + # Write the property to the file + if prop == "Cp_stp": + value = value.tolist() + f.write( + f"particles.{comp_name}_{prop_name} = {vec_to_str(value)} # {unit_txt}\n" + ) + else: + f.write( + f"particles.{comp_name}_{prop_name} = {value:.6f} # {unit_txt}\n" + ) + + +def main(): + """ + Main function to execute the export process. + + :param --fuel_name: Name of the fuel (mandatory). + :type --fuel_name: str + + :param --units: Units for critical properties. Options are "mks" (default) or "cgs". + :type --units: str, optional + + :param --dep_fuel_names: Space-separated list with len(fuel.compounds) or single fuel that all compounds deposit. Default is fuel.compounds. + :type --dep_fuel_names: str, optional + + :param --max_dep_fuels: Maximum number of deposition fuels to consider. Default is 30. + :type --max_dep_fuels: int, optional + + :param --export_dir: Directory to export the properties. Default is "sprayPropsGCM". + :type --export_dir: str, optional + + :raises FileNotFoundError: If required files for the specified fuel are not found. + """ + + # Set up argument parser + parser = argparse.ArgumentParser( + description="Export fuel properties for Pele simulations." + ) + + # Mandatory argument for fuel name + parser.add_argument( + "--fuel_name", + required=True, + help="Name of the fuel (mandatory).", + ) + + # Optional argument for units + # Default is 'mks', but can be set to 'cgs' + parser.add_argument( + "--units", + default="mks", + help="Units for critical properties: mks or cgs (optional, default: mks).", + ) + + # Optional argument for deposition fuel names + parser.add_argument( + "--dep_fuel_names", + nargs="+", # Accepts one or more values + default=None, + help="Space-separated list or single fuel that each compound deposits to (optional, default: fuel.compounds).", + ) + + # Optional argument for maximum number of deposition fuels + parser.add_argument( + "--max_dep_fuels", + type=int, + default=30, + help="Maximum number of deposition fuels to consider (optional, default: 30).", + ) + + # Optional argument for export directory + parser.add_argument( + "--export_dir", + default="sprayPropsGCM", + help="Directory to export the properties (optional, default: sprayPropsGCM).", + ) + + # Parse arguments + args = parser.parse_args() + fuel_name = args.fuel_name + units = args.units.lower() + dep_fuel_names = args.dep_fuel_names + max_dep_fuels = args.max_dep_fuels + export_dir = args.export_dir + + # Print the parsed arguments + print(f"Preparing to export properties:") + print(f" Fuel name: {fuel_name}") + print(f" Units: {units}") + print(f" Export directory: {export_dir}") + + # Check if necessary files exist in the fuelData directory + print("\nChecking for required files...") + decomp_dir = os.path.join( + fl.groupContribution.fuelDataDir, "groupDecompositionData" + ) + gcxgc_dir = os.path.join(fl.groupContribution.fuelDataDir, "gcData") + gcxgc_file = os.path.join(gcxgc_dir, f"{fuel_name}_init.csv") + decomp_file = os.path.join(decomp_dir, f"{fuel_name}.csv") + if not os.path.exists(gcxgc_file): + raise FileNotFoundError( + f"GCXGC file for {fuel_name} not found in {gcxgc_dir}. gxcgc_file = {gcxgc_file}" + ) + if not os.path.exists(decomp_file): + raise FileNotFoundError( + f"Decomposition file for {fuel_name} not found in {decomp_dir}." + ) + print("All required files found.") + + # Create the groupContribution object for the specified fuel + fuel = fl.groupContribution(fuel_name) + + # Export properties for Pele + export_pele( + fuel, + path=export_dir, + units=units, + dep_fuel_names=dep_fuel_names, + max_dep_fuels=max_dep_fuels, + ) + + print("\nExport completed successfully!") + + +if __name__ == "__main__": + main() diff --git a/GroupContributionMethod.py b/FuelLib.py similarity index 90% rename from GroupContributionMethod.py rename to FuelLib.py index a842137..090021c 100644 --- a/GroupContributionMethod.py +++ b/FuelLib.py @@ -73,8 +73,9 @@ def __init__(self, name, decompName=None, W=1): self.fam[i] = 3 # Read initial liquid composition of mixture and normalize to get mass frac - df_gcxgc = pd.read_csv(gcxgcFile, usecols=[1]) - self.Y_0 = df_gcxgc.to_numpy().flatten().astype(float) + df_gcxgc = pd.read_csv(gcxgcFile) + self.compounds = df_gcxgc.iloc[:, 0].to_list() + self.Y_0 = df_gcxgc.iloc[:, 1].to_numpy().flatten().astype(float) self.Y_0 /= np.sum(self.Y_0) # Make sure mixture data is consistent: @@ -181,7 +182,7 @@ def __init__(self, name, decompName=None, W=1): # ------------------------------------------------------------------------- # Member functions # ------------------------------------------------------------------------- - def mass_frac(self, mass): + def mass2Y(self, mass): """ Calculate the mass fractions from the mass of each component. @@ -199,7 +200,7 @@ def mass_frac(self, mass): return Yi - def mole_frac(self, mass): + def mass2X(self, mass): """ Calculate the mole fractions from the mass of each component. @@ -220,6 +221,44 @@ def mole_frac(self, mass): return Xi + def X2Y(self, Xi): + """ + Calculate the mass fractions from the mole fractions of each component. + + :param Xi: Mole fractions of each compound. + :type Xi: np.ndarray + :return: Mass fractions of the compounds (shape: num_compounds,). + :rtype: np.ndarray + """ + # Calculate the mass for each compound + mass = Xi * self.MW + + # Normalize to get group mass fractions + total_mass = np.sum(mass) + if total_mass != 0: + Yi = mass / total_mass + else: + Yi = np.zeros_like(self.MW) + + return Yi + + def Y2X(self, Yi): + """ + Calculate the mole fractions from the mass fractions of each component. + + :param Yi: Mass fractions of each compound. + :type Yi: np.ndarray + :return: Mole fractions of the compounds (shape: num_compounds,). + :rtype: np.ndarray + """ + if np.sum(Yi) != 0: + Mbar = 1 / np.sum(Yi / self.MW) # mean molar weight of the mixture + Xi = Mbar * Yi / self.MW + else: + Xi = np.zeros_like(self.MW) + + return Xi + def density(self, T): """ Calculate the density of each component at temperature T. @@ -579,14 +618,14 @@ def mixture_density(self, Yi, T): return rho - def mixture_kinematic_viscosity(self, mass, T, correlation="Kendall-Monroe"): + def mixture_kinematic_viscosity(self, Yi, T, correlation="Kendall-Monroe"): """ Calculate kinematic viscosity of the mixture. :meta private: Uses Kendall-Monroe (default) or Arrhenius mixing correlations. - :param mass: Mass of each compound in the mixture. - :type mass: np.ndarray + :param Yi: Mass fractions of each compound. + :type Yi: np.ndarray :param T: Temperature in Kelvin. :type T: float :param correlation: Mixing model ("Kendall-Monroe" or "Arrhenius"). @@ -596,8 +635,8 @@ def mixture_kinematic_viscosity(self, mass, T, correlation="Kendall-Monroe"): """ nu_i = self.viscosity_kinematic(T) # Viscosities of individual components - # Calculate group mole fractions for each species - Xi = self.mole_frac(mass) + # Calculate mole fractions for each species + Xi = self.Y2X(Yi) if correlation.casefold() == "Arrhenius".casefold(): # Arrhenius mixing correlation @@ -608,12 +647,12 @@ def mixture_kinematic_viscosity(self, mass, T, correlation="Kendall-Monroe"): return nu - def mixture_dynamic_viscosity(self, mass, T, correlation="Kendall-Monroe"): + def mixture_dynamic_viscosity(self, Yi, T, correlation="Kendall-Monroe"): """ Calculate dynamic viscosity of the mixture. - :param mass: Mass of each compound in the mixture. - :type mass: np.ndarray + :param Yi: Mass fractions of each compound. + :type Yi: np.ndarray :param T: Temperature in Kelvin. :type T: float :param correlation: Mixing model ("Kendall-Monroe" or "Arrhenius"). @@ -622,18 +661,17 @@ def mixture_dynamic_viscosity(self, mass, T, correlation="Kendall-Monroe"): :rtype: float """ - nu = self.mixture_kinematic_viscosity(mass, T, correlation) - Yi = self.mass_frac(mass) + nu = self.mixture_kinematic_viscosity(Yi, T, correlation) rho = self.mixture_density(Yi, T) return rho * nu - def mixture_vapor_pressure(self, mass, T, correlation="Lee-Kesler"): + def mixture_vapor_pressure(self, Yi, T, correlation="Lee-Kesler"): """ Calculate vapor pressure of the mixture. - :param mass: Mass of each compound in the mixture. - :type mass: np.ndarray + :param Yi: Mass fractions of each compound in the mixture. + :type Yi: np.ndarray :param T: Temperature in Kelvin. :type T: float :param correlation: Correlation method ("Ambrose-Walton" or "Lee-Kesler"). @@ -642,8 +680,8 @@ def mixture_vapor_pressure(self, mass, T, correlation="Lee-Kesler"): :rtype: float """ - # Group mole fraction for each compound - Xi = self.mole_frac(mass) + # Mole fraction for each compound + Xi = self.Y2X(Yi) # Saturated vapor pressure for each compound (Pa) p_sati = self.psat(T, correlation) @@ -654,13 +692,13 @@ def mixture_vapor_pressure(self, mass, T, correlation="Lee-Kesler"): return p_v def mixture_vapor_pressure_antoine_coeffs( - self, mass, Tvals, units="mks", correlation="Lee-Kesler" + self, Yi, Tvals, units="mks", correlation="Lee-Kesler" ): """ Estimate Antoine coefficients for vapor pressure of the mixture. - :param mass: Mass of each compound in the mixture. - :type mass: np.ndarray + :param Yi: Mass fractions of each compound in the mixture. + :type Yi: np.ndarray :param Tvals: Temperature range or nodes for Antoine fit in Kelvin. :type Tvals: np.ndarray :param units: Units for pressure in fit ("mks", "cgs", "bar", "atm") @@ -694,7 +732,7 @@ def antoine_eq(T, A, B, C): Pvals = np.zeros_like(T) for k in range(len(T)): - Pvals[k] = self.mixture_vapor_pressure(mass, T[k]) * D + Pvals[k] = self.mixture_vapor_pressure(Yi, T[k]) * D logP = np.log10(Pvals) popt, _ = curve_fit(antoine_eq, T, logP, p0=[1, 1e3, -1]) # initial guess @@ -702,14 +740,14 @@ def antoine_eq(T, A, B, C): return A, B, C, D - def mixture_surface_tension(self, mass, T, correlation="Brock-Bird"): + def mixture_surface_tension(self, Yi, T, correlation="Brock-Bird"): """ Calculate surface tension of the mixture. :meta private: Uses arithmetic pseudo-property method recommended by Hugill and van Welsenes (1986). - :param mass: Mass of each compound in the mixture. - :type mass: np.ndarray + :param Yi: Mass fractions of each compound in the mixture. + :type Yi: np.ndarray :param T: Temperature in Kelvin. :type T: float :param correlation: Correlation method ("Pitzer" or "Brock-Bird"). @@ -718,8 +756,8 @@ def mixture_surface_tension(self, mass, T, correlation="Brock-Bird"): :rtype: float """ - # Group mole fraction for each compound - Xi = self.mole_frac(mass) + # Mole fraction for each compound + Xi = self.Y2X(Yi) # Surface tension for each compound (N/m) sti = self.surface_tension(T, correlation) @@ -729,18 +767,17 @@ def mixture_surface_tension(self, mass, T, correlation="Brock-Bird"): return st - def mixture_thermal_conductivity(self, mass, T): + def mixture_thermal_conductivity(self, Yi, T): """ Calculate thermal conductivity of the mixture. - :param mass: Mass of each compound in the mixture. - :type mass: np.ndarray + :param Yi: Mass fractions of each compound in the mixture. + :type Yi: np.ndarray :param T: Temperature in Kelvin. :type T: float :return: Thermal conductivity in W/m/K. :rtype: float """ - Yi = self.mass_frac(mass) tc = self.thermal_conductivity(T) return np.sum(Yi * tc ** (-2)) ** (-0.5) @@ -811,7 +848,7 @@ def droplet_volume(r): return 4.0 / 3.0 * np.pi * r**3 -def drop_mass(fuel, r, Yi, T): +def droplet_mass(fuel, r, Yi, T): """ Calculate the mass of each compound in the fuel provided the radius of the droplet. @@ -826,9 +863,8 @@ def drop_mass(fuel, r, Yi, T): :return: Mass of each compound in droplet in kg. :rtype: np.ndarray """ - MW = fuel.MW # kg/mol volume = droplet_volume(r) # m^3 if volume > 0: return volume / (fuel.molar_liquid_vol(T) @ Yi) * Yi * fuel.MW else: - return np.zeros_like(MW) + return np.zeros_like(fuel.MW) diff --git a/README.md b/README.md index 8c8d79a..0580f33 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,21 @@ # FuelLib FuelLib (SWR-25-26) utilizes the tables and functions of the Group Contribution Method (GCM) as proposed by [Constantinou and Gani (1994)](https://doi.org/10.1002/aic.690401011) and [Constantinou, Gani and O'Connel (1995)](https://doi.org/10.1016/0378-3812(94)02593-P), with additional physical properties discussed in [Govindaraju & Ihme (2016)](https://doi.org/10.1016/j.ijheatmasstransfer.2016.06.079). The code is based on Pavan B. Govindaraju's [Matlab implementation](https://github.com/gpavanb-old/GroupContribution) of the GCM, and has been expanded to include additional thermodynamic properties and mixture properties. The fuel library contains gas chromatography (GC x GC) data for a variety of fuels ranging from simple single component fuels to complex jet fuels. The GC x GC data for POSF jet fuels comes from [Edwards (2020)](https://apps.dtic.mil/sti/pdfs/AD1093317.pdf). +## Citing this Work +If you use FuelLib in your research, please cite the following software record: + +~~~ +Montgomery, David, Appukuttan, Sreejith, Yellapantula, Shashank, Perry, Bruce, and Binswanger, Adam. FuelLib (Fuel Library) [SWR-25-26]. Computer Software. https://github.com/NREL/FuelLib. USDOE Office of Energy Efficiency and Renewable Energy (EERE), Office of Sustainable Transportation. Vehicle Technologies Office (VTO). 27 Feb. 2025. Web. doi:10.11578/dc.20250317.1. +~~~ + ## Python Environment The following conda environment is required to run this code: ~~~ conda create --name fuellib-env matplotlib pandas scipy black ~~~ -## Running the code -This repository includes multiple examples of ways to use FuelLib. We recommend starting with `examples/ex_mixtureProperties.py`, which calculates a given mixture's density, viscosity and vapor pressure from GC x GC data. The results are plotted against data from NIST and [Edwards (2020)](https://apps.dtic.mil/sti/pdfs/AD1093317.pdf). +## Running the Code +This repository includes multiple tutorials of ways to use FuelLib. We recommend starting with the basic tutorial, `tutorials/basic.py`, which is documented at [https://nrel.github.io/FuelLib/tutorials.html#introduction]. The script `tutorials/mixtureProperties.py` calculates a given mixture's density, viscosity and vapor pressure from GC x GC data. The results are plotted against data from NIST and [Edwards (2020)](https://apps.dtic.mil/sti/pdfs/AD1093317.pdf). # Contributing New contributions are always welcome. If you have an idea for a new feature follow these steps: @@ -33,3 +40,4 @@ cd FuelLib/docs/ sphinx-build -M html . _build/ ~~~ You should now be able to view the html by opening `FuelLib/docs/_build/html/index.html` in a web browser. + diff --git a/docs/conf.py b/docs/conf.py index 5c365cd..c28be09 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,15 +1,7 @@ # Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# import os import sys @@ -26,23 +18,16 @@ release = "2025" # The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] source_suffix = ".rst" # The master toctree document. master_doc = "index" -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. +# The name of an image file to place at the top of the sidebar. html_logo = "comms/FuelLibLogo_Blue.pdf" # -- General configuration --------------------------------------------------- -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. numfig = True extensions = [ "sphinx.ext.mathjax", @@ -78,9 +63,7 @@ # html_theme = "sphinx_rtd_theme" -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". +# Add any paths that contain custom static files (such as style sheets) # html_static_path = ["_static"] # html_css_files = ["custom.css"] diff --git a/docs/figures/hefaBlends.png b/docs/figures/hefaBlends.png index b9b7195..256a5a8 100644 Binary files a/docs/figures/hefaBlends.png and b/docs/figures/hefaBlends.png differ diff --git a/docs/figures/multiCompFuels.png b/docs/figures/multiCompFuels.png index 0c313e1..f3225b6 100644 Binary files a/docs/figures/multiCompFuels.png and b/docs/figures/multiCompFuels.png differ diff --git a/docs/generated/GroupContributionMethod.rst b/docs/generated/GroupContributionMethod.rst deleted file mode 100644 index 61d96a1..0000000 --- a/docs/generated/GroupContributionMethod.rst +++ /dev/null @@ -1,39 +0,0 @@ -GroupContributionMethod -======================= - -.. automodule:: GroupContributionMethod - - - - - - - - .. rubric:: Functions - - .. autosummary:: - - C2K - K2C - drop_mass - droplet_volume - mixing_rule - - - - - - .. rubric:: Classes - - .. autosummary:: - - groupContribution - - - - - - - - - diff --git a/docs/groupcontribution.rst b/docs/groupcontribution.rst index 6ece054..e587dba 100644 --- a/docs/groupcontribution.rst +++ b/docs/groupcontribution.rst @@ -3,7 +3,7 @@ Properties and Model Equations The **Fuel Library** for advanced research on evaporation **(FuelLib)** utilizes the group contribution method (GCM), as developed by Constantinou and -Gani\ :footcite:p:`constantinou_new_1994,constantinou_estimation_1995` in the mid-1990s, +Gani\ :footcite:p:`constantinou_new_1994` \ :footcite:p:`constantinou_estimation_1995` in the mid-1990s, to provide a systematic approach for estimating the thermodynamic properties of pure organic compounds. The GCM decomposes molecules into structural groups, each contributing to a target property based on predefined group values. @@ -143,7 +143,7 @@ provided :math:`T` in K unless noted otherwise. Kinematic viscosity ^^^^^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.viscosity_kinematic +.. automethod:: FuelLib.groupContribution.viscosity_kinematic :noindex: The kinematic viscosity of the *i-th* compound of the fuel, @@ -166,7 +166,7 @@ Liquids\ :footcite:p:`viswanath_viscosity_2007`) provided :math:`T` in :math:`^{ Latent heat of vaporization ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.latent_heat_vaporization +.. automethod:: FuelLib.groupContribution.latent_heat_vaporization :noindex: The latent heat of vaporization for each compound at standard pressure and @@ -185,7 +185,7 @@ temperature\ :footcite:p:`govindaraju_group_2016`: Liquid molar volume ^^^^^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.molar_liquid_vol +.. automethod:: FuelLib.groupContribution.molar_liquid_vol :noindex: The liquid molar volume is calculated at a specific temperature :math:`T` using @@ -211,7 +211,7 @@ where Density ^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.density +.. automethod:: FuelLib.groupContribution.density :noindex: The density of the *i-th* compound is given by @@ -223,7 +223,7 @@ The density of the *i-th* compound is given by Liquid specific heat capacity ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.Cl +.. automethod:: FuelLib.groupContribution.Cl :noindex: The liquid specific heat capacity for each compound at standard pressure temperature is calculated from the specific heat capacity as: @@ -236,7 +236,7 @@ The liquid specific heat capacity for each compound at standard pressure tempera Saturated vapor pressure ^^^^^^^^^^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.psat +.. automethod:: FuelLib.groupContribution.psat :noindex: The saturated vapor pressure for each compound is calculated as a function of @@ -275,7 +275,7 @@ with :math:`\tau_i = 1 - T_{r,i}`. Surface tension ^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.surface_tension +.. automethod:: FuelLib.groupContribution.surface_tension :noindex: Surface tension for each compound is approximated using the relation: @@ -298,7 +298,7 @@ or by Curl and Pitzer\ :footcite:p:`poling_properties_2001` \ :footcite:p:`curl_ Thermal conductivity ^^^^^^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.thermal_conductivity +.. automethod:: FuelLib.groupContribution.thermal_conductivity :noindex: Thermal conductivity for each compound is computed according to the method of @@ -385,7 +385,7 @@ are used throughout this section. Conventional mixing rules ^^^^^^^^^^^^^^^^^^^^^^^^^ -.. autofunction:: GroupContributionMethod.mixing_rule +.. autofunction:: FuelLib.mixing_rule :noindex: While many of the mixture properties in FuelLib have a unique mixing rule, @@ -411,7 +411,7 @@ where :math:`Q_i` is the property of the *i-th* compound of the multicomponent m Mixture density ^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.mixture_density +.. automethod:: FuelLib.groupContribution.mixture_density :noindex: The mixture's density is calculated as: @@ -424,7 +424,7 @@ The mixture's density is calculated as: Mixture kinematic viscosity ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.mixture_kinematic_viscosity +.. automethod:: FuelLib.groupContribution.mixture_kinematic_viscosity :noindex: The kinematic viscosity of the mixture is computed using the Kendall-Monroe\ :footcite:p:`kendall_viscosity_1917` @@ -449,7 +449,7 @@ The Arrhenius rule is: Mixture vapor pressure ^^^^^^^^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.mixture_vapor_pressure +.. automethod:: FuelLib.groupContribution.mixture_vapor_pressure :noindex: The vapor pressure of the mixture is calculated according to Raoult's law: @@ -459,7 +459,7 @@ The vapor pressure of the mixture is calculated according to Raoult's law: p_{v} = \sum_{i = 1}^{N_c} X_i \, p_{\textit{sat},i}. \end{align*} -.. automethod:: GroupContributionMethod.groupContribution.mixture_vapor_pressure_antoine_coeffs +.. automethod:: FuelLib.groupContribution.mixture_vapor_pressure_antoine_coeffs :noindex: Users also have the option to return the coefficients from an Antoine fit based on @@ -479,7 +479,7 @@ for additional information. Mixture surface tension ^^^^^^^^^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.mixture_surface_tension +.. automethod:: FuelLib.groupContribution.mixture_surface_tension :noindex: The surface tension of the mixture is calculated using the :ref:`conventional-mixing-rules` @@ -492,7 +492,7 @@ Hugill and van Welsenes\ :footcite:p:`hugill_surface_1986`: Mixture thermal conductivity ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. automethod:: GroupContributionMethod.groupContribution.mixture_thermal_conductivity +.. automethod:: FuelLib.groupContribution.mixture_thermal_conductivity :noindex: The thermal conductivity of the mixture is calculated using the power law method of diff --git a/docs/index.rst b/docs/index.rst index a871935..bca4088 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,12 +1,12 @@ Welcome to FuelLib's documentation! =================================== -The **Fuel Library** for advanced research on evaporation **(FuelLib)** utilizes +The **Fuel Library (FuelLib)** utilizes the group contribution method (GCM), as developed by Constantinou and Gani\ :footcite:p:`constantinou_new_1994` \ :footcite:p:`constantinou_estimation_1995` in the mid-1990s with additions from Govindaraju and Ihme (2016)\ :footcite:p:`govindaraju_group_2016`, to provide a systematic approach for estimating the thermodynamic properties of -pure organic compounds. If you need help or have questions, please use the +pure organic compounds and mixtures of organic compounds. If you need help or have questions, please use the `GitHub discussion `_. The source code is available at `github.com/NREL/FuelLib `_. @@ -15,6 +15,28 @@ The source code is available at `github.com/NREL/FuelLib ``: + +- ``FuelLib/fuelData/gcData/_init.csv``: an initial weight percentage composition of the fuel components +- ``FuelLib/fuelData/groupDecompositionData/.csv``: the fundamental group decomposition for each component of the fuel + +These files must have the same number of rows and the same order of components. Many examples can be found in the `fuelData `_ directory. + +Basic Usage +^^^^^^^^^^^ + +To demonstrate the usage of FuelLib, we will use the fuel "heptane-decane", which is a +binary mixture of heptane and decane. The initial weight percentage composition is 73.75% +heptane and 26.25% decane, and the group decomposition data is provided in the +`groupDecompositionData `_ directory. +The following tutorial is included in the `FuelLib/tutorials `_ +as ``basic.py``. To begin, we will import the necessary modules and create a ``groupContribution`` object for the two component fuel "heptane-decane": + +.. code-block:: python + + import os + import sys + import numpy as np + + # Add the FuelLib directory to the Python path + fuellib_dir = os.path.dirname(os.path.dirname(__file__)) + sys.path.append(fuellib_dir) + import FuelLib as fl + + # Create a groupContribution object for the fuel "heptane-decane" + fuel = fl.groupContribution("heptane-decane") + +Upon initialization, the ``groupContribution`` object will read the initial weight +percentage composition and group decomposition data from the specified files. The object stores +vectors of the calculated fundamental properties at standard conditions for each component of the fuel as described in :ref:`eq-GCM-properties`. +For example, we can display the fuel name, the components in the fuel, the initial composition, and the critical temperature for each component: + +.. code-block:: python + + # Display fuel name, components, initial composition, and critical temperature + print(f"Fuel name: {fuel.name}") + print(f"Fuel components: {fuel.compounds}") + print(f"Initial composition: {fuel.Y_0}") + print(f"Critical temperature: {fuel.Tc} K") + +.. code-block:: none + + Fuel name: heptane-decane + Fuel components: ['NC7H16', 'NC10H22'] + Initial composition: [0.7375 0.2625] + Critical temperature: [549.85598051 623.69051582] K + +Next, we can calculate any of the component- or mixture-level properties using the +``groupContribution`` object. For example, we can calculate the saturated vapor pressure +for each component and the mixture at a given temperature: + +.. code-block:: python + + # Calculate the saturated vapor pressure at 320 K + T = 320 # K + p_sat_i = fuel.psat(T) + p_sat_mix = fuel.mixture_vapor_pressure(T) + print(f"Saturated vapor pressure at {T} K: {p_sat_i} Pa") + print(f"Mixture saturated vapor pressure at {T} K: {p_sat_mix} Pa") + +.. code-block:: none + + Saturated vapor pressure at 320 K: [13735.84605413 673.28876023] Pa + Mixture saturated vapor pressure at 320 K: 11117.84926875165 Pa + +The following links provide more information on the :ref:`eq-GCM-correlations` and +the :ref:`eq-mixture-properties` that can be calculated using the ``groupContribution`` object. + +Exporting GCM Properties for Pele +--------------------------------- + +The development of FuelLib was motivated by the need for more accurate liquid fuel +property prediction in computational fluid dynamics (CFD) simulations. The fundamental GCM +properties can be exported for use in the spray module of the `PelePhysics `_ library\ :footcite:p:`owen_pelemp_2024` +for combustion simulations in the `PeleLMeX `_ +flow solver\ :footcite:p:`henry_de_frahan_pele_2024` \ :footcite:p:`esclapez_pelelmex_2023`. + +The export script, ``Export4Pele.py``, generates an input file named ``sprayPropsfl.inp`` containing +the necessary properties for each compound in the fuel. The properties are formatted for use in Pele and includes: + +- Initial mass fraction +- Molecular weight +- Critical temperature +- Critical pressure +- Critical volume +- Boiling point +- Accentric factor +- Molar volume +- Specific heat +- Latent heat of vaporization + +.. warning:: + The incorporation of the GCM in Pele is still under development and additional testing is required. + +This example walks through the process and the available options for exporting GCM properties of a fuel named +"heptane-decane", which is a binary mixture of heptane and decane, using the ``Export4Pele.py`` script. + +Default Options +^^^^^^^^^^^^^^^ +.. note:: + The units for PeleLMeX are MKS while the units for PeleC are CGS. This is the same for + the spray inputs. Therefore, when running a spray simulation coupled with PeleC, the units for the + liquid fuel properties must be in CGS. The default units for the ``Export4Pele.py`` script is MKS, + but users can specify CGS by using the ``--units cgs`` option. + +From the ``FuelLib`` directory, run the following command in the terminal, noting that ``--fuel_name`` is the only required input: :: + + python Export4Pele.py --fuel_name heptane-decane + + +This generates the following input file, ``FuelLib/sprayPropsGCM/sprayPropsfl.inp``, for use in a PeleLMeX simulation: :: + + particles.spray_fuel_num = 2 + particles.fuel_species = NC7H16 NC10H22 + particles.Y_0 = 0.7375 0.2625 + particles.dep_fuel_names = NC7H16 NC10H22 + + # Properties for NC7H16 in MKS + particles.NC7H16_molar_weight = 0.100000 # kg/mol + particles.NC7H16_crit_temp = 549.855981 # K + particles.NC7H16_crit_press = 2821129.514417 # Pa + particles.NC7H16_crit_vol = 0.000425 # m^3/mol + particles.NC7H16_boil_temp = 379.073212 # K + particles.NC7H16_acentric_factor = 0.336945 # - + particles.NC7H16_molar_vol = 0.000146 # m^3/mol + particles.NC7H16_cp = 1636.255 3046.5109999999995 -983.6289999999999 # J/kg/K + particles.NC7H16_latent = 383110.000000 # J/kg + + # Properties for NC10H22 in MKS + particles.NC10H22_molar_weight = 0.142000 # kg/mol + particles.NC10H22_crit_temp = 623.690516 # K + particles.NC10H22_crit_press = 2115522.932445 # Pa + particles.NC10H22_crit_vol = 0.000592 # m^3/mol + particles.NC10H22_boil_temp = 452.596977 # K + particles.NC10H22_acentric_factor = 0.468050 # - + particles.NC10H22_molar_vol = 0.000196 # m^3/mol + particles.NC10H22_cp = 1630.488028169014 3098.1056338028166 -1024.456338028169 # J/kg/K + particles.NC10H22_latent = 368035.211268 # J/kg + +To include these parameters in your Pele simulation, copy the ``sprayPropsfl.inp`` +file to the specific case directory and include the following line in your Pele input file: :: + + FILE = sprayPropsfl.inp + + +Note: for liquid fuels from FuelLib with greater than 30 components, the script +will assume that all liquid fuel species deposit to the same gas-phase species, +namely the name of the fuel. This is designed for conventional jet fuels such as POSF10325, where there are +67 liquid fuel species corresponding to the GCxGC data, but only a single +gas-phase mechanism species, "POSF10325". For example: :: + + python Export4Pele.py --fuel_name posf10325 + +will result in the following: :: + + particles.spray_fuel_num = 67 + particles.fuel_species = Toluene C2-Benzene C3-Benzene ... C12-Tricycloparaffin + particles.Y_0 = 0.001610 0.011172 0.0304982 ... 0.00110719 + particles.dep_fuel_names = POSF10325 POSF10325 ... POSF10325 + + # Properties for Toluene in MKS + ... + +Additional Options +^^^^^^^^^^^^^^^^^^ + +There are four additional options that can be specified when running the export script: + +- ``--units``: Specify the units for the properties. The default is "mks" but users can set the units to "cgs" for use in PeleC. +- ``--dep_fuel_names``: Specify which gas-phase species the liquid fuel deposits. The default is the same as the fuel name, but users can specify a single gas-phase species or a list of gas-phase species. +- ``--max_dep_fuels``: Specify the maximum number of dependent fuels. The default is 30 and is a bit arbitrary. +- ``--export_dir``: Specify the directory to export the file. The default is "FuelLib/sprayPropsGCM". + +To specify all liquid fuel species deposity to a single gas-phase species, run the following command: :: + + python Export4Pele.py --fuel_name heptane-decane --dep_fuel_names SINGLE_GAS + +This will result in the following: :: + + particles.spray_fuel_num = 2 + particles.fuel_species = NC7H16 NC10H22 + particles.Y_0 = 0.7375 0.2625 + particles.dep_fuel_names = SINGLE_GAS SINGLE_GAS + + # Properties for NC7H16 in MKS + ... + +Alternatively, to specify a list of gas-phase species, run the following command: :: + + python Export4Pele.py --fuel_name heptane-decane --dep_fuel_names GAS_1 GAS_2 + +which produces: :: + + particles.spray_fuel_num = 2 + particles.fuel_species = NC7H16 NC10H22 + particles.Y_0 = 0.7375 0.2625 + particles.dep_fuel_names = GAS_1 GAS_2 + + # Properties for NC7H16 in MKS + ... + +In the case that the liquid fuel has more than 30 components, the script will +automatically set the deposition mapping to ``fuel.name`` for all components. +If there are more than 30 components and the user wants each component to deposit +to a gas-phase species of the same name, the user can increase ``--max_dep_fuels`` +to a value greater than 30, however this would be required a massive mechanism for Pele and is not advised :: + + python Export4Pele.py --fuel_name posf10325 --max_dep_fuels 67 + + +Exporting GCM-Based Mixture Properties for Converge +--------------------------------------------------- + +The export script, ``Export4Converge.py``, generates a csv file named ``mixturePropsGCM_.csv`` containing +mixture property predictions for a given fuel over a specified temperature range. The properties include: + +- Critical temperature +- Dynamic viscosity +- Surface tension +- Latent heat of vaporization +- Vapor pressure +- Density +- Specific heat +- Thermal conductivity + +.. warning:: + Mixture properties for critical temperature, latent heat, and specific heat are provided by :ref:`conventional-mixing-rules` and need additional validation. + +This example walks through the process and the available options for exporting GCM-based mixture properties for +"posf10325", which is conventional Jet-A, using the ``Export4Converge.py`` script. + +Default Options +^^^^^^^^^^^^^^^ + +From the ``FuelLib`` directory, run the following command in the terminal, noting that ``--fuel_name`` is the only required input: :: + + python Export4Converge.py --fuel_name posf10325 + + +This generates the file ``FuelLib/mixturePropsGCM/mixturePropsGCM_posf10325.csv`` with mixture +property predictions from 0 K to 1000 K for use in a Converge simulation. + +Additional Options +^^^^^^^^^^^^^^^^^^ + +There are four additional options that can be specified when running the export script: + +- ``--units``: Specify the units for the mixture properties. The default is "mks" but users can set the units to "cgs". +- ``--temp_min``: Specify the minimum temperature. The default is 0 K. +- ``--temp_max``: Specify the maximum temperature. The default is 1000 K. +- ``--temp_step``: Specify the temperature step size. The default is :math:`\Delta T = 10` K. +- ``--export_dir``: Specify the directory to export the file. The default is "FuelLib/mixturePropsGCM". + +.. note:: + The mixture property predictions may not be valid from the specified ``temp_min`` to ``temp_max``, + as the mixture properties are based on the GCM properties and correlations of the individual + components. Constant values are set for temperatures below the freezing point of the mixture or above + the minimum critical temperature of all compounds in the fuel. These temperature values will be noted in the + terminal output and should be considered when using the mixture properties in a simulation. + + +.. footbibliography:: \ No newline at end of file diff --git a/fuelData/gcData/decane_init.csv b/fuelData/gcData/decane_init.csv index efff16f..b0d0709 100644 --- a/fuelData/gcData/decane_init.csv +++ b/fuelData/gcData/decane_init.csv @@ -1,2 +1,2 @@ Compound,Weight % -C10H22,100 \ No newline at end of file +NC10H22,100 \ No newline at end of file diff --git a/fuelData/gcData/dodecane_init.csv b/fuelData/gcData/dodecane_init.csv index 3de739c..a9a068e 100644 --- a/fuelData/gcData/dodecane_init.csv +++ b/fuelData/gcData/dodecane_init.csv @@ -1,2 +1,2 @@ Compound,Weight % -C12H26,100 \ No newline at end of file +NC12H26,100 \ No newline at end of file diff --git a/fuelData/gcData/heptane-decane_init.csv b/fuelData/gcData/heptane-decane_init.csv new file mode 100644 index 0000000..70680b1 --- /dev/null +++ b/fuelData/gcData/heptane-decane_init.csv @@ -0,0 +1,3 @@ +Compound,Weight % +NC7H16,73.75 +NC10H22,26.25 \ No newline at end of file diff --git a/fuelData/gcData/heptane_init.csv b/fuelData/gcData/heptane_init.csv index e37df9e..d57c668 100644 --- a/fuelData/gcData/heptane_init.csv +++ b/fuelData/gcData/heptane_init.csv @@ -1,2 +1,2 @@ Compound,Weight % -n-CO7,100 \ No newline at end of file +NC7H16,100 \ No newline at end of file diff --git a/fuelData/groupDecompositionData/decane.csv b/fuelData/groupDecompositionData/decane.csv index dd456ad..2a2d449 100644 --- a/fuelData/groupDecompositionData/decane.csv +++ b/fuelData/groupDecompositionData/decane.csv @@ -1,2 +1,2 @@ Compound,CH3,CH2,CH,C (4),CH2=CH,CH=CH,CH2=C,CH=C,C=C,CH2=C=CH,ACH,AC,ACCH3,ACCH2,ACCH,OH,ACOH,CH3CO,CH2CO,CHO,CH3COO,CH2COO,HCOO,CH3O,CH2O,CH-O,FCH2O,CH2NH2,CHNH2,CH3NH,CH2NH,CHNH,CH3N,CH2N,ACNH2,C5H4N,C5H3N,CH2CN,COOH,CH2CL,CHCL,CCL,CHCL2,CCL2,CCL3,ACCL,CH2NO2,CHNO2,ACNO2,CH2SH,I,Br,CH≡C,C≡c,CL—(C=C),ACF,HCON(CH2)2,CF3,CF2,CF,COO,CCL2F,HCCLF,CCLF2,Fspecial,CONH2,CONHCH3,CONHCH2,CON(CH3)2,CONCH3CH2,CON(CH2)2,C2H5O2,C2H4O2,CH3S,CH2S,CHS,C4H3S,C4H2S,Group j (CH3)2CH,(CH3)3C,CH(CH3)CH(CH3),CH(CH3)C(CH3)2,C(CH3)2C(CH3)2,3 membered ring,4 membered ring,5 membered ring,6 membered ring,7 membered ring,"CHn=CHm—CHp=CHk k,n,m,p in (0,2)","CH3-CHm=CH, m in (0,1), n in (0,2)","CH2-CHm=CHn, m, n in (0,2)","CH-CHm=CHn or C-CHm=CHn, m,n m in (0,2)",Alicyclic side-chain CcyclicCm m > 1,CH3CH3,CHCHO or CCHO,CH3COCH2,CH3COCH or CH3COC,Ccyclic(=0),ACCHO,CHCOOH or CCOOH,ACCOOH,CH3COOCH or CH3COOC,COCH2COO or COCHCOO or COCCOO, CO-O-CO,ACCOO,CHOH,COH,"CHm(OH)CHn(OH), m,n in (0,2)","CHm cyclic-OH, m in (0,1)","CHm(OH)CHn(NHp), m,n,p in (0,3)",CHm(NH2)CHn(NH2),"CHm cyclic-NHp-CHn cyclic, m,n,p in (0,2)","Chm=Chn-F, m,n in (0,2)",AC-O-CHm,"CHm cyclic-S-CHn cyclic, m,n in (0,2)","CHm=CHn—F, m,n in (0,2)","CHm=CHn—Br, m,n in (0,2)","CHm=CHn—I, m,n in (0,2)",ACBr,ACI,"CHm(NH2)-COOH, m,n in (0,2)" -n-C010,2,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 \ No newline at end of file +NC10H22,2,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 \ No newline at end of file diff --git a/fuelData/groupDecompositionData/dodecane.csv b/fuelData/groupDecompositionData/dodecane.csv index e33b205..f75872a 100644 --- a/fuelData/groupDecompositionData/dodecane.csv +++ b/fuelData/groupDecompositionData/dodecane.csv @@ -1,2 +1,2 @@ Compound,CH3,CH2,CH,C (4),CH2=CH,CH=CH,CH2=C,CH=C,C=C,CH2=C=CH,ACH,AC,ACCH3,ACCH2,ACCH,OH,ACOH,CH3CO,CH2CO,CHO,CH3COO,CH2COO,HCOO,CH3O,CH2O,CH-O,FCH2O,CH2NH2,CHNH2,CH3NH,CH2NH,CHNH,CH3N,CH2N,ACNH2,C5H4N,C5H3N,CH2CN,COOH,CH2CL,CHCL,CCL,CHCL2,CCL2,CCL3,ACCL,CH2NO2,CHNO2,ACNO2,CH2SH,I,Br,CH≡C,C≡C,CL—(C=C),ACF,HCON(CH2)2,CF3,CF2,CF,COO,CCL2F,HCCLF,CCLF2,Fspecial,CONH2,CONHCH3,CONHCH2,CON(CH3)2,CONCH3CH2,CON(CH2)2,C2H5O2,C2H4O2,CH3S,CH2S,CHS,C4H3S,C4H2S,Group j (CH3)2CH,(CH3)3C,CH(CH3)CH(CH3),CH(CH3)C(CH3)2,C(CH3)2C(CH3)2,3 membered ring,4 membered ring,5 membered ring,6 membered ring,7 membered ring,"CHn=CHm—CHp=CHk k,n,m,p in (0,2)","CH3-CHm=CH, m in (0,1), n in (0,2)","CH2-CHm=CHn, m, n in (0,2)","CH-CHm=CHn or C-CHm=CHn, m,n m in (0,2)",Alicyclic side-chain CcyclicCm m > 1,CH3CH3,CHCHO or CCHO,CH3COCH2,CH3COCH or CH3COC,Ccyclic(=0),ACCHO,CHCOOH or CCOOH,ACCOOH,CH3COOCH or CH3COOC,COCH2COO or COCHCOO or COCCOO, CO-O-CO,ACCOO,CHOH,COH,"CHm(OH)CHn(OH), m,n in (0,2)","CHm cyclic-OH, m in (0,1)","CHm(OH)CHn(NHp), m,n,p in (0,3)",CHm(NH2)CHn(NH2),"CHm cyclic-NHp-CHn cyclic, m,n,p in (0,2)","Chm=Chn-F, m,n in (0,2)",AC-O-CHm,"CHm cyclic-S-CHn cyclic, m,n in (0,2)","CHm=CHn—F, m,n in (0,2)","CHm=CHn—Br, m,n in (0,2)","CHm=CHn—I, m,n in (0,2)",ACBr,ACI,"CHm(NH2)-COOH, m,n in (0,2)" -C12H26,2,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 \ No newline at end of file +NC12H26,2,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 \ No newline at end of file diff --git a/fuelData/groupDecompositionData/heptane-decane.csv b/fuelData/groupDecompositionData/heptane-decane.csv new file mode 100644 index 0000000..8ec702e --- /dev/null +++ b/fuelData/groupDecompositionData/heptane-decane.csv @@ -0,0 +1,3 @@ +Compound,CH3,CH2,CH,C (4),CH2=CH,CH=CH,CH2=C,CH=C,C=C,CH2=C=CH,ACH,AC,ACCH3,ACCH2,ACCH,OH,ACOH,CH3CO,CH2CO,CHO,CH3COO,CH2COO,HCOO,CH3O,CH2O,CH-O,FCH2O,CH2NH2,CHNH2,CH3NH,CH2NH,CHNH,CH3N,CH2N,ACNH2,C5H4N,C5H3N,CH2CN,COOH,CH2CL,CHCL,CCL,CHCL2,CCL2,CCL3,ACCL,CH2NO2,CHNO2,ACNO2,CH2SH,I,Br,CH≡C,C≡C,CL—(C=C),ACF,HCON(CH2)2,CF3,CF2,CF,COO,CCL2F,HCCLF,CCLF2,Fspecial,CONH2,CONHCH3,CONHCH2,CON(CH3)2,CONCH3CH2,CON(CH2)2,C2H5O2,C2H4O2,CH3S,CH2S,CHS,C4H3S,C4H2S,Group j (CH3)2CH,(CH3)3C,CH(CH3)CH(CH3),CH(CH3)C(CH3)2,C(CH3)2C(CH3)2,3 membered ring,4 membered ring,5 membered ring,6 membered ring,7 membered ring,"CHn=CHm—CHp=CHk k,n,m,p in (0,2)","CH3-CHm=CH, m in (0,1), n in (0,2)","CH2-CHm=CHn, m, n in (0,2)","CH-CHm=CHn or C-CHm=CHn, m,n m in (0,2)",Alicyclic side-chain CcyclicCm m > 1,CH3CH3,CHCHO or CCHO,CH3COCH2,CH3COCH or CH3COC,Ccyclic(=0),ACCHO,CHCOOH or CCOOH,ACCOOH,CH3COOCH or CH3COOC,COCH2COO or COCHCOO or COCCOO, CO-O-CO,ACCOO,CHOH,COH,"CHm(OH)CHn(OH), m,n in (0,2)","CHm cyclic-OH, m in (0,1)","CHm(OH)CHn(NHp), m,n,p in (0,3)",CHm(NH2)CHn(NH2),"CHm cyclic-NHp-CHn cyclic, m,n,p in (0,2)","Chm=Chn-F, m,n in (0,2)",AC-O-CHm,"CHm cyclic-S-CHn cyclic, m,n in (0,2)","CHm=CHn—F, m,n in (0,2)","CHm=CHn—Br, m,n in (0,2)","CHm=CHn—I, m,n in (0,2)",ACBr,ACI,"CHm(NH2)-COOH, m,n in (0,2)" +NC7H16,2,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +NC10H22,2,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 \ No newline at end of file diff --git a/fuelData/groupDecompositionData/heptane.csv b/fuelData/groupDecompositionData/heptane.csv index 8796cd3..a4beac3 100644 --- a/fuelData/groupDecompositionData/heptane.csv +++ b/fuelData/groupDecompositionData/heptane.csv @@ -1,2 +1,2 @@ Compound,CH3,CH2,CH,C (4),CH2=CH,CH=CH,CH2=C,CH=C,C=C,CH2=C=CH,ACH,AC,ACCH3,ACCH2,ACCH,OH,ACOH,CH3CO,CH2CO,CHO,CH3COO,CH2COO,HCOO,CH3O,CH2O,CH-O,FCH2O,CH2NH2,CHNH2,CH3NH,CH2NH,CHNH,CH3N,CH2N,ACNH2,C5H4N,C5H3N,CH2CN,COOH,CH2CL,CHCL,CCL,CHCL2,CCL2,CCL3,ACCL,CH2NO2,CHNO2,ACNO2,CH2SH,I,Br,CH≡C,C≡C,CL—(C=C),ACF,HCON(CH2)2,CF3,CF2,CF,COO,CCL2F,HCCLF,CCLF2,Fspecial,CONH2,CONHCH3,CONHCH2,CON(CH3)2,CONCH3CH2,CON(CH2)2,C2H5O2,C2H4O2,CH3S,CH2S,CHS,C4H3S,C4H2S,Group j (CH3)2CH,(CH3)3C,CH(CH3)CH(CH3),CH(CH3)C(CH3)2,C(CH3)2C(CH3)2,3 membered ring,4 membered ring,5 membered ring,6 membered ring,7 membered ring,"CHn=CHm—CHp=CHk k,n,m,p in (0,2)","CH3-CHm=CH, m in (0,1), n in (0,2)","CH2-CHm=CHn, m, n in (0,2)","CH-CHm=CHn or C-CHm=CHn, m,n m in (0,2)",Alicyclic side-chain CcyclicCm m > 1,CH3CH3,CHCHO or CCHO,CH3COCH2,CH3COCH or CH3COC,Ccyclic(=0),ACCHO,CHCOOH or CCOOH,ACCOOH,CH3COOCH or CH3COOC,COCH2COO or COCHCOO or COCCOO, CO-O-CO,ACCOO,CHOH,COH,"CHm(OH)CHn(OH), m,n in (0,2)","CHm cyclic-OH, m in (0,1)","CHm(OH)CHn(NHp), m,n,p in (0,3)",CHm(NH2)CHn(NH2),"CHm cyclic-NHp-CHn cyclic, m,n,p in (0,2)","Chm=Chn-F, m,n in (0,2)",AC-O-CHm,"CHm cyclic-S-CHn cyclic, m,n in (0,2)","CHm=CHn—F, m,n in (0,2)","CHm=CHn—Br, m,n in (0,2)","CHm=CHn—I, m,n in (0,2)",ACBr,ACI,"CHm(NH2)-COOH, m,n in (0,2)" -n-C07,2,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 \ No newline at end of file +NC7H16,2,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 \ No newline at end of file diff --git a/tests/baselinePredictions/posf10264.csv b/tests/baselinePredictions/posf10264.csv index ecd7541..8504197 100644 --- a/tests/baselinePredictions/posf10264.csv +++ b/tests/baselinePredictions/posf10264.csv @@ -1,13 +1,13 @@ Temperature,Density,Error_Density,Viscosity,Error_Viscosity,VaporPressure,Error_VaporPressure,SurfaceTension,Error_SurfaceTension,ThermalConductivity,Error_ThermalConductivity C,g/cm^3,g/cm^3,mm^2/s,mm^2/s,kPa,kPa,N/m,N/m,W/m/K,W/m/K --40.0,0.8168172198262019,0.006157780173798089,6.051549516393376,0.548450483606624,,,,,, --20.0,0.8031633952190618,0.0054366047809382145,3.519620151263789,0.0196201512637888,,,,,, --10.0,,,,,,,0.027464306235608867,0.0016218672356088683,, -0.0,0.7892487026600817,0.004976297339918223,,,0.14038873920043515,0.09203840920043516,,,0.13001682161843095,0.0009783596184309573 -20.0,0.7750496938811732,0.004800306118826869,,,0.42645244481763017,0.20210184018236982,0.02488596131656372,0.001049723316563722,, -30.0,,,,,,,,,0.1238976396517731,0.00014082234822690443 -40.0,0.7605393184863175,0.0047440145136824485,1.1995687356322697,0.05956873563226983,1.1410418332585637,0.26111772474143624,0.023193676178117118,0.0003600091781171197,0.12189631568305907,0.0018963156830590772 -60.0,,,,,2.7424186076739625,0.6904547933260377,,,0.11793039473473628,0.0017765487347362746 -80.0,,,,,6.009962670288152,1.3876377577118477,,,, -100.0,,,0.6311083846632891,0.021108384663289126,12.154315130184294,2.447484409815706,,,, -120.0,,,,,22.911749852682078,3.6809314273179226,,,, +-40.0,0.8168172198262019,0.006157780173798089,5.504172261461431,1.0958277385385689,,,,,, +-20.0,0.8031633952190618,0.0054366047809382145,3.2462244010117867,0.25377559898821334,,,,,, +-10.0,,,,,,,0.02767774328247316,0.0018353042824731623,, +0.0,0.7892487026600817,0.004976297339918223,,,0.18793495991304693,0.13958462991304693,,,0.13010257682106796,0.0010641148210679685 +20.0,0.7750496938811732,0.004800306118826869,,,0.5607677251346005,0.0677865598653995,0.025048880646984642,0.0012126426469846428,, +30.0,,,,,,,,,0.1239264112971942,0.0001120507028058021 +40.0,0.7605393184863175,0.0047440145136824485,1.1346882321275127,0.005311767872487216,1.4733321654813216,0.0711726074813217,0.023323787531678266,0.0004901205316782675,0.12190512809135769,0.0019051280913576912 +60.0,,,,,3.4779394114749382,0.04506601047493808,,,0.11789748590465501,0.0017436399046550088 +80.0,,,,,7.491327128894398,0.09372670089439872,,,, +100.0,,,0.6050927435154413,0.0049072564845586975,14.906136104495566,0.304336564495566,,,, +120.0,,,,,27.67995358417797,1.0872723041779686,,,, diff --git a/tests/baselinePredictions/posf10289.csv b/tests/baselinePredictions/posf10289.csv index 0b4e30c..d03a05e 100644 --- a/tests/baselinePredictions/posf10289.csv +++ b/tests/baselinePredictions/posf10289.csv @@ -1,15 +1,15 @@ Temperature,Density,Error_Density,Viscosity,Error_Viscosity,VaporPressure,Error_VaporPressure,SurfaceTension,Error_SurfaceTension,ThermalConductivity,Error_ThermalConductivity C,g/cm^3,g/cm^3,mm^2/s,mm^2/s,kPa,kPa,N/m,N/m,W/m/K,W/m/K --40.0,,,8.706261480288557,5.393738519711443,,,,,, --20.0,,,4.807289496514161,1.6927105034858387,,,,,, --10.0,,,,,,,0.028784261047040637,0.00036283104704063623,, -0.0,0.8368640754931359,0.001827591506864068,,,0.049850080762665436,0.0014997507626654388,,,, -20.0,0.8230824683603558,0.0008508646396442332,,,0.16179638875944455,0.17665591824055546,0.026317105629007336,0.0005895946290073346,, -30.0,,,,,,,,,0.1095703946312613,0.008410374368738704 -40.0,0.8090296823758196,0.0007203176241803444,1.4890334549970374,0.08096654500296263,0.4600255086687159,0.024872542668715913,0.024695408978026502,2.9530021973499243e-05,, -60.0,,,,,1.1687215396208384,0.13673735937916165,,,, -75.0,,,,,,,,,0.1022063027916717,0.006736005208328302 -80.0,,,,,2.6944655292086086,0.6417072127913914,,,, -100.0,,,0.7437881790171854,0.016211820982814595,5.7083443848269795,0.6738991211730205,,,, -120.0,,,,,11.229706166647922,2.550137763352078,,,, -125.0,,,,,,,,,0.09416672047398948,0.00669866452601052 +-40.0,,,8.13990895923947,5.960091040760529,,,,,, +-20.0,,,4.538236530580061,1.9617634694199388,,,,,, +-10.0,,,,,,,0.028979688828468762,0.0005582588284687613,, +0.0,0.8368640754931359,0.001827591506864068,,,0.06751068415419094,0.019160354154190942,,,, +20.0,0.8230824683603558,0.0008508646396442332,,,0.21396053492709474,0.12449177207290527,0.026475312206921894,0.0007478012069218921,, +30.0,,,,,,,,,0.11012508761760324,0.007855681382396756 +40.0,0.8090296823758196,0.0007203176241803444,1.4308523671028688,0.13914763289713128,0.5946172851924806,0.1594643191924806,0.02482937749446885,0.00010443849446884965,, +60.0,,,,,1.4785951435944569,0.17313624459445687,,,, +75.0,,,,,,,,,0.10267963182249136,0.0062626761775086415 +80.0,,,,,3.3418202795761762,0.005647537576176198,,,, +100.0,,,0.7216190826614485,0.038380917338551535,6.9522470047918405,0.5700034987918405,,,, +120.0,,,,,13.453084074016212,0.3267598559837879,,,, +125.0,,,,,,,,,0.09454072544230083,0.006324659557699175 diff --git a/tests/baselinePredictions/posf10325.csv b/tests/baselinePredictions/posf10325.csv index cbb4cb4..daddd6f 100644 --- a/tests/baselinePredictions/posf10325.csv +++ b/tests/baselinePredictions/posf10325.csv @@ -1,12 +1,12 @@ Temperature,Density,Error_Density,Viscosity,Error_Viscosity,VaporPressure,Error_VaporPressure,SurfaceTension,Error_SurfaceTension,ThermalConductivity,Error_ThermalConductivity C,g/cm^3,g/cm^3,mm^2/s,mm^2/s,kPa,kPa,N/m,N/m,W/m/K,W/m/K --40.0,0.8407245600223795,0.003142106977620518,7.327450357477861,1.872549642522138,,,,,, --20.0,0.8272451036292856,0.002438229370714362,4.142782657382329,0.3572173426176706,,,,,, --10.0,,,,,,,0.02822092897101752,0.0001925259710175188,, -0.0,0.8135198789271101,0.0015967880728898765,,,0.10060971089776095,0.05225938089776096,,,0.12287925765691673,0.0013515113430832698 -20.0,0.799527797349555,0.002172202650444932,,,0.31002294762258614,0.12513001837741383,0.025689441644058383,0.000870702644058384,0.11912057824575477,0.0010717297542452292 -40.0,0.7852446835087796,0.002080316491220424,1.3415594732535097,0.03155947325350961,0.8390728292355918,0.017117226235591754,0.024026679332593448,0.0004070473325934465,0.11544504546942812,0.0006126465305718864 -60.0,,,,,2.0363027068420876,0.2361627841579126,,,0.11182735967192953,0.0003841783280704725 -80.0,,,,,4.501990474917265,0.4297431440827353,,,, -100.0,,,0.6868084919928388,0.006808491992838728,9.182166700648937,0.6813005363510634,,,, -120.0,,,,,17.455667845520445,1.3042600344795545,,,, +-40.0,0.8407245600223795,0.003142106977620518,6.681530139926496,2.5184698600735036,,,,,, +-20.0,0.8272451036292856,0.002438229370714362,3.829156453437944,0.6708435465620561,,,,,, +-10.0,,,,,,,0.02845275184318056,0.0004243488431805581,, +0.0,0.8135198789271101,0.0015967880728898765,,,0.13729717658561572,0.08894684658561572,,,0.12322910486799102,0.0010016641320089864 +20.0,0.799527797349555,0.002172202650444932,,,0.41508022057018,0.02007274542981996,0.02587160548393405,0.001052866483934052,0.11943166440945686,0.0007606435905431336 +40.0,0.7852446835087796,0.002080316491220424,1.2708416560666673,0.03915834393333273,1.1021089809141875,0.2801533779141875,0.024176552222869102,0.0005569202228691006,0.11571607356306363,0.00034161843693637783 +60.0,,,,,2.624808749444473,0.3523432584444728,,,0.1120566035167615,0.00015493448323850023 +80.0,,,,,5.698939254945763,0.7672056359457633,,,, +100.0,,,0.6592182066733121,0.020781793326687947,11.425993375447765,1.5625261384477653,,,, +120.0,,,,,21.37702866298674,2.617100782986739,,,, diff --git a/tests/test_accuracy.py b/tests/test_accuracy.py index 7cb633e..f51bd05 100644 --- a/tests/test_accuracy.py +++ b/tests/test_accuracy.py @@ -35,13 +35,6 @@ def test_accuracy(self): "ThermalConductivity", ] - # droplet specs - drop = {} - drop["d_0"] = ( - 100 * 1e-6 - ) # initial droplet diameter (m), note: size doesn't matter - drop["r_0"] = drop["d_0"] / 2.0 # initial droplet radius (m) - # Compare to NIST predictions and previous model predictions for fuel_name in fuel_names: @@ -59,7 +52,7 @@ def test_accuracy(self): sum_err_base += sum_err_base * max_error_diff # Get predictions for current model - T, data, pred = fxns.getPredAndData(drop, fuel_name, prop) + T, data, pred = fxns.getPredAndData(fuel_name, prop) err = np.abs(data - pred) sum_err = np.sum(err) diff --git a/tests/test_baseline.py b/tests/test_baseline.py index efe2bfb..d39df48 100644 --- a/tests/test_baseline.py +++ b/tests/test_baseline.py @@ -12,7 +12,7 @@ # Add the FuelLib directory to the Python path fuellib_dir = os.path.dirname(os.path.dirname(__file__)) sys.path.append(fuellib_dir) -import GroupContributionMethod as gcm +import FuelLib as fl # Directories for tests and baseline predictions test_dir = os.path.dirname(__file__) @@ -49,13 +49,6 @@ def get_unit_for_column(col_name): return "" -# droplet specs -drop = {} -drop["d_0"] = 100 * 1e-6 # initial droplet diameter (m), note: size doesn't matter -drop["r_0"] = drop["d_0"] / 2.0 # initial droplet radius (m) -drop["V_0"] = 4.0 / 3.0 * np.pi * drop["r_0"] ** 3 # initial droplet volume - - # Loop through each fuel and generate csv of baseline property predictions for fuel_name in fuel_names: @@ -63,7 +56,7 @@ def get_unit_for_column(col_name): df_combined = None for prop in prop_names: - T, data, pred = fxns.getPredAndData(drop, fuel_name, prop) + T, data, pred = fxns.getPredAndData(fuel_name, prop) # Create a dataframe for this property df_prop = pd.DataFrame( diff --git a/tests/test_functions.py b/tests/test_functions.py index 2c0deb0..c21dd32 100644 --- a/tests/test_functions.py +++ b/tests/test_functions.py @@ -6,15 +6,12 @@ # Add the FuelLib directory to the Python path fuellib_dir = os.path.dirname(os.path.dirname(__file__)) sys.path.append(fuellib_dir) -import GroupContributionMethod as gcm +import FuelLib as fl -def getPredAndData(drop, fuel_name, prop_name): +def getPredAndData(fuel_name, prop_name): # Get the fuel properties based on the GCM - fuel = gcm.groupContribution(fuel_name) - - # initial liquid mass fractions - Y_li = fuel.Y_0 + fuel = fl.groupContribution(fuel_name) data_file = f"{fuel_name}.csv" dataPath = os.path.join(fuel.fuelDataDir, "propertiesData") @@ -27,42 +24,33 @@ def getPredAndData(drop, fuel_name, prop_name): # Vector for predictions pred = np.zeros_like(T_data) - T_pred = gcm.C2K(T_data) + # Vectors for temperature (convert from C to K) + T_pred = fl.C2K(T_data) + + for i in range(0, len(T_pred)): + Y_li = fuel.Y_0 - if prop_name == "Density": - for i in range(0, len(T_pred)): + if prop_name == "Density": # Mixture density (returns rho in kg/m^3) - pred[i] = fuel.mixture_density(fuel.Y_0, T_pred[i]) + pred[i] = fuel.mixture_density(Y_li, T_pred[i]) # Convert density to CGS (g/cm^3) pred[i] *= 1.0e-03 - if prop_name == "VaporPressure": - for i in range(0, len(T_pred)): - # Mass of the droplet at current temp - mass = gcm.drop_mass(fuel, drop["r_0"], Y_li, T_pred[i]) + if prop_name == "VaporPressure": # Mixture vapor pressure (returns pv in Pa) - pred[i] = fuel.mixture_vapor_pressure(mass, T_pred[i]) + pred[i] = fuel.mixture_vapor_pressure(Y_li, T_pred[i]) # Convert vapor pressure to kPa pred[i] *= 1.0e-03 - if prop_name == "Viscosity": - for i in range(0, len(T_pred)): - # Mass of the droplet at current temp - mass = gcm.drop_mass(fuel, drop["r_0"], Y_li, T_pred[i]) - pred[i] = fuel.mixture_kinematic_viscosity(mass, T_pred[i]) + if prop_name == "Viscosity": + pred[i] = fuel.mixture_kinematic_viscosity(Y_li, T_pred[i]) # Convert viscosity to mm^2/s pred[i] *= 1.0e06 - if prop_name == "SurfaceTension": - for i in range(0, len(T_pred)): - # Mass of the droplet at current temp - mass = gcm.drop_mass(fuel, drop["r_0"], Y_li, T_pred[i]) - pred[i] = fuel.mixture_surface_tension(mass, T_pred[i]) + if prop_name == "SurfaceTension": + pred[i] = fuel.mixture_surface_tension(Y_li, T_pred[i]) - if prop_name == "ThermalConductivity": - for i in range(0, len(T_pred)): - # Mass of the droplet at current temp - mass = gcm.drop_mass(fuel, drop["r_0"], Y_li, T_pred[i]) - pred[i] = fuel.mixture_thermal_conductivity(mass, T_pred[i]) + if prop_name == "ThermalConductivity": + pred[i] = fuel.mixture_thermal_conductivity(Y_li, T_pred[i]) return T_data, prop_data, pred diff --git a/tutorials/basic.py b/tutorials/basic.py new file mode 100644 index 0000000..3a28644 --- /dev/null +++ b/tutorials/basic.py @@ -0,0 +1,24 @@ +import os +import sys +import numpy as np + +# Add the FuelLib directory to the Python path +fuellib_dir = os.path.dirname(os.path.dirname(__file__)) +sys.path.append(fuellib_dir) +import FuelLib as fl + +# Create a groupContribution object for the fuel "heptane-decane" +fuel = fl.groupContribution("heptane-decane") + +# Display fuel name, components, initial composition, and critical temperature +print(f"Fuel name: {fuel.name}") +print(f"Fuel components: {fuel.compounds}") +print(f"Initial composition: {fuel.Y_0}") +print(f"Critical temperature: {fuel.Tc} K") + +# Calculate the saturated vapor pressure at 320 K +T = 320 # K +p_sat_i = fuel.psat(T) +p_sat_mix = fuel.mixture_vapor_pressure(fuel.Y_0, T) +print(f"Saturated vapor pressure at {T} K: {p_sat_i} Pa") +print(f"Mixture saturated vapor pressure at {T} K: {p_sat_mix:.2f} Pa") diff --git a/examples/ex_compositionPlots.py b/tutorials/compositionPlots.py similarity index 68% rename from examples/ex_compositionPlots.py rename to tutorials/compositionPlots.py index 4561c52..dc030c0 100644 --- a/examples/ex_compositionPlots.py +++ b/tutorials/compositionPlots.py @@ -8,33 +8,32 @@ # Add the FuelLib directory to the Python path fuellib_dir = os.path.dirname(os.path.dirname(__file__)) sys.path.append(fuellib_dir) -import GroupContributionMethod as gcm +import FuelLib as fl fuel_name = "posf10325" -fuel = gcm.groupContribution(fuel_name) - -# Read gcxgc file -gcxgcFile = os.path.join(fuel.gcxgcDir, f"{fuel.name}_init.csv") -df = pd.read_csv( - gcxgcFile, -) - -# Get column names -colNames = df.columns.tolist() - -# Classify rows based on the first column: -# if df[colNames[0]] contains Toluene, Benzene or aromatic, then classify as aromatic -aromatic = df[colNames[0]].str.contains( - "Toluene|Benzene|Aromatic", case=False, na=False -) -# if df[colNames[0]] contains n-C, then classify as n-alkane -n_alkane = df[colNames[0]].str.contains("n-C", case=False, na=False) -# if df[colNames[0]] contains isoparaffin, then classify as iso-alkane -isoalkane = df[colNames[0]].str.contains("Isoparaffin", case=False, na=False) -# if df[colNames[0]] contains cycloparaffin, then classify as cyclo-alkane -cycloalkane = df[colNames[0]].str.contains("Cycloparaffin", case=False, na=False) - +fuel = fl.groupContribution(fuel_name) + +# Classify compounds into families +aromatic = [ + True if re.search(r"Toluene|Benzene|Aromatic", comp, re.IGNORECASE) else False + for comp in fuel.compounds +] +n_alkane = [ + True if re.search(r"n-C", comp, re.IGNORECASE) else False for comp in fuel.compounds +] +isoalkane = [ + True if re.search(r"Isoparaffin", comp, re.IGNORECASE) else False + for comp in fuel.compounds +] +cycloalkane = [ + True if re.search(r"Cycloparaffin", comp, re.IGNORECASE) else False + for comp in fuel.compounds +] + +# Create a DataFrame with the compounds and their families +colNames = ["Compound", "Weight %"] +df = pd.DataFrame({"Compounds": fuel.compounds, "Weight %": fuel.Y_0 * 100}) # Append classification as a new column family_names = ["n-alkane", "iso-alkane", "cyclo-alkane", "aromatic"] df["Family"] = np.select( @@ -70,10 +69,10 @@ def determine_carbon_number(compound): # Apply the function to the column and append as a new column -df["nC"] = df[colNames[0]].apply(determine_carbon_number) +df["nC"] = df.Compounds.apply(determine_carbon_number) # Remove rows <= 0.01 in weight % column at max(nC) -df = df[df[colNames[1]] > 0.01] +df = df[df["Weight %"] > 0.01] # Plotting parameters spacing = [-0.2985, -0.099, 0.099, 0.2985] @@ -89,16 +88,16 @@ def determine_carbon_number(compound): N = df.nC.unique() for k, family in enumerate(family_names): nC = df[df["Family"] == family].nC - weight = df[df["Family"] == family][colNames[1]] + weight = df[df["Family"] == family]["Weight %"] # check duplicate nC values if len(nC) != len(set(nC)): # If there are duplicates, sum the weights for each nC df_grouped = ( - df[df["Family"] == family].groupby("nC")[colNames[1]].sum().reset_index() + df[df["Family"] == family].groupby("nC")["Weight %"].sum().reset_index() ) nC = df_grouped["nC"] - weight = df_grouped[colNames[1]] + weight = df_grouped["Weight %"] plt.bar( nC + spacing[k], weight, label=family, alpha=1, color=colors[family], width=0.2 ) diff --git a/examples/ex_hefaBlends.py b/tutorials/hefaBlends.py similarity index 81% rename from examples/ex_hefaBlends.py rename to tutorials/hefaBlends.py index bbfaaaa..212f10d 100644 --- a/examples/ex_hefaBlends.py +++ b/tutorials/hefaBlends.py @@ -7,7 +7,7 @@ # Add the FuelLib directory to the Python path fuellib_dir = os.path.dirname(os.path.dirname(__file__)) sys.path.append(fuellib_dir) -import GroupContributionMethod as gcm +import FuelLib as fl # ----------------------------------------------------------------------------- # Calculate mixture properties from the group contribution properties @@ -27,11 +27,6 @@ line_thickness = 4 marker_size = 75 -# droplet specs -drop = {} -drop["d_0"] = 100 * 1e-6 # initial droplet diameter (m), note: size doesn't matter -drop["r_0"] = drop["d_0"] / 2.0 # initial droplet radius (m) - # Line specifications for plotting def linespecs(name): @@ -65,8 +60,8 @@ def getPredAndData(fuel_name, prop_name, blend): blend = np.array(blend) * 1e-2 # Convert to weight percent # Get the fuel properties based on the GCM - fuel = gcm.groupContribution(fuel_name, "hefa") - jetA = gcm.groupContribution(conv_fuel_name) + fuel = fl.groupContribution(fuel_name, "hefa") + jetA = fl.groupContribution(conv_fuel_name) data_file = "hefa-jet-a-blends.csv" dataPath = os.path.join(fuel.fuelDataDir, "propertiesData") @@ -77,29 +72,28 @@ def getPredAndData(fuel_name, prop_name, blend): # Separate properties and associated temperatures from data if prop_name == "Density": - T = gcm.C2K(15) + T = fl.C2K(15) elif prop_name == "Viscosity": - T = gcm.C2K(-20) + T = fl.C2K(-20) # Vector for FuelLib predictions prop_pred = np.zeros_like(blend) - if prop_name == "Density": - for i in range(0, len(prop_pred)): - # initial liquid mass fractions - Y_li = blend[i] * fuel.Y_0 + (1 - blend[i]) * jetA.Y_0 + for i in range(0, len(prop_pred)): + # Initial liquid mass fractions + Y_li = blend[i] * fuel.Y_0 + (1 - blend[i]) * jetA.Y_0 + + if prop_name == "Density": # Mixture density (returns rho in kg/m^3) prop_pred[i] = fuel.mixture_density(Y_li, T) # Convert density to CGS (g/cm^3) prop_pred[i] *= 1.0e-03 - if prop_name == "Viscosity": - for i in range(0, len(prop_pred)): + if prop_name == "Viscosity": # initial liquid mass fractions Y_li = blend[i] * fuel.Y_0 + (1 - blend[i]) * jetA.Y_0 - # Mass of the droplet at current temp - mass = gcm.drop_mass(fuel, drop["r_0"], Y_li, T) - prop_pred[i] = fuel.mixture_kinematic_viscosity(mass, T) + + prop_pred[i] = fuel.mixture_kinematic_viscosity(Y_li, T) # Convert viscosity to mm^2/s prop_pred[i] *= 1.0e06 @@ -149,7 +143,7 @@ def getPredAndData(fuel_name, prop_name, blend): # Add labels and adjust ticks ax[i].set_xlabel("HEFA Concentration [wt %]", fontsize=fsize) ax[i].set_xticks([0, 20, 40, 60, 80, 100]) - ax[i].set_ylabel(ylab(prop_names[i], gcm.K2C(T)), fontsize=fsize) + ax[i].set_ylabel(ylab(prop_names[i], fl.K2C(T)), fontsize=fsize) ax[i].tick_params(labelsize=ticksize) handles, labels = ax[0].get_legend_handles_labels() diff --git a/examples/ex_mixtureProperties.py b/tutorials/mixtureProperties.py similarity index 74% rename from examples/ex_mixtureProperties.py rename to tutorials/mixtureProperties.py index 04b7e50..ea96bef 100644 --- a/examples/ex_mixtureProperties.py +++ b/tutorials/mixtureProperties.py @@ -7,7 +7,7 @@ # Add the FuelLib directory to the Python path fuellib_dir = os.path.dirname(os.path.dirname(__file__)) sys.path.append(fuellib_dir) -import GroupContributionMethod as gcm +import FuelLib as fl # ----------------------------------------------------------------------------- # Calculate mixture properties from the group contribution properties @@ -33,11 +33,6 @@ line_thickness = 4 marker_size = 75 -# droplet specs -drop = {} -drop["d_0"] = 100 * 1e-6 # initial droplet diameter (m), note: size doesn't matter -drop["r_0"] = drop["d_0"] / 2.0 # initial droplet radius (m) - # Line specifications for plotting def linespecs(name): @@ -89,10 +84,7 @@ def leglab(name): def getPredAndData(fuel_name, prop_name): # Get the fuel properties based on the GCM - fuel = gcm.groupContribution(fuel_name) - - # initial liquid mass fractions - Y_li = fuel.Y_0 + fuel = fl.groupContribution(fuel_name) data_file = f"{fuel_name}.csv" dataPath = os.path.join(fuel.fuelDataDir, "propertiesData") @@ -103,46 +95,36 @@ def getPredAndData(fuel_name, prop_name): prop_data = data[prop_name].dropna() # Vectors for temperature (convert from C to K) - T_pred = gcm.C2K(np.linspace(min(T_data), max(T_data), 100)) + T_pred = fl.C2K(np.linspace(min(T_data), max(T_data), 100)) # Vectors for density, viscosity and vapor pressure pred = np.zeros_like(T_pred) - if prop_name == "Density": - for i in range(0, len(T_pred)): + for i in range(0, len(T_pred)): + Y_li = fuel.Y_0 + + if prop_name == "Density": # Mixture density (returns rho in kg/m^3) - pred[i] = fuel.mixture_density(fuel.Y_0, T_pred[i]) + pred[i] = fuel.mixture_density(Y_li, T_pred[i]) # Convert density to CGS (g/cm^3) pred[i] *= 1.0e-03 - if prop_name == "VaporPressure": - for i in range(0, len(T_pred)): - # Mass of the droplet at current temp - mass = gcm.drop_mass(fuel, drop["r_0"], Y_li, T_pred[i]) + if prop_name == "VaporPressure": # Mixture vapor pressure (returns pv in Pa) - pred[i] = fuel.mixture_vapor_pressure(mass, T_pred[i]) + pred[i] = fuel.mixture_vapor_pressure(Y_li, T_pred[i]) # Convert vapor pressure to kPa pred[i] *= 1.0e-03 - if prop_name == "Viscosity": - for i in range(0, len(T_pred)): - # Mass of the droplet at current temp - mass = gcm.drop_mass(fuel, drop["r_0"], Y_li, T_pred[i]) - pred[i] = fuel.mixture_kinematic_viscosity(mass, T_pred[i]) + if prop_name == "Viscosity": + pred[i] = fuel.mixture_kinematic_viscosity(Y_li, T_pred[i]) # Convert viscosity to mm^2/s pred[i] *= 1.0e06 - if prop_name == "SurfaceTension": - for i in range(0, len(T_pred)): - # Mass of the droplet at current temp - mass = gcm.drop_mass(fuel, drop["r_0"], Y_li, T_pred[i]) - pred[i] = fuel.mixture_surface_tension(mass, T_pred[i]) + if prop_name == "SurfaceTension": + pred[i] = fuel.mixture_surface_tension(Y_li, T_pred[i]) - if prop_name == "ThermalConductivity": - for i in range(0, len(T_pred)): - # Mass of the droplet at current temp - mass = gcm.drop_mass(fuel, drop["r_0"], Y_li, T_pred[i]) - pred[i] = fuel.mixture_thermal_conductivity(mass, T_pred[i]) + if prop_name == "ThermalConductivity": + pred[i] = fuel.mixture_thermal_conductivity(Y_li, T_pred[i]) return T_data, prop_data, T_pred, pred @@ -158,7 +140,7 @@ def getPredAndData(fuel_name, prop_name): # Plot GCM predictions and data ax[i].plot( - gcm.K2C(T), + fl.K2C(T), pred, "-", color=line_color,