Skip to content

Source term method for preferential diffusion - #2970

Open
joshkellyjak wants to merge 6 commits into
developfrom
feature_new_pref_diffusion
Open

joshkellyjak wants to merge 6 commits into
developfrom
feature_new_pref_diffusion

Conversation

@joshkellyjak

@joshkellyjak joshkellyjak commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Proposed Changes

Adds the resolved Eq. (14) preferential diffusion flux formulation (model B2 of
Schepers & van Oijen, C&F 280 (2025) 114332) to the flamelet scalar transport,
alongside the existing beta correction, and fixes two defects that leave the
current preferential diffusion model not merely inert but actively wrong.

Two fixes that affect develop today. CSpeciesFlameletVariable sizes
AuxVar and Grad_AuxVar to the four beta terms but never sets nAuxVar, so
SetAuxVar_Gradient_GG/LS loop zero times and every beta gradient stays zero.
The FGM model drives the diffusive flux of the controlling variables by
grad(beta) rather than by their own gradient (Bunschoten, Eqs. 2.8-2.10); the
solver reaches that from the generic scalar base class by adding
div(D grad(beta - phi)) to the ordinary div(D grad phi), which sums to
div(D grad beta). With the beta gradients zero that sum is zero, so the
controlling variables are left with no diffusion at all. Separately,
LEAST_SQUARES falls through the auxiliary gradient switch, with the same
consequence for anyone not on Green-Gauss.

New model. PREFERENTIAL_DIFFUSION_METHOD selects BETA_CORRECTION
(default, unchanged) or SOURCE_TERM. PREFERENTIAL_DIFFUSION_MAJOR_SPECIES
names the species carrying the resolved flux; the manifold variables
(Res_<cv>, Y-<sp>, D_<cv>_<sp>, DT_<cv>) are composed from the
configured controlling variable and species names rather than hard-coded, so one
set of strings describes the table on both sides. The Eq. (14) fluxes are a new
branch of CScalarFlux_Flamelet, driven by the CFD-resolved gradients of the
major species and of temperature — the point of tabulating a coefficient per
species instead of pre-contracting them against the one-dimensional flamelet
gradients. They are applied explicitly, with a stabilising self-diffusion added
to the Jacobian alone so the converged solution is untouched. The Eq. (16)
closure sources are gated on manifold validity only.

Also fixed. Soret coefficients are zeroed on viscous walls, where the
manifold carries no quench-layer data. A collective in the volume output ran
behind an iPoint == 0 test inside the per-point loop, so a rank owning no
points would have hung every other rank; it moves to a new per-write
COutput::PrepareVolumeData hook, where an empty partition contributes the
MIN/MAX identity elements instead of not participating. The cached preferential
diffusion source is cleared at off-manifold nodes, and the Newton
non-convergence message is rank-guarded.

Diagnostics. FLAME_QUALITY volume group (C+, chi_C, Da), hull-miss
deviations, FLAMELET_VERBOSE_MISSES, and per-location probe history files.

Validation

Laminar premixed H2 burner against an OpenFOAM FGM reference, on a manifold
whose progress variable is defined on the major species only.

  • Reproduces the reference: converged residuals agree to ~3 decimals across all
    four equations; Temperature and Density agree with the reference
    implementation to 5-6 significant figures.
  • Manifold misses drop from 592 to 1-2.
  • Stabiliser: converged answer unchanged (residuals agree to 5-7 significant
    figures at CFL 1); CFL ceiling moves from (1, 2) without it to (2, 3) with it;
    misses hold at 1-2 across that range, against 1 -> 7 -> 49 without.

A chemical-activity gate on the closure sources was removed:
fmax(0, .) clipping meant it only closed where the tabulated source was
negative, so it closed at 320 preheat-zone nodes (304-567 K) while staying open
across 21k gradient-free bulk nodes — the inverse of its stated purpose.

Caveats

  • The nAuxVar fix changes results for every existing BETA_CORRECTION
    user
    , including regression case 07, which runs the default method.
    Baselines will move. The fix is correct, but the new behaviour still needs
    validating on a manifold built for the beta formulation — on the
    SOURCE_TERM-oriented manifold used here, BETA_CORRECTION diverges.
  • Wall Soret zeroing is a modelling choice, not a bug fix. It changes wall
    heat flux by up to 1.2% and wall temperature by 0.4 K, decaying to nothing
    within 0.5 mm. Justified by manifold support, not impermeability: the wall
    face carries no Eq. (14) flux in any case, since only interior edges are
    visited. What it changes is the near-wall interior edges, through the
    coefficient averaging.
  • The CFL figures are case-specific — 100 iterations from a converged
    restart on this burner, with a coarse ladder (1, 2, 3). Treat ~1.5x as
    indicative, not a precise factor.
  • The three manifold-miss gates were inert in every test (<= 1e-5 K on two
    different manifolds and two different flux discretizations). Retained as
    insurance against a poorly matched table, but unexercised.

