Пример #1
0
 def test_taylor_maccoll_given_theta(self):
     # Conical shock from cone with half-angle 20deg.
     s1 = Gas({'Air': 1.0})
     s1.set_pT(100.0e3, 300.0)
     M1 = 1.5
     V1 = M1 * s1.a
     beta = beta_cone(s1, V1, 20.0 * math.pi / 180)
     self.assertAlmostEqual(beta * 180 / math.pi, 49.0, delta=0.05)
     return
Пример #2
0
 def test_shock_given_V_with_ideal_guess(self):
     s1 = Gas({'Air': 1.0})
     s1.set_pT(10.0, 300.0)
     self.assertAlmostEqual(s1.rho, 1.1611e-4, delta=0.001)
     s2 = s1.clone()
     V2, Vg = normal_shock(s1, 14000.0, s2, {'gam': 1.35, 'R': 571.49})
     self.assertAlmostEqual(s2.p, 20335.0, delta=1.0)
     self.assertAlmostEqual(s2.T, 32753.03, delta=1.0)
     self.assertAlmostEqual(V2, 1496.26, delta=1.0)
     self.assertAlmostEqual(Vg, 12503.74, delta=1.0)
Пример #3
0
 def test_shock_given_V(self):
     s1 = Gas({'Air': 1.0})
     s1.set_pT(1.0e5, 300.0)
     self.assertAlmostEqual(s1.rho, 1.1612, delta=0.001)
     s2 = s1.clone()
     V2, Vg = normal_shock(s1, 3000.0, s2)
     self.assertAlmostEqual(s2.p, 9.1779e+06, delta=9.1779e+06 * 1.0e-4)
     self.assertAlmostEqual(s2.T, 3572.97, delta=1.0)
     self.assertAlmostEqual(V2, 394.09, delta=1.0)
     self.assertAlmostEqual(Vg, 2605.9, delta=1.0)
     return
Пример #4
0
 def test_reflected_shock(self):
     s1 = Gas({'Air': 1.0})
     s1.set_pT(1.0e5, 300.0)
     s2 = s1.clone()
     V2, Vg = normal_shock(s1, 3000.0, s2)
     s5 = s1.clone()
     Vr_b = reflected_shock(s2, Vg, s5)
     self.assertAlmostEqual(s5.p, 8.4329e+07, delta=10.0e3)
     self.assertAlmostEqual(s5.T, 6121.63, delta=1.0)
     self.assertAlmostEqual(s5.rho, 43.909, delta=0.01)
     self.assertAlmostEqual(Vr_b, 656.69, delta=0.1)
     return
Пример #5
0
 def test_oblique_shock(self):
     # essentially ideal gas at these conditions
     s1 = Gas({'Air': 1.0})
     s1.set_pT(100.0e3, 300.0)
     M1 = 1.5
     beta = 45.0 * math.pi / 180
     V1 = M1 * s1.a
     theta, V2, s2 = theta_oblique(s1, V1, beta)
     self.assertAlmostEqual(s2.p, 114620, delta=50)
     self.assertAlmostEqual(theta, theta_obl(M1, beta), delta=0.001)
     beta2 = beta_oblique(s1, V1, theta)
     self.assertAlmostEqual(beta2 * 180 / math.pi, 45.0, delta=0.01)
     return
Пример #6
0
 def test_finite_wave(self):
     V1 = 0.0
     s9 = Gas({'Air': 1.0})
     s9.set_pT(1.0e5, 320.0)  # keep gas close to ideal
     Jplus = V1 + 2 * s9.a / (1.4 - 1)
     V2, s10 = finite_wave_dp('cplus', V1, s9, 60.0e3)
     ideal_V2 = Jplus - 2 * s10.a / (1.4 - 1)
     self.assertAlmostEqual(V2, ideal_V2, delta=2.0)
     V1 = 0.0
     s9.set_pT(1.0e5, 320.0)
     Jplus = V1 + 2 * s9.a / (1.4 - 1)
     V2, s10 = finite_wave_dv('cplus', V1, s9, 125.0)
     self.assertAlmostEqual(Jplus, V2 + 2 * s10.a / (1.4 - 1), delta=2.0)
     return
Пример #7
0
def add_mass_fractions_to_block(blk):
    # Create cea2_gas object
    air = Gas({'Air': 1.0}, outputUnits='massf')
    for isp, s in enumerate(speciesList):
        key = "massf[%i]-%s" % (isp, s)
        blk.data[key] = zeros((blk.ni, blk.nj, blk.nk), 'd')
        blk.vars.append(key)

    for k in range(blk.nk):
        for j in range(blk.nj):
            for i in range(blk.ni):
                p = blk.data['p'][i, j, k]
                T = blk.data['T[0]'][i, j, k]
                air.set_pT(p, T)
                massf = air.get_fractions(speciesList)
                for isp, mf in enumerate(massf):
                    key = "massf[%i]-%s" % (isp, speciesList[isp])
                    blk.data[key][i, j, k] = mf
    return
Пример #8
0
 def test_expand_from_stagnation(self):
     s1 = Gas({'Air': 1.0})
     s1.set_pT(1.0e5, 300.0)
     s2 = s1.clone()
     V2, Vg = normal_shock(s1, 3000.0, s2)
     s5 = s1.clone()
     Vr_b = reflected_shock(s2, Vg, s5)
     s6, V = expand_from_stagnation(0.0025, s5)
     self.assertAlmostEqual(s6.p, 210820.0, delta=10.0)
     self.assertAlmostEqual(s6.T, 2331.29, delta=1.0)
     self.assertAlmostEqual(s6.rho, 0.31475, delta=0.0001)
     self.assertAlmostEqual(V, 3766.2, delta=0.1)
     s7 = total_condition(s6, V)
     self.assertAlmostEqual(s7.p, 8.4013e+07, delta=10.0e3)
     self.assertAlmostEqual(s7.T, 6120.72, delta=1.0)
     self.assertAlmostEqual(s7.rho, 43.748, delta=0.01)
     s8 = pitot_condition(s6, V)
     self.assertAlmostEqual(s8.p, 4.3691e+06, delta=4.3691e+06 * 1.0e-4)
     self.assertAlmostEqual(s8.T, 5450.51, delta=1.0)
     self.assertAlmostEqual(s8.rho, 2.4222, delta=0.01)
     return
