Beispiel #1
0
    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)
Beispiel #2
0
    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)
Beispiel #3
0
 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)
Beispiel #4
0
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
Beispiel #5
0
    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,
Beispiel #6
0
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