Related Work

This work was developed on a branch that predates the rewrite of the flamelet
scalar transport into CScalarFlux_Flamelet / EdgeFluxResidual, and the flux
assembly was ported onto that framework rather than carried over. The port is
validated by reproducing the pre-port implementation's residuals to the digit
with the stabiliser disabled.

PR Checklist

  • I am submitting my contribution to the develop branch.
  • My contribution generates no new compiler warnings (try with --warnlevel=3 when using meson).
  • My contribution is commented and consistent with SU2 style (https://su2code.github.io/docs_v7/Style-Guide/).
  • I used the pre-commit hook to prevent dirty commits and used pre-commit run --all to format old commits.
  • I have added a test case that demonstrates my contribution, if necessary.
  • I have updated appropriate documentation (Tutorials, Docs Page, config_template.cpp), if necessary.

joshkellyjak and others added 2 commits October 9, 2026 23:46
…te fixes

Adds the resolved Eq. (14) preferential diffusion flux formulation (model B2 of
Schepers & van Oijen, C&F 280 (2025) 114332) to the flamelet scalar transport,
alongside the existing beta correction, and fixes two defects that left the
existing model inert or wrong.

Model
- PREFERENTIAL_DIFFUSION_METHOD selects BETA_CORRECTION (default, unchanged) or
  SOURCE_TERM.
- PREFERENTIAL_DIFFUSION_MAJOR_SPECIES names the species carrying the resolved
  flux. The manifold variables (Res_<cv>, Y-<sp>, D_<cv>_<sp>, DT_<cv>) are
  composed from the configured controlling variable and species names.
- The Eq. (14) fluxes are a new branch of CScalarFlux_Flamelet, driven by the
  CFD-resolved gradients of the major species and of temperature. Explicit, with
  a stabilising self-diffusion added to the Jacobian alone so the converged
  solution is unchanged.
- The Eq. (16) closure sources are gated on manifold validity only.

Fixes
- nAuxVar was never set, so SetAuxVar_Gradient_* looped zero times and every beta
  gradient stayed zero. The beta term then evaluated grad(beta) - grad(phi) as
  -grad(phi), cancelling the ordinary diffusion of the controlling variables
  rather than correcting it.
- LEAST_SQUARES fell through the auxiliary gradient switch, with the same effect.
- Soret coefficients are zeroed on viscous walls, where the manifold carries no
  quench layer data.
- A collective in the volume output ran behind an "iPoint == 0" test inside the
  per point loop; a rank owning no points would have hung the others. Moved to a
  new per write COutput::PrepareVolumeData hook.
- The cached preferential diffusion source is cleared at off manifold nodes, and
  the Newton non convergence message is rank guarded.

Diagnostics
- FLAME_QUALITY volume group, hull miss deviations, FLAMELET_VERBOSE_MISSES, and
  per location probe history files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…le gradient

The stabilising diffusivity is a bound on the Eq. (14) flux recast as a self
diffusion, |J| <= D_stab |grad phi|, so it has to be divided by the controlling
variable's own gradient. Without that division D_stab sits at the raw coefficient
magnitude everywhere, which damps the update far more than the explicit flux
warrants: on the burner case every stabilised run plateaued near rms[h] = -2.45
whatever the CFL, so the higher ceiling bought no convergence. With the division
restored, CFL 2 reaches -2.530 against -2.528 at CFL 1, and the ceiling moves
from (1, 2) without the term to (2, 3) with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@joshkellyjak joshkellyjak self-assigned this Oct 9, 2026
coefficient D^T_{phi_k}. ---*/
if (source_term_active) {
pd_terms_per_cv = FlameletPDTermsPerCV(flamelet_config_options.n_pd_major_species);
pd_flux_coeff.resize(nPoint, flamelet_config_options.n_control_vars * pd_terms_per_cv) = su2double(0.0);
…spaces) (#2935)

## Proposed Changes

`SU2_PY/SU2/run/interface.py` builds the command as
`os.path.join(SU2_RUN, "SU2_CFD") + " config_CFD.cfg"` and runs it with
`shell=True`. The executable path is quoted only on Windows (`quote =
'"' if sys.platform == "win32" else ""`), so on Linux/macOS any SU2_PY
script (shape_optimization.py, parallel_computation.py, ...) fails if
`SU2_RUN` contains a space.

This PR moves the quoting into `build_command`: the first word of the
command is joined with `SU2_RUN` and quoted (`shlex.quote` on POSIX,
double quotes on Windows as before), the callers pass plain `"SU2_CFD
config_CFD.cfg"` strings. The quoted path is then inserted into the MPI
template as before (`mpirun -n %i %s`, `srun`, `SU2_MPI_COMMAND`). The
module-level `quote` variable is removed; it was not used outside
`interface.py`.

Reproduction on macOS, `SU2_RUN=".../su2 bin"`, `shape_opt_euler_py`
from serial_regression.py:

```
before:
Command = /.../su2 bin/SU2_CFD config_CFD.cfg
SU2 process returned error '127'
/bin/sh: /.../su2: No such file or directory

after:
Command = '/.../su2 bin/SU2_CFD' config_CFD.cfg
optimization runs to the end
```

With the change and `SU2_RUN` containing a space, `history_project.csv`
and the optimizer output of `shape_opt_euler_py` are identical to
develop with a `SU2_RUN` without spaces. The MPI path was checked with
`NUMBER_PART=2`: `mpirun -n 2 '/.../su2 bin/SU2_CFD' config_CFD.cfg`
runs with 2 ranks. The Windows branch produces the same string as
before.

## Related Work

None found. Separate from #2934 (also SU2_PY).

## PR Checklist

- [X] I am submitting my contribution to the develop branch.
- [X] My contribution generates no new compiler warnings (try with
--warnlevel=3 when using meson).
- [X] My contribution is commented and consistent with SU2 style
(https://su2code.github.io/docs_v7/Style-Guide/).
- [X] I used the pre-commit hook to prevent dirty commits and used
`pre-commit run --all` to format old commits.
- [X] I have added a test case that demonstrates my contribution, if
necessary. — Not necessary: the change only affects how the executable
path is quoted; `shape_opt_euler_py` passes unchanged, and the
reproduction above (SU2_RUN with a space) fails before and passes after.
- [X] I have updated appropriate documentation (Tutorials, Docs Page,
config_template.cpp), if necessary. — Not necessary: no user-facing
option changed.

Co-authored-by: Nijso <bigfootedrockmidget@hotmail.com>
@bigfooted

Copy link
Copy Markdown
Contributor

CScalarFlux_Flamelet::extraDiffusionTerms then evaluates grad(beta) - grad(phi) as -grad(phi), and res.flux_i -= D * projGrad adds back
+D*grad(phi) — cancelling the ordinary diffusion of the controlling variables
rather than correcting it

This is the correct behavior as described in Everts thesis, the ordinary diffusion should be cancelled, leaving only the beta correction term.
You could choose not to add the diffusion term in the first place.

@joshkellyjak

Copy link
Copy Markdown
Contributor Author

CScalarFlux_Flamelet::extraDiffusionTerms then evaluates grad(beta) - grad(phi) as -grad(phi), and res.flux_i -= D * projGrad adds back
+D*grad(phi) — cancelling the ordinary diffusion of the controlling variables
rather than correcting it

This is the correct behavior as described in Everts thesis, the ordinary diffusion should be cancelled, leaving only the beta correction term. You could choose not to add the diffusion term in the first place.

This description is wrong the beta correction side is unchanged from develop other than the nAuxVar fix

@bigfooted

bigfooted commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

OK, I checked what was really going on with the nAuxvar fix. This bug actually puts the cross-diffusion term of the gradient of beta to zero. On orthogonal meshes this nAuxvar contribution is zero.
So the preferential diffusion results on the testcases that we have in the regression tests are correct. I was a bit worried there... In any case it's a good fix.

@bigfooted

Copy link
Copy Markdown
Contributor

OK, so I checked the paper of Stijn. So it's an extension of Nithin's paper for mixture averaged diffusion (instead of constant Lewis per species) and he adds Soret diffusion. And Stijn uses only major species and then has some truncation source term.
Can you also make Soret optional, it is usually neglected - and negligible.

@joshkellyjak

Copy link
Copy Markdown
Contributor Author

OK, so I checked the paper of Stijn. So it's an extension of Nithin's paper for mixture averaged diffusion (instead of constant Lewis per species) and he adds Soret diffusion. And Stijn uses only major species and then has some truncation source term. Can you also make Soret optional, it is usually neglected - and negligible.

Yes, as the forthcoming PR to DataMiner will show, when you have a PV definition with non-major species you end up with some additional conservation term, relatively small to all other contributions but necessary for conservation

@bigfooted

bigfooted commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

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.

4 participants