Skip to content

Source term model for preferential diffusion - #28

Open
joshkellyjak wants to merge 18 commits into
su2code:developfrom
joshkellyjak:feature_new_pref_diffusion
Open

joshkellyjak wants to merge 18 commits into
su2code:developfrom
joshkellyjak:feature_new_pref_diffusion

Conversation

@joshkellyjak

Copy link
Copy Markdown

Proposed Changes

This PR adds the generator side of the SOURCE_TERM preferential-diffusion method: model B2 of Schepers & van Oijen, Combust. Flame 280 (2025) 114332. It produces the manifolds used by the companion SU2 work, and the existing BETA_CORRECTION path is unchanged. It also fixes several table-generation problems found while validating the method against an OpenFOAM/CHEM1D solution of a lean H2 slot burner. Two of those fixes change every 3-D FGM table, not only preferential-diffusion ones (see Behaviour changes).

Flamelet data (SOURCE_TERM only)

  • New settings: Config_FGM.SetPreferentialDiffusionMethod("BETA_CORRECTION" | "SOURCE_TERM") and SetPDMajorSpecies([...]).

  • For every controlling variable <cv> and major species <sp>, each flamelet now carries:

    • the Eq. (14) molecular coefficients D_<cv>_<sp>;
    • the Soret coefficients DT_<cv>;
    • the major-species mass fractions Y-<sp>;
    • the Eq. (16) closure source Res_<cv> of the non-major species, computed in conservative finite-volume form (ComputeScalarDivergenceSources).

    These are exactly the column names SU2 builds from CONTROLLING_VARIABLE_NAMES and PREFERENTIAL_DIFFUSION_MAJOR_SPECIES (CFluidFlamelet.cpp). If the progress variable is built from major species only, Res_<PV> is identically zero. That matches prefDYc_Res in the reference implementation.

  • SOURCE_TERM switches the mixture fraction to the elemental definition of Eq. (11), via SetMixtureFractionDefinition("BILGER" | "ELEMENTAL"). The two definitions are normalised to agree exactly on the mixing line, so inlet and initial values don't change. Code that used the Bilger offset as Z_st now calls GetStoichiometricMixtureFraction(), because under the elemental definition the offset is no longer Z_st.

  • SetSoretDiffusion(bool) is opt-in (off by default), so existing flamelet data don't change. Turn it on for SOURCE_TERM, because SU2 applies the DT_<cv> coefficients at runtime.

Table generation

  • The Res_<cv> columns are left out of the RBF smoothing pass.
  • Dead bands (SetSourceDeadBands, default 5e-3 at each end) switch the closure sources off at the unburnt and burnt ends of each level:
    • The band is measured between the level's reactant and equilibrium progress variable, not over the meshed extent. The meshed extent is padded below the reactant value, so a band measured from it would sit entirely inside the padding.
    • The conservation projection keeps the band's nodes at zero.
    • A state inside the band only reads exactly zero if every vertex of its triangle is also in the band. The band therefore needs to be wider than the node spacing at its edge.
  • Conservation projection of the closure sources, flamelet by flamelet (ClosureSourceConservation.py, EnforceClosureSourceConservation):
    • It replicates SU2's LookUp_XYZ and corrects the node values so that the source integrated along each flamelet's trajectory matches that flamelet's own integral.
    • If the table axes are not (PV, h | Z), it is skipped with a warning.
  • Hull-edge anchoring (applies to all FGM tables): before smoothing, reaction rates are set to exactly zero on both chemically frozen progress-variable edges of each level, and the equilibrium composition is written on the burnt edge. The smoother then fits those nodes exactly.
  • Fresh-edge smoothing (applies to all FGM tables): nodes in the padding below the reactant progress variable are also fitted exactly by the smoother, through a new _unsmoothedNodes hook. All their smoothing neighbours lie on the reacting side, so smoothing pulled the fresh edge towards the flame.
  • Refinement: adds applyRefinementWithinNormalized, and refineEquilibrium now also works on 3-D tables, with its margin measured per level.

Fixes found along the way (existing upstream behaviour)

  • FlameletConcatenator.SetLookUpVars never stored its list, so every requested look-up variable (Heat_Release, Density, …) was silently left out of the manifold.
  • BurnerFlameSolver._postProcessResults read the solution of a burner flamelet that hadn't converged. Near the lean limit this crashed the whole parallel generation.
  • The table generator's worker pool now uses fork where it is available. On macOS the default (spawn) re-runs a module-level driver script in every worker, and the pool never finishes meshing a level.
  • A SOURCE_TERM collection now raises an error when Res_<cv> columns are missing, as it already did for the flux columns, instead of tabulating zeros.

Behaviour changes for existing tables

  • 3-D tables that call refineEquilibrium (the methane tutorial, for example) will be meshed differently.
  • Frozen edges now carry exactly zero reaction rates.
  • 3-D FGM tables built with smoothing on no longer read too hot at the fresh edge. On the H2 case the fresh-gas temperature at a given enthalpy drops by 3.6 K. So a CFD inlet specified by temperature, which SU2 converts to enthalpy through the table, will now get a different enthalpy.

Related Work

  • Solver side: (Source term method for preferential diffusion SU2#2970)

  • Model: J. Schepers & J. A. van Oijen, Combust. Flame 280 (2025) 114332.

  • Open PR Boundary update with testcases #27 (new_fixed_strain) touches 7 of this PR's 9 files. A trial merge against its head (7566a6d, 15 Oct 2026) conflicts in FlameletSolvers.py, LUTGenerator_Base.py and LUTGenerators.py; the other four files merge cleanly. Where the two PRs interact:

    • setTableAxes makes the level axis configurable. This PR's projection checks the axes, so that case is covered.
    • The per-level envelope boundary (_createBoundaryPolylineForTableLevel) removes the unsupported part of each level. That is why the support taper from the original work was dropped here.
    • setSourceTermClamping zeroes small species sources near the reactant and product boundaries. It overlaps in purpose with this PR's hull-edge anchoring and dead bands.
    • __applyEquilibriumRefinement stays 2-D only there, which conflicts with the 3-D refinement here.

    Whichever PR merges second will need a careful rebase of LUTGenerators.py and LUTGenerator_Base.py, because the overlaps are in meaning as well as in text.

PR Checklist

  • I am submitting my contribution to the develop branch.
  • I have updated the list of python modules in required_packages.txt and environment.yml, if necessary.
  • I have properly commented my changes.
  • I used the pre-commit hook to prevent dirty commits and used pre-commit run --all to format old commits.
  • I have updated the documentation, if necessary.
  • I have added a test case that demonstrates my contribution, if necessary.

🤖 Generated with Claude Code

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants