예제 #1
0
    def create_sim(self,
                   p,
                   fuel='H2:1.0, AR:1.0',
                   T_fuel=300,
                   mdot_fuel=0.24,
                   oxidizer='O2:0.2, AR:0.8',
                   T_ox=300,
                   mdot_ox=0.72,
                   width=0.02):

        # Solution object used to compute mixture properties
        self.gas = ct.Solution('h2o2.xml', 'ohmech')
        self.gas.TP = T_fuel, p

        # Flame object
        self.sim = ct.CounterflowDiffusionFlame(self.gas, width=width)

        # Set properties of the fuel and oxidizer mixtures
        self.sim.fuel_inlet.mdot = mdot_fuel
        self.sim.fuel_inlet.X = fuel
        self.sim.fuel_inlet.T = T_fuel

        self.sim.oxidizer_inlet.mdot = mdot_ox
        self.sim.oxidizer_inlet.X = oxidizer
        self.sim.oxidizer_inlet.T = T_ox

        self.sim.set_initial_guess()
예제 #2
0
    def create_sim(self,
                   p,
                   fuel='H2:1.0, AR:1.0',
                   T_fuel=300,
                   mdot_fuel=0.24,
                   oxidizer='O2:0.2, AR:0.8',
                   T_ox=300,
                   mdot_ox=0.72):

        initial_grid = np.linspace(0, 0.02, 6)  # m
        tol_ss = [2.0e-5, 1.0e-11]  # [rtol, atol] for steady-state problem
        tol_ts = [5.0e-4, 1.0e-11]  # [rtol, atol] for time stepping

        # IdealGasMix object used to compute mixture properties
        self.gas = ct.Solution('h2o2.xml', 'ohmech')
        self.gas.TP = T_fuel, p

        # Flame object
        self.sim = ct.CounterflowDiffusionFlame(self.gas, initial_grid)
        self.sim.flame.set_steady_tolerances(default=tol_ss)
        self.sim.flame.set_transient_tolerances(default=tol_ts)

        # Set properties of the fuel and oxidizer mixtures
        self.sim.fuel_inlet.mdot = mdot_fuel
        self.sim.fuel_inlet.X = fuel
        self.sim.fuel_inlet.T = T_fuel

        self.sim.oxidizer_inlet.mdot = mdot_ox
        self.sim.oxidizer_inlet.X = oxidizer
        self.sim.oxidizer_inlet.T = T_ox

        self.sim.set_initial_guess(fuel='H2')
예제 #3
0
import os

# Create directory for output data files
data_directory = 'diffusion_flame_extinction_data/'
if not os.path.exists(data_directory):
    os.makedirs(data_directory)

# PART 1: INITIALIZATION

# Set up an initial hydrogen-oxygen counterflow flame at 1 bar and low strain
# rate (maximum axial velocity gradient = 2414 1/s)

reaction_mechanism = 'h2o2.xml'
gas = ct.Solution(reaction_mechanism)
width = 18.e-3  # 18mm wide
f = ct.CounterflowDiffusionFlame(gas, width=width)

# Define the operating pressure and boundary conditions
f.P = 1.e5  # 1 bar
f.fuel_inlet.mdot = 0.5  # kg/m^2/s
f.fuel_inlet.X = 'H2:1'
f.fuel_inlet.T = 300  # K
f.oxidizer_inlet.mdot = 3.0  # kg/m^2/s
f.oxidizer_inlet.X = 'O2:1'
f.oxidizer_inlet.T = 500  # K

# Set refinement parameters
f.set_refine_criteria(ratio=3.0, slope=0.1, curve=0.2, prune=0.03)

# Define a limit for the maximum temperature below which the flame is
# considered as extinguished and the computation is aborted
예제 #4
0
tol_ss = [1.0e-5, 1.0e-12]  # [rtol, atol] for steady-state problem
tol_ts = [5.0e-4, 1.0e-11]  # [rtol, atol] for time stepping

loglevel = 1  # amount of diagnostic output (0 to 5)
refine_grid = 1   # 1 to enable refinement, 0 to disable

