When a good mesh gives the wrong answer: OpenFOAM vs code_saturne on the backward-facing step

Published by Ruggero Poletto on

How much can a mesh go wrong before a RANS solver stops converging? And when it does, does a gradient limiter really fix it, or does it just hide the problem? We ran about 95 simulations of the same 2D test case in OpenFOAM and code_saturne on cloudHPC to find out, with four levels of numerical stabilisation. The whole study cost less than 20 โ‚ฌ.

The test case

We used the backward-facing step of Driver & Seegmiller, as set up in the NASA Turbulence Modeling Resource: step height H, Re_H = 36,000, Spalartโ€“Allmaras model, steady solution. The quantity we track is the reattachment length x_r/H. The experiment gives 6.26 ยฑ 0.10. CFL3D, solving the same SA model on a very fine grid, gives 6.06.

Both codes ran the same meshes, converted from the same gmsh file, with the same boundary conditions and relaxation. We tested 18 meshes in four families:

SettingOpenFOAMcode_saturne
Algorithmsteady SIMPLE (incompressibleFluid)steady algorithm
TurbulenceSpalartโ€“Allmaras, y+ โ‰ˆ 1Spalartโ€“Allmaras, y+ โ‰ˆ 1
InletU = 1, ฮฝฬƒ = 3ฮฝU = 1, ฮฝฬƒ = 3ฮฝ
RelaxationU, ฮฝฬƒ 0.7 ยท p 0.3U, ฮฝฬƒ 0.7 ยท p 0.3
Pressure solverGAMGalgebraic multigrid
Max iterations20,0005,000โ€“20,000
  • Refinement: the NASA structured grid and two refinements (20k to 320k cells).
  • Distortion: the same grid with interior nodes randomly moved by up to 45ยฐ.
  • Hybrid: structured wall layers plus an unstructured quad or triangle core.
  • Hybrid variants: different size jumps between the last wall layer and the core, first-cell heights (y+ โ‰ˆ 1, 5, 30) and growth ratios (1.12, 1.2, 1.4).
Structured and distorted meshes near the step
Structured and distorted meshes near the step
Hybrid meshes near the step: note the row of transition cells between the wall layers and the core
Hybrid meshes near the step: note the row of transition cells between the wall layers and the core

Result 1: on good meshes the two codes agree

On the structured and distorted meshes both codes converged with plain second-order numerics and no limiters. Distortion up to 45ยฐ changed almost nothing.

MeshCellsx_r/H OpenFOAMx_r/H code_saturne
NASA grid (T3)20k6.046.01
T3, refined 2ร—80k6.035.99
T3, refined 4ร—319k6.055.98
Distorted 15ยฐ / 30ยฐ80k6.035.99
Distorted 45ยฐ80k5.975.99

Both codes sit within 2.5% of CFL3D (6.06) and 3โ€“6% below the experiment. That gap is the SA model, not the numerics: every code solving SA on a good mesh lands there.

Skin friction on the lower wall: the two codes overlap on the fine structured mesh
Skin friction on the lower wall: the two codes overlap on the fine structured mesh
Velocity profiles at x/H = 1, 4, 6 and 10 on the 4ร— refined grid
Velocity profiles at x/H = 1, 4, 6 and 10 on the 4ร— refined grid

The velocity profiles of the two codes are indistinguishable and follow CFL3D through the shear layer. Near the wall at x/H = 1 and 4 all three codes predict stronger reverse flow than measured: a known SA behaviour.

Result 2: hybrid meshes are where things break

The critical spot is the transition from the last wall layer to the unstructured core. Without limiters:

  • OpenFOAM diverged on 6 hybrid meshes. With a 40-layer boundary layer it diverged even when the size jump to the core was only about 3.7.
  • code_saturne diverged on the two triangle-core meshes and converged on 4 of the 6 hybrid variants.
  • Growth ratio 1.2 was the only hybrid variant on which both codes converged.
Hybrid meshWhat changesOpenFOAMcode_saturne
G1 quad / tricore up to 4โ€“5 H far from the stepdivergesno convergence / diverges
G1b quadcore capped at 0.3 H (jump โ‰ˆ 10)divergesconverges (5.97)
G1b trisame, triangle coredivergesdiverges
Jump โ‰ˆ 3.7core 0.1 H, 297k cellsdivergesconverges (5.97)
Jump โ‰ˆ 22core 0.6 Hdivergesconverges (5.91)
y+ โ‰ˆ 5first cell 3.5e-3stallsstalls
y+ โ‰ˆ 30wall functionsstalls (5.78)stalls (5.70)
Growth 1.228 layersconverges (5.97)converges (5.96)
Growth 1.417 layersstallsconverges (5.91)

The checkMesh aspect ratio does not explain the failures. The NASA grid reaches about 15,700 and converges; the hybrids stay around 1,500 and do not. Wall functions at y+ โ‰ˆ 30 shorten the bubble by 4โ€“5% on top of the convergence problem.

Result 3: limiters stop the divergence, not the problem

We reran the five failed cases (four in OpenFOAM, one in code_saturne) with four stabilisation levels. Each level changes one thing on top of L1, so the effect of each knob can be read on its own.

