Exemple #1
0
def make_clustered_grid(nx, ny, x_cp, y_cp, x_cc, y_cc):
    x_half1 = Flamelet._clustered_grid(nx // 2, x_cp * 2., x_cc)[0] * 0.5
    y_half1 = Flamelet._clustered_grid(nx // 2, y_cp * 2., y_cc)[0] * 0.5
    x_half2 = (0.5 - x_half1)[::-1]
    y_half2 = (0.5 - y_half1)[::-1]
    x_range = np.hstack((x_half1, 0.5 + x_half2))
    y_range = np.hstack((y_half1, 0.5 + y_half2))
    dx_mid = x_range[nx // 2 - 1] - x_range[nx // 2 - 2]
    x_range[nx // 2 - 1] -= dx_mid / 3.
    x_range[nx // 2 + 0] += dx_mid / 3.
    dy_mid = y_range[ny // 2 - 1] - y_range[ny // 2 - 2]
    y_range[ny // 2 - 1] -= dy_mid / 3.
    y_range[ny // 2 + 0] += dy_mid / 3.
    return x_range, y_range
Exemple #2
0
def build_unreacted_library(flamelet_specs, verbose=True):
    """Build a flamelet library for a nonreacting flow, with linear enthalpy and mass fraction profiles.

    Parameters
    ----------
    flamelet_specs : FlameletSpec or dictionary of arguments for a FlameletSpec
        flamelet specifications

    Returns
    -------
    library : spitfire.chemistry.library.Library instance
        a chemistry library with only the "mixture_fraction" dimension

    """
    fs = FlameletSpec(**flamelet_specs) if isinstance(
        flamelet_specs, dict) else copy.copy(flamelet_specs)
    fs.initial_condition = 'unreacted'
    flamelet = Flamelet(fs)
    return flamelet.make_library_from_interior_state(
        flamelet.initial_interior_state)
Exemple #3
0
def build_adiabatic_bs_library(flamelet_specs, verbose=True):
    """Build a flamelet library with the Burke-Schumann (idealized, one-step combustion) assumptions

    Parameters
    ----------
    flamelet_specs : FlameletSpec or dictionary of arguments for a FlameletSpec
        flamelet specifications

    Returns
    -------
    library : spitfire.chemistry.library.Library instance
        a chemistry library with only the "mixture_fraction" dimension

    """
    fs = FlameletSpec(**flamelet_specs) if isinstance(
        flamelet_specs, dict) else copy.copy(flamelet_specs)
    fs.initial_condition = 'Burke-Schumann'
    flamelet = Flamelet(fs)
    return flamelet.make_library_from_interior_state(
        flamelet.initial_interior_state)
Exemple #4
0
def build_adiabatic_eq_library(flamelet_specs, verbose=True):
    """Build a flamelet library with the equilibrium (infinitely fast) chemistry assumption,
        equivalently with Gibbs free energy minimization.

    Parameters
    ----------
    flamelet_specs : FlameletSpec or dictionary of arguments for a FlameletSpec
        flamelet specifications

    Returns
    -------
    library : spitfire.chemistry.library.Library instance
        a chemistry library with only the "mixture_fraction" dimension

    """
    fs = FlameletSpec(**flamelet_specs) if isinstance(
        flamelet_specs, dict) else copy.copy(flamelet_specs)
    fs.initial_condition = 'equilibrium'
    flamelet = Flamelet(fs)
    return flamelet.make_library_from_interior_state(
        flamelet.initial_interior_state)
Exemple #5
0
def _expand_enthalpy_defect_dimension_steady(chi_st, managed_dict,
                                             flamelet_specs, table_dict,
                                             h_stoich_spacing, verbose,
                                             input_integration_args,
                                             solver_verbose):
    flamelet_specs.initial_condition = table_dict[chi_st]['adiabatic_state']
    flamelet_specs.stoich_dissipation_rate = chi_st
    flamelet_specs.heat_transfer = 'nonadiabatic'
    flamelet_specs.scale_heat_loss_by_temp_range = False
    flamelet_specs.scale_convection_by_dissipation = False
    flamelet_specs.use_linear_ref_temp_profile = True
    flamelet_specs.radiative_emissivity = 0.
    flamelet_specs.convection_coefficient = 0.

    flamelet = Flamelet(flamelet_specs)

    first = True
    refine_before_extinction = False
    extinguished = False
    extinguished_first = False
    maxT = -1
    state_old = np.copy(flamelet.current_interior_state)
    hval = 0.
    dh = 1.e-1
    diff_target = 1e-1
    diff_norm = 1e-1

    hval_max = 1.e10

    solutions = []
    hvalues = []
    hvalues.append(hval)
    solutions.append(dict())

    for p in table_dict[chi_st]:
        if p != 'adiabatic_state':
            solutions[-1][p] = table_dict[chi_st][p]

    current_state = table_dict[chi_st]['adiabatic_state']

    cput0000 = perf_counter()
    while first or (not extinguished and hval < hval_max):
        hval += dh
        if first:
            first = False

        flamelet_specs.convection_coefficient = hval
        flamelet_specs.initial_condition = current_state
        flamelet = Flamelet(flamelet_specs)

        g_library = flamelet.compute_steady_state(verbose=solver_verbose)
        current_state = flamelet.current_interior_state
        maxT = np.max(current_state)

        diff_norm = np.max(
            np.abs(current_state - state_old) /
            (np.abs(current_state) + 1.e-4))

        extinguished = maxT < (
            np.max([flamelet.oxy_stream.T, flamelet.fuel_stream.T]) + 10.)
        if (extinguished and
            (not extinguished_first)) and refine_before_extinction:
            extinguished_first = True
            extinguished = False

            hval -= dh
            dh *= 0.1
            diff_target *= 0.1
            current_state = state_old.copy()

            continue

        state_old = np.copy(current_state)
        dh *= np.min([np.max([np.sqrt(diff_target / diff_norm), 0.1]), 2.])
        hvalues.append(hval)
        solutions.append(dict())
        for p in g_library.props:
            solutions[-1][p] = g_library[p].ravel()

    z_dim = Dimension(_mixture_fraction_name, flamelet.mixfrac_grid)
    h_dim = Dimension(_enthalpy_defect_name + _stoich_suffix,
                      np.array(hvalues))
    steady_lib = Library(z_dim, h_dim)
    steady_lib.extra_attributes['mech_spec'] = flamelet_specs.mech_spec
    for p in table_dict[chi_st]:
        if p != 'adiabatic_state':
            steady_lib[p] = steady_lib.get_empty_dataset()
    for ig, sol in enumerate(solutions):
        for p in sol:
            steady_lib[p][:, ig] = sol[p].ravel()

    indices = [0]
    z = flamelet.mixfrac_grid
    z_st = flamelet.mechanism.stoich_mixture_fraction(flamelet.fuel_stream,
                                                      flamelet.oxy_stream)
    h_tz = sca.compute_specific_enthalpy(flamelet_specs.mech_spec,
                                         steady_lib)['enthalpy']
    h_ad = h_tz[:, 0]
    nz, nt = h_tz.shape
    last_hst = interp1d(z, h_ad)(z_st)
    for i in range(nt - 1):
        this_hst = interp1d(z, h_tz[:, i])(z_st)
        if last_hst - this_hst > h_stoich_spacing:
            indices.append(i)
            last_hst = this_hst

    for i in indices:
        defect = h_tz[:, i] - h_ad
        gst = float(interp1d(z, defect)(z_st))
        this_data = dict()
        this_data['enthalpy_defect'] = np.copy(defect)
        this_data['enthalpy_cons'] = np.copy(h_ad)
        this_data['enthalpy'] = np.copy(h_tz[:, i])
        this_data[_mixture_fraction_name] = flamelet.mixfrac_grid
        for q in steady_lib.props:
            this_data[q] = steady_lib[q][:, i]
        managed_dict[(chi_st, gst)] = this_data

    dcput = perf_counter() - cput0000

    if verbose:
        print('chi_st = {:8.1e} 1/s converged in {:6.2f} s'.format(
            chi_st, dcput),
              flush=True)
Exemple #6
0
def _expand_enthalpy_defect_dimension_transient(chi_st, managed_dict,
                                                flamelet_specs, table_dict,
                                                h_stoich_spacing, verbose,
                                                input_integration_args,
                                                solver_verbose):
    flamelet_specs.initial_condition = table_dict[chi_st]['adiabatic_state']
    flamelet_specs.stoich_dissipation_rate = chi_st
    flamelet_specs.heat_transfer = 'nonadiabatic'
    flamelet_specs.scale_heat_loss_by_temp_range = True
    flamelet_specs.scale_convection_by_dissipation = True
    flamelet_specs.use_linear_ref_temp_profile = True
    flamelet_specs.convection_coefficient = 1.e7
    flamelet_specs.radiative_emissivity = 0.

    integration_args = dict({
        'first_time_step': 1.e-9,
        'max_time_step': 1.e-1,
        'write_log': solver_verbose,
        'log_rate': 100
    })

    if input_integration_args is not None:
        integration_args.update(input_integration_args)

    if 'transient_tolerance' not in integration_args:
        integration_args['transient_tolerance'] = 1.e-8

    cput0000 = perf_counter()
    running = True
    while running and integration_args['transient_tolerance'] > 1.e-15:
        try:
            fnonad = Flamelet(flamelet_specs)
            transient_lib = fnonad.integrate_for_heat_loss(**integration_args)
            running = False
        except Exception as e:
            if solver_verbose:
                print(
                    f'Transient heat loss calculation failed with tolerance of {integration_args["transient_tolerance"]:.1e}, retrying with 100x lower...'
                )
            integration_args.update(
                dict({
                    'transient_tolerance':
                    integration_args['transient_tolerance'] * 1.e-2
                }))
    indices = [0]
    z = fnonad.mixfrac_grid
    z_st = fnonad.mechanism.stoich_mixture_fraction(fnonad.fuel_stream,
                                                    fnonad.oxy_stream)
    h_tz = sca.compute_specific_enthalpy(flamelet_specs.mech_spec,
                                         transient_lib)['enthalpy']
    h_ad = h_tz[0, :]
    nt, nz = h_tz.shape
    last_hst = interp1d(z, h_ad)(z_st)
    for i in range(nt):
        this_hst = interp1d(z, h_tz[i, :])(z_st)
        if last_hst - this_hst > h_stoich_spacing:
            indices.append(i)
            last_hst = this_hst
    if nt - 1 not in indices:
        indices.append(-1)

    for i in indices:
        defect = h_tz[i, :] - h_ad
        gst = float(interp1d(z, defect)(z_st))
        this_data = dict()
        this_data['enthalpy_defect'] = np.copy(defect)
        this_data['enthalpy_cons'] = np.copy(h_ad)
        this_data['enthalpy'] = np.copy(h_tz[i, :])
        this_data[_mixture_fraction_name] = fnonad.mixfrac_grid
        for q in transient_lib.props:
            this_data[q] = transient_lib[q][i, :]
        managed_dict[(chi_st, gst)] = this_data

    dcput = perf_counter() - cput0000

    if verbose:
        print('chi_st = {:8.1e} 1/s converged in {:6.2f} s'.format(
            chi_st, dcput),
              flush=True)
Exemple #7
0
def build_adiabatic_slfm_library(flamelet_specs,
                                 diss_rate_values=np.logspace(-3, 2, 16),
                                 diss_rate_ref='stoichiometric',
                                 verbose=True,
                                 solver_verbose=False,
                                 _return_intermediates=False,
                                 include_extinguished=False):
    """Build a flamelet library with an adiabatic strained laminar flamelet model

    Parameters
    ----------
    flamelet_specs : dictionary or FlameletSpec instance
        data for the mechanism, streams, mixture fraction grid, etc.
    diss_rate_values : np.array
        reference dissipation rate values in the table (note that if the flamelet extinguishes at any point,
        the extinguished flamelet and larger dissipation rates are not included in the library unless the
        include_extinguished argument is set to True)
    diss_rate_ref : str
        the reference point of the specified dissipation rate values, either 'stoichiometric' or 'maximum'
    verbose : bool
        whether or not to show progress of the library construction
    include_extinguished : bool
        whether or not to include extinguished states in the output table, if encountered in the provided range of
        dissipation rates, off by default

    Returns
    -------
    library : spitfire.chemistry.library.Library instance
        the structured chemistry library

    """

    if isinstance(flamelet_specs, dict):
        flamelet_specs = FlameletSpec(**flamelet_specs)

    m = flamelet_specs.mech_spec
    fuel = flamelet_specs.fuel_stream
    oxy = flamelet_specs.oxy_stream
    flamelet_specs.initial_condition = 'equilibrium'
    if diss_rate_ref == 'maximum':
        flamelet_specs.max_dissipation_rate = 0.
    else:
        flamelet_specs.stoich_dissipation_rate = 0.

    cput00 = _write_library_header('adiabatic SLFM', m, fuel, oxy, verbose)

    f = Flamelet(flamelet_specs)

    table_dict = dict()

    nchi = diss_rate_values.size
    suffix = _stoich_suffix if diss_rate_ref == 'stoichiometric' else '_max'

    x_values = list()
    for idx, chival in enumerate(diss_rate_values):
        if diss_rate_ref == 'maximum':
            flamelet_specs.max_dissipation_rate = chival
        else:
            flamelet_specs.stoich_dissipation_rate = chival

        flamelet = Flamelet(flamelet_specs)
        if verbose:
            print(f'{idx + 1:4}/{nchi:4} (chi{suffix} = {chival:8.1e} 1/s) ',
                  end='',
                  flush=True)
        cput0 = perf_counter()
        x_library = flamelet.compute_steady_state(tolerance=1.e-6,
                                                  verbose=solver_verbose,
                                                  use_psitc=True)
        dcput = perf_counter() - cput0

        if np.max(flamelet.current_temperature - flamelet.linear_temperature
                  ) < 10. and not include_extinguished:
            if verbose:
                print(
                    ' extinction detected, stopping. The extinguished state will not be included in the table.'
                )
            break
        else:
            if verbose:
                print(
                    f' converged in {dcput:6.2f} s, T_max = {np.max(flamelet.current_temperature):6.1f}'
                )

        z_st = flamelet.mechanism.stoich_mixture_fraction(
            flamelet.fuel_stream, flamelet.oxy_stream)
        chi_st = flamelet._compute_dissipation_rate(
            np.array([z_st]), flamelet._max_dissipation_rate,
            flamelet._dissipation_rate_form)[0]
        x_values.append(chi_st)

        table_dict[chi_st] = dict()
        for k in x_library.props:
            table_dict[chi_st][k] = x_library[k].ravel()
        flamelet_specs.initial_condition = flamelet.current_interior_state
        if _return_intermediates:
            table_dict[chi_st]['adiabatic_state'] = np.copy(
                flamelet.current_interior_state)

    if _return_intermediates:
        _write_library_footer(cput00, verbose)
        return table_dict, f.mixfrac_grid, np.array(x_values)
    else:
        z_dim = Dimension(_mixture_fraction_name, f.mixfrac_grid)
        x_dim = Dimension(_dissipation_rate_name + _stoich_suffix,
                          np.array(x_values))

        output_library = Library(z_dim, x_dim)
        output_library.extra_attributes['mech_spec'] = m

        for quantity in table_dict[chi_st]:
            output_library[quantity] = output_library.get_empty_dataset()
            for ix, x in enumerate(x_values):
                output_library[quantity][:, ix] = table_dict[x][quantity]

        _write_library_footer(cput00, verbose)
        return output_library
Exemple #8
0
def _build_nonadiabatic_defect_unstrained_library(initialization,
                                                  flamelet_specs,
                                                  n_defect_st=16,
                                                  verbose=True):
    flamelet_specs = FlameletSpec(**flamelet_specs) if isinstance(
        flamelet_specs, dict) else copy.copy(flamelet_specs)

    m = flamelet_specs.mech_spec
    fuel = flamelet_specs.fuel_stream
    oxy = flamelet_specs.oxy_stream

    z_st = m.stoich_mixture_fraction(fuel, oxy)

    flamelet_specs.initial_condition = initialization
    flamelet = Flamelet(flamelet_specs)

    # compute the extreme enthalpy defect
    state_ad = flamelet.initial_interior_state
    adiabatic_lib = flamelet.make_library_from_interior_state(state_ad)
    enthalpy_ad = sca.compute_specific_enthalpy(m, adiabatic_lib)['enthalpy']

    z_interior = flamelet.mixfrac_grid[1:-1]
    state_cooled_eq = state_ad.copy()
    state_cooled_eq[::m.
                    n_species] = z_interior * fuel.T + (1 - z_interior) * oxy.T
    cooled_lib = flamelet.make_library_from_interior_state(state_cooled_eq)
    enthalpy_cooled_eq = sca.compute_specific_enthalpy(m,
                                                       cooled_lib)['enthalpy']

    z = flamelet.mixfrac_grid
    h_ad_st = interp1d(z, enthalpy_ad)(z_st)
    h_ce_st = interp1d(z, enthalpy_cooled_eq)(z_st)
    defect_ext = h_ad_st - h_ce_st

    # build the library with equilibrium solutions at with enthalpies offset by the triangular defect form
    defect_range = np.linspace(-defect_ext, 0, n_defect_st)[::-1]
    z_dim = Dimension(_mixture_fraction_name, flamelet.mixfrac_grid)
    g_dim = Dimension(_enthalpy_defect_name + _stoich_suffix, defect_range)
    output_library = Library(z_dim, g_dim)
    output_library.extra_attributes['mech_spec'] = m

    for p in adiabatic_lib.props:
        output_library[p] = output_library.get_empty_dataset()
    output_library['enthalpy_defect'] = output_library.get_empty_dataset()
    output_library['enthalpy_cons'] = output_library.get_empty_dataset()
    output_library['enthalpy'] = output_library.get_empty_dataset()
    output_library[_mixture_fraction_name] = output_library.get_empty_dataset()

    fz = z.copy()
    fz[z <= z_st] = z[z <= z_st] / z_st
    fz[z > z_st] = (1 - z[z > z_st]) / (1 - z_st)

    ns = m.n_species
    g_library = flamelet.make_library_from_interior_state(
        flamelet.initial_interior_state)
    for ig in range(n_defect_st):
        defected_enthalpy = enthalpy_ad + defect_range[ig] * fz

        for iz in range(1, z.size - 1):
            y = np.zeros(ns)
            for ispec in range(ns):
                y[ispec] = g_library['mass fraction ' +
                                     m.species_names[ispec]][iz]
            m.gas.HPY = defected_enthalpy[iz], flamelet.pressure, y
            if initialization == 'equilibrium':
                m.gas.equilibrate('HP')
            g_library['temperature'][iz] = m.gas.T
            for ispec in range(ns):
                g_library['mass fraction ' +
                          m.species_names[ispec]][iz] = m.gas.Y[ispec]

        for p in g_library.props:
            if p != 'defected_enthapy':
                output_library[p][:, ig] = g_library[p].ravel()
        output_library['enthalpy_defect'][:,
                                          ig] = defected_enthalpy - enthalpy_ad
        output_library['enthalpy_cons'][:, ig] = enthalpy_ad
        output_library['enthalpy'][:, ig] = defected_enthalpy
        output_library[
            _mixture_fraction_name][:, ig] = flamelet.mixfrac_grid.ravel()

    return output_library
def update_figure(cpoint, ccoeff, npts):
    z, inv_dz = get_data(cpoint, ccoeff, npts)
    traces_dz = [
        dict(
            x=z,
            y=inv_dz,
            mode='lines+markers',
            opacity=0.7,
            line=dict(width=4, color='Black'),
            marker={
                'symbol': 'square',
                'size': 8,
                'color': 'RoyalBlue',
                'line': dict(width=1, color='Black')
            },
        )
    ]
    fs = dict(flamelet_specs)
    fs.update(
        dict({
            'grid_points': npts,
            'grid_cluster_intensity': ccoeff,
            'grid_cluster_point': cpoint,
            'initial_condition': 'equilibrium'
        }))
    f = Flamelet(**fs)
    T_eq = f.initial_temperature
    fs.update(dict({'initial_condition': 'Burke-Schumann'}))
    f = Flamelet(**fs)
    T_bs = f.initial_temperature
    traces_T = [
        dict(
            name='Equilibrium',
            x=z,
            y=T_eq,
            mode='lines+markers',
            opacity=0.7,
            line=dict(width=4, color='Black'),
            marker={
                'symbol': 'square',
                'size': 8,
                'color': 'RoyalBlue',
                'line': dict(width=1, color='Black')
            },
        ),
        dict(
            name='Burke-Schumann',
            x=z,
            y=T_bs,
            mode='lines+markers',
            opacity=0.7,
            line=dict(width=4, color='Black'),
            marker={
                'symbol': 'square',
                'size': 8,
                'color': 'Salmon',
                'line': dict(width=1, color='Black')
            },
        )
    ]

    return {
               'data': traces_dz,
               'layout': dict(
                   xaxis={'type': 'linear', 'title': 'mixture fraction', 'range': [0, 1]},
                   yaxis={'type': 'log', 'title': 'equivalent uniform grid points', 'range': [0, 4]},
                   margin={'l': 40, 'b': 40, 't': 10, 'r': 10},
                   legend={'x': 0, 'y': 1},
                   hovermode='closest',
                   transition={'duration': 1e-3},
               )
           }, \
           {
               'data': traces_T,
               'layout': dict(
                   xaxis={'type': 'linear', 'title': 'mixture fraction', 'range': [0, 1]},
                   yaxis={'type': 'linear', 'title': 'T (K)', 'range': [298, 3000]},
                   margin={'l': 40, 'b': 40, 't': 10, 'r': 10},
                   legend={'x': 0, 'y': 1},
                   hovermode='closest',
                   transition={'duration': 1e-3},
               )
           }
def get_data(cpoint, ccoeff, npts):
    z, dz = Flamelet._clustered_grid(npts, cpoint, ccoeff)
    dz = np.hstack([dz, 1. - z[-2]])
    return z, 1. / dz