# Create the gas object used to evaluate all thermodynamic, kinetic, and
# transport properties.
gas = ct.Solution('gri30.xml', 'gri30_mix')
gas.TP = gas.T, p

# Create an object representing the counterflow flame configuration,
# which consists of a fuel inlet on the left, the flow in the middle,
# and the oxidizer inlet on the right.
f = ct.CounterflowDiffusionFlame(gas, initial_grid)

# Set the state of the two inlets
f.fuel_inlet.mdot = mdot_f
f.fuel_inlet.X = comp_f
f.fuel_inlet.T = tin_f

f.oxidizer_inlet.mdot = mdot_o
f.oxidizer_inlet.X = comp_o
f.oxidizer_inlet.T = tin_o

# Set error tolerances
f.flame.set_steady_tolerances(default=tol_ss)
f.flame.set_transient_tolerances(default=tol_ts)

# Set the boundary emissivities
def CounterflowPartiallyPremixedFlame(mech='gri30.xml',
                                      transport='UnityLewis',
                                      flag_soret=False,
                                      flag_radiation=False,
                                      fuel_name='CH4',
                                      strain_rate=285.,
                                      width=0.01,
                                      p=1.,
                                      phi_f='inf',
                                      phi_o=0.,
                                      tin_f=300.,
                                      tin_o=300.,
                                      solution=None):

    ################################################################################

    # Create the gas object used to evaluate all thermodynamic, kinetic, and
    # transport properties.
    gas = ct.Solution(mech)

    phi_f = float(phi_f)
    if phi_f <= 1.:
        sys.exit('Equivalence ratio of fuel side {:g}'.format(phi_f))
    if phi_o >= 1.:
        sys.exit('Equivalence ratio of oxidizer side {:g}'.format(phi_o))

    # construct case name
    flame_params = {}
    flame_params['F'] = fuel_name
    flame_params['p'] = p
    flame_params['a'] = strain_rate
    flame_params['phif'] = phi_f
    flame_params['phio'] = phi_o
    flame_params['tf'] = tin_f
    flame_params['to'] = tin_o

    case_name = params2name(flame_params)

    ################################################################################

    p *= ct.one_atm  # pressure

    # Create an object representing the counterflow flame configuration,
    # which consists of a fuel inlet on the left, the flow in the middle,
    # and the oxidizer inlet on the right.
    f = ct.CounterflowDiffusionFlame(gas, width=width)
    f.transport_model = transport
    f.P = p

    if solution is not None:
        f.restore(solution, loglevel=0)

        solution_width = f.grid[-1] - f.grid[0]
        width_factor = width / solution_width

        solution_strain = (f.u[0] - f.u[-1]) / solution_width
        strain_factor = strain_rate / solution_strain

        normalized_grid = f.grid / solution_width

        u_factor = strain_factor * width_factor

        # update solution initialization following Fiala & Sattelmayer
        f.flame.grid = normalized_grid * width
        f.set_profile('u', normalized_grid, f.u * u_factor)
        f.set_profile('V', normalized_grid, f.V * strain_factor)
        f.set_profile('lambda', normalized_grid,
                      f.L * np.square(strain_factor))

    oxy = {'O2': 1., 'N2': 3.76}  # air composition
    fuel_index = gas.species_index(fuel_name)
    stoich_nu = gas.n_atoms(fuel_index,
                            'C') + gas.n_atoms(fuel_index, 'H') / 4.

    comp_f = {}
    comp_o = {}
    comp_f[fuel_name] = 1
    for k, v in oxy.items():
        comp_o[k] = v
        comp_f[k] = v * stoich_nu / phi_f

    comp_o[fuel_name] = phi_o / stoich_nu

    gas.TPX = tin_f, p, comp_o
    dens_o = gas.density

    gas.TPX = tin_o, p, comp_f
    dens_f = gas.density

    # fuel and oxidizer streams have the same velocity
    u = strain_rate * width / 2.

    # get mass flow rate
    mdot_o = u * dens_o
    mdot_f = u * dens_f  # kg/m^2/s

    # Set the state of the two inlets
    f.fuel_inlet.mdot = mdot_f
    f.fuel_inlet.X = comp_f
    f.fuel_inlet.T = tin_f

    f.oxidizer_inlet.mdot = mdot_o
    f.oxidizer_inlet.X = comp_o
    f.oxidizer_inlet.T = tin_o

    # Set the boundary emissivities
    f.set_boundary_emissivities(0.0, 0.0)
    # Turn radiation off
    f.radiation_enabled = False

    f.set_refine_criteria(ratio=2, slope=0.1, curve=0.1, prune=0.01)

    # Solve the problem
    try:
        f.solve(loglevel=0, auto=True)
    except Exception as e:
        print('Error: not converge for case:', e)
        return -1

    if flag_radiation:
        f.radiation_enabled = True
        try:
            f.solve(loglevel=0, auto=True)
        except Exception as e:
            print('Error: not converge for case:', e)
            return -1

    if flag_soret:
        f.soret_enabled = True
        try:
            f.solve(loglevel=0, auto=True)
        except Exception as e:
            print('Error: not converge for case:', e)
            return -1

    f.save('{}.xml'.format(case_name))

    if np.max(f.T) < np.max((tin_f, tin_o)) + 100:
        return 1
    else:
        return 0
