예제 #1
0
def free_flame(chemistry='gri30.cti',
               fuel={'CH4': 1.},
               oxidizer={
                   'O2': 1.,
                   'N2': 3.76
               },
               temperature=300.,
               pressure=1.,
               phi=1.,
               **kwargs):

    # for unrealistic parameters
    if pressure < 0.:
        raise ValueError('Negative pressure')
    if temperature < 0.:
        raise ValueError('Negative inlet temperature')
    if phi < 0.:
        raise ValueError('Negative equivalence ratio')

    # parameters
    params = {}
    params['T'] = temperature
    params['p'] = pressure
    params['phi'] = phi

    case = params2name(params)

    # pressure, convert to [Pa]
    pressure *= ct.one_atm

    # gas object
    gas = cg.mixture(chemistry, fuel, oxidizer, temperature, pressure, phi)

    f = free_flame_(gas, **kwargs)

    # return for unburnt flame
    if np.max(f.T) < temperature + 100.:
        return 1

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

    return 0
예제 #2
0
def counterflow_premixed_extinction(chemistry='FFCM-1.cti',
                                    fuel={'CH4': 1.},
                                    oxidizer={
                                        'O2': 1.,
                                        'N2': 3.76
                                    },
                                    T=300.,
                                    p=1.,
                                    phi=1.,
                                    **kwargs):

    # read kwargs

    # IO flags
    if 'folder_overwrite' in kwargs.keys():
        flag_folder = kwargs['folder_overwrite']
    else:
        flag_folder = True

    # parameters to approach extinction
    if 'a_init' in kwargs.keys():
        a_init = kwargs['a_init']
    else:
        a_init = 100.

    if 'a_max' in kwargs.keys():
        a_max = kwargs['a_max']
    else:
        a_max = 1.E+5

    if 'L_init' in kwargs.keys():
        L_init = kwargs['L_init']
    else:
        L_init = 0.05

    # factors
    # a_{n+1} = exp(f0) * a_n
    if 'f0' in kwargs.keys():
        f0 = kwargs['f0']
    else:
        f0 = 0.1

    # f0_{n+1} = f0_n / f1
    if 'f1' in kwargs.keys():
        f1 = kwargs['f1']
    else:
        f1 = 2.0

    # a_threshold_n = a_n * f2
    if 'f2' in kwargs.keys():
        f2 = kwargs['f2']
    else:
        f2 = 1.E-3

    # for unrealistic parameters
    if p < 0.:
        raise ValueError('Negative pressure')
    if T < 0.:
        raise ValueError('Negative inlet temperature')
    if phi < 0.:
        raise ValueError('Negative equivalence ratio')

    params = {}
    params['T'] = T
    params['p'] = p
    params['phi'] = phi

    folder_name = fn.params2name(params)

    pwd = os.getcwd()

    os.makedirs(folder_name, exist_ok=flag_folder)
    os.chdir(folder_name)

    # calculate free flame
    ctd.free_flame(chemistry=chemistry,
                   fuel=fuel,
                   oxidizer=oxidizer,
                   pressure=p,
                   temperature=T,
                   phi=phi,
                   **kwargs)

    # iterate to get the extinction
    params['a'] = a_init

    L = L_init

    flag = 3

    while True:

        if flag == 1:

            print('Strain rate = {:g} extinct'.format(params['a']))
            f0 /= f1
            break

        if flag == 2:

            print('Strain rate = {:g} negative flame speed'.format(
                params['a']))
            #break

        if flag == 3:

            print('Strain rate = {:g} initialization'.format(params['a']))
            solution = None

        else:

            print('Strain rate = {:g} success'.format(params['a']))
            flame_name = fn.params2name(params)
            solution = '{}.xml'.format(flame_name)

            a_old = params['a']
            L_old = L

            f0_a = np.exp(f0)

            L = L_old / np.power(f0_a, 0.5)
            params['a'] = a_old * f0_a

            a_diff = params['a'] - a_old
            if params['a'] > a_max or a_diff < f2 * a_old:
                break

        flag = ctd.counterflow_premixed_flame(chemistry=chemistry,
                                              fuel=fuel,
                                              oxidizer=oxidizer,
                                              temperature=T,
                                              pressure=p,
                                              phi=phi,
                                              a=params['a'],
                                              solution=solution,
                                              width=L,
                                              **kwargs)

    os.chdir(pwd)

    return
