From d89a5f86d078602c7dd70da65ced45b91ec5a9f5 Mon Sep 17 00:00:00 2001 From: bigfooted Date: Sun, 27 Sep 2026 14:22:01 +0200 Subject: [PATCH 1/4] BCGSTAB: return the iterate with the smallest residual BCGSTAB does not reduce the residual monotonically. With a small iteration limit (e.g. LINEAR_SOLVER_ITER= 3) the last iterate can have a larger residual than the initial guess, and returning it gives a bad update. On the RAE2822 SA case with multigrid at CFL 200-1500 this caused erratic divergence; keeping the best iterate makes every CFL converge. Co-Authored-By: Claude Opus 5.5 --- Common/include/linear_algebra/CSysSolve.hpp | 1 + Common/src/linear_algebra/CSysSolve.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/Common/include/linear_algebra/CSysSolve.hpp b/Common/include/linear_algebra/CSysSolve.hpp index 1f9bc851b92e..4d5aea756dd5 100644 --- a/Common/include/linear_algebra/CSysSolve.hpp +++ b/Common/include/linear_algebra/CSysSolve.hpp @@ -111,6 +111,7 @@ class CSysSolve { mutable VectorType r_0; /*!< \brief The "arbitrary" vector in BCGSTAB. */ mutable VectorType v; /*!< \brief BCGSTAB "v" vector (v = A * M^-1 * p). */ + mutable VectorType x_best; /*!< \brief BCGSTAB iterate with the smallest residual. */ mutable bool ritz_failed = false; mutable unsigned long k = 0, k_new = 0; diff --git a/Common/src/linear_algebra/CSysSolve.cpp b/Common/src/linear_algebra/CSysSolve.cpp index 8ec1b19b23b3..b480dcacdd95 100644 --- a/Common/src/linear_algebra/CSysSolve.cpp +++ b/Common/src/linear_algebra/CSysSolve.cpp @@ -1087,6 +1087,7 @@ unsigned long CSysSolve::BCGSTAB_LinSolver(const CSysVector::BCGSTAB_LinSolver(const CSysVector::BCGSTAB_LinSolver(const CSysVector::BCGSTAB_LinSolver(const CSysVectorGetComm_Level() == COMM_FULL) && (norm_r > norm_best)) { + x = x_best; + norm_r = norm_best; + } + /*--- Recalculate final residual (this should be optional) ---*/ if ((monitoring) && (config->GetComm_Level() == COMM_FULL)) { From e08ba03788791c07b9afea6f8b8aed4e6dff279c Mon Sep 17 00:00:00 2001 From: bigfooted Date: Sun, 27 Sep 2026 17:02:34 +0200 Subject: [PATCH 2/4] clang --- Common/include/linear_algebra/CSysSolve.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/include/linear_algebra/CSysSolve.hpp b/Common/include/linear_algebra/CSysSolve.hpp index 4d5aea756dd5..98ab059804ce 100644 --- a/Common/include/linear_algebra/CSysSolve.hpp +++ b/Common/include/linear_algebra/CSysSolve.hpp @@ -109,8 +109,8 @@ class CSysSolve { mutable VectorType p; /*!< \brief Direction in CG and BCGSTAB. */ mutable VectorType z; /*!< \brief Preconditioned residual/direction in CG/BCGSTAB. */ - mutable VectorType r_0; /*!< \brief The "arbitrary" vector in BCGSTAB. */ - mutable VectorType v; /*!< \brief BCGSTAB "v" vector (v = A * M^-1 * p). */ + mutable VectorType r_0; /*!< \brief The "arbitrary" vector in BCGSTAB. */ + mutable VectorType v; /*!< \brief BCGSTAB "v" vector (v = A * M^-1 * p). */ mutable VectorType x_best; /*!< \brief BCGSTAB iterate with the smallest residual. */ mutable bool ritz_failed = false; From c81e8ffb951ec41785d483dd5837fd86e213e06f Mon Sep 17 00:00:00 2001 From: bigfooted Date: Mon, 12 Oct 2026 09:12:18 +0200 Subject: [PATCH 3/4] guard initialization --- Common/src/linear_algebra/CSysSolve.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/src/linear_algebra/CSysSolve.cpp b/Common/src/linear_algebra/CSysSolve.cpp index b480dcacdd95..c1a356dfbcce 100644 --- a/Common/src/linear_algebra/CSysSolve.cpp +++ b/Common/src/linear_algebra/CSysSolve.cpp @@ -1087,7 +1087,7 @@ unsigned long CSysSolve::BCGSTAB_LinSolver(const CSysVectorGetComm_Level() == COMM_FULL) x_best.Initialize(nBlk, nBlkDomain, nVar, nullptr); bcg_ready = true; } @@ -1137,7 +1137,7 @@ unsigned long CSysSolve::BCGSTAB_LinSolver(const CSysVectorGetComm_Level() == COMM_FULL) x_best = x; p = ScalarType(0.0); v = ScalarType(0.0); r_0 = r; From d2201a852be47a689ee08a8535179d35c7bcd7c2 Mon Sep 17 00:00:00 2001 From: bigfooted Date: Tue, 13 Oct 2026 09:17:57 +0200 Subject: [PATCH 4/4] update regressions --- TestCases/hybrid_regression.py | 6 +++--- TestCases/parallel_regression.py | 16 ++++++++-------- TestCases/serial_regression.py | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/TestCases/hybrid_regression.py b/TestCases/hybrid_regression.py index f63748ba9283..a2d58a89a5cc 100644 --- a/TestCases/hybrid_regression.py +++ b/TestCases/hybrid_regression.py @@ -80,7 +80,7 @@ def main(): wedge.cfg_dir = "euler/wedge" wedge.cfg_file = "inv_wedge_HLLC.cfg" wedge.test_iter = 20 - wedge.test_vals = [-0.480786, 5.329367, -0.244869, 0.043126] + wedge.test_vals = [ 0.036140, 6.976887, -0.219795, 0.055341] test_list.append(wedge) # ONERA M6 Wing @@ -170,7 +170,7 @@ def main(): rae2822_sa.cfg_dir = "rans/rae2822" rae2822_sa.cfg_file = "turb_SA_RAE2822.cfg" rae2822_sa.test_iter = 20 - rae2822_sa.test_vals = [-2.639525, -4.027096, 0.792680, 0.020549, 1000.000000] + rae2822_sa.test_vals = [-2.913915, -5.160924, 0.801922, 0.019587, 1000.000000] test_list.append(rae2822_sa) # RAE2822 SST @@ -452,7 +452,7 @@ def main(): inc_turb_naca0012.cfg_dir = "incomp_rans/naca0012" inc_turb_naca0012.cfg_file = "naca0012.cfg" inc_turb_naca0012.test_iter = 20 - inc_turb_naca0012.test_vals = [-4.758114, -10.974548, -0.000004, -0.028637, 5.000000, -4.081478, 2.000000, -4.490126] + inc_turb_naca0012.test_vals = [-4.758114, -10.974548, -0.000006, -0.028637, 4.000000, -4.016988, 2.000000, -4.487046] test_list.append(inc_turb_naca0012) # NACA0012, SST_SUST diff --git a/TestCases/parallel_regression.py b/TestCases/parallel_regression.py index e79219efbeba..0c94bf9109ef 100755 --- a/TestCases/parallel_regression.py +++ b/TestCases/parallel_regression.py @@ -156,7 +156,7 @@ def main(): invwedge_roe.cfg_dir = "nonequilibrium/invwedge" invwedge_roe.cfg_file = "invwedge_roe.cfg" invwedge_roe.test_iter = 10 - invwedge_roe.test_vals = [-1.158437, -1.683200, -17.734417, -18.064156, -18.007526, 2.157771, 1.789407, 5.196450, 0.767270] + invwedge_roe.test_vals = [-0.856717, -1.381479, -16.733080, -17.063919, -17.006196, 2.492274, 1.625077, 5.504576, 1.052309] invwedge_roe.test_vals_aarch64 = [-1.156325, -1.681088, -17.726749, -18.056513, -17.999860, 2.159488, 1.793498, 5.198638, 0.769831] test_list.append(invwedge_roe) @@ -430,7 +430,7 @@ def main(): rae2822_sa.cfg_dir = "rans/rae2822" rae2822_sa.cfg_file = "turb_SA_RAE2822.cfg" rae2822_sa.test_iter = 20 - rae2822_sa.test_vals = [-2.888183, -5.136146, 0.788144, 0.019032, 1000.000000] + rae2822_sa.test_vals = [-3.032297, -5.144001, 0.789972, 0.019664, 1000.000000] test_list.append(rae2822_sa) # RAE2822 SST @@ -891,7 +891,7 @@ def main(): turbmod_sa_bsl_rae2822.cfg_dir = "turbulence_models/sa/rae2822" turbmod_sa_bsl_rae2822.cfg_file = "turb_SA_BSL_RAE2822.cfg" turbmod_sa_bsl_rae2822.test_iter = 20 - turbmod_sa_bsl_rae2822.test_vals = [-3.182935, -0.447793, -0.875861, -3.286652, 0.769925, 0.017709] + turbmod_sa_bsl_rae2822.test_vals = [-3.066175, -0.410328, -0.836186, -5.131450, 0.790218, 0.018113] test_list.append(turbmod_sa_bsl_rae2822) # SA Negative @@ -899,7 +899,7 @@ def main(): turbmod_sa_neg_rae2822.cfg_dir = "turbulence_models/sa/rae2822" turbmod_sa_neg_rae2822.cfg_file = "turb_SA_NEG_RAE2822.cfg" turbmod_sa_neg_rae2822.test_iter = 10 - turbmod_sa_neg_rae2822.test_vals = [1.570952, 1.355242, -0.869320, 1.244343, 0.452923, 0.000000] + turbmod_sa_neg_rae2822.test_vals = [1.462498, 1.294317, -1.866969, 1.240402, 0.461990, 0.000000] turbmod_sa_neg_rae2822.test_vals_aarch64 = [-1.345593, 1.448310, 1.208721, -0.846597, 1.248410, 0.489117, 0.000000] test_list.append(turbmod_sa_neg_rae2822) @@ -908,7 +908,7 @@ def main(): turbmod_sa_comp_rae2822.cfg_dir = "turbulence_models/sa/rae2822" turbmod_sa_comp_rae2822.cfg_file = "turb_SA_COMP_RAE2822.cfg" turbmod_sa_comp_rae2822.test_iter = 20 - turbmod_sa_comp_rae2822.test_vals = [-3.192776, -0.471890, -0.893254, -5.190537, 0.777261, 0.017904] + turbmod_sa_comp_rae2822.test_vals = [-3.067270, -0.409333, -0.836419, -5.163006, 0.790775, 0.018091] test_list.append(turbmod_sa_comp_rae2822) # SA Edwards @@ -916,7 +916,7 @@ def main(): turbmod_sa_edw_rae2822.cfg_dir = "turbulence_models/sa/rae2822" turbmod_sa_edw_rae2822.cfg_file = "turb_SA_EDW_RAE2822.cfg" turbmod_sa_edw_rae2822.test_iter = 20 - turbmod_sa_edw_rae2822.test_vals = [-3.198033, -0.439446, -0.883563, -3.899428, 0.786167, 0.017883] + turbmod_sa_edw_rae2822.test_vals = [-3.074021, -0.406573, -0.837105, -5.186866, 0.794308, 0.017860] test_list.append(turbmod_sa_edw_rae2822) # SA Compressibility and Edwards @@ -924,7 +924,7 @@ def main(): turbmod_sa_comp_edw_rae2822.cfg_dir = "turbulence_models/sa/rae2822" turbmod_sa_comp_edw_rae2822.cfg_file = "turb_SA_COMP_EDW_RAE2822.cfg" turbmod_sa_comp_edw_rae2822.test_iter = 20 - turbmod_sa_comp_edw_rae2822.test_vals = [-2.943295, -0.168387, -0.632480, -5.127730, 0.802507, 0.020196] + turbmod_sa_comp_edw_rae2822.test_vals = [-3.070896, -0.339529, -0.812604, -5.279982, 0.809740, 0.019809] test_list.append(turbmod_sa_comp_edw_rae2822) # SA QCR @@ -932,7 +932,7 @@ def main(): turbmod_sa_qcr_rae2822.cfg_dir = "turbulence_models/sa/rae2822" turbmod_sa_qcr_rae2822.cfg_file = "turb_SA_QCR_RAE2822.cfg" turbmod_sa_qcr_rae2822.test_iter = 20 - turbmod_sa_qcr_rae2822.test_vals = [-3.056565, -0.419621, -0.805532, -3.857890, 0.760796, 0.016908] + turbmod_sa_qcr_rae2822.test_vals = [-3.030070, -0.419207, -0.799348, -5.089007, 0.761556, 0.016831] test_list.append(turbmod_sa_qcr_rae2822) ############################ diff --git a/TestCases/serial_regression.py b/TestCases/serial_regression.py index e1a826cbf170..228dbeff7f4f 100755 --- a/TestCases/serial_regression.py +++ b/TestCases/serial_regression.py @@ -228,7 +228,7 @@ def main(): rae2822_sa.cfg_dir = "rans/rae2822" rae2822_sa.cfg_file = "turb_SA_RAE2822.cfg" rae2822_sa.test_iter = 20 - rae2822_sa.test_vals = [-3.131221, -5.161756, 0.778275, 0.019566, 1000.000000] + rae2822_sa.test_vals = [-3.119066, -5.151318, 0.777084, 0.019422, 1000.000000] test_list.append(rae2822_sa) # RAE2822 SST @@ -500,7 +500,7 @@ def main(): inc_turb_naca0012.cfg_dir = "incomp_rans/naca0012" inc_turb_naca0012.cfg_file = "naca0012.cfg" inc_turb_naca0012.test_iter = 20 - inc_turb_naca0012.test_vals = [-4.758064, -10.974498, -0.000003, -0.028654, 4, -6.049653, 2, -4.951206] + inc_turb_naca0012.test_vals = [-4.758064, -10.974498, -0.000003, -0.028654, 3.000000, -4.499423, 2.000000, -4.951202] test_list.append(inc_turb_naca0012) # NACA0012, SST_SUST