def __call__(self, t, y): """ Set of ODEs to solve ZND Detonation Problem. INPUT: t = time y = solution array [pressure, density, position, species mass 1, 2, ..] gas = working gas object U1 = shock velocity (m/s) r1 = initial density (kg/m^3) OUTPUT: An array containing time derivatives of: pressure, density, distance and species mass fractions, formatted in a way that the integrator in zndsolve can recognize. """ self.gas.DPY = y[1], y[0], y[3:] c = soundspeed_fr(self.gas) U = self.U1 * self.r1 / self.gas.density M = U / c eta = 1 - M**2 sigmadot = getThermicity(self.gas) Pdot = -self.gas.density * U**2 * sigmadot / eta rdot = -self.gas.density * sigmadot / eta dYdt = self.gas.net_production_rates * self.gas.molecular_weights / self.gas.density return np.hstack((Pdot, rdot, U, dYdt))
def __call__(self, t, y): self.gas.DPY = y[1], y[0], y[4:] rho = y[1] wdot = self.gas.net_production_rates mw = self.gas.molecular_weights c = soundspeed_fr(self.gas) U = y[2] # velocity has to be updated M = U / c # Mach Number eta = 1 - M**2 # Sonic Parameter walpha = self.U1 * self.r1 / self.Delta / rho # area change function sigmadot = getThermicity(self.gas) Pdot = -rho * U**2 * (sigmadot - walpha) / eta # Pressure Derivative rdot = -rho * (sigmadot - walpha * M**2) / eta # Density Derivative Udot = U * (sigmadot - walpha) / eta # Velocity Derivative dYdt = mw * wdot / rho # mass production rates return np.hstack((Pdot, rdot, Udot, U, dYdt))
## # set the initial state and compute properties P1 = 100000. T1 = 300. q = 'O2:0.2095 N2:0.7808 CO2:0.0004 Ar:0.0093' mech = 'airNASA9ions.cti' gas = ct.Solution(mech) gas.TPX = T1, P1, q if EQ: # use this for equilibrium expansion gas.equilibrate('TP') a1 = soundspeed_eq(gas) else: # use this for frozen expansion a1 = soundspeed_fr(gas) x1 = gas.X rho1 = gas.density v1 = 1 / rho1 s1 = gas.entropy_mass h1 = gas.enthalpy_mass ## # Set freestream velocity .01% above sound speed U = a1 * 1.0001 mu_min = np.arcsin(a1 / U) # Mach angle # check to see if flow speed is supersonic if U < a1: exit('Flow subsonic. Exiting.') # stagnation enthalpy
import cantera as ct from sdtoolbox.thermo import soundspeed_fr from sdtoolbox.postshock import PostShock_fr from numpy import linspace import datetime # set initial state of gas, avoid using precise stoichiometric ratios. P1 = 100000 T1 = 300 q = 'O2:0.2095 N2:0.7808 CO2:0.0004 Ar:0.0093' mech = 'airNASA9ions.cti' gas1 = ct.Solution(mech) gas1.TPX = T1, P1, q print('Computing frozen postshock state for ' + q + ' using ' + mech) Umin = soundspeed_fr(gas1) + 50 # Evaluate the frozen state of the gas behind a shock wave traveling at speeds up to a maximum value. Umax = 2000. Ustep = 100. # Ustep will be approximated nsteps = int((Umax - Umin) / Ustep) speed = [] P = [] R = [] T = [] a = [] gamma = [] w2 = [] u2 = []
# make solution and initialize to starting conditions, store density gas_initial = ct.Solution(mech) gas_initial.TPX = T1, P1, q rho_1 = gas_initial.density csound = soundspeed_eq(gas_initial) # compute CJ speed, print, and add to speed array [cj_speed, R2, plot_data] = CJspeed(P1, T1, q, mech, fullOutput=True) # compute equilibrium CJ state parameters gas = PostShock_eq(cj_speed, P1, T1, q, mech) ae = soundspeed_eq(gas) af = soundspeed_fr(gas) rho_2 = gas.density gammae = ae**2 * rho_2 / gas.P gammaf = af**2 * rho_2 / gas.P w2 = cj_speed * rho_1 / rho_2 u2 = cj_speed - w2 D = cj_speed # u2 * rho_2 / rho_1 Dcalc = (1.29 + 1) / 1.29 * np.power(1.29 * 8314 * 2700 / 28, 0.5) mach = D / csound print('\nCJ computation for ' + mech + ' with composition:') print(q) print('Initial conditions: P1 = %.3e Pa & T1 = %.2f K' % (P1, T1)) print('CJ Speed %.1f m/s' % cj_speed) print('CJ State') print(' Pressure %.3e Pa' % gas.P) print(' Temperature %.1f K' % gas.T)
## Select case for the driven gas operations (use equilibrium only for very strong shocks) CASE_DRIVEN = 'frozen' # non reactive driven gas #CASE_DRIVEN = 'equilibrium' #reactive driven gas print('demo_ShockTube, driver case: '+CASE_DRIVER+' driven case: '+CASE_DRIVEN) ## set initial state, composition, and gas object for driven section P1 = 1200.; T1 = 300. q1 = 'N2:1.0 O2:3.76'; driven_mech = 'airNASA9noions.cti' driven_gas = ct.Solution(driven_mech) driven_gas.TPX = T1,P1,q1 ## Evaluate initial state rho1 = driven_gas.density a1 = soundspeed_fr(driven_gas) ## Evaluate post-shock state (frozen) for a range of shock speeds print('Generating points on shock P-u curve') Ustart = a1*1.01; Ustop = 8*a1; Ustep = 25 nsteps = int((Ustop-Ustart)/Ustep) a2 = []; P2 = []; T2 = []; rho2 = []; u2 = []; Us = [] for U in np.linspace(Ustart,Ustop,num=nsteps): if CASE_DRIVEN=='frozen': shocked_gas = PostShock_fr(U, P1, T1, q1, driven_mech) elif CASE_DRIVEN=='equilibrium': shocked_gas = PostShock_eq(U, P1, T1, q1, driven_mech) a2.append(soundspeed_fr(shocked_gas)) P2.append(shocked_gas.P)
EQ = False ## # set the initial state and compute properties PA = 100000.; TA = 1000. # layer state q = 'PG:1' mech = 'PG14.cti' gas = ct.Solution(mech) gas.TPX = TA,PA,q x1 = gas.X P1 = gas.P T1 = gas.T rho1 = gas.density v1 = 1/rho1 a1 = soundspeed_fr(gas) s1 = gas.entropy_mass h1 = gas.enthalpy_mass RU = ct.gas_constant W = gas.mean_molecular_weight R = RU/W ## # Set lower layer velocity using the Mach number M2 = 1.05 layer_speed = a1*M2 U = layer_speed mu_min = np.arcsin(a1/U) # Mach angle # check to see if flow speed is supersonic if U < a1: exit('Flow subsonic. Exiting.')
xfuel.append(fuelmin + i*deltafuel) xoxidizer.append((1-xfuel[-1])/(1+beta)) xdiluent.append(beta*xoxidizer[-1]) phi.append(xfuel[-1]/(stoich*xoxidizer[-1])) x[ifuel] = xfuel[-1] x[ioxidizer] = xoxidizer[-1] x[idiluent] = xdiluent[-1] print('Case '+str(i+1)+' Fuel concentration: '+str(x[ifuel]*100)+'%') print('Molefractions') print(' fuel ('+fuel+'): '+str(x[ifuel])) print(' oxidizer ('+oxidizer+'): '+ str(x[ioxidizer])) print(' diluent ('+diluent+'): '+ str(x[idiluent])) print(' Phi = '+str(phi[-1])) gas.TPX = T1,P1,x init_rho = gas.density init_af = soundspeed_fr(gas) # Constant Pressure Explosion State gas.equilibrate('HP') hp_rho.append(gas.density) hp_exp.append(init_rho/hp_rho[-1]) hp_T.append(gas.T) hp_ae.append(soundspeed_eq(gas)) # Constant Volume Explosion State gas.TPX = T1,P1,x gas.equilibrate('UV') uv_P.append(gas.P) uv_T.append(gas.T) uv_ae.append(soundspeed_eq(gas))
def stgsolve(gas, gas1, U1, Delta, t_end=1e-3, max_step=1e-4, t_eval=None, relTol=1e-5, absTol=1e-8): """ Reaction zone structure computation for blunt body flow using Hornung's approximation of linear gradient in rho u FUNCTION SYNTAX: output = stgsolve(gas,gas1,U1,Delta,**kwargs) INPUT gas = Cantera gas object - postshock state gas1 = Cantera gas object - initial state U1 = shock velocity (m/s) Delta = shock standoff distance (m) OPTIONAL INPUT: t_end = end time for integration, in sec max_step = maximum time step for integration, in sec t_eval = array of time values to evaluate the solution at. If left as 'None', solver will select values. Sometimes these may be too sparse for good-looking plots. relTol = relative tolerance absTol = absolute tolerance OUTPUT: output = a dictionary containing the following results: time = time array distance = distance array T = temperature array P = pressure array rho = density array U = velocity array thermicity = thermicity array distance = distance array species = species mass fraction array M = Mach number array af = frozen sound speed array g = gamma (cp/cv) array wt = mean molecular weight array sonic = sonic parameter (c^2-U^2) array gas1 = a copy of the input initial state U1 = shock velocity Delta = shock standoff distance """ r1 = gas1.density r = gas.density U = U1 * r1 / r x_start = 0 y0 = np.hstack((gas.P, r, U, x_start, gas.Y)) # scaled pressure starts at 1, i.e. PSC/PSC tel = [0, t_end] # Timespan output = {} out = solve_ivp(StgSys(gas, U1, r1, Delta), tel, y0, method='Radau', atol=absTol, rtol=relTol, max_step=max_step, t_eval=t_eval) output['time'] = out.t output['P'] = out.y[0, :] output['rho'] = out.y[1, :] output['U'] = out.y[2, :] output['distance'] = out.y[3, :] output['species'] = out.y[4:, :] # Initialize additional output matrices where needed b = len(output['time']) output['T'] = np.zeros(b) output['thermicity'] = np.zeros(b) output['M'] = np.zeros(b) output['af'] = np.zeros(b) output['g'] = np.zeros(b) output['wt'] = np.zeros(b) output['sonic'] = np.zeros(b) output['Delta'] = Delta # Have to loop for operations involving the working gas object for i, P in enumerate(output['P']): gas.DPY = output['rho'][i], P, output['species'][:, i] output['T'][i] = gas.T ################################################################################################# # Extract WEIGHT, GAMMA, SOUND SPEED, VELOCITY, MACH NUMBER, c^2-U^2, # THERMICITY, and TEMPERATURE GRADIENT ################################################################################################# af = soundspeed_fr(gas) # frozen sound speed M = output['U'][i] / af # Mach Number in shock-fixed frame eta = 1 - M**2 # Sonic Parameter sonic = af**2 * eta # Assign output structure output['thermicity'][i] = getThermicity(gas) output['M'][i] = M output['af'][i] = af output['g'][i] = gas.cp / gas.cv output['wt'][i] = gas.mean_molecular_weight output['sonic'][i] = sonic output['gas1'] = gas1 output['U1'] = U1 return output
mu1 = gas.viscosity nu1 = mu1/rho1 kcond1 = gas.thermal_conductivity kdiff1 = kcond1/(rho1*gas.cp_mass) ## Find Explosion state gas.equilibrate(CASE) ## Evaluate properties of gas object T2 = gas.T P2 = gas.P rho2 = gas.density V2 = 1/rho2 S2 = gas.entropy_mass x2 = gas.X c2_eq = soundspeed_eq(gas) c2_fr = soundspeed_fr(gas) gamma2_fr = c2_fr**2*rho2/P2 gamma2_eq = c2_eq**2*rho2/P2 if transport: mu = gas.viscosity nu = mu/rho2 kcond = gas.thermal_conductivity kdiff = kcond/(rho2*gas.cp_mass) Pr = mu*gas.cp_mass/kcond ## Print out print(CASE+' computation for '+mech+' with composition '+q) print('Initial State') print(' Pressure '+str(P1)+' (Pa)') print(' Temperature '+str(T1)+' (K)')
T1 = 300 P1atm = P1 / ct.one_atm q = 'H2:2 O2:1 N2:3.76' mech = 'Mevel2017.cti' gas1 = ct.Solution(mech) gas1.TPX = T1, P1, q print('Initial state: ' + q + ', P1 = %.2f atm, T1 = %.2f K' % (P1atm, T1)) print('Mechanism: ' + mech) # create gas objects for other states gas2 = ct.Solution(mech) gas3 = ct.Solution(mech) # compute minimum incident wave speed a_fr = soundspeed_fr(gas1) # incident wave must be greater than or equal to frozen sound speed for # frozen shock wave computations UI = 3 * a_fr print('Incident shock speed UI = %.2f m/s' % (UI)) # compute postshock gas state object gas2 gas2 = PostShock_fr(UI, P1, T1, q, mech) P2 = gas2.P / ct.one_atm print('Frozen Post-Incident-Shock State') print('T2 = %.2f K, P2 = %.2f atm' % (gas2.T, P2)) # compute reflected shock post-shock state gas3 [p3, UR, gas3] = reflected_fr(gas1, gas2, gas3, UI)
def zndsolve(gas, gas1, U1, t_end=1e-3, max_step=1e-4, t_eval=None, relTol=1e-5, absTol=1e-8, advanced_output=False): """ ZND Model Detonation Struction Computation Solves the set of ODEs defined in ZNDSys. FUNCTION SYNTAX: output = zndsolve(gas,gas1,U1,**kwargs) INPUT gas = Cantera gas object - postshock state gas1 = Cantera gas object - initial state U1 = shock velocity (m/s) OPTIONAL INPUT: t_end = end time for integration, in sec max_step = maximum time step for integration, in sec t_eval = array of time values to evaluate the solution at. If left as 'None', solver will select values. Sometimes these may be too sparse for good-looking plots. relTol = relative tolerance absTol = absolute tolerance advanced_output = calculates optional extra parameters such as induction lengths OUTPUT: output = a dictionary containing the following results: time = time array distance = distance array T = temperature array P = pressure array rho = density array U = velocity array thermicity = thermicity array species = species mass fraction array M = Mach number array af = frozen sound speed array g = gamma (cp/cv) array wt = mean molecular weight array sonic = sonic parameter (c^2-U^2) array tfinal = final target integration time xfinal = final distance reached gas1 = a copy of the input initial state U1 = shock velocity and, if advanced_output=True: ind_time_ZND = time to maximum thermicity gradient ind_len_ZND = distance to maximum thermicity gradient exo_time_ZND = pulse width (in secs) of thermicity (using 1/2 max) ind_time_ZND = pulse width (in meters) of thermicity (using 1/2 max) max_thermicity_width_ZND = according to Ng et al definition """ ########################################################### # Define initial information ########################################################### r1 = gas1.density x_start = 0. y0 = np.hstack((gas.P, gas.density, x_start, gas.Y)) tel = [0., t_end] # Timespan output = {} out = solve_ivp(ZNDSys(gas, U1, r1), tel, y0, method='Radau', atol=absTol, rtol=relTol, max_step=max_step, t_eval=t_eval) output['time'] = out.t output['P'] = out.y[0, :] output['rho'] = out.y[1, :] output['distance'] = out.y[2, :] output['species'] = out.y[3:, :] output['tfinal'] = t_end output['xfinal'] = output['distance'][-1] # Initialize additional output matrices where needed b = len(output['time']) output['T'] = np.zeros(b) output['U'] = np.zeros(b) output['thermicity'] = np.zeros(b) output['af'] = np.zeros(b) output['g'] = np.zeros(b) output['wt'] = np.zeros(b) if advanced_output: output['ind_len_ZND'] = 0 output['ind_time_ZND'] = 0 output['exo_len_ZND'] = 0 output['exo_time_ZND'] = 0 ############################################################################# # Extract TEMPERATURE, WEIGHT, GAMMA, SOUND SPEED, VELOCITY, MACH NUMBER, # c^2-U^2, THERMICITY, and TEMPERATURE GRADIENT ############################################################################# # Have to loop for operations involving the working gas object for i, P in enumerate(output['P']): gas.DPY = output['rho'][i], P, output['species'][:, i] af = soundspeed_fr(gas) U = U1 * r1 / gas.density output['T'][i] = gas.T output['U'][i] = U output['thermicity'][i] = getThermicity(gas) output['af'][i] = af output['g'][i] = gas.cp / gas.cv output['wt'][i] = gas.mean_molecular_weight # Vectorize operations where possible output['M'] = output['U'] / output['af'] eta = 1 - output['M']**2 output['sonic'] = eta * output['af']**2 if advanced_output: ################################################################################################ # Find INDUCTION TIME and LENGTH based on MAXIMUM THERMICITY ################################################################################################ n = output['thermicity'].argmax() output['ind_time_ZND'] = output['time'][n] output['ind_len_ZND'] = output['distance'][n] output['max_thermicity_ZND'] = max( output['thermicity']) # required for Ng et al Chi parameter ####################################################### # Check for eigenvalue detonation ####################################################### if n == b: print( 'Error: Maximum thermicity occurs at the end of the reaction zone' ) print( ' You may have an eigenvalue detonation, your final integration length may be too short,' ) print( ' your mixture may be too rich/lean, or something else may be wrong' ) print(' ') print('Mach Number (end of reaction): ' + str(output['M'][b]) + ' - if close to 1, check for eigenvalue detonation') output['ind_time_ZND'] = output['time'][b] output['ind_len_ZND'] = output['distance'][b] output['exo_time_ZND'] = 0 output['exo_len_ZND'] = 0 print('Induction Time: ' + str(output['ind_time_ZND'])) print('Exothermic Pulse Time: ' + str(output['exo_time_ZND'])) return output elif n == 0: print( 'Error: Maximum thermicity occurs at the beginning of the reaction zone' ) print( ' You may have an eigenvalue detonation, your final integration length may be too short,' ) print( ' your mixture may be too rich/lean, or something else may be wrong' ) print(' ') print('Mach Number (end of reaction): ' + str(output['M'][b]) + ' - if close to 1, check for eigenvalue detonation') output['ind_time_ZND'] = output['time'][0] output['ind_len_ZND'] = output['distance'][0] output['exo_time_ZND'] = 0 output['exo_len_ZND'] = 0 print('Induction Time: ' + str(output['ind_time_ZND'])) print('Exothermic Pulse Time: ' + str(output['exo_time_ZND'])) return output else: max_sigmadot = max(output['thermicity']) half_sigmadot_flag1 = 0 half_sigmadot_flag2 = 0 # Go into a loop to find two times when sigma_dot is half its maximum tstep2 = 0 # JML temporary for j, thermicity in enumerate(list(output['thermicity'])): if half_sigmadot_flag1 == 0: if thermicity > 0.5 * max_sigmadot: half_sigmadot_flag1 = 1 tstep1 = j elif half_sigmadot_flag2 == 0: if thermicity < 0.5 * max_sigmadot: half_sigmadot_flag2 = 1 tstep2 = j else: tstep2 = 0 if tstep2 == 0: print('Error: No pulse in the thermicity') print( ' You may have an eigenvalue detonation, your final integration length may be too short,' ) print( ' your mixture may be too rich/lean, or something else may be wrong' ) output['exo_time_ZND'] = 0 output['exo_len_ZND'] = 0 else: output['exo_time_ZND'] = output['time'][tstep2] - output['time'][ tstep1] output['exo_len_ZND'] = output['distance'][tstep2] - output[ 'distance'][tstep1] ################################################################# # Append extra data used to make output file (via znd_fileout) output['gas1'] = gas1 output['U1'] = U1 return output
P.append(gas.P) R.append(gas.density) T.append(gas.T) # species X = gas.X xH.append(X[iH]) xO.append(X[iO]) xOH.append(X[iOH]) xH2.append(X[iH2]) xO2.append(X[iO2]) xH2O.append(X[iH2O]) # gamma computed from Gruneisen coefficient grun_eq.append(gruneisen_eq(gas)) grun_fr.append(gruneisen_fr(gas)) a_eq.append(soundspeed_eq(gas)) a_fr.append(soundspeed_fr(gas)) # logarithmic slope of isentropes in P-V coordinates kappa_fr.append(a_fr[-1]**2*R[-1]/P[-1]) kappa_eq.append(a_eq[-1]**2*R[-1]/P[-1]) # logarithmic slope of isentropes in T-V coordinates # equilibrium gas.SV = S2,1.01*V gas.equilibrate('SV') T_2 = gas.T gas.SV = S2,0.99*V gas.equilibrate('SV') T_1 = gas.T tvdvdt_eq.append(-V*(T_2-T_1)/(0.02*V)/T[-1]) # frozen gas.SVX = S2,V*1.01,X2 T_2 = gas.T
#P1 = 200000.; T1 = 300.; #Fujiwara initial state #q = 'C2H4:1.0, O2:3'; #ethylene oxygen, Kasahara #q = 'H2:2.0, O2:1.0, AR:7.0'; #hydrogen oxygen argon #q = 'H2:2.0, O2:1.0'; #hydrogen oxygen #q = 'H2:2.0, O2:1.0, N2:3.76'; #hydrogen air #q = 'C2H4:1.0, O2:3, N2:11.28'; #ethylene air q = 'CH4:1.0, O2:2.0, N2:7.52'; #methane-air #q = 'C3H8:1.0, O2:5'; #propane oxygen mech = 'gri30_highT.cti' gas = ct.Solution(mech) gas.TPX = T1,P1,q h1 = gas.enthalpy_mass s1 = gas.entropy_mass rho1 = gas.density a1_fr = soundspeed_fr(gas) w1 = gas.mean_molecular_weight R1 = ct.gas_constant/w1 gamma1_fr = a1_fr**2*rho1/P1 print('Layer detonation computation for '+mech+' with composition '+q) print('State 1 - Initial state of reacting layer') print(' Pressure '+str(P1)+' (Pa)') print(' Temperature '+str(T1)+' (K)') print(' Density '+str(rho1)+' (kg/m3)') print(' Sound speed (frozen) '+str(a1_fr)+' (m/s)') print(' Enthalpy '+str(h1)+' (J/kg)') print(' Entropy '+str(s1)+' (J/kg K)') print(' gamma (frozen) '+str(gamma1_fr)+' ') ##
# P1 = Initial Pressure # T1 = Initial Temperature # U = Shock Speed # q = Initial Composition # mech = Cantera mechanism File name plots = True #set initial state P1 = 100000 T1 = 295 q = 'C2H4:1 O2:3.01' mech = 'gri30_highT.cti' gas1 = ct.Solution(mech) gas = ct.Solution(mech) gas1.TPX = T1, P1, q a1_fr = soundspeed_fr(gas1) D1 = gas1.density gamma1_fr = a1_fr * a1_fr * D1 / P1 print('Initial State:') print(' Composition ' + q) print(' Pressure %.2f (Pa) ' % (P1)) print(' Temperature %.2f (K) ' % (T1)) print(' Density %.3f (kg/m3) ' % (D1)) print(' a1 (frozen) %.2f (m/s)' % (a1_fr)) print(' gamma1 (frozen) %.4f ' % (gamma1_fr)) print('Computing CJ state and isentrope for ' + q + ' using ' + mech) # compute CJ speed cj_speed = CJspeed(P1, T1, q, mech)
cj_speed = CJspeed(P1, T1, q, mech) # Evaluate gas state gas = PostShock_eq(cj_speed,P1, T1, q, mech) # Evaluate properties of gas object T2 = gas.T P2 = gas.P R2 = gas.density V2 = 1/R2 S2 = gas.entropy_mass w2 = gas1.density*cj_speed/R2 u2 = cj_speed - w2 x2 = gas.X a2_eq = soundspeed_eq(gas) a2_fr = soundspeed_fr(gas) gamma2_fr = a2_fr**2*R2/P2 gamma2_eq = a2_eq**2*R2/P2 # Print out set_printoptions(precision=4) print('CJ computation for '+mech+' with composition '+q) print('CJ Parameters') print(' UCJ '+str(cj_speed)+' (m/s)') print(' Pressure '+str(P2)+' (Pa)') print(' Temperature '+str(T2)+' (K)') print(' Density '+str(R2)+' (kg/m3)') print(' Entropy '+str(S2)+' (J/kg-K)') print(' w2 (wave frame) '+str(w2)+' (m/s)') print(' u2 (lab frame) '+str(u2)+' (m/s)') print(' a2 (frozen) '+str(a2_fr)+' (m/s)')
from sdtoolbox.thermo import soundspeed_eq,soundspeed_fr from sdtoolbox.postshock import PostShock_eq,PostShock_fr transport = True mech = 'airNASA9noions.cti' gas1 = ct.Solution(mech) gas2 = ct.Solution(mech) gas3 = ct.Solution(mech) ## set initial state of gas. P1 = 770 T1 = 728 q = 'O2:1 N2:3.76' gas1.TPX = T1,P1,q rho1 = gas1.density af1 = soundspeed_fr(gas1) M1 = 7.16 # shock Mach number speed = M1*af1 gamma1_fr = af1**2*rho1/P1 if transport: mu1 = gas1.viscosity nu1 = mu1/rho1 kcond1 = gas1.thermal_conductivity kdiff1 = kcond1/(rho1*gas1.cp_mass) Pr = mu1*gas1.cp_mass/kcond1 ## Print out initial state print('Shock computation for '+mech+' with composition '+q) print('Initial State') print(' Shock speed '+str(speed)+' (m/s)') print(' Frozen sound Speed '+str(af1)+' (m/s)')
## set initial state, composition, and gas object P1 = 100000. T1 = 300. #q = 'H2:2.00 O2:1.0 N2:3.76' #q = 'C2H4:1.00 O2:3 N2:11.28' q = 'C2H2:1 O2:2.5 AR:3' #q = 'C2H4:1. O2:3' #q = 'O2:1. N2:3.76' mech = 'gri30_highT.cti' gas1 = ct.Solution(mech) gas1.TPX = T1, P1, q ## Evaluate initial state R1 = gas1.density c1_fr = soundspeed_fr(gas1) cp1 = gas1.cp_mass w1 = gas1.mean_molecular_weight gamma1_fr = c1_fr**2 * R1 / P1 ## Set shock speed cj_speed = CJspeed(P1, T1, q, mech) Us = cj_speed ## Evaluate gas state # q = 'O2:1. N2:3.76' gas = PostShock_eq(Us, P1, T1, q, mech) ## Evaluate properties of gas object T2 = gas.T P2 = gas.P
Windows 8.1, Windows 10, Linux (Debian 9) """ import cantera as ct from sdtoolbox.thermo import soundspeed_fr from sdtoolbox.postshock import PostShock_fr import datetime import matplotlib.pyplot as plt # set initial state of gas, avoid using precise stoichiometric ratios. P1 = 100000 T1 = 295 q = 'O2:0.2095 N2:0.7808 CO2:0.0004 Ar:0.0093' mech = 'airNASA9ions.cti' gas1 = ct.Solution(mech) gas1.TPX = T1, P1, q a1_fr = soundspeed_fr(gas1) R1 = gas1.density gamma1_fr = a1_fr**2 * R1 / P1 print('Initial Conditions') print(' pressure ' + str(P1) + ' (Pa)') print(' temperature ' + str(T1) + ' (K)') print(' density ' + str(R1) + ' (kg/m3)') print('a1 (frozen) ' + str(a1_fr) + ' (m/s)') print('gamma1 (frozen) ' + str(gamma1_fr) + ' (m/s)') print('Computing shock state and isentrope for ' + q + ' using ' + mech) # Evaluate the frozen state of the gas behind a shock wave # traveling at a specified speed (must be greater than sound speed) shock_speed = 1633.
vR[i] = v2 PRpa = (P1 - r1**2 * U1**2 * (v2 - v1)) PR[i] = PRpa / ct.one_atm i = i + 1 v2 = v2 - stepv print('Rayleigh Line Array Created') # Frozen (reactant) HUGONIOT n = 50 PH1 = np.zeros(n + 1, float) vH1 = np.zeros(n + 1, float) PH1[0] = P1 / ct.one_atm vH1[0] = v1 Umin = 1.1 * soundspeed_fr(gas1) stepU = (1.1 * U1 - Umin) / float(n) i = 0 while (i < n): U = Umin + stepU * float(i) gas = PostShock_fr(U, P1, T1, q, mech) PH1[i + 1] = gas.P / ct.one_atm vH1[i + 1] = 1 / gas.density i = i + 1 print('Reactant Hugoniot Array Created') # Compute four frozen isentropes # one passing through initial state # one passing through postshock state
# (where U = w) so that we can keep the code as similar as possible to the MATLAB equivalent # Numpy actually handles this case and returns the correct value for the limit arctan(inf) import warnings warnings.filterwarnings("ignore", category=RuntimeWarning) ## # set the initial state and compute properties P1 = 100000 T1 = 300 q = 'H2:2 O2:1 N2:3.76' mech = 'Mevel2017.cti' gas1 = ct.Solution(mech) gas1.TPX = T1, P1, q rho1 = gas1.density a1 = soundspeed_fr(gas1) ## # Set freestream velocity and find limiting speeds U = 1500. beta_min = np.arcsin(a1 / U) # Mach angle wmin = a1 + 1. # start just above sound speed # check to see if shock speed is above sound speed if (U < a1): exit('Shock speed below sound speed. Exiting.') # set maximum normal speed wmax = U # initialize variables for plotting rho2 = []