def counterflow_flame(mech='gri30.xml',
                      transport='Multi',
                      flag_soret=True,
                      flag_radiation=False,
                      fuel={'CH4': 1},
                      oxy={
                          'O2': 1,
                          'N2': 3.76
                      },
                      strain_rate=100.,
                      width=0.01,
                      p=1.,
                      phi_f='inf',
                      phi_o=0.,
                      tin_f=300.,
                      tin_o=300.,
                      solution=None):

    ################################################################################
    # Create the gas object used to evaluate all thermodynamic, kinetic, and
    # transport properties.
    gas = ct.Solution(mech)

    phi_f = float(phi_f)
    if phi_f <= 1.:
        sys.exit('Equivalence ratio of fuel side {:g}'.format(phi_f))
    if phi_o >= 1.:
        sys.exit('Equivalence ratio of oxidizer side {:g}'.format(phi_o))

    # construct case name
    flame_params = {}
    flame_params['p'] = p
    flame_params['a'] = strain_rate
    flame_params['phif'] = phi_f
    flame_params['phio'] = phi_o
    flame_params['tf'] = tin_f
    flame_params['to'] = tin_o

    case_name = params2name(flame_params)

    p *= ct.one_atm  # pressure
    ################################################################################

    #fuel = { 'H2':1., 'N2':1. } # fuel composition
    #oxy = {'O2':1., 'N2':3.76}  # air composition

    Z_element = ['C', 'H', 'O']
    for e in Z_element:
        if e not in gas.element_names:
            Z_element.remove(e)

    # get stoichiometric coefficients
    element_nu = {'C': 2, 'O': -1, 'H': 0.5}

    o_fuel = 0.
    for k, v in fuel.items():
        for e in gas.element_names:
            if e in element_nu.keys():
                o_fuel += v * gas.n_atoms(k, e) * element_nu[e]

    o_oxy = 0.
    for k, v in oxy.items():
        for e in gas.element_names:
            if e in element_nu.keys():
                o_oxy += v * gas.n_atoms(k, e) * element_nu[e]

    stoich_nu = -o_fuel / o_oxy

    # composition for two streams
    comp_f = {}
    comp_o = {}

    for k in fuel.keys():
        comp_f[k] = 0.
        comp_o[k] = 0.
    for k in oxy.keys():
        comp_f[k] = 0.
        comp_o[k] = 0.

    for k, v in fuel.items():
        comp_f[k] += v
        comp_o[k] += v * phi_o / stoich_nu

    for k, v in oxy.items():
        comp_o[k] += v
        comp_f[k] += v * stoich_nu / phi_f


