def induction_length(self, cj_speed=False, P1=False, T1=False, q=False, mech=False, t_end=1e-5): # Assign default values innit if cj_speed is False: cj_speed = self.cj_speed if P1 is False: P1 = self.P1 if T1 is False: T1 = self.T1 if q is False: q = self.q if mech is False: mech = self.SDTmech # Set up gas object gas1 = ct.Solution(mech) gas1.TPX = T1, P1, q # Find post-shock conditions gas = PostShock_fr(cj_speed, P1, T1, q, mech) # Solve ZND ODEs to find the width of the ZND "plateau" znd_out = zndsolve(gas, gas1, cj_speed, t_end=t_end, advanced_output=True) plateau_length = znd_out['ind_len_ZND'] return plateau_length
def calc_vnpressure(self): # Calculation for the Chapman-Jouget speeds cj_speed_mps = self.calc_cjspeed() if self.ps_fr is False: # Post shock (frozen) pressure to be determined self.ps_fr = PostShock_fr(U1=cj_speed_mps, P1=self.P1, T1=self.T1, q=self.q, mech=self.mech) vn_pressure_pa = self.ps_fr.P return vn_pressure_pa
print(' gamma2 (equilibrium) '+str(gamma2_eq)+' (m/s)') print('--------------------------------------') # gas3 = ct.Solution(mech) p3,UR,gas3 = reflected_eq(gas1,gas,gas3,cj_speed) print('Reflected CJ shock (equilibrium) computation for '+mech+' with composition '+q) print(' CJ speed '+str(cj_speed)+' (m/s)') print(' Reflected wave speed '+str(UR)+' (m/s)') print('Post-Reflected Shock Parameters') print(' Pressure '+str(gas3.P)+' (Pa)') print(' Temperature '+str(gas3.T)+' (K)') print(' Density '+str(gas3.density)+' (kg/m3)') print('--------------------------------------'); # print('Shock computation for '+mech+' with composition '+q) gas = PostShock_fr(cj_speed,P1,T1,q,mech) print(' shock speed '+str(cj_speed)+' (m/s)') print('Postshock State') print(' Pressure '+str(gas.P)+' (Pa)') print(' Temperature '+str(gas.T)+' (K)') print(' Density '+str(gas.density)+' (kg/m3)') print(' Entropy '+str(gas.entropy_mass)+' (J/kg-K)') w2 = cj_speed*gas1.density/gas.density u2 = cj_speed-w2 print(' w2 (wave frame) '+str(w2)+' (m/s)') print(' u2 (lab frame) '+str(u2)+' (m/s)') print(' a2 (frozen) '+str(soundspeed_fr(gas))+' (m/s)') gamma2_fr = soundspeed_fr(gas)**2*gas.density/gas.P print(' gamma2 (frozen) '+str(gamma2_fr)+' (m/s)') print('--------------------------------------') #
Umax = 2000. Ustep = 100. # Ustep will be approximated nsteps = int((Umax - Umin) / Ustep) speed = [] P = [] R = [] T = [] a = [] gamma = [] w2 = [] u2 = [] for speeds in linspace(Umin, Umax, num=nsteps): speed.append(speeds) gas = PostShock_fr(speed[-1], P1, T1, q, mech) P.append(gas.P) R.append(gas.density) T.append(gas.T) a.append(soundspeed_fr(gas)) gamma.append(a[-1]**2 * R[-1] / P[-1]) w2.append(gas1.density * speed[-1] / R[-1]) u2.append(speed[-1] - w2[-1]) ################################################################################################## # Create output file in text format with Tecplot-style variable labels for # columns ################################################################################################## fn = 'shock_adiabat.txt' d = datetime.date.today() fid = open(fn, 'w')
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) T2.append(shocked_gas.T) rho2.append(shocked_gas.density) w2 = rho1*U/shocked_gas.density u2.append(U - w2) Us.append(U) if CASE_DRIVER=='gas': ## Set initial state for driver section - pressurized gas and no reaction # for nonreacting driver, use frozen expansion EQ_EXP = False P_driver = 3e6; T_driver = 300.;
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)) # CJ speed gas.TPX = T1,P1,x Ucj.append(CJspeed(P1, T1, x, mech)) # vN state gas1 = PostShock_fr(Ucj[-1], P1, T1, x, mech) vn_T.append(gas1.T) vn_P.append(gas1.P) vn_rho.append(gas1.density) vn_af.append(soundspeed_fr(gas1)) # ZND Structure ZNDout = zndsolve(gas1,gas,Ucj[-1],advanced_output=True) ind_len_ZND.append(ZNDout['ind_len_ZND']) exo_len_ZND.append(ZNDout['exo_len_ZND']) # CJ state gas1 = PostShock_eq(Ucj[-1],P1, T1,x,mech) cj_T.append(gas1.T) cj_P.append(gas1.P) cj_rho.append(gas1.density)
print(q) print('Initial conditions: P1 = %.3e atm & T1 = %.2f K' % (initpress, inittemp)) # generate gas solution and set initial conditions preshockgas = ct.Solution(mech) preshockgas.TPX = inittemp, initpress * ct.one_atm, q # calculate CJ speed for gas mixture cj_speed = CJspeed(initpress * ct.one_atm, inittemp, q, mech, fullOutput=False) # calculate postshock gas condition postshockgas = PostShock_fr(cj_speed, initpress * ct.one_atm, inittemp, q, mech) # save and print initial shock temp and pressure shockedpress = postshockgas.P / 101325 shockedtemp = postshockgas.T print(f' PostShock Pressure: {postshockgas.P/101325} atm') print(f' PostShock Temperature: {postshockgas.T} K') # Resolution: The PFR will be simulated by 'n_steps' time steps n_steps = 3000000 # create a new reactor r1 = ct.IdealGasConstPressureReactor(postshockgas) # create a reactor network for performing time integration sim1 = ct.ReactorNet([r1]) # approximate a time step to achieve a similar resolution as in the next method
print(' Frozen sound Speed '+str(af1)+' (m/s)') print(' Shock Mach number '+str(M1)) print(' Pressure '+str(P1)+' (Pa)') print(' Temperature '+str(T1)+' (K)') print(' Density '+str(rho1)+' (kg/m3)') print(' gamma2 (based on frozen sound speed) '+str(gamma1_fr)+' (m/s)') print(' Specific heat at constant pressure '+str(gas1.cp_mass)+' (J/kg K)') if transport: print(' viscosity '+str(mu1)+' (kg/m s)') print(' viscosity (kinematic)'+str(nu1)+' (m2/s)') print(' thermal conductivity '+str(kcond1)+' (W/m K)') print(' thermal diffusivity '+str(kdiff1)+' (m2/s)') print(' Prandtl number '+str(Pr)) ## Postshock (Frozen) gas2 = PostShock_fr(speed,P1,T1,q,mech) af2 = soundspeed_fr(gas2) ae2 = soundspeed_eq(gas2) P2 = gas2.P T2 = gas2.T S2 = gas2.entropy_mass rho2 = gas2.density gamma2_fr = af2**2*rho2/P2 gamma2_eq = ae2**2*rho2/P2 w2 = rho1*speed/rho2 u2 = speed - w2 if transport: mu = gas2.viscosity nu = mu/rho2 kcond = gas2.thermal_conductivity kdiff = kcond/(rho2*gas2.cp_mass)
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) # Outputs: # p3 - pressure behind reflected wave # UR = Reflected shock speed relative to reflecting surface # gas3 = gas object with properties of postshock state P3 = gas3.P / ct.one_atm print('Frozen Post-Reflected-Shock State') print('T3 = %.2f K, P3 = %.2f atm' % (gas3.T, P3))
print('Initial Conditions') print(x + ', Temperature = %.2f K' % (T1)) print('For %s initial pressures' % (npoints)) for i in range(npoints): P1[i] = Po*(0.1 +1.1/npoints*(i)) P = P1[i] print('%i : P1 = %.2f atm' % (i+1,P/ct.one_atm)) gas.TPX = T1,P1[i],x ### Constant Volume Explosion Data ### # FIND POST SHOCK STATE FOR GIVEN SPEED cj_speed[i] = CJspeed(P1[i], T1, x, mech) gas = PostShock_fr(cj_speed[i], P1[i], T1, x, mech) Ts[i] = gas.T #frozen shock temperature Ps[i] = gas.P #frozen shock pressure # SOLVE CONSTANT VOLUME EXPLOSION ODES CVout = cvsolve(gas,t_end=1e-4) exo_time_CV[i] = CVout['exo_time'] ind_time_CV[i] = CVout['ind_time'] ### ZND Detonation Data ### # FIND POST SHOCK STATE FOR GIVEN SPEED gas1.TPX = T1,P1[i],x gas = PostShock_fr(cj_speed[i], P1[i], T1, x, mech) Ts[i] = gas.T #frozen shock temperature Ps[i] = gas.P #frozen shock pressure # SOLVE ZND DETONATION ODES
h1 = gas1.enthalpy_mass r1 = gas1.density v1 = 1.0 / gas1.density #Get CJ Point cj_speed = CJspeed(P1, T1, q, mech) gas = PostShock_eq(cj_speed, P1, T1, q, mech) vcj = 1.0 / gas.density Pcj = gas.P / ct.one_atm print('CJ Point Found') U1 = od * cj_speed #Find Postshock specific volume for U1 gas = PostShock_fr(U1, P1, T1, q, mech) vsj = 1.0 / gas.density Psj = gas.P / ct.one_atm #Find Gamma gas = PostShock_fr(gbound * cj_speed, P1, T1, q, mech) g = gas.cp_mass / gas.cv_mass # RAYLEIGH LINE, SJUMP MIN & MAX, GAMMA CONSTRAINT minp = 0.1 * vcj maxp = 2.0 * vcj step = 0.01 * vcj i = 0 v2 = minp n = np.int((maxp - minp) / step) vR = np.zeros(n, float)
P1 = ct.one_atm; P1atm = P1/ct.one_atm print('Initial Conditions') print(x + ', Pressure = %.2f atm, Temperature = %.2f K' % (P1atm,T1)) print('For %s values of overdrive' % (npoints)) cj_speed = CJspeed(P1, T1, x, mech) for i in range(npoints): overdrive[i] = (1.0 +0.6/npoints*(i)) #Overdrive = U/Ucj ratio = overdrive[i] print('%i : Overdrive = %.2f ' % (i+1,ratio)) # Find post shock state for given speed gas.TPX = T1,P1,x gas = PostShock_fr(cj_speed*overdrive[i], P1, T1, x, mech) Ts[i] = gas.T # frozen shock temperature Ps[i] = gas.P # frozen shock pressure ### Constant Volume Explosion Data ### # Solve constant volume explosion ODEs CVout = cvsolve(gas) exo_time_CV[i] = CVout['exo_time'] ind_time_CV[i] = CVout['ind_time'] ### ZND Detonation Data ### gas.TPX = T1,P1,x gas = PostShock_fr(cj_speed*overdrive[i], P1, T1, x, mech) # Solve znd detonation ODEs ZNDout = zndsolve(gas,gas1,cj_speed*overdrive[i],advanced_output=True)
rho5 = []; w4 = []; w5 = []; u5 = []; vt4 = []; a5 = []; P5 = []; T5 = []; h5 = []; s5 = []; beta = []; theta = []; ## # compute shock jump conditions over range from minimum to maximum normal # speeds. Adjust the increment to get a smooth output curve. wstep = 5 nsteps = int((wmax-wmin)/wstep) for w in np.linspace(wmin,wmax,num=nsteps): if EQ: # equilibrium state gas = PostShock_eq(w, P4, T4, x4, mech) a5.append(soundspeed_eq(gas)) else: # for non-reactive or cold upstream state, use frozen shock calculation gas = PostShock_fr(w, P4, T4, qs, mech) a5.append(soundspeed_fr(gas)) rho5.append(gas.density) ratio = rho4/rho5[-1] w4.append(w) w5.append(w*ratio) P5.append(gas.P) T5.append(gas.T) h5.append(gas.enthalpy_mass) s5.append(gas.entropy_mass) beta.append(np.arcsin(w/U4)) vt4.append(U4*np.cos(beta[-1])) theta.append(beta[-1] - np.arctan(w5[-1]/np.sqrt(U4**2-w**2))) u5.append(np.sqrt(w5[-1]**2 + vt4[-1]**2))
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. gas = PostShock_fr(shock_speed, P1, T1, q, mech) # Evaluate properties of gas object and print out T2 = gas.T P2 = gas.P R2 = gas.density V2 = 1 / R2 S2 = gas.entropy_mass w2 = gas1.density * shock_speed / R2 u2 = shock_speed - w2 x2 = gas.X a2_fr = soundspeed_fr(gas) gamma2_fr = a2_fr**2 * R2 / P2 print('Shock speed ' + str(shock_speed) + ' (m/s)') print('Frozen Post-Shock State')
mech = 'airNASA9ions.cti' fname = 'AirFr' U1 = 1000. plt_num = 1 # EDIT VALUES ABOVE THIS LINE ############################## # set initial state gas1 = ct.Solution(mech) gas1.TPX = T1, P1, q h1 = gas1.enthalpy_mass r1 = gas1.density v1 = 1.0 / gas1.density s1 = gas1.s #Get postshock state gas = PostShock_fr(U1, P1, T1, q, mech) v_ps = 1.0 / gas.density P_ps = gas.P / ct.one_atm # RAYLEIGH LINE, minv = 0.9 * v_ps maxv = 1.00 * v1 stepv = 0.01 * v1 n = np.int((maxv - minv) / stepv) vR = np.zeros(n, float) PR = np.zeros(n, float) i = 0 v2 = maxv while (i < n): vR[i] = v2
## # compute shock jump conditions over range from minimum to maximum normal # speeds. Adjust the increment to get a smooth output curve. step = 5 # approximate desired step size (will not be exactly followed) npoints = int((wmax-wmin)/step) for w in np.linspace(wmin,wmax,num=npoints): if EQ: # equilibrium state gas = PostShock_eq(w, Ps, Ts, xs, mech) a2.append(soundspeed_eq(gas)) else: # for non-reactive or cold upstream state, use frozen shock calculation gas = PostShock_fr(w, Ps, Ts, qs, mech) a2.append(soundspeed_fr(gas)) rho2.append(gas.density) ratio = rhos/rho2[-1] w1.append(w) w2.append(w*ratio) P2.append(gas.P) beta.append(np.arcsin(w/US)) vt.append(US*np.cos(beta[-1])) theta.append(beta[-1] - np.arctan(w2[-1]/np.sqrt(US**2-w**2))) u2.append(np.sqrt(w2[-1]**2 + vt[-1]**2)) # pick up normal shock as last point w = US
Tested with: Python 3.5 and 3.6, Cantera 2.3 and 2.4 Under these operating systems: Windows 8.1, Windows 10, Linux (Debian 9) """ import cantera as ct from sdtoolbox.postshock import PostShock_fr # Initial state specification: # P1 = Initial Pressure # T1 = Initial Temperature # U = Shock Speed # q = Initial Composition # mech = Cantera mechanism File name P1 = 100000; P1atm = P1/ct.one_atm T1 = 300 U = 2000 q = 'H2:2 O2:1 N2:3.76' mech = 'Mevel2017.cti' gas = PostShock_fr(U, P1, T1, q, mech) Ps = gas.P/ct.one_atm print(' ') print('Initial state: ' + q + ', P1 = %.2f atm, T1 = %.2f K' % (P1atm,T1) ) print('Mechanism: ' + mech) print('Frozen postshock state: Ps = %.2f atm, Ts = %.2f K' % (Ps,gas.T)) print(' ')
w1 = [] w2 = [] u2 = [] v = [] a2 = [] P2 = [] beta = [] theta = [] ## # compute shock jump conditions over range from minimum to maximum normal # speeds. Adjust the increment to get a smooth output curve. wstep = 5 nsteps = int((wmax - wmin) / wstep) for w in np.linspace(wmin, wmax, num=nsteps): gas = PostShock_fr(w, P1, T1, q, mech) # gas = PostShock_eq(w, P1, T1, q, mech) #will not converge at low temperature. rho2.append(gas.density) a2.append(soundspeed_fr(gas)) ratio = rho1 / rho2[-1] w1.append(w) w2.append(w * ratio) P2.append(gas.P) beta.append(np.arcsin(w / U)) v.append(U * np.cos(beta[-1])) theta.append(beta[-1] - np.arctan(w2[-1] / np.sqrt(U**2 - w**2))) u2.append(np.sqrt(w2[-1]**2 + v[-1]**2)) ## pick up normal shock as last point w = U gas = PostShock_fr(w, P1, T1, q, mech)