def solution(self, x, y): (X, Y) = self.transform_xy_2_XY(x, y) if (X < 0.0): rho = self.rho1 p = self.p1 T = self.T1 f = [1.0, 0.0] u = self.u1 v = self.v1 else: def f(lmbda): X = self.calculate_X(lmbda) (xg, yg) = self.transform_XY_2_xy(X, Y) return (x - xg) lmbda = secant(f, 0.0, 0.999, limits=[0.0, 0.999]) rho = self.calculate_rho(lmbda) p = self.calculate_p(lmbda, rho) T = self.calculate_T(lmbda, rho) U = self.calculate_U(lmbda, rho) V = self.V (u, v) = self.transform_UV_2_uv(U, V) f = [1.0 - lmbda, lmbda] return (x, y, rho, p, T, f, u, v, X, Y)
def find_XYw_from_x(self, x): def f(lmbda): X = self.calculate_X(lmbda) Yw = self.calculate_Yw(lmbda) (xg, yg) = self.transform_XY_2_xy(X, Yw) return (x - xg) lmbda = secant(f, 0.0, 0.999, limits=[0.0, 0.999]) X = self.calculate_X(lmbda) Yw = self.calculate_Yw(lmbda) return (X, Yw)
def set_ps(self, p, s, transProps=True): """ Compute the thermodynamic state from given pressure and entropy :param p: pressure, Pa :param s: entropy, J/(kg.K) :param transProps: if True, compute transport properties as well. """ # The libgas library does not have a pressure-entropy thermodynamic # state solver, so we need to do the iterative calculation ourselves. #print #print "s_in=",s #print "p_in=",p def entropy_solve(temp): self.set_pT(p, temp) # calculate density entropy = self.gasModel.mixture_entropy(self.gasData) # entropy from temp and density #print "s-entropy=",s-entropy return s - entropy T = secant(entropy_solve, 250.0, 260.0, tol=1.0e-4) #print "T_out=",T if T == "FAIL": raise Exception("Secant solver failed, bailing out!") return self.set_pT(p, T, transProps)
def reflected_shock_tube_calculation(gasModel, gasName, p1, T1, Vs, pe, pp_on_pe, area_ratio, task): """ Runs the reflected-shock-tube calculation from initial fill conditions observed shock speed and equilibrium pressure. This function may be imported into other applications (such as nenzfr). :param gasModel: pointer to the gas model (cea2_gas or libgas_gas) :param gasName: name of the specific gas model to create via make_gas_from_name() :param p1: fill pressure of gas initially filling shock tube :param T1: fill temperature of gas initially filling shock tube :param Vs: observed incident shock speed :param pe: observed pressure once shock-reflected region reaches equilibrium :param pp_on_pe: specify this ratio if we want the supersonic nozzle expansion to terminate at a particular Pitot pressure :param area_ratio: specify this ratio if we want the supersonic nozzle expansion to proceed to a particular quasi-one-dimensional area ratio. :param task: one of 'ishock', 'st', 'stn', 'stnp' """ PRINT_STATUS = True # the start of each stage of the computation is noted. # if PRINT_STATUS: print 'Write pre-shock condition.' state1 = gasModel.make_gas_from_name(gasName) state1.set_pT(p1, T1) H1 = state1.e + state1.p/state1.rho result = {'state1':state1, 'H1':H1} # if PRINT_STATUS: print 'Start incident-shock calculation.' state2 = gasModel.make_gas_from_name(gasName) (V2,Vg) = normal_shock(state1, Vs, state2) result['state2'] = state2 result['V2'] = V2 result['Vg'] = Vg # if task == 'ishock': # We want post-incident-shock conditions only. return result # if PRINT_STATUS: print 'Start reflected-shock calculation.' state5 = gasModel.make_gas_from_name(gasName) Vr = reflected_shock(state2, Vg, state5) result['state5'] = state5 result['Vr'] = Vr # if PRINT_STATUS: print 'Start calculation of isentropic relaxation.' state5s = gasModel.make_gas_from_name(gasName) # entropy is set, then pressure is relaxed via an isentropic process if pe==None: state5s.set_ps(state5.p, state5.s) else: state5s.set_ps(pe, state5.s); result['state5s'] = state5s H5s = state5s.e + state5s.p/state5s.rho # stagnation enthalpy result['H5s'] = H5s # if task in ['stn','stnp']: if PRINT_STATUS: print 'Start isentropic relaxation to throat (Mach 1)' def error_at_throat(x, s5s=state5s, gasName=gasName): "Returns Mach number error as pressure is changed." state, V = expand_from_stagnation(x, s5s) return (V/state.a) - 1.0 x6 = secant(error_at_throat, 0.95, 0.90, tol=1.0e-4) if x6 == 'FAIL': print "Failed to find throat conditions iteratively." x6 = 1.0 state6, V6 = expand_from_stagnation(x6, state5s) mflux6 = state6.rho * V6 # mass flux per unit area, at throat result['state6'] = state6 result['V6'] = V6 result['mflux6'] = mflux6 # if task == 'stn': if PRINT_STATUS: print 'Start isentropic relaxation to nozzle exit.' # The mass flux going through the nozzle exit has to be the same # as that going through the nozzle throat. def error_at_exit(x, s5s=state5s, s6=state6, mflux_throat=mflux6, area_ratio=area_ratio): "Returns mass_flux error as pressure is changed." state, V = expand_from_stagnation(x, s5s) mflux = state.rho * V * area_ratio if DEBUG_ESTCJ: print "x=", x, "p=", state.p, "T=", state.T, "V=", V, \ "mflux=", mflux, "mflux_throat=", mflux_throat return (mflux-mflux_throat)/mflux_throat # It appears that we need a pretty good starting guess for the pressure ratio. # Maybe a low value is OK. x7 = secant(error_at_exit, 0.001*x6, 0.00005*x6, tol=1.0e-4, limits=[1.0/state5s.p,1.0]) if x7 == 'FAIL': print "Failed to find exit conditions iteratively." x7 = x6 state7, V7 = expand_from_stagnation(x7, state5s) mflux7 = state7.rho * V7 * area_ratio result['area_ratio'] = area_ratio state7_pitot = pitot_condition(state7, V7) result['state7'] = state7 result['V7'] = V7 result['mflux7'] = mflux7 result['pitot7'] = state7_pitot.p elif task == 'stnp': if PRINT_STATUS: print 'Start isentropic relaxation to nozzle exit pitot pressure.' # The exit pitot pressure has to be the same as that measured def error_at_exit(x, s5s=state5s, s6=state6, pp_pe=pp_on_pe): "Returns pitot pressure error as static pressure is changed." state1, V = expand_from_stagnation(x, s5s) state2 = pitot_condition(state1, V) if DEBUG_ESTCJ: print "x=", x, "pitot_to_supply=", state2.p/s5s.p, \ "relative error=", (state2.p/s5s.p - pp_pe)/pp_pe return (state2.p/s5s.p - pp_pe)/pp_pe # We need a low starting guess for the pressure ratio. #x7 = secant(error_at_exit, 0.001*x6, 0.00005*x6, tol=1.0e-4) # Changed the tolerance on 25/07/2011 in order to get the M8 nozzle to work (shot 10803) x7 = secant(error_at_exit, 0.001*x6, 0.00005*x6, tol=2.0e-4, limits=[1.0/state5s.p,1.0]) if x7 == 'FAIL': print "Failed to find exit conditions iteratively." x7 = x6 state7, V7 = expand_from_stagnation(x7, state5s) result['area_ratio'] = mflux6/(state7.rho * V7) state7_pitot = pitot_condition(state7, V7) #mflux7 = mflux6 result['state7'] = state7 result['V7'] = V7 result['mflux7'] = mflux6 result['pitot7'] = state7_pitot.p if DEBUG_ESTCJ: print "area_ratio=", area_ratio, "pitot7=", state7_pitot.p # if PRINT_STATUS: print 'Done with reflected shock tube calculation.' return result
Vector(410.0, 7.73) * mm, Vector(430.0, 3.51) * mm, Vector(450.0, 1.07) * mm, Vector(476.2, 0.0) * mm ]) # On the body, we want only a little bit of spline 2, # just along to the position x=347.57mm y=40.0mm. spl2b = spl2.copy(direction=-1) # going up the west face def my_error(t, path=spl2b): return abs(path.eval(t).y - 0.040) from cfpylib.nm import zero_solvers t_trim = zero_solvers.secant(my_error, 0.6, 0.61) if t_trim == 'FAIL': print "Failed to solve intersection with spline 2" sys.exit() spl2b.t0 = t_trim c = spl2b.eval(1.0) d = spl2b.eval(0.0) assert vabs(c - c_test) < 1.0e-6 assert vabs(d - d_test) < 1.0e-6 # Combustor blk_2 = SuperBlock2D(CoonsPatch(Polyline([Line(f0, b), spl1]), spl3, Line(f0, f1), Line(c, h)), nni=int(ni0 / 2), nnj=nj0, nbi=3,
def main(): print "Helium driver gas" state4 = Gas({'He':1.0}) state4.set_pT(30.0e6, 3000.0) print "state4:" state4.write_state(sys.stdout) # print "Air driven gas" state1 = Gas({'Air':1.0}) state1.set_pT(30.0e3, 300.0) print "state1:" state1.write_state(sys.stdout) # print "\nNow do the classic shock tube solution..." # For the unsteady expansion of the driver gas, regulation of the amount # of expansion is determined by the shock-processed test gas. # Across the contact surface between these gases, the pressure and velocity # have to match so we set up some trials of various pressures and check # that velocities match. def error_in_velocity(p3p4, state4=state4, state1=state1): "Compute the velocity mismatch for a given pressure ratio across the expansion." # Across the expansion, we get a test-gas velocity, V3g. p3 = p3p4*state4.p V3g, state3 = finite_wave_dp('cplus', 0.0, state4, p3) # Across the contact surface. p2 = p3 print "current guess for p3 and p2=", p2 V1s, V2, V2g, state2 = normal_shock_p2p1(state1, p2/state1.p) return (V3g - V2g)/V3g p3p4 = secant(error_in_velocity, 0.1, 0.11, tol=1.0e-3) print "From secant solve: p3/p4=", p3p4 print "Expanded driver gas:" p3 = p3p4*state4.p V3g, state3 = finite_wave_dp('cplus', 0.0, state4, p3) print "V3g=", V3g print "state3:" state3.write_state(sys.stdout) print "Shock-processed test gas:" V1s, V2, V2g, state2 = normal_shock_p2p1(state1, p3/state1.p) print "V1s=", V1s, "V2g=", V2g print "state2:" state2.write_state(sys.stdout) assert abs(V2g - V3g)/V3g < 1.0e-3 # # Make a record for plotting against the Eilmer3 simulation data. # We reconstruct the expected data along a tube 0.0 <= x <= 1.0 # at t=100us, where the diaphragm is at x=0.5. x_centre = 0.5 # metres t = 100.0e-6 # seconds fp = open('exact.data', 'w') fp.write('# 1:x(m) 2:rho(kg/m**3) 3:p(Pa) 4:T(K) 5:V(m/s)\n') print 'Left end' x = 0.0 fp.write('%g %g %g %g %g\n' % (x, state4.rho, state4.p, state4.T, 0.0)) print 'Upstream head of the unsteady expansion.' x = x_centre - state4.a * t fp.write('%g %g %g %g %g\n' % (x, state4.rho, state4.p, state4.T, 0.0)) print 'The unsteady expansion in n steps.' n = 100 dp = (state3.p - state4.p) / n state = state4.clone() V = 0.0 p = state4.p for i in range(n): rhoa = state.rho * state.a dV = -dp / rhoa V += dV p += dp state.set_ps(p, state4.s) x = x_centre + t * (V - state.a) fp.write('%g %g %g %g %g\n' % (x, state.rho, state.p, state.T, V)) print 'Downstream tail of expansion.' x = x_centre + t * (V3g - state3.a) fp.write('%g %g %g %g %g\n' % (x, state3.rho, state3.p, state3.T, V3g)) print 'Contact surface.' x = x_centre + t * V3g fp.write('%g %g %g %g %g\n' % (x, state3.rho, state3.p, state3.T, V3g)) x = x_centre + t * V2g # should not have moved fp.write('%g %g %g %g %g\n' % (x, state2.rho, state2.p, state2.T, V2g)) print 'Shock front' x = x_centre + t * V1s # should not have moved fp.write('%g %g %g %g %g\n' % (x, state2.rho, state2.p, state2.T, V2g)) fp.write('%g %g %g %g %g\n' % (x, state1.rho, state1.p, state1.T, 0.0)) print 'Right end' x = 1.0 fp.write('%g %g %g %g %g\n' % (x, state1.rho, state1.p, state1.T, 0.0)) fp.close() return
def main(): print "Titan gas" state1 = Gas({ 'N2': 0.95, 'CH4': 0.05 }, inputUnits='moles', outputUnits='moles') state1.set_pT(2600.0, 300.0) print "state1:" state1.write_state(sys.stdout) # print "Air accelerator gas" state10 = Gas({'Air': 1.0}) state10.set_pT(10.0, 300.0) print "state10:" state10.write_state(sys.stdout) # print "Incident shock" state2 = state1.clone() V2, V2g = normal_shock(state1, 4100.0, state2) print "V2=", V2, "Vg=", V2g, "expected 3670.56" print "state2:" state2.write_state(sys.stdout) print "Checks:" print "p2/p1=", state2.p / state1.p, "expected 166.4" print "rho2/rho1=", state2.rho / state1.rho, "expected 9.5474" print "T2/T1=", state2.T / state1.T, "expected 14.9" # print "\nNow do unsteady expansion..." # For the unsteady expansion of the test gas, regulation of the amount # of expansion is determined by the shock-processed accelerator gas. # Across the contact surface between these gases, the pressure and velocity # have to match so we set up some trials of various pressures and check # that velocities match. def error_in_velocity(p5p2, state2=state2, V2g=V2g, state10=state10): "Compute the velocity mismatch for a given pressure ratio across the expansion." # Across the expansion, we get a test-gas velocity, V5g. V5g, state5 = finite_wave_dp('cplus', V2g, state2, p5p2 * state2.p) # Across the contact surface, p20 == p5 p20 = p5p2 * state2.p print "current guess for p5 and p20=", p20 V10, V20, V20g, state20 = normal_shock_p2p1(state10, p20 / state10.p) return ( V5g - V10 ) / V5g # V10 was V20g - lab speed of accelerator gas - we now make the assumption that this is the same as the shock speed p5p2 = secant(error_in_velocity, 0.01, 0.011, tol=1.0e-3) print "From secant solve: p5/p2=", p5p2 # It would have been faster and the code closer to Hadas' spreadsheet if we had # stepped down in pressure until we found the point where the velocities matched. # The expansion along the u+a wave would have appeared in the code here. V5g, state5 = finite_wave_dp('cplus', V2g, state2, p5p2 * state2.p) print "Expanded test gas, at end of acceleration tube:" print "V5g=", V5g print "state5:" state5.write_state(sys.stdout) V10, V20, V20g, state20 = normal_shock_p2p1(state10, state5.p / state10.p) print V10 print "Done." return