# fuel and oxidizer streams have the same velocity
    u = strain_rate * width / 2.

    # get mass flow rate
    gas.TPX = tin_f, p, comp_o
    dens_o = gas.density
    mdot_o = u * dens_o

    gas.TPX = tin_o, p, comp_f
    dens_f = gas.density
    mdot_f = u * dens_f  # kg/m^2/s

    # Create an object representing the counterflow flame configuration,
    # which consists of a fuel inlet on the left, the flow in the middle,
    # and the oxidizer inlet on the right.
    f = ct.CounterflowDiffusionFlame(gas, width=width)

    if solution is not None:
        try:
            f.restore(solution, loglevel=0)
        except Exception as e:
            print(e, 'Start to solve from initialization')

    f.transport_model = transport

    # Set the state of the two inlets
    f.fuel_inlet.mdot = mdot_f
    f.fuel_inlet.X = comp_f
    f.fuel_inlet.T = tin_f

    f.oxidizer_inlet.mdot = mdot_o
    f.oxidizer_inlet.X = comp_o
    f.oxidizer_inlet.T = tin_o

    # Set the boundary emissivities
    f.set_boundary_emissivities(0.0, 0.0)
    # Turn radiation off
    f.radiation_enabled = False

    f.set_refine_criteria(ratio=2, slope=0.1, curve=0.1, prune=0.01)

    # Solve the problem
    try:
        f.solve(loglevel=0, auto=True)
    except Exception as e:
        print('Error: not converge for case:', e)
        return -1

    if flag_radiation:
        f.radiation_enabled = True
        try:
            f.solve(loglevel=0, auto=True)
        except Exception as e:
            print('Error: not converge for case:', e)
            return -1

    if flag_soret:
        f.soret_enabled = True
        try:
            f.solve(loglevel=0, auto=True)
        except Exception as e:
            print('Error: not converge for case:', e)
            return -1

    f.save('{}.xml'.format(case_name))

    ################################################################################
    # post-processing

    # Calculate Bilger's mixture fraction

    # fuel
    gas.TPX = tin_f, p, comp_f

    z_f = 0
    for e in Z_element:
        z_f += (element_nu[e] * gas.elemental_mass_fraction(e) /
                gas.atomic_weight(e))

    comp_fuel = np.hstack((gas.T, gas.Y))
    fuel_str = ' '.join([format(x, '12.6e') for x in comp_fuel])

    # oxidizer
    gas.TPX = tin_o, p, comp_o

    z_o = 0
    for e in Z_element:
        z_o += (element_nu[e] * gas.elemental_mass_fraction(e) /
                gas.atomic_weight(e))

    comp_oxy = np.hstack((gas.T, gas.Y))
    oxy_str = ' '.join([format(x, '12.6e') for x in comp_oxy])

    # stoichiometric mixture
    comp_st = {}

    for k in fuel.keys():
        comp_st[k] = 0.
    for k in oxy.keys():
        comp_st[k] = 0.

    for k, v in fuel.items():
        comp_st[k] += v
    for k, v in oxy.items():
        comp_st[k] += v * stoich_nu

    gas.TPX = tin_o, p, comp_st

    z_st = 0
    for e in Z_element:
        z_st += (element_nu[e] * gas.elemental_mass_fraction(e) /
                 gas.atomic_weight(e))

    Zst = (z_st - z_o) / (z_f - z_o)

    z = np.zeros(f.T.shape)
    for e in Z_element:
        z += (element_nu[e] * f.elemental_mass_fraction(e) /
              gas.atomic_weight(e))

    Z = (z - z_o) / (z_f - z_o)

    # thermal diffusivity
    alpha = f.thermal_conductivity / (f.cp_mass * f.density)

    # kinetic viscosity
    nu = f.viscosity / f.density

    # a mixture fraction based on fuel stream is pure fuel
    gas.TPX = tin_f, p, fuel

    z_f = 0
    for e in Z_element:
        z_f += (element_nu[e] * gas.elemental_mass_fraction(e) /
                gas.atomic_weight(e))

    gas.TPX = tin_o, p, oxy

    z_o = 0
    for e in Z_element:
        z_o += (element_nu[e] * gas.elemental_mass_fraction(e) /
                gas.atomic_weight(e))

    Z1st = (z_st - z_o) / (z_f - z_o)

    z = np.zeros(f.T.shape)
    for e in Z_element:
        z += (element_nu[e] * f.elemental_mass_fraction(e) /
              gas.atomic_weight(e))

    Z1 = (z - z_o) / (z_f - z_o)

    # heat release rate
    Q = f.heat_release_rate

    ################################################################################
    # output

    data = np.column_stack((f.grid, f.T, f.Y.transpose(), Z, Z1, Q, alpha, nu))
    data_names = (['grid', 'T'] + gas.species_names +
                  ['Z', 'Z1', 'Q', 'alpha', 'nu'])

    np.savetxt('{}.dat'.format(case_name),
               data,
               header=('FUEL: {0}\nOXIDIZER: {1}\n'.format(fuel_str, oxy_str) +
                       'Zst = {:g}; Z1st = {:g}\n'.format(Zst, Z1st) +
                       ' '.join(data_names)),
               comments='')

    if np.max(f.T) < np.max((tin_f, tin_o)) + 100:
        return 1
    else:
        return 0
