def _extend_presumed_pdf_first_dim(lam_lib, pdf_spec, added_suffix, num_procs, verbose=False): turb_dims = [ Dimension(d.name + added_suffix, d.values) for d in lam_lib.dims ] if pdf_spec.pdf != 'delta': turb_dims.append( Dimension( pdf_spec.variance_name, pdf_spec.scaled_variance_values if pdf_spec.scaled_variance_values is not None else pdf_spec.variance_values)) turb_lib = Library(*turb_dims) for p in lam_lib.props: turb_lib[p] = turb_lib.get_empty_dataset() if pdf_spec.pdf == 'delta': turb_lib = Library(*turb_dims) for p in lam_lib.props: turb_lib[p] = lam_lib[p].copy() return turb_lib if verbose: cput0 = perf_counter() num_integrals = len(turb_lib.props) for d in turb_lib.dims: num_integrals *= d.npts print( f'{pdf_spec.variance_name}: computing {num_integrals} integrals... ', end='', flush=True) if num_procs == 1: for p in turb_lib.props: turb_lib[p] = _convolve_full_property(p, None, turb_lib, lam_lib, pdf_spec) else: pool = Pool(processes=num_procs) manager = Manager() managed_dict = manager.dict() pool.map( partial(_convolve_full_property, managed_dict=managed_dict, turb_lib=turb_lib, lam_lib=lam_lib, pdf_spec=pdf_spec), turb_lib.props) for p in managed_dict: turb_lib[p] = managed_dict[p] if verbose: cputf = perf_counter() dcput = cputf - cput0 avg = float(num_integrals) / dcput print( f'completed in {dcput:.1f} seconds, average = {int(avg)} integrals/s.' ) return turb_lib
def _build_nonadiabatic_defect_slfm_library(flamelet_specs, heat_loss_expansion='transient', diss_rate_values=np.logspace( -3, 2, 16), diss_rate_ref='stoichiometric', verbose=True, solver_verbose=False, h_stoich_spacing=10.e3, num_procs=1, integration_args=None, n_defect_st=32, extend_defect_dim=False): 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 cput00 = _write_library_header('nonadiabatic (defect) SLFM', m, fuel, oxy, verbose) ugt = _build_unstructured_nonadiabatic_defect_slfm_library( flamelet_specs, heat_loss_expansion, diss_rate_values, diss_rate_ref, verbose, solver_verbose, h_stoich_spacing, num_procs, integration_args) structured_defect_table, x_values, g_values = _interpolate_to_structured_defect_dimension( ugt, n_defect_st, verbose=verbose, extend=extend_defect_dim) key0 = list(structured_defect_table.keys())[0] z_values = structured_defect_table[key0][_mixture_fraction_name] z_dim = Dimension(_mixture_fraction_name, z_values) x_dim = Dimension(_dissipation_rate_name + _stoich_suffix, x_values) g_dim = Dimension(_enthalpy_defect_name + _stoich_suffix, g_values) output_library = Library(z_dim, x_dim, g_dim) output_library.extra_attributes['mech_spec'] = m for quantity in structured_defect_table[key0]: values = output_library.get_empty_dataset() for ix, x in enumerate(x_values): for ig, g in enumerate(g_values): values[:, ix, ig] = structured_defect_table[(x, g)][quantity] output_library[quantity] = values _write_library_footer(cput00, verbose) return output_library
def test(self): gas = ct.Solution('h2o2.yaml', transport_model='Multi') mech = ChemicalMechanismSpec.from_solution(gas) fs = FlameletSpec(mech_spec=mech, initial_condition='equilibrium', oxy_stream=mech.stream('TPX', (300, 1.e5, 'O2:1, N2:3.76')), fuel_stream=mech.stream('TPY', (300, 1.e5, 'H2:1')), grid_points=16) eq_lib1 = build_adiabatic_eq_library(fs, verbose=False) z_dim = Dimension(eq_lib1.mixture_fraction_name, eq_lib1.mixture_fraction_values) fuel_T_dim = Dimension('fuel_temperature', np.linspace(0.0, 1.0, 4)) air_T_dim = Dimension('air_temperature', np.linspace(0.0, 1.0, 3)) eq_lib2 = Library(z_dim, fuel_T_dim) eq_lib2T = Library(fuel_T_dim, z_dim) eq_lib3 = Library(z_dim, fuel_T_dim, air_T_dim) eq_lib3T1 = Library(fuel_T_dim, z_dim, air_T_dim) eq_lib3T2 = Library(fuel_T_dim, air_T_dim, z_dim) for p in eq_lib1.props: eq_lib2[p] = eq_lib2.get_empty_dataset() eq_lib2T[p] = eq_lib2T.get_empty_dataset() eq_lib3[p] = eq_lib3.get_empty_dataset() eq_lib3T1[p] = eq_lib3T1.get_empty_dataset() eq_lib3T2[p] = eq_lib3T2.get_empty_dataset() for i, fuel_T_offset in enumerate(fuel_T_dim.values): fuel_T = 300 + fuel_T_offset * 500. fs2 = copy(fs) fs2.fuel_stream.TP = fuel_T, 1.e5 eq_tmp = build_adiabatic_eq_library(fs2, verbose=False) for p in eq_lib1.props: eq_lib2[p][:, i] = eq_tmp[p] eq_lib2T[p][i, :] = eq_tmp[p] for j, air_T_offset in enumerate(air_T_dim.values): air_T = 300 + air_T_offset * 500. fs3 = copy(fs2) fs3.oxy_stream.TP = air_T, 1.e5 eq_tmp = build_adiabatic_eq_library(fs3, verbose=False) for p in eq_lib1.props: eq_lib3[p][:, i, j] = eq_tmp[p] eq_lib3T1[p][i, :, j] = eq_tmp[p] eq_lib3T2[p][i, j, :] = eq_tmp[p] nonT_props = list(eq_lib1.props) nonT_props.remove('temperature') eq_lib1.remove(*nonT_props) eq_lib2.remove(*nonT_props) eq_lib2T.remove(*nonT_props) eq_lib3.remove(*nonT_props) eq_lib3T1.remove(*nonT_props) eq_lib3T2.remove(*nonT_props) z_svv = np.linspace(0., 1., 6) Tf_svv = np.linspace(0., 1., 5) eq_lib1_t = apply_presumed_PDF_model(eq_lib1, 'ClipGauss', z_svv, verbose=False) eq_lib2_t = apply_presumed_PDF_model(eq_lib2, 'ClipGauss', z_svv, verbose=False) eq_lib3_t = apply_presumed_PDF_model(eq_lib3, 'ClipGauss', z_svv, num_procs=1, verbose=False) eq_lib2T_t = apply_presumed_PDF_model(eq_lib2T, 'ClipGauss', z_svv, verbose=False) eq_lib3T1_t = apply_presumed_PDF_model(eq_lib3T1, 'ClipGauss', z_svv, num_procs=1, verbose=False) eq_lib3T2_t = apply_presumed_PDF_model(eq_lib3T2, 'ClipGauss', z_svv, num_procs=1, verbose=False) eq_lib2_tt = apply_presumed_PDF_model(eq_lib2_t, 'Beta', Tf_svv, 'fuel_temperature_mean', '', 'Tfvar', num_procs=1, verbose=False) eq_lib3_tt = apply_presumed_PDF_model(eq_lib3_t, 'Beta', Tf_svv, 'fuel_temperature_mean', '', 'Tfvar', num_procs=1, verbose=False) def get_dim_names(lib): return [d.name for d in lib.dims] self.assertEqual(['mixture_fraction'], get_dim_names(eq_lib1)) self.assertEqual(['mixture_fraction_mean', 'scaled_scalar_variance_mean'], get_dim_names(eq_lib1_t)) self.assertEqual(['mixture_fraction', 'fuel_temperature'], get_dim_names(eq_lib2)) self.assertEqual(['mixture_fraction_mean', 'fuel_temperature_mean', 'scaled_scalar_variance_mean'], get_dim_names(eq_lib2_t)) self.assertEqual( ['mixture_fraction_mean', 'fuel_temperature_mean', 'scaled_scalar_variance_mean', 'Tfvar'], get_dim_names(eq_lib2_tt)) self.assertEqual(['mixture_fraction', 'fuel_temperature', 'air_temperature'], get_dim_names(eq_lib3)) self.assertEqual(['mixture_fraction_mean', 'fuel_temperature_mean', 'air_temperature_mean', 'scaled_scalar_variance_mean'], get_dim_names(eq_lib3_t)) self.assertEqual(['mixture_fraction_mean', 'fuel_temperature_mean', 'air_temperature_mean', 'scaled_scalar_variance_mean', 'Tfvar'], get_dim_names(eq_lib3_tt)) self.assertEqual(['fuel_temperature', 'mixture_fraction'], get_dim_names(eq_lib2T)) self.assertEqual(['fuel_temperature_mean', 'mixture_fraction_mean', 'scaled_scalar_variance_mean'], get_dim_names(eq_lib2T_t), eq_lib2T_t) self.assertEqual(['fuel_temperature', 'mixture_fraction', 'air_temperature'], get_dim_names(eq_lib3T1)) self.assertEqual(['fuel_temperature', 'air_temperature', 'mixture_fraction'], get_dim_names(eq_lib3T2)) self.assertEqual(['fuel_temperature_mean', 'mixture_fraction_mean', 'air_temperature_mean', 'scaled_scalar_variance_mean'], get_dim_names(eq_lib3T1_t)) self.assertEqual(['fuel_temperature_mean', 'air_temperature_mean', 'mixture_fraction_mean', 'scaled_scalar_variance_mean'], get_dim_names(eq_lib3T2_t)) self.assertFalse(np.any(np.isnan(eq_lib1['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib1_t['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib2['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib2T['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib2_t['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib2T_t['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib3['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib3T1['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib3T2['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib3_t['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib3_tt['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib3T1_t['temperature']))) self.assertFalse(np.any(np.isnan(eq_lib3T2_t['temperature']))) self.assertIsNone(assert_allclose(eq_lib2T['temperature'].T, eq_lib2['temperature'])) self.assertIsNone(assert_allclose(np.swapaxes(eq_lib3T1['temperature'], 0, 1), eq_lib3['temperature'])) self.assertIsNone(assert_allclose(np.swapaxes(np.swapaxes(eq_lib3T2['temperature'], 1, 2), 0, 1), eq_lib3['temperature'])) self.assertIsNone(assert_allclose(np.squeeze(eq_lib1_t['temperature'][:, 0]), eq_lib1['temperature'])) self.assertIsNone(assert_allclose(np.squeeze(eq_lib2_t['temperature'][:, :, 0]), eq_lib2['temperature'])) self.assertIsNone(assert_allclose(np.squeeze(eq_lib3_t['temperature'][:, :, :, 0]), eq_lib3['temperature'])) self.assertIsNone(assert_allclose(np.squeeze(eq_lib3_tt['temperature'][:, :, :, 0, 0]), eq_lib3['temperature']))
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)
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
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