Пример #9
0
 def test_taylor_maccoll_given_beta(self):
     # At these conditions, expect essentially-ideal gas flow.
     # M1=1.5, beta=49deg, expect theta=20deg from NACA1135.
     s1 = Gas({'Air': 1.0})
     s1.set_pT(100.0e3, 300.0)
     M1 = 1.5
     V1 = M1 * s1.a
     beta = 49.0 * math.pi / 180
     theta_c, V_c, s_c = theta_cone(s1, V1, beta)
     self.assertAlmostEqual(theta_c * 180.0 / math.pi, 20.0, delta=0.05)
     surface_pressure_coeff = (s_c.p - s1.p) / (0.5 * s1.rho * V1 * V1)
     self.assertAlmostEqual(surface_pressure_coeff, 0.385, delta=0.01)
     # M1=1.8, beta=45deg, theta=24deg from NACA1135.
     M1 = 1.8
     V1 = M1 * s1.a
     beta = 45.0 * math.pi / 180
     theta_c, V_c, s_c = theta_cone(s1, V1, beta)
     self.assertAlmostEqual(theta_c * 180.0 / math.pi, 24.0, delta=0.1)
     surface_pressure_coeff = (s_c.p - s1.p) / (0.5 * s1.rho * V1 * V1)
     self.assertAlmostEqual(surface_pressure_coeff, 0.466, delta=0.01)
     return
Пример #10
0
def main():
    # These are the inputs!
    primary_shock = 3376.0  # m/s
    secondary_shock = 6580.0  # m/s
    nozzle_exp_ratio = 7.5
    conehead_pressure = 26642.0  # Pa
    # Set up the shock tube test gas
    print "Titan gas"
    state1 = Gas({
        'N2': 0.95,
        'CH4': 0.05
    },
                 inputUnits='moles',
                 outputUnits='moles')
    state1.set_pT(25400.0, 300.0)
    print "state1:"
    state1.write_state(sys.stdout)
    # Set up the acceleration tube gas
    print "Air accelerator gas"
    state10 = Gas({'Air': 1.0})
    state10.set_pT(68.7, 300.0)
    print "state10:"
    state10.write_state(sys.stdout)
    # Compute the primary shock here
    print "Incident shock"
    state2 = state1.clone()
    V2, V2g = normal_shock(state1, primary_shock, state2)
    print "V2=", V2, "Vg=", V2g
    print "state2:"
    state2.write_state(sys.stdout)
    # For the unsteady expansion of the test gas, regulation of the amount
    # of expansion is determined by the shock-processed accelerator gas.
    print "\nNow do unsteady expansion..."
    V5g, state5 = finite_wave_dv('cplus', V2g, state2, secondary_shock)
    # Write out expanded test gas conditions
    print "\nExpanded test gas, at end of acceleration tube:"
    print "V5g=", V5g
    print "state5:"
    state5.write_state(sys.stdout)
    # Now lets put in the nozzle with a steady flow area change
    V6g, state6 = steady_flow_with_area_change(state5, V5g, nozzle_exp_ratio)
    # Print out nozzle expanded flow properties
    print "\nNozzle exit gas conditions for an area ratio of:", nozzle_exp_ratio
    print "V6g:", V6g
    print "state6:"
    state6.write_state(sys.stdout)
    # Try and work out my conehead pressure for this particular flow condition
    # First I need to work out the shock angle
    shock_angle = beta_cone(state6, V6g, math.radians(15))
    print "\nShock angle over cone:", math.degrees(shock_angle)
    # Reverse the process to get the flow state behind the shock and check the surface angle is correct
    delta_s, vel_cond, state7 = theta_cone(state6, V6g, shock_angle)
    print "Surface angle should be the same.....: 15deg = ", math.degrees(
        delta_s), "deg"
    print "\nConehead surface conditions:"
    state7.write_state(sys.stdout)
    # Need to check whether the pressure are the same
    print "\nComputed conehead pressure should be the same as the experimental pressure"
    print "Computed:", state7.p, "Experimental:", conehead_pressure
    print "If pressure are not the same 'tweak' the nozzle_exp_ratio until they match"
    # Grab the total conditions
    total6 = total_condition(state6, V6g)
    # Now print my total conditions
    print "\nTotal conditions of nozzle exit test gas:"
    print "total6:"
    total6.write_state(sys.stdout)
    # And finally.... let's output a 'flight equivalent' speed
    flight_eq = math.sqrt(2 * total6.h)
    print "\nFlight equivalent speed:", flight_eq
    print "Done."
    return
