def main(mech_filename: str = "data/mechanisms/HeliumArgon.xml", show_results: bool = True, results_location: Optional[str] = None) -> None: #parameters fontsize = 12 tFinal = 7.5e-3 p5, p1 = 18 * ct.one_atm, 0.48e5 T5 = 1698.0 g4 = g1 = 5.0 / 3.0 #monatomic gas in driver and driven sections W4, W1 = 4.002602, 39.948 #Helium and argon MachReduction = 0.985 #account for shock wave attenuation nXCoarse, nXFine = 200, 1000 #mesh resolution LDriver, LDriven = 3.0, 5.0 DDriver, DDriven = 7.5e-2, 5.0e-2 plt.close("all") mpl.rcParams['font.size'] = fontsize plt.rc('text', usetex=True) #set up geometry xLower = -LDriver xUpper = LDriven xShock = 0.0 Delta = 10 * (xUpper - xLower) / float(nXFine) geometry = (nXCoarse, xLower, xUpper, xShock) DInner = lambda x: np.zeros_like(x) dDInnerdx = lambda x: np.zeros_like(x) def DOuter(x): return smoothingFunction(x, xShock, Delta, DDriver, DDriven) def dDOuterdx(x): return dSFdx(x, xShock, Delta, DDriver, DDriven) A = lambda x: np.pi / 4.0 * (DOuter(x)**2.0 - DInner(x)**2.0) dAdx = lambda x: np.pi / 2.0 * (DOuter(x) * dDOuterdx(x) - DInner(x) * dDInnerdx(x)) dlnAdx = lambda x, t: dAdx(x) / A(x) #compute the gas dynamics def res(Ms1): return p5/p1-((2.0*g1*Ms1**2.0-(g1-1.0))/(g1+1.0)) \ *((-2.0*(g1-1.0)+Ms1**2.0*(3.0*g1-1.0))/(2.0+Ms1**2.0*(g1-1.0))) Ms1 = newton(res, 2.0) Ms1 *= MachReduction T5oT1 = (2.0*(g1-1.0)*Ms1**2.0+3.0-g1) \ *((3.0*g1-1.0)*Ms1**2.0-2.0*(g1-1.0)) \ /((g1+1.0)**2.0*Ms1**2.0) T1 = T5 / T5oT1 a1oa4 = np.sqrt(W4 / W1) p4op1 = (1.0+2.0*g1/(g1+1.0)*(Ms1**2.0-1.0)) \ *(1.0-(g4-1.0)/(g4+1.0)*a1oa4*(Ms1-1.0/Ms1))**(-2.0*g4/(g4-1.0)) p4 = p1 * p4op1 #set up the gasses u1 = 0.0 u4 = 0.0 #initially 0 velocity gas1 = ct.Solution(mech_filename) gas4 = ct.Solution(mech_filename) T4 = T1 #assumed gas1.TPX = T1, p1, "AR:1" gas4.TPX = T4, p4, "HE:1" #set up solver parameters boundaryConditions = ['reflecting', 'reflecting'] state1 = (gas1, u1) state4 = (gas4, u4) ss = stanShock( gas1, initializeRiemannProblem=(state4, state1, geometry), boundaryConditions=boundaryConditions, cfl=.9, outputEvery=100, includeBoundaryLayerTerms=True, Tw=T1, #assume wall temperature is in thermal eq. with gas DOuter=DOuter, dlnAdx=dlnAdx) #Solve t0 = time.perf_counter() tTest = 2e-3 tradeoffParam = 1.0 eps = 0.01**2.0 + tradeoffParam * 0.01**2.0 ss.optimizeDriverInsert(tFinal, p5=p5, tTest=tTest, tradeoffParam=tradeoffParam, eps=eps) t1 = time.perf_counter() print("The process took ", t1 - t0) #recalculate at higher resolution with the insert geometry = (nXFine, xLower, xUpper, xShock) gas1.TPX = T1, p1, "AR:1" gas4.TPX = T4, p4, "HE:1" ss = stanShock( gas1, initializeRiemannProblem=(state4, state1, geometry), boundaryConditions=boundaryConditions, cfl=.9, outputEvery=100, includeBoundaryLayerTerms=True, Tw=T1, #assume wall temperature is in thermal eq. with gas DOuter=DOuter, DInner=ss.DInner, dlnAdx=ss.dlnAdx) ss.addXTDiagram("p") ss.addXTDiagram("T") ss.addProbe(max(ss.x)) #end wall probe t0 = time.perf_counter() ss.advanceSimulation(tFinal) t1 = time.perf_counter() print("The process took ", t1 - t0) pInsert = np.array(ss.probes[0].p) tInsert = np.array(ss.probes[0].t) ss.plotXTDiagram(ss.XTDiagrams["t"], limits=[200.0, 1800.0]) ss.plotXTDiagram(ss.XTDiagrams["p"], limits=[0.5, 25]) xInsert = ss.x DOuterInsert = ss.DOuter(ss.x) DInnerInsert = ss.DInner(ss.x) #recalculate at higher resolution without the insert gas1.TPX = T1, p1, "AR:1" gas4.TPX = T4, p4, "HE:1" ss = stanShock( gas1, initializeRiemannProblem=(state4, state1, geometry), boundaryConditions=boundaryConditions, cfl=.9, outputEvery=100, includeBoundaryLayerTerms=True, Tw=T1, #assume wall temperature is in thermal eq. with gas DOuter=DOuter, dlnAdx=dlnAdx) ss.addXTDiagram("p") ss.addXTDiagram("T") ss.addProbe(max(ss.x)) #end wall probe t0 = time.perf_counter() ss.advanceSimulation(tFinal) t1 = time.perf_counter() print("The process took ", t1 - t0) pNoInsert = np.array(ss.probes[0].p) tNoInsert = np.array(ss.probes[0].t) ss.plotXTDiagram(ss.XTDiagrams["t"], limits=[200.0, 1800.0]) ss.plotXTDiagram(ss.XTDiagrams["p"], limits=[0.5, 25]) #plot plt.figure() plt.plot(tNoInsert / 1e-3, pNoInsert / 1e5, 'k', label="$\mathrm{No\ Insert}$") plt.plot(tInsert / 1e-3, pInsert / 1e5, 'r', label="$\mathrm{Optimized\ Insert}$") plt.xlabel("$t\ [\mathrm{ms}]$") plt.ylabel("$p\ [\mathrm{bar}]$") plt.legend(loc="best") plt.tight_layout() plt.figure() plt.plot(xInsert, DOuterInsert, 'k', label="$D_\mathrm{o}$") plt.plot(xInsert, DInnerInsert, 'r', label="$D_\mathrm{i}$") plt.xlabel("$x\ [\mathrm{m}]$") plt.ylabel("$D\ [\mathrm{m}]$") plt.legend(loc="best") plt.tight_layout() if show_results: plt.show() if results_location is not None: np.savez(os.path.join(results_location, "optimization.npz"), pressure_with_insert=pInsert, pressure_without_insert=pNoInsert, insert_diameter=DInnerInsert, shock_tube_diameter=DOuterInsert, position=xInsert, time_with_insert=tInsert, time_without_insert=tNoInsert) plt.savefig(os.path.join(results_location, "optimization.png"))
def main(data_filename: str = "data/validation/case2.csv", mech_filename: str = "data/mechanisms/Nitrogen.xml", show_results: bool = True, results_location: Optional[str] = None) -> None: #============================================================================= #provided condtions for Case 2 Ms = 2.518914 T1 = 291.75 p1 = 2026.499994 p2 = 14730.642333 tFinal = 60e-3 #plotting parameters fontsize = 12 #provided geometry DDriven = 4.5 * 0.0254 DDriver = 7.0 * 0.0254 LDriver = 142.0 * 0.0254 LDriven = 9.73 #Set up gasses and determine the initial pressures u1 = 0.0 u4 = 0.0 #initially 0 velocity gas1 = ct.Solution(mech_filename) gas4 = ct.Solution(mech_filename) T4 = T1 #assumed gas1.TP = T1, p1 gas4.TP = T4, p1 #use p1 as a place holder g1 = gas1.cp / gas1.cv g4 = gas4.cp / gas4.cv a4oa1 = np.sqrt(g4 / g1 * T4 / T1 * gas1.mean_molecular_weight / gas4.mean_molecular_weight) p4 = p2 * (1.0 - (g4 - 1.0) / (g1 + 1.0) / a4oa1 * (Ms - 1.0 / Ms))**(-2.0 * g4 / (g4 - 1.0)) #from handbook of shock waves p4 *= DDriven / DDriver #just made this up p4 *= 1.05 gas4.TP = T4, p4 #set up geometry nX = 1000 #mesh resolution xLower = -LDriver xUpper = LDriven xShock = 0.0 geometry = (nX, xLower, xUpper, xShock) DeltaD = DDriven - DDriver DeltaX = (xUpper - xLower ) / float(nX) * 10 #diffuse area change for numerical stability #DeltaX = 0.75 #from Eduardo's case def D(x): diameter = DDriven + (DeltaD / DeltaX) * (x - xShock) diameter[x < (xShock - DeltaX)] = DDriver diameter[x > xShock] = DDriven return diameter def dDdx(x): dDiameterdx = np.ones(len(x)) * (DeltaD / DeltaX) dDiameterdx[x < (xShock - DeltaX)] = 0.0 dDiameterdx[x > xShock] = 0.0 return dDiameterdx A = lambda x: np.pi / 4.0 * D(x)**2.0 dAdx = lambda x: np.pi / 2.0 * D(x) * dDdx(x) dlnAdx = lambda x, t: dAdx(x) / A(x) #set up solver parameters print("Solving with boundary layer terms") boundaryConditions = ['reflecting', 'reflecting'] state1 = (gas1, u1) state4 = (gas4, u4) ssbl = stanShock( gas1, initializeRiemannProblem=(state4, state1, geometry), boundaryConditions=boundaryConditions, cfl=.9, outputEvery=100, includeBoundaryLayerTerms=True, Tw=T1, #assume wall temperature is in thermal eq. with gas DOuter=D, dlnAdx=dlnAdx) ssbl.addProbe(max(ssbl.x)) #end wall probe #Solve t0 = time.perf_counter() ssbl.advanceSimulation(tFinal) t1 = time.perf_counter() print("The process took ", t1 - t0) #without boundary layer model print("Solving without boundary layer model") boundaryConditions = ['reflecting', 'reflecting'] gas1.TP = T1, p1 gas4.TP = T4, p4 ssnbl = stanShock(gas1, initializeRiemannProblem=(state4, state1, geometry), boundaryConditions=boundaryConditions, cfl=.9, outputEvery=100, includeBoundaryLayerTerms=False, DOuter=D, dlnAdx=dlnAdx) ssnbl.addProbe(max(ssnbl.x)) #end wall probe #Solve t0 = time.perf_counter() ssnbl.advanceSimulation(tFinal) t1 = time.perf_counter() print("The process took ", t1 - t0) #import shock tube data tExp, pExp = getPressureData(data_filename) timeDifference = ( 12.211 - 8.10) / 1000.0 #difference between the test data and simulation times tExp += timeDifference #make plots of probe and XT diagrams plt.close("all") mpl.rcParams['font.size'] = fontsize plt.rc('text', usetex=True) plt.figure(figsize=(4, 4)) plt.plot(np.array(ssnbl.probes[0].t) * 1000.0, np.array(ssnbl.probes[0].p) / 1.0e5, 'k', label="$\mathrm{Without\ BL\ Model}$", linewidth=2.0) plt.plot(np.array(ssbl.probes[0].t) * 1000.0, np.array(ssbl.probes[0].p) / 1.0e5, 'r', label="$\mathrm{With\ BL\ Model}$", linewidth=2.0) plt.plot(tExp * 1000.0, pExp / 1.0e5, label="$\mathrm{Experiment}$", alpha=0.7) plt.axis([0, 60, -.25, 2.75]) plt.xlabel("$t\ [\mathrm{ms}]$") plt.ylabel("$p\ [\mathrm{bar}]$") plt.legend(loc="lower right") plt.tight_layout() if show_results: plt.show() if results_location is not None: np.savez(os.path.join(results_location, "case2.npz"), pressure_with_boundary_layer=ssbl.probes[0].p, pressure_without_boundary_layer=ssnbl.probes[0].p, time_with_boundary_layer=ssbl.probes[0].t, time_without_boundary_layer=ssnbl.probes[0].t) plt.savefig(os.path.join(results_location, "case2.png"))
def main(data_filename: str = "data/validation/case4.png", mech_filename: str = "data/mechanisms/N2O2HeAr.xml", show_results: bool = True, results_location: Optional[str] = None) -> None: #============================================================================= #provided condtions for Case4 T1 = T4 = 292.05 p1 = 390.0 * 133.322 p4 = 82.0 * 6894.76 * 0.9 tFinal = 60e-3 #plotting parameters fontsize = 12 #provided geometry DDriven = 4.5 * 0.0254 DDriver = DDriven LDriver = 142.0 * 0.0254 LDriven = 9.73 #Set up gasses and determine the initial pressures u1 = 0.0 u4 = 0.0 #initially 0 velocity gas1 = ct.Solution(mech_filename) gas4 = ct.Solution(mech_filename) T4 = T1 #assumed gas1.TPX = T1, p1, "O2:0.21,AR:0.79" gas4.TPX = T4, p4, "HE:0.25,N2:0.75" #set up geometry nX = 1000 #mesh resolution xLower = -LDriver xUpper = LDriven xShock = 0.0 geometry = (nX, xLower, xUpper, xShock) #arrays from HTGL xInterp = -0.0254 * np.array([ 142, 140, 130, 120, 110, 100, 90, 80, 70, 60, 50, 40, 36, 37, 30, 20, 10, 0 ]) dInterp = 0.0254 * np.array([ 3.25, 3.21, 3.01, 2.81, 2.61, 2.41, 2.21, 2.01, 1.81, 1.61, 1.41, 1.21, 1.13, 0.00, 0.00, 0.00, 0.00, 0.00 ]) dDInterpdxInterp = (dInterp[1:] - dInterp[:-1]) / (xInterp[1:] - xInterp[:-1]) def DOuter(x): nX = x.shape[0] return DDriven * np.ones(nX) def DInner(x): diameter = np.interp(x, xInterp, dInterp) return diameter def dDOuterdx(x): return np.zeros(nX) def dDInnerdx(x): dDiameterdx = np.interp(x, xInterp[:-1], dDInterpdxInterp) return dDiameterdx A = lambda x: np.pi / 4.0 * (DOuter(x)**2.0 - DInner(x)**2.0) dAdx = lambda x: np.pi / 2.0 * (DOuter(x) * dDOuterdx(x) - DInner(x) * dDInnerdx(x)) dlnAdx = lambda x, t: dAdx(x) / A(x) #solve with boundary layer model boundaryConditions = ['reflecting', 'reflecting'] state1 = (gas1, u1) state4 = (gas4, u4) ssbl = stanShock( gas1, initializeRiemannProblem=(state4, state1, geometry), boundaryConditions=boundaryConditions, cfl=.9, outputEvery=100, includeBoundaryLayerTerms=True, Tw=T1, #assume wall temperature is in thermal eq. with gas DInner=DInner, DOuter=DOuter, dlnAdx=dlnAdx) ssbl.addProbe(max(ssbl.x)) #end wall probe ssbl.addXTDiagram("p") ssbl.addXTDiagram("T") #adjust for partial filling strategy XN2Lower = 0.80 #assume smearing during fill XN2Upper = 1.5 - XN2Lower dx = ssbl.x[1] - ssbl.x[0] dV = A(ssbl.x) * dx VDriver = np.sum(dV[ssbl.x < xShock]) V = np.cumsum(dV) V -= V[0] / 2.0 #center VNorms = V / VDriver #get gas properties iHE, iN2 = gas4.species_index("HE"), gas4.species_index("N2") for iX, VNorm in enumerate(VNorms): if VNorm <= 1.0: #nitrogen and helium X = np.zeros(gas4.n_species) XN2 = XN2Lower + (XN2Upper - XN2Lower) * VNorm XHE = 1.0 - XN2 X[[iHE, iN2]] = XHE, XN2 gas4.TPX = T4, p4, X ssbl.r[iX] = gas4.density ssbl.Y[iX, :] = gas4.Y ssbl.gamma[iX] = gas4.cp / gas4.cv #Solve t0 = time.perf_counter() ssbl.advanceSimulation(tFinal) t1 = time.perf_counter() print("The process took ", t1 - t0) #Solve without boundayr layer model boundaryConditions = ['reflecting', 'reflecting'] gas1.TP = T1, p1 gas4.TP = T4, p4 ssnbl = stanShock( gas1, initializeRiemannProblem=(state4, state1, geometry), boundaryConditions=boundaryConditions, cfl=.9, outputEvery=100, includeBoundaryLayerTerms=False, Tw=T1, #assume wall temperature is in thermal eq. with gas DInner=DInner, DOuter=DOuter, dlnAdx=dlnAdx) ssnbl.addProbe(max(ssnbl.x)) #end wall probe ssnbl.addXTDiagram("p") ssnbl.addXTDiagram("T") #adjust for partial filling strategy XN2Lower = 0.80 #assume smearing during fill XN2Upper = 1.5 - XN2Lower dx = ssnbl.x[1] - ssnbl.x[0] dV = A(ssnbl.x) * dx VDriver = np.sum(dV[ssnbl.x < xShock]) V = np.cumsum(dV) V -= V[0] / 2.0 #center VNorms = V / VDriver #get gas properties iHE, iN2 = gas4.species_index("HE"), gas4.species_index("N2") for iX, VNorm in enumerate(VNorms): if VNorm <= 1.0: #nitrogen and helium X = np.zeros(gas4.n_species) XN2 = XN2Lower + (XN2Upper - XN2Lower) * VNorm XHE = 1.0 - XN2 X[[iHE, iN2]] = XHE, XN2 gas4.TPX = T4, p4, X ssnbl.r[iX] = gas4.density ssnbl.Y[iX, :] = gas4.Y ssnbl.gamma[iX] = gas4.cp / gas4.cv #Solve t0 = time.perf_counter() ssnbl.advanceSimulation(tFinal) t1 = time.perf_counter() print("The process took ", t1 - t0) #import shock tube data tExp, pExp = getPressureData(data_filename) timeDifference = ( 18.6 - 6.40) / 1000.0 #difference between the test data and simulation times tExp += timeDifference #make plots of probe and XT diagrams plt.close("all") mpl.rcParams['font.size'] = fontsize plt.rc('text', usetex=True) plt.figure(figsize=(4, 4)) plt.plot(np.array(ssnbl.probes[0].t) * 1000.0, np.array(ssnbl.probes[0].p) / 1.0e5, 'k', label="$\mathrm{Without\ BL\ Model}$", linewidth=2.0) plt.plot(np.array(ssbl.probes[0].t) * 1000.0, np.array(ssbl.probes[0].p) / 1.0e5, 'r', label="$\mathrm{With\ BL\ Model}$", linewidth=2.0) plt.plot(tExp * 1000.0, pExp / 1.0e5, label="$\mathrm{Experiment}$", alpha=0.7) plt.axis([0, 60, 0, 5]) plt.xlabel("$t\ [\mathrm{ms}]$") plt.ylabel("$p\ [\mathrm{bar}]$") plt.legend(loc="lower right") plt.tight_layout() if show_results: plt.show() if results_location is not None: np.savez(os.path.join(results_location, "case4.npz"), pressure_with_boundary_layer=ssbl.probes[0].p, pressure_without_boundary_layer=ssnbl.probes[0].p, time_with_boundary_layer=ssbl.probes[0].t, time_without_boundary_layer=ssnbl.probes[0].t) plt.savefig(os.path.join(results_location, "case4.png"))
def main(mech_filename: str = "data/mechanisms/Hong.xml", show_results: bool = True, results_location: Optional[str] = None) -> None: #user parameters TU=300.0 p = 1e5 estFlameThickness=1e-2 ntFlowThrough=.1 fontsize=12 f = 0.1 #factor to reduce Cantera domain #find the initial state of the fluids gas = ct.Solution(mech_filename) unburnedState = TU,p,"H2:2,O2:1,N2:3.76" gas.TPX = unburnedState #get the flame thickness _, flame = flameSpeed(gas,estFlameThickness,returnFlame=True) TU, TB = flame.T[0] ,flame.T[-1] flameThickness=(TB-TU)/max(np.gradient(flame.T,flame.grid)) #get flame parameters gasUnburned = ct.Solution(mech_filename) gasUnburned.TPY = flame.T[0], flame.P, flame.Y[:,0] uUnburned = flame.velocity[0] unburnedState = gasUnburned, uUnburned gasBurned = ct.Solution(mech_filename) gasBurned.TPY = flame.T[-1], flame.P, flame.Y[:,-1] uBurned = flame.velocity[-1] burnedState = gasBurned, uBurned #set up grid nX = flame.grid.shape[0] xCenter = flame.grid[np.argmax(np.gradient(flame.T,flame.grid))] L = flame.grid[-1] - flame.grid[0] xUpper, xLower = xCenter +L*f, xCenter-L*f geometry=(nX,xLower,xUpper,(xUpper+xLower)/2.0) boundaryConditions = (gasUnburned.density,uUnburned,None,gasUnburned.Y),(None,None,gasBurned.P,None) ss = stanShock(gas,initializeRiemannProblem=(unburnedState,burnedState,geometry), boundaryConditions=boundaryConditions, cfl=.9, reacting=True, includeDiffusion=True, outputEvery=10) #interpolate flame solution ss.r = np.interp(ss.x,flame.grid,flame.density) ss.u = np.interp(ss.x,flame.grid,flame.velocity) ss.p[:] = flame.P for iSp in range(gas.n_species): ss.Y[:,iSp] = np.interp(ss.x,flame.grid,flame.Y[iSp,:]) T = ss.thermoTable.getTemperature(ss.r,ss.p,ss.Y) ss.gamma = ss.thermoTable.getGamma(T,ss.Y) #calculate the final time tFinal = ntFlowThrough*(xUpper-xLower)/(uUnburned+uBurned)*2.0 #Solve t0 = time.perf_counter() ss.advanceSimulation(tFinal) t1 = time.perf_counter() print("The process took ", t1-t0) #plot setup plt.close("all") font = {'family':'serif', 'serif': ['computer modern roman']} plt.rc('font',**font) mpl.rcParams['font.size']=fontsize plt.rc('text',usetex=True) #plot plt.plot((flame.grid-xCenter)/flameThickness,flame.T/flame.T[-1],'r',label="$T/T_\mathrm{F}$") T = ss.thermoTable.getTemperature(ss.r,ss.p,ss.Y) plt.plot((ss.x-xCenter)/flameThickness,T/flame.T[-1],'r--s') iOH = gas.species_index("OH") plt.plot((flame.grid-xCenter)/flameThickness,flame.Y[iOH,:]*10,'k',label="$Y_\mathrm{OH}\\times 10$") plt.plot((ss.x-xCenter)/flameThickness,ss.Y[:,iOH]*10,'k--s') iO2 = gas.species_index("O2") plt.plot((flame.grid-xCenter)/flameThickness,flame.Y[iO2,:],'g',label="$Y_\mathrm{O_2}$") plt.plot((ss.x-xCenter)/flameThickness,ss.Y[:,iO2],'g--s') iH2 = gas.species_index("H2") plt.plot((flame.grid-xCenter)/flameThickness,flame.Y[iH2,:],'b',label="$Y_\mathrm{H_2}$") plt.plot((ss.x-xCenter)/flameThickness,ss.Y[:,iH2],'b--s') plt.xlabel("$x/\delta_\mathrm{F}$") plt.legend(loc="best") if show_results: plt.show() if results_location is not None: np.savez( os.path.join(results_location, "laminarFlame.npz"), position=ss.x, temperature=ss.thermoTable.getTemperature(ss.r,ss.p,ss.Y), ) plt.savefig(os.path.join(results_location, "laminarFlame.png"))
def main(data_filename: str = "data/validation/case3.csv", mech_filename: str = "data/mechanisms/Nitrogen.xml", show_results: bool = True, results_location: Optional[str] = None) -> None: #============================================================================= #provided condtions for case 3 Ms = 2.409616 T1 = 292.25 p1 = 1999.83552 p2 = 13267.880629 tFinal = 60e-3 #plotting parameters fontsize = 12 #provided geometry DDriven = 4.5 * 0.0254 DDriver = 4.5 * 0.0254 LDriver = 142.0 * 0.0254 LDriven = 9.73 DOuterInsertBack = 3.375 * 0.0254 DOuterInsertFront = 1.25 * 0.0254 LOuterInsert = 102.0 * 0.0254 DInnerInsert = 0.625 * 0.0254 LInnerInsert = 117.0 * 0.0254 #Set up gasses and determine the initial pressures u1 = 0.0 u4 = 0.0 #initially 0 velocity gas1 = ct.Solution(mech_filename) gas4 = ct.Solution(mech_filename) T4 = T1 #assumed gas1.TP = T1, p1 gas4.TP = T4, p1 #use p1 as a place holder g1 = gas1.cp / gas1.cv g4 = gas4.cp / gas4.cv a4oa1 = np.sqrt(g4 / g1 * T4 / T1 * gas1.mean_molecular_weight / gas4.mean_molecular_weight) p4 = p2 * (1.0 - (g4 - 1.0) / (g1 + 1.0) / a4oa1 * (Ms - 1.0 / Ms))**(-2.0 * g4 / (g4 - 1.0)) #from handbook of shock waves p4 *= 1.04 gas4.TP = T4, p4 #set up geometry nX = 1000 #mesh resolution xLower = -LDriver xUpper = LDriven xShock = 0.0 geometry = (nX, xLower, xUpper, xShock) DeltaD = DDriven - DDriver dDOuterInsertdx = (DOuterInsertFront - DOuterInsertBack) / LOuterInsert DeltaSmoothingFunction = (xUpper - xLower) / float(nX) * 10.0 def DOuter(x): return DDriven * np.ones(nX) def DInner(x): diameter = np.zeros(nX) diameter += smoothingFunction(x, xLower + LInnerInsert, DeltaSmoothingFunction, DInnerInsert, 0.0) diameter += smoothingFunction(x, xLower + LOuterInsert, DeltaSmoothingFunction, DOuterInsertFront - DInnerInsert, 0.0) diameter += smoothingFunction(x, xLower + LOuterInsert / 2.0, LOuterInsert, DOuterInsertBack - DOuterInsertFront, 0.0) return diameter def dDOuterdx(x): return np.zeros(nX) def dDInnerdx(x): dDiameterdx = np.zeros(nX) dDiameterdx += dSFdx(x, xLower + LInnerInsert, DeltaSmoothingFunction, DInnerInsert, 0.0) dDiameterdx += dSFdx(x, xLower + LOuterInsert, DeltaSmoothingFunction, DOuterInsertFront - DInnerInsert, 0.0) dDiameterdx += dSFdx(x, xLower + LOuterInsert / 2.0, LOuterInsert, DOuterInsertBack - DOuterInsertFront, 0.0) return dDiameterdx A = lambda x: np.pi / 4.0 * (DOuter(x)**2.0 - DInner(x)**2.0) dAdx = lambda x: np.pi / 2.0 * (DOuter(x) * dDOuterdx(x) - DInner(x) * dDInnerdx(x)) dlnAdx = lambda x, t: dAdx(x) / A(x) #set up solver parameters print("Solving with boundary layer terms") boundaryConditions = ['reflecting', 'reflecting'] state1 = (gas1, u1) state4 = (gas4, u4) ssbl = stanShock( gas1, initializeRiemannProblem=(state4, state1, geometry), boundaryConditions=boundaryConditions, cfl=.9, outputEvery=100, includeBoundaryLayerTerms=True, Tw=T1, #assume wall temperature is in thermal eq. with gas DInner=DInner, DOuter=DOuter, dlnAdx=dlnAdx) ssbl.addProbe(max(ssbl.x)) #end wall probe #Solve t0 = time.perf_counter() ssbl.advanceSimulation(tFinal) t1 = time.perf_counter() print("The process took ", t1 - t0) #without boundary layer model print("Solving without boundary layer model") boundaryConditions = ['reflecting', 'reflecting'] gas1.TP = T1, p1 gas4.TP = T4, p4 ssnbl = stanShock(gas1, initializeRiemannProblem=(state4, state1, geometry), boundaryConditions=boundaryConditions, cfl=.9, outputEvery=100, includeBoundaryLayerTerms=False, DInner=DInner, DOuter=DOuter, dlnAdx=dlnAdx) ssnbl.addProbe(max(ssnbl.x)) #end wall probe #Solve t0 = time.perf_counter() ssnbl.advanceSimulation(tFinal) t1 = time.perf_counter() print("The process took ", t1 - t0) #import shock tube data tExp, pExp = getPressureData(data_filename) timeDifference = ( 12.211 - 8.10) / 1000.0 #difference between the test data and simulation times tExp += timeDifference #make plots of probe and XT diagrams plt.close("all") mpl.rcParams['font.size'] = fontsize plt.rc('text', usetex=True) plt.figure(figsize=(4, 4)) plt.plot(np.array(ssnbl.probes[0].t) * 1000.0, np.array(ssnbl.probes[0].p) / 1.0e5, 'k', label="$\mathrm{Without\ BL\ Model}$", linewidth=2.0) plt.plot(np.array(ssbl.probes[0].t) * 1000.0, np.array(ssbl.probes[0].p) / 1.0e5, 'r', label="$\mathrm{With\ BL\ Model}$", linewidth=2.0) plt.plot(tExp * 1000.0, pExp / 1.0e5, label="$\mathrm{Experiment}$", alpha=0.7) plt.axis([0, 60, -.5, 2]) plt.xlabel("$t\ [\mathrm{ms}]$") plt.ylabel("$p\ [\mathrm{bar}]$") plt.legend(loc="lower right") plt.tight_layout() if show_results: plt.show() if results_location is not None: np.savez(os.path.join(results_location, "case3.npz"), pressure_with_boundary_layer=ssbl.probes[0].p, pressure_without_boundary_layer=ssnbl.probes[0].p, time_with_boundary_layer=ssbl.probes[0].t, time_without_boundary_layer=ssnbl.probes[0].t) plt.savefig(os.path.join(results_location, "case3.png"))