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)
    """
Exemple #2
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
Exemple #3
0
def main():
    """top level function!"""
    
    #dictionaries to store useful stuff
    
    # pressure, mach number, temperature, sound speed, velocity, density, R, gamma
    
    P={};M={};T={};a={};V={};rho={};RU2={};G={}
    
    #a couple of switches
    
    ref = 0 #ref = 1 allows shock reflection at D2
    stand = 1 #if stand = 1, calculate pressure for standing shock in region 2
    REV = 0
    
    #inputs (asks user for some of these inputs)
         
    print 'Driver condition'
    
    piston = is_valid(raw_input('Piston configuration? {0}'.format(pistons.keys())),pistons.keys())
    
    primary = is_valid(str(raw_input('Percentage of Helium in the primary driver? {0} '.format(primary_driver.keys()))),primary_driver.keys())
    
    GP = primary_driver[primary][0]; RP = primary_driver[primary][1]
       
    secondary_input = is_valid(str(raw_input('Is the secondary driver being used (y/n)? ')),['y','n'])
    if secondary_input == 'y': 
        secondary = True   
    else:
        secondary = None
       
    test_gas = is_valid(raw_input('Test gas? {0} '.format(gases.keys())), gases.keys())
    
    if secondary:
        
        GS = gases['He'][0]; RS = gases['He'][1]
        
    GT = gases[test_gas][0]; RT = gases[test_gas][1]
        
    #air as accelorator gas
    GA = gases['air'][0]; RA = gases['air'][1]
    
    filename = raw_input('filename? ')
    
    if filename == '':
        filename = 'x2run.txt'
               
    print 'Enter shock speeds (in m/s) below to find solution.'
    
    if secondary: Vsd = int(raw_input('Vsd? '))
    
    Vs1 = int(raw_input('Vs1? '))
    Vs2 = int(raw_input('Vs2? ')) 
    
    T0 = 300.0;T['s4'] = pistons[piston][0]; P['s4'] = pistons[piston][1] #ambient + reservoir temp (K), reservoir pressure (Pa) (this is the current lightweight piston driver condition used for all shots in X2)
    M['s3s'] = primary_driver[str(primary)][2] #Mach numbers terminating steady expansions (used for orifice plate) set M[11] to 0 for constant area shock tunnel (not normally used), M[11] =1 is no orifice plate, sonic throat. normal configuration, theoretical optimum. set M[11] to 2.15 to use pure He driver orifice plate 
    
    #put gammas into dictionaries
    if secondary:
        G['sd1'] = GS; G['sd2'] = GS; G['sd3'] = GP; G['s3'] = GS
    else:
        G['s3'] = GP
    G['s4'] = GP; G['s3s'] = GP; G['s1'] = GT; G['s2'] = GT
    G['s7'] = GT; G['s5'] = GA; G['s6'] = GA; G['s13'] = GA; G['s8'] = GT
    
    #add ambient temperature to arrays where required
    T['sd1' ]= T0; T['s1'] = T0; T['s5'] = T0
    
    M['s4'] = 0; V['s4']= 0; rho['s4'] = 0
    
    arbitrary = True #dummy variable
    
    while arbitrary:
        
        #output file creation

        output = open(filename,"w")
    
        #----------------- starting off ----------------------
        
        #calculate the sound speeds known
        if secondary:
            a['sd1'] = math.sqrt(T['sd1']*GS*RS)
        a['s4'] = math.sqrt(T['s4']*GP*RP) 
        a['s1'] = math.sqrt(T['s1']*GT*RT)
        a['s5'] = math.sqrt(T['s5']*GA*RA)
        a['s3s'] = a['s4']*IP(M['s3s'],GP)**((GP-1.0)/2.0/GP) 
        P['s3s'] = P['s4']*IP(M['s3s'],GP)
        V['s3s'] = a['s3s']*M['s3s'] 
        T['s3s'] = T['s4']*(a['s3s']/a['s4'])**2.0
        rho['s3s'] = P['s3s']/RP/T['s3s']
        RU2['s3s'] = rho['s3s']*V['s3s']**2.0
        
        #---------------------- secondary driver ------------------------------
        
        if secondary: #if secondary driver is in use
            #conditions behind shock         
            Msd = Vsd/a['sd1']
            V['sd2'] = Vsd*(1.0-u2_u1(Msd,GS))
            T['sd2'] = T['sd1']*T2_T1(Msd,GS)
            a['sd2'] = math.sqrt(T['sd2']*GS*RS)
            M['sd2'] = V['sd2']/a['sd2']
            
            #unsteady expansion using Vsd2 = Vsd3
            V['sd3'] = V['sd2']
            
            a['sd3'] = ad(GP, a['s3s'], V['s3s'], V['sd3'])
            P['sd3'] = P['s3s']*isen((a['sd3']/a['s3s']),GP) 
            T['sd3'] = T['s3s']*(a['sd3']/a['s3s'])**2.0
            M['sd3'] = V['sd3']/a['sd3'] 
            rho['sd3'] = P['sd3']/RP/T['sd3'] 
            RU2['sd3']=rho['sd3']*V['sd3']**2.0
            
            #can now get conditions at state sd2 now we have Psd3
            P['sd2'] = P['sd3']
            rho['sd2'] = P['sd2']/RS/T['sd2']
            RU2['sd2'] = rho['sd2']*V['sd2']**2.0
            #and then finally the fill pressure...
            P['sd1'] = P['sd2']/p2_p1(Msd,GS)
            M['sd1']=0; V['sd1']=0; rho['sd1'] = P['sd1']/RS/T['sd1']; RU2['sd1'] = 0

        #-------------------- shock tube ------------------------------
        
        #conditions behind shock         
        Ms1 = Vs1/a['s1']
        V['s2'] = Vs1*(1.0 - u2_u1(Ms1,GT))
        T['s2'] = T['s1']*T2_T1(Ms1,GT)
        a['s2'] = math.sqrt(T['s2']*GT*RT)
        M['s2'] = V['s2']/a['s2']
        
        #unsteady expansion using Vs2 = Vs3
        V['s3'] = V['s2']
        
        if secondary: #expansion of secondary driver gas into shock tube
            a['s3'] = ad(GS, a['sd2'], V['sd2'], V['s3'])
            P['s3'] = P['sd2']*isen((a['s3']/a['sd2']),GS) 
            T['s3'] = T['sd2']*(a['s3']/a['sd2'])**2.0
            rho['s3'] = P['s3']/RS/T['s3'] 
        else: #expansion of primary driver gas into shock tube
            a['s3'] = ad(GP, a['s3s'], V['s3s'], V['s3'])
            P['s3'] = P['s3s']*isen((a['s3']/a['s3s']),GP) 
            T['s3'] = T['s3s']*(a['s3']/a['s3s'])**2.0
            rho['s3'] = P['s3']/RP/T['s3'] 
        M['s3'] = V['s3']/a['s3'] 
        RU2['s3']=rho['s3']*V['s3']**2.0
        
        #can now get conditions at state s2 now we have Ps3
        P['s2'] = P['s3']
        rho['s2'] = P['s2']/RT/T['s2']
        RU2['s2'] = rho['s2']*V['s2']**2.0
        #and then finally the fill pressure...
        P['s1'] = P['s2']/p2_p1(Ms1,GT)
        M['s1']=0; V['s1']=0; rho['s1'] = P['s1']/RT/T['s1']; RU2['s1'] = 0
        
        #------------- acceleration tube -------------------------------
        
        #conditions behind shock         
        Ms2 = Vs2/a['s5']
        V['s6'] = Vs2*(1.0 - u2_u1(Ms2,GA))
        T['s6'] = T['s5']*T2_T1(Ms2,GA)
        a['s6'] = math.sqrt(T['s6']*GA*RA)
        M['s6'] = V['s6']/a['s6']
        
        #unsteady expansion using Vs6 = Vs7
        V['s7'] = V['s6']
        
        a['s7'] = ad(GT, a['s2'], V['s2'], V['s7'])
        P['s7'] = P['s2']*isen((a['s7']/a['s2']),GT) 
        T['s7'] = T['s2']*(a['s7']/a['s2'])**2.0
        rho['s7'] = P['s7']/RA/T['s7'] 
        M['s7'] = V['s7']/a['s7'] 
        RU2['s7']=rho['s7']*V['s7']**2.0
        
        #can now get conditions at state s6 now we have Ps7
        P['s6'] = P['s7']
        rho['s6'] = P['s6']/RA/T['s6']
        RU2['s6'] = rho['s6']*V['s6']**2.0
        #and then finally the fill pressure...
        P['s5'] = P['s6']/p2_p1(Ms2,GA)
        M['s5']=0; V['s5']=0; rho['s5'] = P['s5']/RA/T['s5']; RU2['s5'] = 0
               
        #--------------- nozzle calculations--------------------
        
        #currently using area ratio of 2.5!
        
        M['s8'] = nozzleMfinder (GT, 2.5  , M['s7'], M['s7']+5.0)
        
        T['s8'] = T['s7']*nozzleTratio(M['s7'],M['s8'],GT)
        P['s8'] = P['s7']*nozzlepratio(M['s7'],M['s8'],GT)
        V['s8'] = V['s7']*(M['s8']/M['s7'])*(T['s8']/T['s7'])**(1.0/2.0)
        rho['s8'] = rho['s7']*nozzlerhoratio(M['s7'],M['s8'],GT)
        a['s8'] = V['s8']/M['s8']
        
        #------------ normal shock calculation over the model -----------
        
        #NOTE: this part of the code actually does use chemistry for the equilibrium part...
        #it also uses the states dictionary syntax from pitot, so I can use the pitot printing function        
        
        #build states dictionary:
        states = {}
        
        #first build a gas object at the nozzle conditions
        
        states['s8'] = gases[test_gas][2].clone()
        states['s8'].set_pT(P['s8'],T['s8'])
        
        #and then the two different state 10 conditions that we will then shock
        
        states['s10f'] = states['s8'].clone()
        states['s10e'] = states['s8'].clone()
        
        #do a frozen and then an equilibrium normal shock on these conditions:
        
        V10f, V10fg = shock_ideal(states['s8'],V['s8'],states['s10f'])
        V['s10f'] = V10fg; M['s10f'] = V['s10f']/states['s10f'].son
        
        V10e, V10eg = normal_shock(states['s8'],V['s8'],states['s10e'])
        V['s10e'] = V10eg; M['s10e'] = V['s10e']/states['s10e'].son
                     
        #------------------------ output -------------------------------------
        
        #pillaged from new pitot!
        
        print " "
        
        version_printout = "Pitot Classic Version: {0}".format(VERSION_STRING)
        print version_printout
        output.write(version_printout + '\n')
        
        if secondary:
            description_sd = 'sd1 is secondary driver fill.'
            print description_sd
            output.write(description_sd + '\n')   
            
        description_1 = 'state 1 is shock tube fill. state 5 is acceleration tube fill.'    
        print description_1
        output.write(description_1 + '\n')
            
        description_2 = 'state 7 is expanded test gas entering the nozzle.'
        print description_2
        output.write(description_2 + '\n')
            
        description_3 = 'state 8 is test gas exiting the nozzle (using area ratio of {0}).'.format(2.5)
        print description_3
        output.write(description_3 + '\n')
        
        description_4 = 'state 10f is frozen shocked test gas flowing over the model.'
        print description_4
        output.write(description_4 + '\n')  
        
        description_5 = 'state 10e is equilibrium shocked test gas flowing over the model.'
        print description_5
        output.write(description_5 + '\n')     
        
        test_gas_used = 'Test gas is {0} (gamma = {1}, R = {2}, {3}).'.format(test_gas,GT,RT,gases[test_gas][2].reactants)
        print test_gas_used
        output.write(test_gas_used + '\n')  
        
        driver_gas_used = 'Driver gas has {0}%He (gamma = {1}, R = {2})'.format(primary,GP,RP)        
        print driver_gas_used
        output.write(driver_gas_used + '\n')  

        if secondary:
            secondary_shockspeeds = "Vsd = {0:.2f} m/s, Msd = {1:.2f}".format(Vsd,Msd)
            print secondary_shockspeeds
            output.write(secondary_shockspeeds + '\n')
        
        shockspeeds = "Vs1= {0:.2f} m/s, Ms1= {1:.2f} ,Vs2= {2:.2f} m/s, Ms2= {3:.2f}".format(Vs1,Ms1,Vs2,Ms2) 
        print shockspeeds #prints above line in console
        output.write(shockspeeds + '\n') #writes above line to output file (input to write command must be a string)
        
        key = "{0:6}{1:11}{2:9}{3:6}{4:9}{5:6}{6:9}{7:8}{8:9}".format("state","P","T","a","V","M","rho","pitot","stgn")
        print key
        output.write(key + '\n')
        
        units = "{0:6}{1:11}{2:9}{3:6}{4:9}{5:6}{6:9}{7:9}{8:9}".format("","Pa","K","m/s","m/s","","m^3/kg","kPa","MPa")
        print units
        output.write(units + '\n')
        
        #new dictionaries here to add pitot and stagnation pressure calcs
        
        pitot_pressure = {} #pitot pressure dict
        p0 = {} #stagnation pressure dict
        
        def condition_printer(it_string):
            """Prints the values of a specified condition to the screen and to 
            the output file. 
            
            I made a function of this so I didn't have to keep pasting the code in."""
            
            if M.has_key(it_string):
                    
                if M[it_string] == 0:
                    pitot_pressure[it_string] = 0
                    p0[it_string] = 0
                else:
                    pitot_pressure[it_string] = P[it_string]*pitot(M[it_string],G[it_string])/1000.0
                    p0[it_string] = p0_p(M[it_string], G[it_string])*P[it_string]/1.0e6
                
                conditions = "{0:<6}{1:<11.7g}{2:<9.1f}{3:<6.0f}{4:<9.1f}{5:<6.2f}{6:<9.4f}{7:<8.0f}{8:<9.1f}"\
                .format(it_string, P[it_string], T[it_string], a[it_string],
                        V[it_string],M[it_string],rho[it_string], 
                        pitot_pressure[it_string], p0[it_string])
                        
                print conditions
                output.write(conditions + '\n')
                
        def condition_printer_pitot(it_string):
            """The states based condition printer from pitot, used for the
            normal shock stuff at the end of the tunnel!"""
            
            if states.has_key(it_string):
                    
                if M[it_string] == 0:
                    pitot_pressure[it_string] = 0
                    p0[it_string] = 0
                else:
                    pitot_pressure[it_string] = pitot_p(states[it_string].p,M[it_string],states[it_string].gam)/1000.0
                    p0[it_string] = p0_p(M[it_string], states[it_string].gam)*states[it_string].p/1.0e6
                
                conditions = "{0:<6}{1:<11.7}{2:<9.1f}{3:<6.0f}{4:<9.1f}{5:<6.2f}{6:<9.4f}{7:<8.0f}{8:<9.1f}"\
                .format(it_string, states[it_string].p, states[it_string].T,
                        states[it_string].son,V[it_string],M[it_string],
                        states[it_string].rho, pitot_pressure[it_string], p0[it_string])
                        
                print conditions
                output.write(conditions + '\n')   
                
        #print the driver related stuff first
        
        condition_printer('s4')
        condition_printer('s3s')
        
        if secondary: #need a separate printing thing for the secondary driver
            
            for i in range(1,4): #will do 1 - 3
            
                it_string = 'sd{0}'.format(i)
                condition_printer(it_string)
                        
        for i in range(1,4): #shock tube stuff
            
            it_string = 's{0}'.format(i)
            condition_printer(it_string)
            
        for i in range(5,9): #acc tube and nozzle if it's there
        
            it_string = 's{0}'.format(i)
            condition_printer(it_string)
            
        #do the conditions over the model
        condition_printer_pitot('s10f')
        condition_printer_pitot('s10e')
            
                
        Cp_test_gas = (gases[test_gas][0]*gases[test_gas][1])/(gases[test_gas][0]-1.0)
        
        stagnation_enthalpy = (((0.5)*V['s7']**2.0)+(Cp_test_gas*T['s7'])) #MJ/kg

        stag_enth = 'The stagnation enthalpy (Ht) at the end of the acceleration tube {0:<.5g} MJ/kg.'.format(stagnation_enthalpy/1.0e6)
        print stag_enth
        output.write(stag_enth + '\n')
        
        #calculate flight equivalent speed
        u_eq = math.sqrt(2.0*stagnation_enthalpy) #supposedly why this is is discussed in Bianca's thesis
        u_eq_print = 'The flight equivalent speed is {0:<.5g} m/s.'.format(u_eq)
        print u_eq_print
        output.write(u_eq_print + '\n')
        
        #added ability to get the species in the post-shock condition
        
        show_species = True
        
        if show_species:
            species1 = 'species in the shock layer at equilibrium:'        
            print species1
            output.write(species1 + '\n')
            
            species2 = '{0}'.format(states['s10e'].species)
            print species2
            output.write(species2 + '\n')
    
        output.close()
               
        #------------------------------ user commands---------------------------
        
        if secondary:
            change_tuple = ('Vsd','Vs1','Vs2', 'quit')
        else:
            change_tuple = ('Vs1','Vs2', 'quit')
        
        change = is_valid(raw_input('What do you want to change? {0}'.format(change_tuple)), change_tuple)
            
        if change == 'quit':
            print "Removing temporary files and leaving the program."
            if os.path.isfile('thermo.inp'): os.remove('thermo.inp')
            if os.path.isfile('thermo.out'): os.remove('thermo.out')
            if os.path.isfile('thermo.lib'): os.remove('thermo.lib')
            if os.path.isfile('tmp.inp'): os.remove('tmp.inp')
            if os.path.isfile('tmp.out'): os.remove('tmp.out')
            if os.path.isfile('trans.inp'): os.remove('trans.inp')
            if os.path.isfile('trans.out'): os.remove('trans.out')
            if os.path.isfile('trans.lib'): os.remove('trans.lib')
            arbitrary == False
            break
            #quit()
                    
        elif change == 'Vsd':
            difference = int(raw_input('How much do you want to change it by? '))
            Vsd += difference
            print 'Vsd = {0}m/s'.format(Vsd)
            
        elif change == 'Vs1':    
            difference = int(raw_input('How much do you want to change it by? '))
            Vs1 += difference
            print 'Vs1 = {0}m/s'.format(Vs1)
        
        else:
            difference = int(raw_input('How much do you want to change it by? '))
            Vs2 += difference
            print 'Vs2 = {0}m/s'.format(Vs2)
Exemple #4
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
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