Пример #11
0
def calculate_pressure(data, variable_list, theta):
    """
    Using the input data, determine the gas properties
    and then calculate the expected pressure on the 
    surface of a cone of half-angle theta assuming an
    equilibrium gas.
    """

    theta_rad = theta * numpy.pi / 180.0

    # Find the species present in data set
    species_onlyList = []
    for name in variable_list:
        if name.startswith('massf'):
            speciesName = name.split('-')[-1]
            species_onlyList.append(speciesName)
    # Initialise some variables
    eq_pitot_p = []
    cone_beta = []
    cone_theta = []
    cone_V = []
    cone_p = []
    cone_T = []

    for j in range(len(data['pos.y'])):
        # Create Gas object for current location...
        react = {}
        for spc in species_onlyList:
            react[spc] = data['massf['+\
                    str(species_onlyList.index(spc))+']-'+spc][j]
        #print "reactants=",react
        gasState = Gas(reactants=react, inputUnits='massf',\
                       onlyList=species_onlyList,\
                       outputUnits='massf')
        # Set pressure and temperature...
        gasState.set_pT(p=data['p'][j], T=data['T[0]'][j])

        # Calculate the pitot pressure
        pitotState = pitot_condition(gasState, data['vel.x'][j])
        eq_pitot_p.append(pitotState.p)

        #print eq_pitot_p

        # Calculate the cone static pressure
        #
        # Only if the Mach number is greater than 1 do we calculate
        # the surface pressure on the cone using the Taylor-Maccoll
        # equations. Otherwise we just set it equal to the freestream
        # pressure (we aren't interested in these low supersonic
        # regions).
        if data['M_local'][j] > 2.1:  #1.05:
            # Calculate the conical shock angle
            cone_beta.append(beta_cone(gasState, data['vel.x'][j], theta_rad))
            #print cone_beta
            # Calculate the gas properties on the cone surface
            theta_c, V_c, coneState = theta_cone(gasState, data['vel.x'][j],
                                                 cone_beta[j])

            cone_theta.append(theta_c)
            cone_V.append(V_c)
            cone_p.append(coneState.p)
            cone_T.append(coneState.T)

            #assert abs(theta_c-theta_rad) < 1.0e-4
            print "theta_error=", abs(theta_c - theta_rad)
        else:
            cone_p.append(data['p'][j])
            cone_T.append(data['T[0]'][j])
            cone_V.append(0.0)
            cone_theta.append(0.0)
            cone_beta.append(0.0)

        print "j = {0:d} of {1:d} complete".format(j, len(data['pos.y']))

    variable_list.append('cone_p')
    variable_list.append('cone_T')
    variable_list.append('cone_beta')
    variable_list.append('cone_theta')
    variable_list.append('cone_V')
    variable_list.append('eq_pitot_p')

    data['cone_p'] = cone_p
    data['cone_T'] = cone_T
    data['cone_beta'] = cone_beta
    data['cone_theta'] = cone_theta
    data['cone_V'] = cone_V
    data['eq_pitot_p'] = eq_pitot_p

    return data, variable_list
Пример #12
0
Demonstration of using the library functions to compute flow conditions
across an oblique shock in equilibrium air. 
Data are chosen to match examples from Hunt and Souders NASA-SP-3093.