예제 #3
0
def counterflow_premixed_flame(chemistry='gri30.xml',
                               fuel={'CH4': 1.},
                               oxidizer={
                                   'O2': 1,
                                   'N2': 3.76
                               },
                               temperature=300.,
                               pressure=1.,
                               phi=1.,
                               a=1000.,
                               solution=None,
                               **kwargs):

    # for unrealistic parameters
    if pressure < 0.:
        raise ValueError('Negative pressure')
    if temperature < 0.:
        raise ValueError('Negative inlet temperature')
    if phi < 0.:
        raise ValueError('Negative equivalence ratio')

    # read kwargs
    if 'transport' in kwargs.keys():
        transport = kwargs['transport']
    else:
        transport = 'Mix'

    if 'width' in kwargs.keys():
        width = kwargs['width']
    else:
        width = 0.05

    if 'loglevel' in kwargs.keys():
        loglevel = kwargs['loglevel']
    else:
        # supress log output
        loglevel = 0

    # kwargs for flame solver
    if 'ct_ratio' in kwargs.keys():
        ct_ratio = kwargs['ct_ratio']
    else:
        ct_ratio = 2.

    if 'ct_slope' in kwargs.keys():
        ct_slope = kwargs['ct_slope']
    else:
        ct_slope = 0.02

    if 'ct_curve' in kwargs.keys():
        ct_curve = kwargs['ct_curve']
    else:
        ct_curve = 0.02

    if 'ct_prune' in kwargs.keys():
        ct_prune = kwargs['ct_prune']
    else:
        ct_prune = 0.01

    if 'ct_max_grids' in kwargs.keys():
        ct_max_grids = kwargs['ct_max_grids']
    else:
        ct_max_grids = 5000

    # case name
    params = {}
    params['T'] = temperature
    params['p'] = pressure
    params['phi'] = phi
    params['a'] = a

    case = params2name(params)

    # pressure
    pressure *= ct.one_atm

    # gas object
    #gas = ct.Solution(chemistry)
    # construct mixutre
    #mixture = cg.mixture_two_streams(gas, fuel, oxidizer, phi)
    # unburnt stream
    #gas.TPX = temperature, pressure, mixture
    gas = cg.mixture(chemistry, fuel, oxidizer, temperature, pressure, phi)

    rho_u = gas.density

    # burnt stream
    gas.equilibrate('HP')
    rho_b = gas.density

    gas = cg.mixture(chemistry, fuel, oxidizer, temperature, pressure, phi)

    # get inlet velocity based on the strain rate
    # $a_1=\dfrac{2U_1}{L}\left(1+\dfrac{U_2\sqrt{\rho_2}}{U_1\sqrt{\rho_1}}\right)$
    # $a_2=\dfrac{2U_2}{L}\left(1+\dfrac{U_1\sqrt{\rho_1}}{U_2\sqrt{\rho_2}}\right)$
    # with $\rho_1 U_1^2 = \rho_2 U_2^2$
    # $a_1=\dfrac{4U_1}{L}$ $a_2=\dfrac{4U_2}{L}$
    # set stream 1 and 2 for unburnt and equilibrium status respectively
    v_u = a * width / 4.0
    v_b = np.sqrt(rho_u * np.square(v_u) / rho_b)

    # mass rate
    m_u = rho_u * v_u
    m_b = rho_b * v_b

    # Create flame object
    f = ct.CounterflowPremixedFlame(gas=gas, width=width)

    f.transport_model = transport
    f.P = pressure
    f.reactants.mdot = m_u
    f.products.mdot = m_b

    f.set_refine_criteria(ratio=ct_ratio,
                          slope=ct_slope,
                          curve=ct_curve,
                          prune=ct_prune)

    f.set_max_grid_points(f.flame, ct_max_grids)

    # load saved case if presented
    if solution is not None:

        f.restore(solution, loglevel=loglevel)

        # scaling of saved solution
        solution_width = f.grid[-1] - f.grid[0]
        width_factor = width / solution_width

        solution_a = 4. * f.u[0] / solution_width
        a_factor = a / solution_a

        normalized_grid = f.grid / solution_width

        u_factor = a_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 * a_factor)
        f.set_profile('lambda', normalized_grid, f.L * np.square(a_factor))

        f.reactants.mdot = m_u
        f.products.mdot = m_b

    else:

        f.set_initial_guess()

    f.solve(loglevel=loglevel, auto=True)

    HRR = f.heat_release_rate

    idx = HRR.argmax()

    if HRR[idx] > 1000:

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

        if f.u[idx] > 0:

            return 0

        else:

            return 2

    else:

        return 1
예제 #4
0
def Ze(chemistry='FFCM-1.cti',
       fuel={'CH4': 1.},
       oxidizer={
           'O2': 1.,
           'N2': 3.76
       },
       T=300.,
       p=1.,
       phi=1.,
       perturb=0.01,
       **kwargs):

    # working directory
    pwd = os.getcwd()

    # solution name
    flame_params = {}
    flame_params['T'] = T
    flame_params['p'] = p
    flame_params['phi'] = phi
    flame_name = params2name(flame_params)
    solution = '{}.xml'.format(flame_name)

    # perturbation
    factor = np.array([1. - perturb, 1., 1. + perturb])

    # quantaties
    flux = np.zeros(3)
    Tb = np.zeros(3)

    params = {}
    for i, f in enumerate(factor):

        # subfolder
        params['N2'] = f
        folder_name = params2name(params)

        os.makedirs(folder_name, exist_ok=True)
        os.chdir(folder_name)

        if not os.path.isfile(solution):

            # oxidizer stream with perturbation
            stream = {}
            for k, v in oxidizer.items():
                stream[k] = v
            stream['N2'] = oxidizer['N2'] * f

            pc.driver.free_flame(chemistry, fuel, stream, T, p, phi, **kwargs)

        fs = pc.flame.FreeFlameState(solution, chemistry, fuel, oxidizer)

        flux[i] = fs.mass_flux()
        Tb[i] = fs.flame.T[-1]

        os.chdir(pwd)

    grad = np.gradient(flux, Tb)
    Ze = 2. * grad[1] * (Tb[1] - T) / flux[1]

    return Ze