You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
LINELET segfaults, no LINELET regression tests #2877
Describe the bug
There are no regression tests for LINELET and there are reports about LINELET crashing with a segmentation fault for certain testcases. The crashes need to be confirmed preferably with an existing testcase using LINELET.
I'd like to look at this. Starting by enabling LINELET on some existing wall-bounded cases (s809, SST flat plate, laminar NACA0012) to try to reproduce a crash.
I had a look at this. No segfault so far, but LINELET does cause a clean divergence on one case and degrades convergence on another.
Three wall-bounded cases, 500 iterations, only LINEAR_SOLVER_PREC changed (all other settings identical):
Case
Default prec
LINELET
rans/s809/turb_S809 (unstructured)
−5.22
−1.14, with 226 non-physical points
rans/flatplate/turb_SST_flatplate (structured)
−7.15
−6.10
navierstokes/naca0012/lam_NACA0012 (structured)
−8.19
−8.66
So it helps slightly on laminar NACA0012, hurts on the SST flat plate, and is bad on s809.
Running s809 further, it diverges outright at iteration 1140:
Error in "void CSolver::SetResidual_RMS(const CGeometry*, const CConfig*)":
SU2 has diverged (Residual > 10^20 detected).
The same config without LINELET converges to −9.02 at 10k iterations.
One thing that might be relevant: with multigrid, the linelets become very short on coarse levels. SU2 reports:
lam_NACA0012: 23, 3, 4 points per line (avg) across MG levels
turb_SST_flatplate: 32, 13, 3 points per line (avg)
turb_S809: 32 points per line (avg)
Three or four points per line seems close to degenerate - I'd guess the linelet structure isn't being rebuilt meaningfully on the coarse grids.
I also confirmed there are currently no configs in TestCases that set LINEAR_SOLVER_PREC= LINELET - the only occurrence is a comment listing the available options in turbomachinery/Aachen_turbine/aachen_3D_MP_restart.cfg. So there's no existing coverage at all.
Happy to add regression tests for LINELET once there's a case that behaves sensibly with it - lam_NACA0012 is the only one of the three I'd currently trust. Also happy to test other cases if you know which ones the segfault reports came from.
Built from develop, serial (-Dwith-mpi=disabled), GCC 15.2.1, Fedora 42.
The coarse-grid behavior is particularly interesting. If the linelets are collapsing to only a few points on the coarser MG levels, that could definitely explain why the preconditioner behaves so differently across cases.
lam_NACA0012 seems like a good starting point for regression coverage given that it currently behaves sensibly with LINELET. I’ll report back if I find any other cases where LINELET gives stable convergence
The coarse-grid behavior is particularly interesting. If the linelets are collapsing to only a few points on the coarser MG levels, that could definitely explain why the preconditioner behaves so differently across cases.
lam_NACA0012 seems like a good starting point for regression coverage given that it currently behaves sensibly with LINELET. I’ll report back if I find any other cases where LINELET gives stable convergence
Thanks that'd be useful. I'll start putting together a LINELET regression case based on lam_NACA0012 in the meantime. If you turn up other cases where it's stable, especially anything without multigrid, that'd help narrow down whether the coarse-level linelets are actually the cause
I've opened #2899, which adds a LINELET regression case: laminar NACA0012, serial, the existing config plus LINEAR_SOLVER_PREC= LINELET, compared against the default ILU(0). It covers the missing-tests half of this issue only, not the segfault reports. It is also a multigrid case, so it doesn't address the no-multigrid question from earlier.
A correction to my earlier table: those numbers came from incremental builds that I no longer trust across a develop merge. On a clean build, lam_NACA0012 at 500 iterations gives:
Default (ILU(0))
LINELET
rms[Rho]
−8.276
−8.263
So LINELET does not help on this case, contrary to what I wrote before. It is essentially level. Run to −12, ILU(0) needs 5909 iterations and LINELET 6108. I'll re-take the turb_S809 and turb_SST_flatplate rows on a clean build before citing them again.
On the coarse levels: the config sets MGLEVEL= 3, but SU2 reduces it to 2 because level 3 has only 233 CVs (below MG_MIN_MESHSIZE=500), so three grids are used. The linelets average 23, 4 and 3 points per line on those three grids (I listed them as 23, 3, 4 earlier).
My build is serial only, so I can't check the possible MPI cause at the moment.
segmentation fault (address 0x8) in CSysMatrix::BuildLineletPreconditioner, called from CSysSolve::Solve
The same case with the default preconditioner runs on 4 ranks. This is why serial regression tests cannot see it.
Cause.CGeometry::GetLineletInfo uses linelets.empty() as its "already computed" flag. A rank that owns no solid-wall vertex (common with a few partitions) never gets a non-empty list, so:
BuildLineletPreconditioner only resizes LineletUpper/Vector/InvDiag when linelets is non-empty, but then loops over LineletUpper[iThread]. On such a rank that indexes an empty vector.
Even without the crash, GetLineletInfo recomputes on every preconditioner application on those ranks, including its two MPI_Allreduce calls. The other ranks do not call them, so the collectives do not match.
Fix I tested (about 10 lines): add bool computed to CLineletInfo, return on it in GetLineletInfo, and make BuildLineletPreconditioner always call GetLineletInfo and always resize the per-thread vectors. With it the same case runs on 2, 4 and 8 ranks; after 5 iterations the residuals on 4 ranks match the default preconditioner closely (rms[rho] -4.966 vs -4.968).
I have not opened a PR. Happy to do so, together with the regression test from #2899 run on 4 ranks, if that is useful.
Diff:
diff --git a/Common/include/geometry/CGeometry.hpp b/Common/include/geometry/CGeometry.hpp
index 9d3e574b43..a5ec356e1b 100644
--- a/Common/include/geometry/CGeometry.hpp+++ b/Common/include/geometry/CGeometry.hpp@@ -226,6 +226,8 @@ class CGeometry {
static passivedouble ALPHA_ISOTROPIC() { return 0.8; }
enum : unsigned long { MAX_LINELET_POINTS = 32 }; /*!< \brief Maximum points per linelet. */
+ bool computed = false; /*!< \brief Whether the structure was computed (ranks may have no linelets). */+
std::vector<std::vector<unsigned long>> linelets; /*!< \brief Point indices for each linelet. */
/*!< \brief Index of the linelet of each point ("linelets" transfered to points). */
diff --git a/Common/src/geometry/CGeometry.cpp b/Common/src/geometry/CGeometry.cpp
index 360da1aaaa..f6976bc99c 100644
--- a/Common/src/geometry/CGeometry.cpp+++ b/Common/src/geometry/CGeometry.cpp@@ -4339,7 +4339,8 @@ void CGeometry::ColorMGLevels(unsigned short nMGLevels, const CGeometry* const*
const CGeometry::CLineletInfo& CGeometry::GetLineletInfo(const CConfig* config) const {
auto& li = lineletInfo;
- if (!li.linelets.empty() || nPoint == 0) return li;+ if (li.computed || nPoint == 0) return li;+ li.computed = true;
li.lineletIdx.resize(nPoint, CLineletInfo::NO_LINELET);
diff --git a/Common/src/linear_algebra/CSysMatrix.cpp b/Common/src/linear_algebra/CSysMatrix.cpp
index 503e2ad489..03796fee76 100644
--- a/Common/src/linear_algebra/CSysMatrix.cpp+++ b/Common/src/linear_algebra/CSysMatrix.cpp@@ -1461,12 +1461,11 @@ void CSysMatrix<ScalarType>::BuildLineletPreconditioner(const CGeometry* geometr
const auto nThreads = omp_get_max_threads();
BEGIN_SU2_OMP_SAFE_GLOBAL_ACCESS {
- const auto& li = geometry->GetLineletInfo(config);- if (!li.linelets.empty()) {- LineletUpper.resize(nThreads);- LineletVector.resize(nThreads);- LineletInvDiag.resize(nThreads);- }+ /*--- All ranks must call this (it communicates), even those without linelets. ---*/+ geometry->GetLineletInfo(config);+ LineletUpper.resize(nThreads);+ LineletVector.resize(nThreads);+ LineletInvDiag.resize(nThreads);
}
END_SU2_OMP_SAFE_GLOBAL_ACCESS
Thanks @rois1995, that matches what I found. The same fix is already in #2899 (commit d4851e8, since Sep 27), together with lam_naca0012_linelet in parallel_regression.py on 4 ranks (2 ranks doesn't trigger it). One small difference: #2899 also drops the || nPoint == 0 early return in GetLineletInfo, since a rank with no points would otherwise skip the Allreduce/Allgather the other ranks call, and it guards the average-linelet-size print against a divide by zero when there are no linelets anywhere. A review on #2899 would be very welcome.
Activity
Syphonicc commentedon Aug 26, 2026
I'd like to look at this. Starting by enabling LINELET on some existing wall-bounded cases (s809, SST flat plate, laminar NACA0012) to try to reproduce a crash.
Syphonicc commentedon Aug 26, 2026
I had a look at this. No segfault so far, but LINELET does cause a clean divergence on one case and degrades convergence on another.
Three wall-bounded cases, 500 iterations, only
LINEAR_SOLVER_PRECchanged (all other settings identical):So it helps slightly on laminar NACA0012, hurts on the SST flat plate, and is bad on s809.
Running s809 further, it diverges outright at iteration 1140:
The same config without LINELET converges to −9.02 at 10k iterations.
One thing that might be relevant: with multigrid, the linelets become very short on coarse levels. SU2 reports:
Three or four points per line seems close to degenerate - I'd guess the linelet structure isn't being rebuilt meaningfully on the coarse grids.
I also confirmed there are currently no configs in
TestCasesthat setLINEAR_SOLVER_PREC= LINELET- the only occurrence is a comment listing the available options inturbomachinery/Aachen_turbine/aachen_3D_MP_restart.cfg. So there's no existing coverage at all.Happy to add regression tests for LINELET once there's a case that behaves sensibly with it -
lam_NACA0012is the only one of the three I'd currently trust. Also happy to test other cases if you know which ones the segfault reports came from.Built from
develop, serial (-Dwith-mpi=disabled), GCC 15.2.1, Fedora 42.SiddDart commentedon Aug 28, 2026
The coarse-grid behavior is particularly interesting. If the linelets are collapsing to only a few points on the coarser MG levels, that could definitely explain why the preconditioner behaves so differently across cases.
lam_NACA0012 seems like a good starting point for regression coverage given that it currently behaves sensibly with LINELET. I’ll report back if I find any other cases where LINELET gives stable convergence
Syphonicc commentedon Aug 28, 2026
Thanks that'd be useful. I'll start putting together a LINELET regression case based on lam_NACA0012 in the meantime. If you turn up other cases where it's stable, especially anything without multigrid, that'd help narrow down whether the coarse-level linelets are actually the cause
bigfooted commentedon Sep 9, 2026
This might be an MPI problem... to be continued...
Syphonicc commentedon Sep 16, 2026
I've opened #2899, which adds a LINELET regression case: laminar NACA0012, serial, the existing config plus
LINEAR_SOLVER_PREC= LINELET, compared against the default ILU(0). It covers the missing-tests half of this issue only, not the segfault reports. It is also a multigrid case, so it doesn't address the no-multigrid question from earlier.A correction to my earlier table: those numbers came from incremental builds that I no longer trust across a develop merge. On a clean build,
lam_NACA0012at 500 iterations gives:So LINELET does not help on this case, contrary to what I wrote before. It is essentially level. Run to −12, ILU(0) needs 5909 iterations and LINELET 6108. I'll re-take the
turb_S809andturb_SST_flatplaterows on a clean build before citing them again.On the coarse levels: the config sets
MGLEVEL= 3, but SU2 reduces it to 2 because level 3 has only 233 CVs (belowMG_MIN_MESHSIZE=500), so three grids are used. The linelets average 23, 4 and 3 points per line on those three grids (I listed them as 23, 3, 4 earlier).My build is serial only, so I can't check the possible MPI cause at the moment.
rois1995 commentedon Oct 1, 2026
I can reproduce a LINELET segfault, and I think it is the MPI problem suspected above.
Reproduction (current develop code, MPI build):
TestCases/navierstokes/naca0012/lam_NACA0012.cfg(hybrid mesh v1, 3 multigrid levels),ITER= 5, plusLINEAR_SOLVER_PREC= LINELET.CSysMatrix::BuildLineletPreconditioner, called fromCSysSolve::SolveThe same case with the default preconditioner runs on 4 ranks. This is why serial regression tests cannot see it.
Cause.
CGeometry::GetLineletInfouseslinelets.empty()as its "already computed" flag. A rank that owns no solid-wall vertex (common with a few partitions) never gets a non-empty list, so:BuildLineletPreconditioneronly resizesLineletUpper/Vector/InvDiagwhenlineletsis non-empty, but then loops overLineletUpper[iThread]. On such a rank that indexes an empty vector.GetLineletInforecomputes on every preconditioner application on those ranks, including its twoMPI_Allreducecalls. The other ranks do not call them, so the collectives do not match.Fix I tested (about 10 lines): add
bool computedtoCLineletInfo, return on it inGetLineletInfo, and makeBuildLineletPreconditioneralways callGetLineletInfoand always resize the per-thread vectors. With it the same case runs on 2, 4 and 8 ranks; after 5 iterations the residuals on 4 ranks match the default preconditioner closely (rms[rho] -4.966 vs -4.968).I have not opened a PR. Happy to do so, together with the regression test from #2899 run on 4 ranks, if that is useful.
Diff:
Syphonicc commentedon Oct 1, 2026
Thanks @rois1995, that matches what I found. The same fix is already in #2899 (commit d4851e8, since Sep 27), together with lam_naca0012_linelet in parallel_regression.py on 4 ranks (2 ranks doesn't trigger it). One small difference: #2899 also drops the || nPoint == 0 early return in GetLineletInfo, since a rank with no points would otherwise skip the Allreduce/Allgather the other ranks call, and it guards the average-linelet-size print against a divide by zero when there are no linelets anywhere. A review on #2899 would be very welcome.
rois1995 commentedon Oct 1, 2026
Sure, I'll look into that over the next few days!
Fix LINELET with mpi, add regression case for laminar NACA0012 (#2899)