PJ, 01-Jan-2014
"""
from math import pi
import sys, os
sys.path.append(os.path.expandvars("$HOME/e3bin"))
from cfpylib.gasdyn.cea2_gas import Gas
from cfpylib.gasdyn.gas_flow import theta_oblique, beta_oblique

print "Example 1: Hunt and Souders Table VIII, sub-table (j)"
print "Given shock angle, compute post-shock conditions."
s1 = Gas({'Air': 1.0})
s1.set_pT(52.671, 268.858)
print "Initial gas state:"
s1.write_state(sys.stdout)
beta = 45.0 * pi / 180  # shock angle
V1 = 7.9248e3
theta, V2, s2 = theta_oblique(s1, V1, beta)
print(
    "Following oblique shock, beta=%g degrees, theta=%g degrees (Hunt&Souders 45 40.638)"
    % (beta * 180 / pi, theta * 180 / pi))
s2.write_state(sys.stdout)
print "Across shock:"
print "p2/p1=%g, T2/T1=%g (Hunt&Souders: 376.84 21.206)" % (s2.p / s1.p,
                                                            s2.T / s1.T)

print "\nExample 2: Hunt and Souders Table VI, sub-table (a)"
print "Given deflection angle, compute shock angle and then post-shock conditions."
def run_pitot_differing_compression_ratio_analysis(cfg={},
                                                   config_file=None,
                                                   force_restart=False):
    """
    
    Chris James ([email protected]) 23/12/14
    
    run_pitot_differing_compression_ratio_analysis(dict) - > depends
    
    force_restart can be used to force the simulation to start again instead of 
    looking for an unfinished simulation that may be there...
    
    """

    #---------------------- get the inputs set up --------------------------

    if config_file:
        cfg = config_loader(config_file)

    # some dummy stuff here to pass the initial pitot input test if values are not there

    cfg['facility'] = 'custom'
    cfg['compression_ratio'] = 10.0

    #----------------- check inputs ----------------------------------------

    cfg = input_checker(cfg)

    cfg = check_new_inputs(cfg)

    intermediate_filename = cfg[
        'filename'] + '-differing-compression-ratio-analysis-intermediate-result-pickle.dat'

    # now check if we have attempted an old run before or not....
    if not os.path.isfile(intermediate_filename) or force_restart:
        # if not, we set up a new one...

        # clean up any old files if the user has asked for it

        if cfg['cleanup_old_files']:
            # build a list of auxiliary files and run the cleanup_old_files function frim pitot_condition_builder.py
            auxiliary_file_list = [
                '-differing-compression-ratio-analysis-log-and-result-files.zip',
                '-differing-compression-ratio-analysis-final-result-pickle.dat',
                '-differing-compression-ratio-analysis-normalised.csv',
                '-differing-compression-ratio-analysis-summary.txt',
                '-differing-compression-ratio-analysis.csv'
            ]
            cleanup_old_files(auxiliary_file_list)
            cleanup_old_files()

        # make a counter so we can work out what test we're running
        # also make one to store how many runs are successful

        cfg['number_of_test_runs'] = calculate_number_of_test_runs(cfg)

        # we use this variable to try to speed some things up later on
        cfg['last_run_successful'] = None

        import copy
        cfg['original_filename'] = copy.copy(cfg['filename'])

        # I think install the original cfg too

        cfg['cfg_original'] = copy.copy(cfg)

        # print the start message

        cfg = start_message(cfg)

        # work out what we need in our results dictionary and make the dictionary

        results = build_results_dict(cfg)

        # build the dictionary with the details of all the tests we want to run...

        test_condition_input_details = build_test_condition_input_details_dictionary(
            cfg)

        # so we can make the first run check the time...
        cfg['have_checked_time'] = False

        # counter to count the experiments that don't fail
        cfg['good_counter'] = 0
        # list that will be filled by the experiment numbers as they finish...
        cfg['finished_simulations'] = []

    else:
        # we can load an unfinished simulation and finishing it...!
        print '-' * 60
        print "It appears that an unfinished simulation was found in this folder"
        print "We are now going to attempt to finish this simulation."
        print "If this is not what you want, please delete the file '{0}' and run the condition builder again.".format(
            intermediate_filename)

        import pickle
        with open(intermediate_filename, "rU") as data_file:
            intermediate_result = pickle.load(data_file)
            cfg = intermediate_result['cfg']
            results = intermediate_result['results']
            test_condition_input_details = intermediate_result[
                'test_condition_input_details']
            data_file.close()

    #now start the main for loop for the simulation...

    for test_name in test_condition_input_details['test_names']:
        # this is for a re-loaded simulation, to make sure we don't re-run what has already been run
        if test_name in cfg['finished_simulations']:
            print '-' * 60
            print "test_name '{0}' is already in the 'finished_simulations' list.".format(
                test_name)
            print "Therefore it has probably already been run and will be skipped..."
            continue  # code to skip iteration

        # first set the test number variable...
        cfg['test_number'] = test_name
        # then set the details that every simulation will have
        cfg['compression_ratio'] = test_condition_input_details[test_name][
            'compression_ratio']

        # if 'specified_pressure' is 'driver_p' we don't need to do anything here,
        # if it's 'p4' we need to get the related 'driver_p'

        if cfg['specified_pressure'] == 'p4':
            from cfpylib.gasdyn.cea2_gas import Gas
            primary_driver = Gas(cfg['driver_composition'],
                                 inputUnits=cfg['driver_inputUnits'],
                                 outputUnits=cfg['driver_inputUnits'])
            primary_driver.set_pT(101300.0, 300.0)
            pressure_ratio = cfg[
                'compression_ratio']**primary_driver.gam  #pressure ratio is compression ratio to the power of gamma
            cfg['driver_p'] = cfg['p4'] / pressure_ratio

        run_status, results = differing_compression_ratio_analysis_test_run(
            cfg, results)
        if run_status:
            cfg['good_counter'] += 1

        # add this to finished simulations list, regardless of whether it finished correctly or not...
        cfg['finished_simulations'].append(test_name)

        # now pickle the intermediate result so we can result the simulation if needed...
        pickle_intermediate_data(cfg,
                                 results,
                                 test_condition_input_details,
                                 filename=intermediate_filename)

    # now that we're done we can dump the results in various ways using tools from pitot condition builder...
    intro_line = "Output of pitot differing compression ratio analysis program Version {0}."\
                 .format(VERSION_STRING)
    results_csv_builder(results,
                        test_name=cfg['original_filename'],
                        intro_line=intro_line,
                        filename=cfg['original_filename'] +
                        '-differing-compression-ratio-analysis.csv')

    #and a normalised csv also
    normalised_results_csv_builder(
        results,
        cfg,
        test_name=cfg['original_filename'],
        intro_line=intro_line,
        normalised_by=cfg['normalise_results_by'],
        filename=cfg['original_filename'] +
        '-differing-compression-ratio-analysis-normalised.csv',
        extra_normalise_exceptions=['compression_ratio'])

    pickle_result_data(
        cfg,
        results,
        filename=cfg['original_filename'] +
        '-differing-compression-ratio-analysis-final-result-pickle.dat')

    # now delete the intermediate pickle that we made during the simulation...
    print "Removing the final intermediate pickle file."

    if os.path.isfile(intermediate_filename):
        os.remove(intermediate_filename)

    # now analyse results dictionary and print some results to the screen
    # and another external file

    differing_compression_ratio_analysis_summary(cfg, results)

    #zip up the final result using the function from pitot_condition_builder.py
    zip_result_and_log_files(
        cfg,
        output_filename=cfg['original_filename'] +
        '-differing-compression-ratio-analysis-log-and-result-files.zip')

    return
Пример #14
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
Пример #15
0
def poshax_python(
        p_inf,
        T_inf,
        reactants,
        inputUnits,
        species_list,
        no_of_temperatures,
        reaction_file,
        outputUnits='massf',
        u_inf=None,
        M_inf=None,
        energy_exchange_file=None,
        gas_model_file='gas_model',
        cfg_file='cfg_file.cfg',
        output_file='output_file.data',
        source_term_coupling='loose',
        dx=1.0e-16,
        adaptive_dx='false',
        final_x=5.0e-3,
        plot=True,
        save_figures=True,
        temp_result_fig_name='temp_result',
        species_result_fig_name='species_result',
        freestream_normalised_result_fig_name='freestream_normalised_result',
        eq_normalised_result_fig_name='equilibrium_normalised_result',
        title=None,
        log_x_axis=False,
        plot_x_limits=None):
    """

    :param p_inf: Freestream pressure (Pa)
    :param T_inf: Freestream temperature (K)
    :param reactants: Reactants dictionary which will be sent to cfypylib's cea2 Gas object.
        So it must conform with the required syntax!! an example is {'N2':0.79,'O2':0.21}
        for 'cfd air' specified by moles, but check the cea2_gas info for more info about
        the required format. inputUnits for this dictionary can be either in 'moles' or 'massf'
        with the standard specified in the next input
    :param inputUnits: inputUnits string to be again set to the cea2 Gas object. Should be either
        'moles' or 'massf'
    :param species_list: Species list for POSHAX!! NOT CEA!! so ions and electons will be N2_plus, e_minus
        This data will be parsed to cea as the input state will only use these species, but the code
        will automatically perform the conversion need to send this list to CEA. This list is for
        sending to the program whcih creates the gas file for poshax
    :param no_of_temperatures: Number of temperatures. Integer input of 1,2, or 3. More than one
        temperature models require the specification of an energy exchange .lua file. (See below.)
    :param reaction_file: String pointing to the location of the reaction scheme.
    :param u_inf: Freestream velocity (m/s). Defaults to None, but either u_inf or M_inf must be specified.
    :param M_inf: Freestream Mach number. Defaults to None, but either u_inf or M_inf must be specified.
    :param energy_exchange_file: String pointing to the location of the energy exchange scheme for
        multi temperature models. Defaults to None, but the code will not run with a multi temperature
        model if this file is not found.
    :param gas_model_file: String name of the gas model file which the code will create as a .inp
        file which the program gasfile uses to make the .lua gasfile for poshax. Defaults to 'gas_model'.
    :param cfg_file: String name of the poshax cfg file. Defaults to 'cfg_file.cfg'.
    :param output_file: String name of the poshax output file. Defaults to 'output_file.data'.
    :param source_term_coupling: poshax source term coupling file. Defaults to 'loose'.
    :param dx: poshax dx (in m) defaults to 1.0e-16 m.
    :param adaptive_dx: Whether to use adaptive_dx with poshax. Defaults to 'true'.
    :param final_x: poshax final x value (in m). Defaults to 5.0e-3.
    :param plot: Whether to plot the result or not. Defaults to True. Will make four plots.
        A temperature plot, mass fraction plot of all species, result normalised by freestream values,
        and a result normalised by equilibrium values.
    :param save_figures: Whether to save figures or not. Defaults to True. results are saved in eps, png,
        and pdf formats.
    :param temp_result_fig_name: Temperature result plot file name. Defaults to 'temp_result'.
    :param species_result_fig_name: Species result plot file name. Defaults to 'species_result'.
    :param freestream_normalised_result_fig_name: Freestream normalised results plot file name.
        Defaults to 'freestream_normalised_result'.
    :param eq_normalised_result_fig_name: Equilibrium normalised results plot file name.
        Defaults to 'equilibrium_normalised_result'.
    :param title: allows a title to be added to the plots. Defaults to None.
        Is a single title so, for example, the condition being simulated can be added to the title.
    :param log_x_axis: Plots the figure with the x axis on a log scale. Defaults to False.
