Advertisement
phystota

512 python

Dec 16th, 2024
37
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.69 KB | None | 0 0
  1. # main.py
  2.  
  3. import numpy as np
  4. from RHjump import calculate_rh_conditions
  5. from species import calculate_thermodynamic_properties
  6. from mixture import compute_cp, get_mixture_properties  # Importing necessary functions
  7.  
  8. def initialize_composition():
  9.     """
  10.    Initialize the gas mixture composition (N2/N Mixture).
  11.    """
  12.     # Example composition: 100% N2, 0% N
  13.     return 1.0  # Return y (mole fraction of N2)
  14.  
  15. def simulate_shock_flow(x_max, post_shock_conditions):
  16.     """
  17.    Simulate the flow downstream of the shock.
  18.    """
  19.     # Placeholder for flow field simulation
  20.     return {
  21.         "x": np.linspace(0, x_max, 100),
  22.         "rho_s": None,
  23.         "T": None,
  24.         "Tv": None,
  25.         "U": None
  26.     }
  27.  
  28. def main():
  29.     """
  30.    The main program computes the flowfield in a shock tube.
  31.    """
  32.     # Initialize parameters
  33.     P1 = 5.0        # Pre-shock pressure [Pa]
  34.     T1 = 200.0      # Pre-shock temperature [K]
  35.     TV1 = T1        # Pre-shock vibrational temperature [K]
  36.     U1 = 7000.0     # Shock speed [m/s]
  37.     x_max = 0.1     # Standoff distance [m]
  38.  
  39.     # Initialize composition
  40.     y = initialize_composition()  # Mole fraction of N2
  41.  
  42.     # Load species data
  43.     species_data = np.loadtxt("data2.txt", skiprows=1)
  44.    
  45.     print("Shock-Tube Simulation")
  46.     print("========================================")
  47.     print("Mixture: N2/N")
  48.  
  49.     # Calculate properties for N (species_idx=0) at T=7000 K
  50.     properties_N = calculate_thermodynamic_properties(
  51.         temperature=7000,
  52.         species_idx=0,
  53.         species_data=species_data
  54.     )
  55.  
  56.     # Access and display the results
  57.     print(f"Q_in: {properties_N['Q_in']}")
  58.     print(f"Q_tr: {properties_N['Q_tr']}")
  59.     print(f"Q_total: {properties_N['Q_total']}")
  60.     print(f"Entropy: {properties_N['S']} J/mol/K")
  61.     print(f"H-H0: {properties_N['H_H0']} J/mol")
  62.  
  63.     # Compute Cp for each species at T = 7000 K
  64.     Cp_N = compute_cp(T=7000, species_idx=0, species_data=species_data)
  65.     Cp_N2 = compute_cp(T=7000, species_idx=1, species_data=species_data)
  66.  
  67.     print(f"Cp (N): {Cp_N} J/mol/K")
  68.     print(f"Cp (N2): {Cp_N2} J/mol/K")
  69.  
  70.     # Compute mixture properties including Cp
  71.     mixture_props = get_mixture_properties(T=7000, y=y, species_data=species_data)
  72.     print(f"Mixture Cp: {mixture_props['Cp']} J/mol/K")
  73.    
  74.     print("========================================")
  75.  
  76.     # Compute initial conditions (Post-Shock)
  77.     print("Computing Rankine-Hugoniot jump relations for hot gas.")
  78.     post_shock_conditions = calculate_rh_conditions(P1, T1, U1, y, species_data)
  79.     print("Post-Shock Conditions (Hot Gas):")
  80.     print(f"P2: {post_shock_conditions['P2']} Pa")
  81.     print(f"T2: {post_shock_conditions['T2']} K")
  82.     print(f"rho2: {post_shock_conditions['rho2']} kg/m³")
  83.     print(f"u2: {post_shock_conditions['u2']} m/s")
  84.     print(f"a2: {post_shock_conditions['a2']} m/s")
  85.     print(f"M2: {post_shock_conditions['M2']}")
  86.     print(f"gamma2: {post_shock_conditions['gamma2']}")
  87.     print("========================================")
  88.  
  89.     # Simulate the flowfield downstream of the shock
  90.     flow_field = simulate_shock_flow(x_max, post_shock_conditions)
  91.     print("Shock-tube simulation complete.")
  92.  
  93. if __name__ == "__main__":
  94.     main()
  95.  
  96.  
  97.  
  98. # RHjump.py
  99.  
  100. import numpy as np
  101. from mixture import get_mixture_properties, get_sound_speed, R_UNIVERSAL
  102.  
  103. def calculate_rh_conditions(P1: float, T1: float, u1: float, y: float, species_data: np.ndarray) -> dict:
  104.     """
  105.    Calculate Rankine-Hugoniot jump conditions.
  106.  
  107.    Args:
  108.        P1 (float): Initial pressure (Pa)
  109.        T1 (float): Initial temperature (K)
  110.        u1 (float): Initial velocity (m/s)
  111.        y (float): Mole fraction of N2
  112.        species_data (np.ndarray): Array containing species data
  113.  
  114.    Returns:
  115.        dict: Dictionary containing post-shock conditions
  116.              Keys: 'P2', 'T2', 'rho2', 'u2', 'a2', 'M2', 'gamma2'
  117.    """
  118.     # Step 1: Get initial mixture properties
  119.     props1 = get_mixture_properties(T1, y, species_data)
  120.     gamma1 = props1['gamma']
  121.     M_mix = props1['M']
  122.  
  123.     # Step 2: Calculate specific gas constant (R_specific)
  124.     # R_UNIVERSAL is in J/mol/K, M_mix should be in kg/mol
  125.     R_specific = R_UNIVERSAL / M_mix  # J/kg/K
  126.  
  127.     # Step 3: Calculate initial density (rho1)
  128.     rho1 = P1 / (R_specific * T1)  # kg/m³
  129.  
  130.     # Step 4: Calculate sound speed (a1)
  131.     a1 = get_sound_speed(T1, y, species_data)  # m/s
  132.  
  133.     # Step 5: Calculate Mach number (M1)
  134.     M1 = u1 / a1
  135.  
  136.     # Step 6: Apply Rankine-Hugoniot jump conditions
  137.     P2 = P1 * (2 * gamma1 * M1**2 - (gamma1 - 1)) / (gamma1 + 1)  # Post-shock pressure (Pa)
  138.     rho2 = rho1 * ((gamma1 + 1) * M1**2) / ((gamma1 - 1) * M1**2 + 2)  # Post-shock density (kg/m³)
  139.     u2 = u1 * (((gamma1 - 1) * M1**2 + 2) / ((gamma1 + 1) * M1**2))  # Post-shock velocity (m/s)
  140.  
  141.     # Step 7: Calculate temperature ratio and absolute temperature (T2)
  142.     T2_T1 = (P2 / P1) * (rho1 / rho2)  # Temperature ratio T2/T1
  143.     T2 = T1 * T2_T1  # Post-shock temperature (K)
  144.  
  145.     # Step 8: Assume frozen flow; sound speed remains the same
  146.     a2 = a1  # Post-shock sound speed (m/s)
  147.  
  148.     # Step 9: Calculate post-shock Mach number (M2)
  149.     M2 = u2 / a1  # Assuming a2 = a1
  150.  
  151.     # Step 10: Assume gamma remains the same across the shock
  152.     gamma2 = gamma1
  153.  
  154.     # Step 11: Compile results into a dictionary
  155.     return {
  156.         'P2': P2,          # Post-shock pressure (Pa)
  157.         'T2': T2,          # Post-shock temperature (K)
  158.         'rho2': rho2,      # Post-shock density (kg/m³)
  159.         'u2': u2,          # Post-shock velocity (m/s)
  160.         'a2': a2,          # Post-shock sound speed (m/s)
  161.         'M2': M2,          # Post-shock Mach number
  162.         'gamma2': gamma2   # Post-shock specific heat ratio
  163.     }
  164.  
  165.  
  166.  
  167. import numpy as np
  168. import math
  169. from dataclasses import dataclass
  170.  
  171. # Physical constants
  172. R = 0.25  # O2 N2 ratio
  173. PRESSURE = 1  # pressure
  174. KB = 1.380649E-23  # Boltzmann constant
  175. H = 6.62607015E-34  # Planck constant
  176. C = 3.0E+10  # speed of light, cm/s
  177. DT = 1.0E-8  # T step for finite differences
  178. NA = 6.02214076E+23  # Avogadro number
  179. NU = 1.0  # number of moles
  180. P_ATM = 101325.0  # atmospheric pressure
  181. EV = 1.60218E-19  # eV -> J translation coefficient
  182.  
  183.  
  184. @dataclass
  185. class Species:
  186.     constants: np.ndarray
  187.  
  188. def calculate_thermodynamic_properties(temperature: float, species_idx: int, species_data: np.ndarray) -> dict:
  189.     """
  190.    Calculate thermodynamic properties for a given species at specified temperature.
  191.    
  192.    Args:
  193.        temperature: Temperature in Kelvin
  194.        species_idx: Species index (0 for N, 1 for N2)
  195.        species_data: Array containing species data
  196.        
  197.    Returns:
  198.        Dictionary containing:
  199.        - Q_in: Internal partition function
  200.        - Q_tr: Translational partition function
  201.        - Q_total: Total partition function
  202.        - S: Entropy (J/mol/K)
  203.        - H_H0: Enthalpy difference from 0K (kJ/mol)
  204.    """
  205.     # Create Species object for the selected species
  206.     species = Species(constants=species_data[species_idx])
  207.    
  208.     # Calculate Q_in
  209.     if species.constants[1] == 0:
  210.         Q_rot = 1.0
  211.     else:
  212.         Q_rot = (8.0 * math.pi**2 * species.constants[1] * KB * temperature) / (H**2 * species.constants[0])
  213.  
  214.     if species.constants[2] == 0:
  215.         Q_vib = 1.0
  216.     else:
  217.         Q_vib = 1.0 / (1.0 - math.exp((-H * C * species.constants[2]) / (KB * temperature)))
  218.  
  219.     if species.constants[3] == 0:
  220.         Q_el = 1.0
  221.     else:
  222.         Q_el = sum(
  223.             species.constants[3+i] * math.exp(-H * C * species.constants[22+i] / (KB * temperature))
  224.             for i in range(19)
  225.         )
  226.    
  227.     Q_in = Q_rot * Q_vib * Q_el
  228.    
  229.     # Calculate Q_tr
  230.     Q_tr = (NU * KB * NA * temperature / (PRESSURE * P_ATM)) * \
  231.            (2 * math.pi * species.constants[41] * KB * temperature / (H * H))**(1.5)
  232.    
  233.     # Calculate Q_total
  234.     Q_total = Q_in * Q_tr
  235.    
  236.     # Calculate Entropy [J/(mol*K)]
  237.     S = KB * NA * (
  238.         math.log(Q_in) + math.log(Q_tr)
  239.     ) + KB * NA * temperature * (
  240.         (Q_tr_calc(species, temperature + DT) - Q_tr_calc(species, temperature - DT)) /
  241.         (2.0 * DT * Q_tr) +
  242.         (Q_in_calc(species, temperature + DT) - Q_in_calc(species, temperature - DT)) /
  243.         (2.0 * DT * Q_in)
  244.     ) - KB * NA * math.log(NA)
  245.    
  246.     # Calculate H-H0 [J/mol]
  247.     H_H0 = KB * NA * temperature * (
  248.         (temperature / Q_in) *
  249.         (Q_in_calc(species, temperature + DT) - Q_in_calc(species, temperature - DT)) /
  250.         (2.0 * DT) + 2.5
  251.     )
  252.    
  253.     return {
  254.         'Q_in': Q_in,
  255.         'Q_tr': Q_tr,
  256.         'Q_total': Q_total,
  257.         'S': S,
  258.         'H_H0': H_H0
  259.     }
  260.  
  261. # Helper functions for finite difference calculations
  262. def Q_in_calc(species: Species, T: float) -> float:
  263.     """Calculate Q_in at a specific temperature (helper function for derivatives)"""
  264.     if species.constants[1] == 0:
  265.         Q_rot = 1.0
  266.     else:
  267.         Q_rot = (8.0 * math.pi**2 * species.constants[1] * KB * T) / (H**2 * species.constants[0])
  268.  
  269.     if species.constants[2] == 0:
  270.         Q_vib = 1.0
  271.     else:
  272.         Q_vib = 1.0 / (1.0 - math.exp((-H * C * species.constants[2]) / (KB * T)))
  273.  
  274.     if species.constants[3] == 0:
  275.         Q_el = 1.0
  276.     else:
  277.         Q_el = sum(
  278.             species.constants[3+i] * math.exp(-H * C * species.constants[22+i] / (KB * T))
  279.             for i in range(19)
  280.         )
  281.    
  282.     return Q_rot * Q_vib * Q_el
  283.  
  284. def Q_tr_calc(species: Species, T: float) -> float:
  285.     """Calculate Q_tr at a specific temperature (helper function for derivatives)"""
  286.     return (NU * KB * NA * T / (PRESSURE * P_ATM)) * \
  287.            (2 * math.pi * species.constants[41] * KB * T / (H * H))**(1.5)
  288.  
  289.  
  290. # mixture.py
  291.  
  292. import numpy as np
  293. from species import calculate_thermodynamic_properties
  294.  
  295. # Constants
  296. R_UNIVERSAL = 8.314462  # J/mol/K
  297. Na = 6.02214076E23 # Avogadro
  298. M_N = 0.014             # kg/mol
  299. M_N2 = 0.028            # kg/mol
  300. EV_TO_J = 1.60218E-19  # eV to J conversion
  301. H_F_N = 4.87933027 * EV_TO_J * Na  # Convert eV to J/mol
  302. H_F_N2 = 0.0            # Formation enthalpy for N2 in J/mol
  303.  
  304.  
  305. def compute_cp(T: float, species_idx: int, species_data: np.ndarray, delta_T: float = 1e-8) -> float:
  306.     """
  307.    Compute the specific heat at constant pressure (Cp) for a given species using the provided formula.
  308.    
  309.    Args:
  310.        T: Temperature in Kelvin
  311.        species_idx: Species index (0 for N, 1 for N2)
  312.        species_data: Array containing species data
  313.        delta_T: Temperature increment for finite differences (default: 1e-3 K)
  314.        
  315.    Returns:
  316.        Cp in J/mol/K
  317.    """
  318.     # Calculate Q_in at T
  319.     props_T = calculate_thermodynamic_properties(T, species_idx, species_data)
  320.     Q_in_T = props_T['Q_in']
  321.    
  322.     # Calculate Q_in at T + delta_T
  323.     props_T_plus = calculate_thermodynamic_properties(T + delta_T, species_idx, species_data)
  324.     Q_in_T_plus = props_T_plus['Q_in']
  325.    
  326.     # Calculate Q_in at T - delta_T
  327.     props_T_minus = calculate_thermodynamic_properties(T - delta_T, species_idx, species_data)
  328.     Q_in_T_minus = props_T_minus['Q_in']
  329.    
  330.     # Compute ln(Q_in) at T, T + delta_T, T - delta_T
  331.     ln_Q_in_T = np.log(Q_in_T)
  332.     ln_Q_in_T_plus = np.log(Q_in_T_plus)
  333.     ln_Q_in_T_minus = np.log(Q_in_T_minus)
  334.    
  335.     # First derivative d(lnQ_in)/dT using central difference
  336.     dlnQin_dT = (ln_Q_in_T_plus - ln_Q_in_T_minus) / (2 * delta_T)
  337.    
  338.     # Second derivative d²(lnQ_in)/dT² using central difference
  339.     d2lnQin_dT2 = (ln_Q_in_T_plus - 2 * ln_Q_in_T + ln_Q_in_T_minus) / (delta_T ** 2)
  340.    
  341.     # Calculate Cp_int using Capitelli
  342.     Cp_int = R_UNIVERSAL * (2 * T * dlnQin_dT + T**2 * d2lnQin_dT2)
  343.    
  344.     # Total Cp
  345.     Cp = Cp_int + (5.0 / 2.0) * R_UNIVERSAL
  346.    
  347.     return Cp
  348.  
  349. def get_mixture_properties(T: float, y: float, species_data: np.ndarray) -> dict:
  350.     """
  351.    Calculate mixture properties including formation enthalpies and Cp.
  352.    
  353.    Args:
  354.        T: Temperature in K
  355.        y: Mole fraction of N2 (1-y is mole fraction of N)
  356.        species_data: Array containing thermodynamic data for species
  357.        
  358.    Returns:
  359.        Dictionary containing gamma, molar mass, sound speed coefficient, mixture enthalpy, and Cp
  360.    """
  361.     # Get thermodynamic properties for both species
  362.     N_props = calculate_thermodynamic_properties(T, 0, species_data)
  363.     N2_props = calculate_thermodynamic_properties(T, 1, species_data)
  364.    
  365.     # Calculate mixture enthalpy including formation enthalpies
  366.     H_mix = (1 - y) * (N_props['H_H0'] + H_F_N) + y * (N2_props['H_H0'] + H_F_N2)
  367.    
  368.     # Compute Cp for each species using the new compute_cp function
  369.     Cp_int_N = compute_cp(T, 0, species_data)
  370.     Cp_int_N2 = compute_cp(T, 1, species_data)
  371.    
  372.     # Calculate mixture Cp using mole fractions
  373.     Cp_mix = (1 - y) * Cp_int_N + y * Cp_int_N2
  374.    
  375.     # Calculate gamma using Cp and Cv = Cp - R
  376.     Cv_mix = Cp_mix - R_UNIVERSAL
  377.     gamma = Cp_mix / Cv_mix
  378.    
  379.     # Calculate mixture molar mass
  380.     M_mix = (1 - y) * M_N + y * M_N2
  381.    
  382.     # Calculate sound speed coefficient
  383.     sound_coeff = np.sqrt(gamma * R_UNIVERSAL / M_mix)
  384.    
  385.     return {
  386.         'gamma': gamma,
  387.         'M': M_mix,
  388.         'sound_coeff': sound_coeff,
  389.         'H_mix': H_mix,
  390.         'Cp': Cp_mix
  391.     }
  392.  
  393. def get_sound_speed(T: float, y: float, species_data: np.ndarray) -> float:
  394.     """
  395.    Calculate mixture sound speed.
  396.    
  397.    Args:
  398.        T: Temperature in K
  399.        y: Mole fraction of N2
  400.        species_data: Array containing thermodynamic data for species
  401.        
  402.    Returns:
  403.        Sound speed in m/s
  404.    """
  405.     props = get_mixture_properties(T, y, species_data)
  406.     return props['sound_coeff'] * np.sqrt(T)
  407.  
  408.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement