Repository navigation
Fix the internal energy used by the under-relaxation factor - #2942
Conversation
The factor compares the old and new internal energy, computed as rho*E - 0.5*|rho*u|^2 without the division by rho (the code comment already refers to the static energy). For dimensional cases this value can be negative, and those points got a zero update: in the axisymmetric air nozzle 28 % of the points were frozen, and the case could not re-converge from a restart. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
Test casesBoth cases: axisymmetric air nozzle, dimensional, 2 MPI ranks, develop against this PR. Files and scripts: pr1 (see the README). Restart from a converged solution (SST). The start solution was converged with this PR. Develop does not stay converged: the density residual rises from -12 to -10.2 in 300 iterations, because the points with a "negative internal energy" are frozen. With this PR the residual stays at -12 and the run stops after 10 iterations. Start from rest (SA, CFL adaptation). Develop stays at a density residual of -2 for 20 000 iterations, with a wrong outlet pressure (5.1 bar). With this PR it reaches -11 in 11 647 iterations (outlet pressure 1.64 bar). |
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
|
@rois1995 if this PR is finished can you update the regression tests? looks like it's a small PR that can be merged soon. |
|
Pushed 3062a04822 to materialize Added an actual-solver AD regression checking relaxation factors and density derivatives for density- and energy-limited updates. The forward-AD unit suite passes, and the new under-relaxation regression passes in reverse AD with AddressSanitizer. Both previously failing direct-differentiation file comparisons now match the existing references with zero tolerance; no reference files were changed. The fix and test are also propagated through #2943, #2944 and #2945. Full CI will confirm the remaining configurations. |
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
There are some concerns regarding the EPS floor. I am not too worried about it and will approve the PR, just something to test later maybe and see if this is better or not: Why the floor blocks the update. Say the full update would push rho_new to or below 0. The density ratio |Δrho|/rho_old is then at least 1. With MAX_UPDATE_FLOW below 1, the density limit alone gives a factor of allowable/ratio, which is small but nonzero. Options, best first Linearize the energy change. This is what I'd do. With e = E − m²/(2ρ), the first-order change is: Δe ≈ ΔE − u·Δm + ½|u|²·Δρ It needs no division by rho_new and no floor, and it stays bounded. It's a small code change but a larger validation job. Code. It is a rewrite of the loop body in CEulerSolver::ComputeUnderRelaxationFactor, about 10 lines. Energy change. de is the Δe formula from before. Only rho is floored, and it is a divisor of the old state, so it can't be driven to EPS by the update. For small updates it matches the PR's formula to second order, so well-behaved cases barely move. Unit test. Extend under_relaxation_ad_tests.cpp. The expected factor and derivative change, and a new case should drive rho_new to 0 and assert that the factor is positive and equals the density-limited value. The AD/DD derivative checks need new analytic values, so recompute them. |
bigfooted
left a comment
There was a problem hiding this comment.
Looks good, see my comment. Maybe test later and see if it helps any cases to do a linearization.
|
@bigfooted, thanks for the comment! Should we test that now before merging? |
|
@rois1995 sure you can test now and see if it helps. if it is a very clear win you can add it now, if it is inconclusive we can merge this now. |
|
@bigfooted I tested the linearized version against this PR. Smooth cases: same result.
In these cases no point is frozen with this PR. On the nozzle from rest, the two histories are the same up to about iteration 5000. After that, only the slow end of the convergence differs. Hard start-ups: the linearized version is worse. Blunt body M6 from freestream, 6000 iterations (final log rms[Rho], iterations with non-physical points in brackets):
This PR: 2 converged, 6 stalled, 1 diverged. Linearized: 1 converged, 5 stalled, 3 diverged, and non-physical points in 8 of 9 runs. You were right about the freeze. With this PR, a point freezes only when the full update makes the density zero or negative. This happened only in these hard runs. At 1st order CFL 10 the run still converges, and the linearized version stalls there. The reason: the exact change of rho*e is the linear one minus |d(rho u) − u d(rho)|² / (2 rho_new). This term always lowers the internal energy. The linear estimate misses it, so large velocity updates can make the energy negative. The density limit does not catch this. The linearized version would also change 7 of the 13 serial regression cases that I ran by hand. So I would merge this PR as it is. |


Proposed Changes
The implicit compressible solver limits the update of each point with an under-relaxation factor. To decide how much to limit, it compares the internal energy before and after the update. This internal energy was computed wrongly: the kinetic energy was not divided by the density.
SU2/SU2_CFD/src/solvers/CEulerSolver.cpp
Lines 2555 to 2556 in a6b7496
In cases run with dimensional values the wrong internal energy can become negative. When it does, the point gets no update at all and stays frozen. In an air nozzle about a quarter of the points were frozen, so the case could not converge.
The fix is 5 lines: the kinetic energy is divided by the density, using the old and the new density.
Almost all compressible implicit regression cases converge a little differently, so most regression values change. They are updated from the CI.
This is the first of four PRs that replace #2941, to make the review easier. The other three build on this one:
Related Work
PR Checklist
pre-commit run --allto format old commits.🤖 Generated with Claude Code
https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6