plot_x_limits = None
    :return: Returns a Python dictionary version of the poshax results file.
    """

    print '-' * 60
    print "Running poshax python version {0}".format(VERSION_STRING)

    # do any input checking which is required
    # probably don't need to do everything in the world here,
    # but just some important things...
    # probably want to check that p, T, and u values,

    if not isinstance(p_inf, (float, int)):
        raise Exception, "poshax_python(): 'p_inf' input ({0}) is not a float or an int.".format(
            p_inf)
    if not isinstance(T_inf, (float, int)):
        raise Exception, "poshax_python(): 'T_inf' input ({0}) is not a float or an int.".format(
            T_inf)
    if not u_inf and not M_inf:
        raise Exception, "poshax_python(): Simulation must have either a 'u_inf' or 'M_inf' value."
    if u_inf and M_inf:
        raise Exception, "poshax_python(): Simulation cannot have have both a 'u_inf' and an 'M_inf' value."
    if u_inf and not isinstance(u_inf, (float, int)):
        raise Exception, "poshax_python(): 'u_inf' input ({0}) is not a float or an int.".format(
            u_inf)
    if M_inf and not isinstance(M_inf, (float, int)):
        raise Exception, "poshax_python(): 'M_inf' input ({0}) is not a float or an int.".format(
            M_inf)

    if not isinstance(reactants, dict):
        raise Exception, "poshax_python(): 'reactants' input ({0}) is not a dictionary.".format(
            reactants)
    if inputUnits not in ['moles', 'massf']:
        raise Exception, "poshax_python(): 'inputUits' input ({0}) is not either 'moles' or 'massf'.".format(
            inputUnits)

    if not isinstance(reaction_file, str):
        raise Exception, "poshax_python(): 'reaction_file' input ({0}) is not a string.".format(
            reaction_file)

    if not os.path.exists(reaction_file):
        raise Exception, "poshax_python(): 'reaction_file' input ({0}) does not appear to exist in the specified location.".format(
            reaction_file)

    if no_of_temperatures > 1 and not energy_exchange_file:
        raise Exception, "poshax_python(): Multi temperature model has been specified without an energy exchange file."

    if no_of_temperatures > 1:
        if not isinstance(energy_exchange_file, str):
            raise Exception, "poshax_python(): 'energy_exchange_file:' input ({0}) is not a string.".format(
                energy_exchange_file)

        if not os.path.exists(energy_exchange_file):
            raise Exception, "poshax_python(): 'reaction_file' input ({0}) does not appear to exist in the specified location.".format(
                energy_exchange_file)

    if not isinstance(dx, float):
        raise Exception, "poshax_python(): 'dx' input ({0}) is not a float.".format(
            dx)
    if not isinstance(final_x, float):
        raise Exception, "poshax_python(): 'final_x' input ({0}) is not a float.".format(
            final_x)

    print '-' * 60
    print "User specified input values are:"

    if no_of_temperatures == 1:
        model = "thermally perfect gas"
    elif no_of_temperatures == 2:
        model = "two temperature gas"
    elif no_of_temperatures == 3:
        model = "three temperature gas"

    print "Gas state input settings:"
    print "p_inf = {0} Pa, T_inf = {1} K, u_inf = {2} m/s".format(
        p_inf, T_inf, u_inf)
    print "Reactants for start of CEA inflow calculation are:"
    print '{0} (by {1})'.format(reactants, inputUnits)
    print "Species in the calculation are:"
    print species_list
    print "Note: the CEA equilibrium inflow calculation will use only these species."
    print "This means that the inflow may be unrealistic if the species do not match "
    print "the real state of the gas at the user specified temperature and pressure"
    print '-' * 60
    print "poshax settings:"
    print "dx = {0} m, final_x = {1} m ({2} mm), with adaptive_dx set to {3}".format(
        dx, final_x, final_x * 1000, adaptive_dx)
    print "calculation uses a {0} model, with {1} source term coupling.".format(
        model, source_term_coupling)
    print "Reaction scheme file is {0}".format(reaction_file)
    if no_of_temperatures > 1:
        print "Energy exchange file is {0}.".format(energy_exchange_file)
    print "Gas model file to be created will be called {0}.lua.".format(
        gas_model_file)
    print "poshax input file to be created will be called {0}.".format(
        cfg_file)
    print "poshax output / results file to be created will be called {0}".format(
        output_file)

    # as cea wants a slightly different form from poshax...
    species_list_for_cea = []

    for species in species_list:
        if '_plus' in species:
            # copy the original species here so we don't mess with the old one!!
            species_copy = copy.copy(species)
            species_list_for_cea.append(species_copy.replace('_plus', '+'))
        elif '_minus' in species:
            # copy the original species here so we don't mess with the old one!!
            species_copy = copy.copy(species)
            species_list_for_cea.append(species_copy.replace('_minus', '-'))
        else:
            # just append the value...
            species_list_for_cea.append(species)

    print '-' * 60
    print "Creating user specified equilibrium gas inflow using CEA:"

    # get mass fractions from CEA as poshax needs massf inflow
    state1 = Gas(reactants=reactants,
                 with_ions=True,
                 inputUnits=inputUnits,
                 outputUnits=outputUnits,
                 onlyList=species_list_for_cea)
    state1.set_pT(p_inf, T_inf)  #Pa, K

    # print state to the screen...
    state1.write_state(sys.stdout)

    print '-' * 60
    print "Preparing the gas .inp file from user specifications..."

    with open('{0}.inp'.format(gas_model_file), 'w') as gas_file:
        gas_file.write('model = "{0}"'.format(model) + '\n')

        species_line = 'species = {'

        for species in species_list:
            if species != species_list[-1]:
                species_line += "'{0}', ".format(species)
            else:
                species_line += "'{0}'".format(species)

        # now add the end bracket...
        species_line += '}'

        gas_file.write(species_line + '\n')

        gas_file.close()

    print "Running gasfile program to generate .lua gasfile."

    subprocess.check_call([
        "gasfile", "{0}.inp".format(gas_model_file),
        "{0}.lua".format(gas_model_file)
    ])

    print "Gas file prepared successfully."

    # now we need to build the .cfg file...

    print '-' * 60
    print "Building poshax .cfg file from user specifications"

    with open(cfg_file, 'w') as cfg_file_ojbect:
        # add in all of the controls...
        cfg_file_ojbect.write('[controls]' + '\n')
        cfg_file_ojbect.write(
            'source_term_coupling = {0}'.format(source_term_coupling) + '\n')
        cfg_file_ojbect.write('dx = {0}'.format(dx) + '\n')
        if adaptive_dx:  # remember that a value of 'false' would still be a string...
            cfg_file_ojbect.write('adaptive_dx = {0}'.format(adaptive_dx) +
                                  '\n')
        cfg_file_ojbect.write('final_x = {0}'.format(final_x) + '\n')
        cfg_file_ojbect.write('output_file = {0}'.format(output_file) + '\n')
        cfg_file_ojbect.write('species_output = {0}'.format(outputUnits) +
                              '\n')

        # the models...
        cfg_file_ojbect.write('[models]' + '\n')
        # a version of this without the .lua was defined above...
        cfg_file_ojbect.write(
            'gas_model_file = {0}.lua'.format(gas_model_file) + '\n')
        cfg_file_ojbect.write('reaction_file = {0}'.format(reaction_file) +
                              '\n')
        if no_of_temperatures > 1:
            cfg_file_ojbect.write(
                'energy_exchange_file = {0}'.format(energy_exchange_file) +
                '\n')

        # initial conditions...
        cfg_file_ojbect.write('[initial-conditions]' + '\n')
        cfg_file_ojbect.write('p_inf = {0}'.format(p_inf) + '\n')
        if no_of_temperatures == 1:
            cfg_file_ojbect.write('T_inf = {0}'.format(T_inf) + '\n')
        elif no_of_temperatures == 2:
            cfg_file_ojbect.write('T_inf = {0}, {0}'.format(T_inf) + '\n')
        elif no_of_temperatures == 3:
            cfg_file_ojbect.write('T_inf = {0}, {0}, {0}'.format(T_inf) + '\n')
        if u_inf:
            cfg_file_ojbect.write('u_inf = {0}'.format(u_inf) + '\n')
        if M_inf:
            cfg_file_ojbect.write('M_inf = {0}'.format(M_inf) + '\n')

        # now go through species and we'll make a species line

        if outputUnits == 'moles':
            species_line = 'molef_inf = '
        elif outputUnits == 'massf':
            species_line = 'massf_inf = '

        for species in species_list:
            if species in state1.species:
                if species != species_list[-1]:
                    species_line += '{0}, '.format(state1.species[species])
                else:
                    species_line += '{0}'.format(state1.species[species])
            else:
                if species != species_list[-1]:
                    species_line += '0.0, '
                else:
                    species_line += '0.0'

        cfg_file_ojbect.write(species_line + '\n')

        cfg_file_ojbect.close()

    print "Cfg file building successfully"

    print '-' * 60
    print "Now running poshax program..."

    exit_code = subprocess.check_call(["poshax3.x", cfg_file])

    if exit_code == 0:
        print "poshax ran successfully"
    else:
        print "poshax appears to have had some issues. check your inputs!"

    print '-' * 60
    print "Performing equilibrium normal shock calculation to compare with poshax result."

    state2 = state1.clone()

    if not u_inf:
        u_inf = M_inf * state1.a

    V2, V2g = normal_shock(state1, u_inf, state2)

    print "Post-shock equilibrium state is :"
    print "post-shock velocity = {0} m/s".format(V2)
    state2.write_state(sys.stdout)

    # now opening the result so it can be returned...

    no_of_species = len(species_list)
    species_start_line = 6 + no_of_temperatures  # 2 intro lines, x, p, rho, u

    lines_to_skip = 6 + no_of_temperatures + no_of_species  # 2 intro lines, x, p, rho, u

    # I wanted to call my variable output_file (I nromally called the string output_filename)
    # but wanred to try to keep my variables consistent with poshax... so now I have results_file!
    with open(output_file, "r") as results_file:

        results_dict = {}
        columns = []
        output_species_list = []

        # start by grabbing columns names which wek now
        columns.append('x')
        if no_of_temperatures == 1:
            T_list = ['T']
        elif no_of_temperatures == 2:
            T_list = ['T_trans_rotational', 'T_vibrational_electronic']
        elif no_of_temperatures == 3:
            T_list = [
                'T_trans_rotational', 'T_vibrational_electronic', 'T_electron'
            ]

        columns += T_list

        columns += ['p', 'rho', 'u']

        # we'll get the rest of the columns from species...

        for i, row in enumerate(results_file):

            if i >= species_start_line and i < lines_to_skip:
                # we could just get the species here, but good to keep it this way
                # so we can abstract the plotting into a function in the future...
                # (i.e. so it could run with no knowledge of the species beforehand, just the number of them...
                # here we want to split the line about the '-' so we can get the final value
                # need to use .strip() to get rid of the new line character on teh end too...
                split_row = row.strip().split('-')
                # last should be what we want...
                columns.append(split_row[-1])
                output_species_list.append(split_row[-1])

            elif i >= lines_to_skip:  # to skip the header and know when the data starts...

                if i == lines_to_skip:
                    # we need to add our columns to the dictionary!
                    for column in columns:
                        results_dict[column] = []

                # now we start filling in data...

                split_row = row.split()

                # go through the split row and fill the data away in the right columns..
                for column, value in zip(columns, split_row):
                    results_dict[column].append(float(value))

        results_dict['output_species_list'] = output_species_list

    if plot:
        print '-' * 60
        print "Now plotting the result"
        import matplotlib.pyplot as plt
        import numpy as np

        # this is from shot_class_plotter.py, even if we don't use all of these...
        font_sizes = {
            'title_size': 18,
            'label_size': 18,
            'annotation_size': 10,
            'legend_text_size': 12,
            'tick_size': 13,
            'marker_size': 7,
            'main_title_size': 20,
            'marker': 'o',
            'capsize': 4
        }

        #---------------------------------------------------------------------------
        # temp plot
        fig, ax = plt.subplots()

        x_list = np.array(results_dict['x']) * 1000.0  # convert to mm

        for T in T_list:
            ax.plot(x_list, results_dict[T], label=T)

        # add eq temp from CEA...
        ax.plot([x_list[0], x_list[-1]], [state2.T, state2.T],
                label='eq T from CEA')

        ax.set_xlabel('post-shock distance (mm)')
        ax.set_ylabel('temperature (K)')

        if log_x_axis:
            ax.set_xscale('log')

        if plot_x_limits:
            ax.set_xlim(plot_x_limits)

        plt.legend(loc='best')

        if title:
            plt.title(title)

        if save_figures:
            plt.savefig(temp_result_fig_name + '.png', dpi=300)
            plt.savefig(temp_result_fig_name + '.eps', dpi=300)
            plt.savefig(temp_result_fig_name + '.pdf', dpi=300)

        plt.show()

        #-------------------------------------------------------------------------
        # now do massf plot
        species_fig, species_ax = plt.subplots()

        for i, species in enumerate(output_species_list):
            # use solid lines if we are line 7 or less
            # change over for lines past this
            # this gives maximum 12 species, I guess, before overlap
            # works with earlier version of matplotlib will only 7 colours too..
            if i < 7:
                linestyle = '-'
            else:
                linestyle = '--'

            # change the _plus or _minus to + or - here to make the labels nicer...
            if '_plus' in species:
                species_label = species.replace('_plus', '+')
            elif '_minus' in species:
                species_label = species.replace('_minus', '-')
            else:
                species_label = species
            species_ax.plot(x_list,
                            results_dict[species],
                            linestyle=linestyle,
                            label=species_label)

        species_ax.set_xlabel('post-shock distance (mm)')
        if outputUnits == 'moles':
            species_ax.set_ylabel('moles per original mole')
        elif outputUnits == 'massf':
            species_ax.set_ylabel('mass fraction of species')

        if log_x_axis:
            species_ax.set_xscale('log')

        if plot_x_limits:
            species_ax.set_xlim(plot_x_limits)

        plt.legend(loc='best')

        if title:
            plt.title(title)

        if save_figures:
            plt.savefig(species_result_fig_name + '.png', dpi=300)
            plt.savefig(species_result_fig_name + '.eps', dpi=300)
            plt.savefig(species_result_fig_name + '.pdf', dpi=300)

        plt.show()

        # -------------------------------------------------------------------
        # now do the freestream normalised plot
        freestream_normalised_fig, freestream_normalised_ax = plt.subplots()

        for T in T_list:
            freestream_normalised_ax.plot(x_list,
                                          np.array(results_dict[T]) / T_inf,
                                          label=T)

        # now do p, rho, and u
        # I commented out pressure here as it changes by too much and messes with the plot
        #freestream_normalised_ax.plot(x_list, np.array(results_dict['p'])/p_inf, label = 'p')
        # have to get rho from state 1 as we didn't need to specify it for inflow calculation...
        freestream_normalised_ax.plot(x_list,
                                      np.array(results_dict['rho']) /
                                      state1.rho,
                                      label='rho')
        freestream_normalised_ax.plot(x_list,
                                      np.array(results_dict['u']) / u_inf,
                                      label='u')

        # add eq values from CEA
        freestream_normalised_ax.plot([x_list[0], x_list[-1]],
                                      [state2.T / T_inf, state2.T / T_inf],
                                      label='eq T from CEA')
        freestream_normalised_ax.plot(
            [x_list[0], x_list[-1]],
            [state2.rho / state1.rho, state2.rho / state1.rho],
            label='eq rho from CEA')
        freestream_normalised_ax.plot([x_list[0], x_list[-1]],
                                      [V2 / u_inf, V2 / u_inf],
                                      label='eq u from CEA')

        freestream_normalised_ax.set_xlabel('post-shock distance (mm)')
        freestream_normalised_ax.set_ylabel(
            'quantity normalised by freestream value')

        if log_x_axis:
            freestream_normalised_ax.set_xscale('log')

        if plot_x_limits:
            freestream_normalised_ax.set_xlim(plot_x_limits)

        plt.legend(loc='best')

        if title:
            plt.title(title)

        if save_figures:
            plt.savefig(freestream_normalised_result_fig_name + '.png',
                        dpi=300)
            plt.savefig(freestream_normalised_result_fig_name + '.eps',
                        dpi=300)
            plt.savefig(freestream_normalised_result_fig_name + '.pdf',
                        dpi=300)

        plt.show()

        #------------------------------------------------------------------------
        # now do the equilibrium normalised plot
        eq_normalised_fig, eq_normalised_ax = plt.subplots()

        for T in T_list:
            eq_normalised_ax.plot(x_list,
                                  np.array(results_dict[T]) / state2.T,
                                  label=T)

        # now do p, rho, and u
        eq_normalised_ax.plot(x_list,
                              np.array(results_dict['p']) / state2.p,
                              label='p')
        eq_normalised_ax.plot(x_list,
                              np.array(results_dict['rho']) / state2.rho,
                              label='rho')
        eq_normalised_ax.plot(x_list,
                              np.array(results_dict['u']) / V2,
                              label='u')

        eq_normalised_ax.set_xlabel('post-shock distance (mm)')
        eq_normalised_ax.set_ylabel(
            'quantity normalised by equilibrium value from CEA')

        if log_x_axis:
            eq_normalised_ax.set_xscale('log')

        if plot_x_limits:
            eq_normalised_ax.set_xlim(plot_x_limits)

        plt.legend(loc='best')

        if title:
            plt.title(title)

        if save_figures:
            plt.savefig(eq_normalised_result_fig_name + '.png', dpi=300)
            plt.savefig(eq_normalised_result_fig_name + '.eps', dpi=300)
            plt.savefig(eq_normalised_result_fig_name + '.pdf', dpi=300)

        plt.show()

    return results_dict
Пример #16
0
def main():

    #build some gas objects

    print "pure He driver gas"
    state4 = Gas({'He': 1.0}, inputUnits='moles', outputUnits='moles')
    state4.set_pT(2.79e+07, 2700.0)
    print "state1:"
    state4.write_state(sys.stdout)

    print "Air test gas"
    state1 = Gas({
        'Air': 1.0,
    })
    state1.set_pT(3000.0, 300.0)
    print "state1:"
    state1.write_state(sys.stdout)
    #
    print "Air accelerator gas"
    state5 = Gas({'Air': 1.0})
    state5.set_pT(10.0, 300.0)
    print "state10:"
    state5.write_state(sys.stdout)

    print "Steady expansion of driver"
    #for 100%He condition mach number terminating steady expansion is 2.15
    #need to work out the corresponding pressure for this to put into
    #the function
    M4dash = 2.15  #mach number terminating steady expansion
    (state4dash,
     V4dash) = expand_from_stagnation(1.0 / (p0_p(M4dash, state4.gam)), state4)
    print "state4dash:"
    state4dash.write_state(sys.stdout)
    print "V4dash = {0} m/s".format(V4dash)

    #I think we need to start guessing shock speeds to be able to keep going here

    print "Start working on the shock into the test gas"
    print "Guess US1 of 5080 m/s"
    state2 = state1.clone()
    V2, V2g = normal_shock(state1, 5080.0, state2)
    print "state2:"
    state2.write_state(sys.stdout)
    print "Checks:"
    print "p2/p1=", state2.p / state1.p
    print "rho2/rho1=", state2.rho / state1.rho
    print "T2/T1=", state2.T / state1.T
    print "V2g = {0} m/s".format(V2g)

    print "Unsteady expansion from state 4dash to state 3"
    print "Well, giving it a go for now anyway"
    (V3, state3) = finite_wave_dp('cplus',
                                  V4dash,
                                  state4dash,
                                  state2.p,
                                  steps=100)
    print "state3:"
    state3.write_state(sys.stdout)
    print "V3 = {0} m/s".format(V3)

    print "Start working on the shock into the accelerator gas"
    print "Guess US2 of 11100 m/s"
    state6 = state5.clone()
    V6, V6g = normal_shock(state5, 11100.0, state6)
    print "state6:"
    state6.write_state(sys.stdout)
    print "Checks:"
    print "p2/p1=", state6.p / state5.p
    print "rho2/rho1=", state6.rho / state5.rho
    print "T2/T1=", state6.T / state5.T
    print "V6g = {0} m/s".format(V6g)

    print "Unsteady expansion from state 2 to state 7"
    print "Well, giving it a go for now anyway"
    (V7, state7) = finite_wave_dp('cplus', V2g, state2, state6.p, steps=100)
    print "state7:"
    state7.write_state(sys.stdout)
    print "V7 = {0} m/s".format(V7)
    M7 = V7 / (state7.gam * state7.R * state7.T)**(0.5)
    print "M7 = {0}".format(M7)
    """
Пример #17
0
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