예제 #7
0
def counterflow_flame(mech='gri30.xml',
                      transport='Multi',
                      flag_soret=True,
                      flag_radiation=False,
                      fuel_name='CH4',
                      strain_rate=100.,
                      width=0.01,
                      p=1.,
                      phi_f='inf',
                      phi_o=0.,
                      tin_f=300.,
                      tin_o=300.,
                      solution=None):

    ################################################################################
    # Create the gas object used to evaluate all thermodynamic, kinetic, and
    # transport properties.
    gas = ct.Solution(mech)

    phi_f = float(phi_f)
    if phi_f <= 1.:
        sys.exit('Equivalence ratio of fuel side {:g}'.format(phi_f))
    if phi_o >= 1.:
        sys.exit('Equivalence ratio of oxidizer side {:g}'.format(phi_o))

    # construct case name
    flame_params = {}
    flame_params['F'] = fuel_name
    flame_params['p'] = p
    flame_params['a'] = strain_rate
    flame_params['phif'] = phi_f
    flame_params['phio'] = phi_o
    flame_params['tf'] = tin_f
    flame_params['to'] = tin_o

    #    flame_params_str = []
    #    for k, v in flame_params.items():
    #        try:
    #            param_str = '{0}-{1:g}'.format(k,v)
    #        except ValueError:
    #            param_str = '{0}-{1}'.format(k,v)
    #        flame_params_str.append(param_str)
    #
    #    case_name = '_'.join(flame_params_str)
    case_name = params2name(flame_params)

    p *= ct.one_atm  # pressure

    #    if phi_f < 10.0:
    #        case_name = '{0}_p{1:g}_a{2:g}_phif{3:g}_phio{4:g}_tf{5:g}_to{6:g}'\
    #                .format(fuel_name,p/ct.one_atm,strain_rate,
    #                        phi_f,phi_o,tin_f,tin_o)
    #    else:
    #        case_name = '{0}_p{1:g}_a{2:g}_phifinf_phio{3:g}_tf{4:g}_to{5:g}'\
    #                .format(fuel_name,p/ct.one_atm,strain_rate,
    #                        phi_f,phi_o,tin_f,tin_o)
    #
    ## parameters of the counterflow flame
    ## a = (U_f+U+o)/width
    #strain_rate = 100 # 1/s
    #
    #width = 0.01 # Distance between inlets is 2 cm
    #
    ## single fuel
    #fuel_name = 'CH4'
    #
    #phi_f = 1.7 # equivalence ratio of the fuel side stream
    #phi_o = 0.  # equivalence ratio of the oxidizer side stream
    #
    #tin_f = 300.0  # fuel inlet temperature
    #tin_o = 300.0  # oxidizer inlet temperature
    #
    ################################################################################

    oxy = {'O2': 1., 'N2': 3.76}  # air composition

    fuel_index = gas.species_index(fuel_name)

    stoich_nu = gas.n_atoms(fuel_index,
                            'C') + gas.n_atoms(fuel_index, 'H') / 4.

    comp_f = {}
    comp_o = {}
    comp_f[fuel_name] = 1
    for k, v in oxy.items():
        comp_o[k] = v
        comp_f[k] = v * stoich_nu / phi_f

    comp_o[fuel_name] = phi_o

    # fuel and oxidizer streams have the same velocity
    u = strain_rate * width / 2.

    # get mass flow rate
    gas.TPX = tin_f, p, comp_o
    dens_o = gas.density
    mdot_o = u * dens_o

    gas.TPX = tin_o, p, comp_f
    dens_f = gas.density
    mdot_f = u * dens_f  # kg/m^2/s

    # Create an object representing the counterflow flame configuration,
    # which consists of a fuel inlet on the left, the flow in the middle,
    # and the oxidizer inlet on the right.
    f = ct.CounterflowDiffusionFlame(gas, width=width)

    if solution is not None:
        try:
            f.restore(solution, loglevel=0)
        except Exception as e:
            print(e, 'Start to solve from initialization')

    f.transport_model = transport

    # Set the state of the two inlets
    f.fuel_inlet.mdot = mdot_f
    f.fuel_inlet.X = comp_f
    f.fuel_inlet.T = tin_f

    f.oxidizer_inlet.mdot = mdot_o
    f.oxidizer_inlet.X = comp_o
    f.oxidizer_inlet.T = tin_o

    # Set the boundary emissivities
    f.set_boundary_emissivities(0.0, 0.0)
    # Turn radiation off
    f.radiation_enabled = False

    f.set_refine_criteria(ratio=2, slope=0.1, curve=0.1, prune=0.01)

    # Solve the problem
    try:
        f.solve(loglevel=0, auto=True)
    except Exception as e:
        print('Error: not converge for case:', e)
        return -1

    if flag_radiation:
        f.radiation_enabled = True
        try:
            f.solve(loglevel=0, auto=True)
        except Exception as e:
            print('Error: not converge for case:', e)
            return -1

    if flag_soret:
        f.soret_enabled = True
        try:
            f.solve(loglevel=0, auto=True)
        except Exception as e:
            print('Error: not converge for case:', e)
            return -1

    f.save('{}.xml'.format(case_name))

    ################################################################################
    # post-processing

    # Calculate Bilger's mixture fraction

    # fuel
    gas.TPX = tin_f, p, comp_f
    YC_f = gas.elemental_mass_fraction('C')
    YH_f = gas.elemental_mass_fraction('H')
    YO_f = gas.elemental_mass_fraction('O')

    comp_fuel = np.hstack((gas.T, gas.Y))
    fuel_str = ' '.join([format(x, '12.6e') for x in comp_fuel])

    # oxidizer
    gas.TPX = tin_o, p, comp_o
    YC_o = gas.elemental_mass_fraction('C')
    YH_o = gas.elemental_mass_fraction('H')
    YO_o = gas.elemental_mass_fraction('O')

    comp_oxy = np.hstack((gas.T, gas.Y))
    oxy_str = ' '.join([format(x, '12.6e') for x in comp_oxy])

    # stoichiometric mixture
    comp_st = {}
    comp_st[fuel_name] = 1
    for k, v in oxy.items():
        comp_st[k] = v * stoich_nu

    gas.TPX = tin_o, p, comp_st
    YC_st = gas.elemental_mass_fraction('C')
    YH_st = gas.elemental_mass_fraction('H')
    YO_st = gas.elemental_mass_fraction('O')

    Zst = (2.*(YC_st-YC_o)/gas.atomic_weight('C')
            +(YH_st-YH_o)/2./gas.atomic_weight('H')
            -(YO_st-YO_o)/gas.atomic_weight('O')) / \
            (2.*(YC_f-YC_o)/gas.atomic_weight('C')
            +(YH_f-YH_o)/2./gas.atomic_weight('H')
            -(YO_f-YO_o)/gas.atomic_weight('O'))

    YC = f.elemental_mass_fraction('C')
    YH = f.elemental_mass_fraction('H')
    YO = f.elemental_mass_fraction('O')

    Z = (2.*(YC-YC_o)/gas.atomic_weight('C')
            +(YH-YH_o)/2./gas.atomic_weight('H')
            -(YO-YO_o)/gas.atomic_weight('O')) / \
            (2.*(YC_f-YC_o)/gas.atomic_weight('C')
            +(YH_f-YH_o)/2./gas.atomic_weight('H')
            -(YO_f-YO_o)/gas.atomic_weight('O'))

    # thermal diffusivity
    alpha = f.thermal_conductivity / (f.cp_mass * f.density)

    # kinetic viscosity
    nu = f.viscosity / f.density

    # a mixture fraction based on fuel stream is pure CH4
    gas.TPX = tin_f, p, {fuel_name: 1}
    YC_f = gas.elemental_mass_fraction('C')
    YH_f = gas.elemental_mass_fraction('H')
    YO_f = gas.elemental_mass_fraction('O')

    gas.TPX = tin_o, p, oxy
    YC_o = gas.elemental_mass_fraction('C')
    YH_o = gas.elemental_mass_fraction('H')
    YO_o = gas.elemental_mass_fraction('O')

    Z1st = (2.*(YC_st-YC_o)/gas.atomic_weight('C')
            +(YH_st-YH_o)/2./gas.atomic_weight('H')
            -(YO_st-YO_o)/gas.atomic_weight('O')) / \
            (2.*(YC_f-YC_o)/gas.atomic_weight('C')
            +(YH_f-YH_o)/2./gas.atomic_weight('H')
            -(YO_f-YO_o)/gas.atomic_weight('O'))

    Z1 = (2.*(YC-YC_o)/gas.atomic_weight('C')
             +(YH-YH_o)/2./gas.atomic_weight('H')
             -(YO-YO_o)/gas.atomic_weight('O')) / \
             (2.*(YC_f-YC_o)/gas.atomic_weight('C')
             +(YH_f-YH_o)/2./gas.atomic_weight('H')
             -(YO_f-YO_o)/gas.atomic_weight('O'))

    # progress variable
    # C_o: mass fractio of O in products CO2, CO, H2O
    # C_4spe: mass fraction of CO2, CO, H2O, H2
    # C_2spe: mass fraction of CO2 and CO

    index_H2O = gas.species_index('H2O')
    index_CO2 = gas.species_index('CO2')
    index_CO = gas.species_index('CO')
    index_H2 = gas.species_index('H2')

    MW_H2O = gas.molecular_weights[index_H2O]
    MW_CO2 = gas.molecular_weights[index_CO2]
    MW_CO = gas.molecular_weights[index_CO]
    MW_H2 = gas.molecular_weights[index_H2]

    C_o = gas.atomic_weight('O') * (f.Y[index_H2O] / MW_H2O +
                                    2. * f.Y[index_CO2] / MW_CO2 +
                                    f.Y[index_CO] / MW_CO)

    C_4spe = f.Y[index_CO2] + f.Y[index_CO] + f.Y[index_H2O] + f.Y[index_H2]

    C_2spe = f.Y[index_CO2] + f.Y[index_CO]

    # heat release rate
    Q = f.heat_release_rate

    ################################################################################
    # output

    data = np.column_stack((f.grid, f.T, f.Y.transpose(), Z, Z1, C_o, C_4spe,
                            C_2spe, Q, alpha, nu))
    data_names = (['grid', 'T'] + gas.species_names +
                  ['Z', 'Z1', 'C_o', 'C_4spe', 'C_2spe', 'Q', 'alpha', 'nu'])

    np.savetxt('{}.dat'.format(case_name),
               data,
               header=('FUEL: {0}\nOXIDIZER: {1}\n'.format(fuel_str, oxy_str) +
                       'Zst = {:g}; Z1st = {:g}\n'.format(Zst, Z1st) +
                       ' '.join(data_names)),
               comments='')

    if np.max(f.T) < np.max((tin_f, tin_o)) + 100:
        return 1
    else:
        return 0