LevelOpenFOAMcode_saturneWhat it tests
L1cellLimited gradients, limited corrected 0.5, 1 non-orthogonal correctorslope test + cell gradient limitergradient limiting alone
L2L1 + bounded Gauss upwind on ฮฝฬƒ, limited 0.33, 2 correctorsL1 + upwind, no reconstruction on ฮฝฬƒfirst-order turbulence transport
L3L1 + limitedLinear 1 on ฮฝฬƒL1 + 50% SOLU / 50% upwind blend on ฮฝฬƒa bounded second-order alternative to L2
L4L1 + PCG/DIC pressure solver instead of GAMGL1 + Jacobi-preconditioned CG on pressurewhether the pressure solver drives the failure
SettingCases convergedx_r/H range
L10 of 5 (all stall, bounded)6.00โ€“6.05
L21 of 56.04โ€“6.48
Failed caseL1L2L3L4
OpenFOAM, hybrid quadstalls, 6.05stalls, 6.11stalls, 6.05stalls, 6.05
OpenFOAM, hybrid tristalls, 6.00stalls, 6.48stalls, 6.08stalls, 6.00
OpenFOAM, jump โ‰ˆ 3.7stalls, 6.00stalls, 6.04stalls, 6.00stalls, 6.00
OpenFOAM, jump โ‰ˆ 22stalls, 6.04converges, 6.28stalls, 6.09stalls, 6.04
code_saturne, hybrid tristalls, 6.04stalls, 6.37stalls, 6.20stalls like L1 (1,900 it, 6ร— slower)

Values are x_r/H. โ€œStallsโ€ means bounded but not converged after 20,000 iterations (OpenFOAM) or 5,000 (code_saturne). Good meshes give 5.91โ€“6.05.

What the two new levels tell us:

  • L4: the pressure solver is not the culprit. Swapping GAMG for a Krylov solver changed nothing: same stall, same x_r as L1 to the second decimal. We had suspected multigrid struggling with the high-aspect-ratio wall layers. That hypothesis is now ruled out, and the mesh transition is the remaining suspect.
  • L3: a bounded second-order scheme is no free lunch either. limitedLinear on ฮฝฬƒ did not converge anywhere, and its ฮฝฬƒ residual stalled about four orders of magnitude higher than with L1 (2e-4 to 9e-4 instead of 1e-8 to 1e-6). x_r drifted up by up to 1.5% in OpenFOAM and 3% in code_saturne: less than L2, in the same direction.
  • Rule of thumb: every step away from pure second-order transport of ฮฝฬƒ (L3, then L2) lengthens the bubble. On these meshes the limiter level is a numerical parameter you must verify, just like the grid.

L1 is the useful one. It removed every divergence, and although the residuals stalled, x_r stayed in the same band as the good meshes.

L2 is the trap. The upwind scheme on the turbulence variable lengthened the bubble by up to 8%. In the one case where it converged, it gave x_r/H = 6.28: almost exactly the experiment. That is not accuracy. It is a numerical error that happens to compensate the known shortfall of the SA model.

Result 4: a perfect mesh that gives the wrong answer

Our first mesh family was structured and perfectly orthogonal, and passed checkMesh with zero non-orthogonality. The coarsest level gave x_r/H = 6.06: a great result. Refining it made things worse at every level, down to 2.10 in OpenFOAM and 4.88 in code_saturne.

LevelCellsx_r/H OpenFOAMx_r/H code_saturne
Coarse18k6.065.94
Medium74k4.365.41
Fine296k2.104.88

The cause: the generator kept wall-type clustering along the step-lip height all the way downstream, where there is no wall but a free shear layer. Every refinement added more thin cells there and distorted the eddy viscosity.

Three lessons:

  1. Mesh-quality checks look at cell shapes, not at whether the cells suit the flow.
  2. One mesh level is never enough. Only the refinement study exposed the problem.
  3. Both codes were wrong in the same direction. Comparing solvers does not replace mesh verification.

Takeaways

  • Keep the transition from the wall layers to the core gradual, with a growth ratio of 1.2 or less.
  • Use gradient limiting (L1) as a safety net, and check that x_r does not move when you switch it on. If L1 stalls, fix the mesh: in our tests neither a different convection scheme (L2, L3) nor a different pressure solver (L4) did.
  • Avoid first-order upwind on the turbulence variable as a default. It converges more easily and moves the answer.
  • Separate verification from validation. Matching the experiment better with a cheaper scheme is not a better simulation.

All runs used hypercore machines on cloudHPC with 2 to 8 vCPU. A typical run cost between 0.04 and 0.30 โ‚ฌ.

Run it yourself on cloudHPC

Each case is a small 2D model, so it fits on the smallest machines:

  1. Pack the OpenFOAM case folder (or the code_saturne study folder) as a tar.gz and upload it to your cloudHPC storage.
  2. Launch it on a hypercore machine: 2 vCPU are enough up to about 100k cells, 8 vCPU for about 300k.
  3. Download the results archive and compute x_r from the zero crossing of the wall shear stress on the lower wall.

A full mesh study like this one (refinement, distortion and limiter checks) costs a few euros and runs in parallel in an afternoon.

References


CloudHPC is a HPC provider to run engineering simulations on the cloud. CloudHPC provides from 1 to 224 vCPUs for each process in several configuration of HPC infrastructure - both multi-thread and multi-core. Current software ranges includes several CAE, CFD, FEA, FEM software among which OpenFOAM, FDS, Blender and several others.

New users benefit of a FREE trial of 300 vCPU/Hours to be used on the platform in order to test the platform, all each features and verify if it is suitable for their needs


Categories: Code SaturneOpenFOAM