Skip to content

Commit 74e33b0

Browse files
authored
Merge pull request #2668 from su2code/pedro/more_inner_solvers
Add smoother to the options for nested preconditioning
2 parents 8fc25db + 1a781ea commit 74e33b0

File tree

5 files changed

+78
-41
lines changed

5 files changed

+78
-41
lines changed

Common/include/linear_algebra/CSysSolve.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,12 @@ class CSysSolve {
295295
ScalarType& residual, bool monitoring, const CConfig* config,
296296
FgcrodrMode mode) const;
297297

298+
/*!
299+
* \brief Creates the inner solver for nested preconditioning if the settings allow it.
300+
* \returns True if the inner solver can be used.
301+
*/
302+
bool SetupInnerSolver(unsigned short kind_solver, const CConfig* config);
303+
298304
public:
299305
/*!
300306
* \brief default constructor of the class.

Common/include/option_structure.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,10 +2389,12 @@ static const MapType<std::string, ENUM_LINEAR_SOLVER> Linear_Solver_Map = {
23892389
enum class LINEAR_SOLVER_INNER {
23902390
NONE, /*!< \brief Do not use a nested linear solver. */
23912391
BCGSTAB, /*!< \brief Use BCGSTAB as the preconditioning linear solver. */
2392+
SMOOTHER, /*!< \brief Iterative smoother. */
23922393
};
23932394
static const MapType<std::string, LINEAR_SOLVER_INNER> Inner_Linear_Solver_Map = {
23942395
MakePair("NONE", LINEAR_SOLVER_INNER::NONE)
23952396
MakePair("BCGSTAB", LINEAR_SOLVER_INNER::BCGSTAB)
2397+
MakePair("SMOOTHER", LINEAR_SOLVER_INNER::SMOOTHER)
23962398
};
23972399

23982400

Common/src/linear_algebra/CSysSolve.cpp

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ unsigned long CSysSolve<ScalarType>::CG_LinSolver(const CSysVector<ScalarType>&
312312
/*--- Only compute the residuals in full communication mode. ---*/
313313

314314
if (config->GetComm_Level() == COMM_FULL) {
315-
norm_r = r.norm();
316315
norm0 = b.norm();
316+
norm_r = xIsZero ? norm0 : r.norm();
317317

318318
/*--- Set the norm to the initial initial residual value ---*/
319319

@@ -1032,8 +1032,8 @@ unsigned long CSysSolve<ScalarType>::BCGSTAB_LinSolver(const CSysVector<ScalarTy
10321032
/*--- Only compute the residuals in full communication mode. ---*/
10331033

10341034
if (config->GetComm_Level() == COMM_FULL) {
1035-
norm_r = r.norm();
10361035
norm0 = b.norm();
1036+
norm_r = xIsZero ? norm0 : r.norm();
10371037

10381038
/*--- Set the norm to the initial initial residual value ---*/
10391039

@@ -1205,8 +1205,8 @@ unsigned long CSysSolve<ScalarType>::Smoother_LinSolver(const CSysVector<ScalarT
12051205
/*--- Only compute the residuals in full communication mode. ---*/
12061206

12071207
if (config->GetComm_Level() == COMM_FULL) {
1208-
norm_r = r.norm();
12091208
norm0 = b.norm();
1209+
norm_r = xIsZero ? norm0 : r.norm();
12101210

12111211
/*--- Set the norm to the initial initial residual value ---*/
12121212

@@ -1246,15 +1246,19 @@ unsigned long CSysSolve<ScalarType>::Smoother_LinSolver(const CSysVector<ScalarT
12461246
current residual, the system is linear so this saves some computation
12471247
compared to re-evaluating r = b-A*x. ---*/
12481248

1249-
mat_vec(z, A_x);
1249+
if (!fix_iter_mode || i != m - 1) {
1250+
mat_vec(z, A_x);
1251+
}
12501252

12511253
/*--- Update solution and residual with relaxation omega. Mathematically this
12521254
is a modified Richardson iteration for the left-preconditioned system
12531255
M^{-1}(b-A*x) which converges if ||I-w*M^{-1}*A|| < 1. Combining this method
12541256
with a Gauss-Seidel preconditioner and w>1 is NOT equivalent to SOR. ---*/
12551257

12561258
x += omega * z;
1257-
r -= omega * A_x;
1259+
if (!fix_iter_mode || i != m - 1) {
1260+
r -= omega * A_x;
1261+
}
12581262

12591263
/*--- Only compute the residuals in full communication mode. ---*/
12601264
/*--- Check if solution has converged, else output the relative residual if necessary. ---*/
@@ -1282,6 +1286,33 @@ unsigned long CSysSolve<ScalarType>::Smoother_LinSolver(const CSysVector<ScalarT
12821286
return i;
12831287
}
12841288

1289+
template <class ScalarType>
1290+
bool CSysSolve<ScalarType>::SetupInnerSolver(unsigned short kind_solver, const CConfig* config) {
1291+
bool flexible = false;
1292+
switch (kind_solver) {
1293+
case FGMRES:
1294+
case FGCRODR:
1295+
case RESTARTED_FGMRES:
1296+
case SMOOTHER:
1297+
flexible = true;
1298+
break;
1299+
default:
1300+
flexible = false;
1301+
}
1302+
const bool is_linear = config->GetKind_Linear_Solver_Inner() == LINEAR_SOLVER_INNER::SMOOTHER;
1303+
1304+
if (config->GetKind_Linear_Solver_Inner() != LINEAR_SOLVER_INNER::NONE && (flexible || is_linear)) {
1305+
BEGIN_SU2_OMP_SAFE_GLOBAL_ACCESS
1306+
if (!inner_solver) {
1307+
inner_solver = std::make_unique<CSysSolve<ScalarType>>(LINEAR_SOLVER_MODE::STANDARD);
1308+
inner_solver->SetxIsZero(true);
1309+
}
1310+
END_SU2_OMP_SAFE_GLOBAL_ACCESS
1311+
return true;
1312+
}
1313+
return false;
1314+
}
1315+
12851316
template <class ScalarType>
12861317
unsigned long CSysSolve<ScalarType>::Solve(CSysMatrix<ScalarType>& Jacobian, const CSysVector<su2double>& LinSysRes,
12871318
CSysVector<su2double>& LinSysSol, CGeometry* geometry,
@@ -1334,16 +1365,7 @@ unsigned long CSysSolve<ScalarType>::Solve(CSysMatrix<ScalarType>& Jacobian, con
13341365
}
13351366
}
13361367

1337-
const bool nested = (KindSolver == FGMRES || KindSolver == RESTARTED_FGMRES || KindSolver == SMOOTHER) &&
1338-
config->GetKind_Linear_Solver_Inner() != LINEAR_SOLVER_INNER::NONE;
1339-
1340-
if (nested && !inner_solver) {
1341-
BEGIN_SU2_OMP_SAFE_GLOBAL_ACCESS {
1342-
inner_solver = std::make_unique<CSysSolve<ScalarType>>(LINEAR_SOLVER_MODE::STANDARD);
1343-
inner_solver->SetxIsZero(true);
1344-
}
1345-
END_SU2_OMP_SAFE_GLOBAL_ACCESS
1346-
}
1368+
const bool nested = SetupInnerSolver(KindSolver, config);
13471369

13481370
/*--- Stop the recording for the linear solver ---*/
13491371
bool TapeActive = NO;
@@ -1389,11 +1411,15 @@ unsigned long CSysSolve<ScalarType>::Solve(CSysMatrix<ScalarType>& Jacobian, con
13891411
auto f = [&](const CSysVector<ScalarType>& u, CSysVector<ScalarType>& v) {
13901412
/*--- Initialize to 0 to be safe. ---*/
13911413
v = ScalarType{};
1392-
ScalarType unused{};
1414+
ScalarType res{};
13931415
/*--- Handle other types here if desired but do not call Solve because
13941416
* that will create issues with the AD external function. ---*/
1395-
(void)inner_solver->BCGSTAB_LinSolver(u, v, mat_vec, *normal_prec, sqrt(SolverTol), MaxIter, unused, false,
1396-
config);
1417+
if (config->GetKind_Linear_Solver_Inner() == LINEAR_SOLVER_INNER::BCGSTAB) {
1418+
inner_solver->BCGSTAB_LinSolver(u, v, mat_vec, *normal_prec, sqrt(SolverTol), MaxIter, res, false, config);
1419+
} else {
1420+
const auto smooth_iter = static_cast<unsigned long>(std::round(fmax(2, sqrt(MaxIter))));
1421+
inner_solver->Smoother_LinSolver(u, v, mat_vec, *normal_prec, 0, smooth_iter, res, false, config);
1422+
}
13971423
};
13981424
nested_prec = new CAbstractPreconditioner<ScalarType>(f);
13991425
}
@@ -1545,16 +1571,7 @@ unsigned long CSysSolve<ScalarType>::Solve_b(CSysMatrix<ScalarType>& Jacobian, c
15451571
}
15461572
}
15471573

1548-
const bool nested = (KindSolver == FGMRES || KindSolver == RESTARTED_FGMRES || KindSolver == SMOOTHER) &&
1549-
config->GetKind_Linear_Solver_Inner() != LINEAR_SOLVER_INNER::NONE;
1550-
1551-
if (nested && !inner_solver) {
1552-
BEGIN_SU2_OMP_SAFE_GLOBAL_ACCESS {
1553-
inner_solver = std::make_unique<CSysSolve<ScalarType>>(LINEAR_SOLVER_MODE::STANDARD);
1554-
inner_solver->SetxIsZero(true);
1555-
}
1556-
END_SU2_OMP_SAFE_GLOBAL_ACCESS
1557-
}
1574+
const bool nested = SetupInnerSolver(KindSolver, config);
15581575

15591576
/*--- Set up preconditioner and matrix-vector product ---*/
15601577

@@ -1572,13 +1589,15 @@ unsigned long CSysSolve<ScalarType>::Solve_b(CSysMatrix<ScalarType>& Jacobian, c
15721589
CPreconditioner<ScalarType>* nested_prec = nullptr;
15731590
if (nested) {
15741591
auto f = [&](const CSysVector<ScalarType>& u, CSysVector<ScalarType>& v) {
1575-
/*--- Initialize to 0 to be safe. ---*/
1592+
/*--- See "Solve". ---*/
15761593
v = ScalarType{};
1577-
ScalarType unused{};
1578-
/*--- Handle other types here if desired but do not call Solve because
1579-
* that will create issues with the AD external function. ---*/
1580-
(void)inner_solver->BCGSTAB_LinSolver(u, v, mat_vec, *normal_prec, sqrt(SolverTol), MaxIter, unused, false,
1581-
config);
1594+
ScalarType res{};
1595+
if (config->GetKind_Linear_Solver_Inner() == LINEAR_SOLVER_INNER::BCGSTAB) {
1596+
inner_solver->BCGSTAB_LinSolver(u, v, mat_vec, *normal_prec, sqrt(SolverTol), MaxIter, res, false, config);
1597+
} else {
1598+
const auto smooth_iter = static_cast<unsigned long>(std::round(fmax(2, sqrt(MaxIter))));
1599+
inner_solver->Smoother_LinSolver(u, v, mat_vec, *normal_prec, 0, smooth_iter, res, false, config);
1600+
}
15821601
};
15831602
nested_prec = new CAbstractPreconditioner<ScalarType>(f);
15841603
}

SU2_CFD/include/integration/CNewtonIntegration.hpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,25 @@ class CNewtonIntegration final : public CIntegration {
152152
template<class T, su2enable_if<std::is_same<T,MixedScalar>::value> = 0>
153153
inline unsigned long Preconditioner_impl(const CSysVector<T>& u, CSysVector<T>& v,
154154
unsigned long iters, Scalar& eps) const {
155-
if (iters == 0) {
155+
const auto inner_solver = config->GetKind_Linear_Solver_Inner();
156+
157+
if (iters == 0 || (iters == 1 && inner_solver == LINEAR_SOLVER_INNER::SMOOTHER)) {
156158
(*preconditioner)(u, v);
157159
return 0;
158160
}
159161
auto product = CSysMatrixVectorProduct<MixedScalar>(solvers[FLOW_SOL]->Jacobian, geometry, config);
160162
v = MixedScalar(0.0);
161163
MixedScalar eps_t = eps;
162-
if (config->GetKind_Linear_Solver_Inner() == LINEAR_SOLVER_INNER::NONE) {
163-
iters = solvers[FLOW_SOL]->System.FGMRES_LinSolver(u, v, product, *preconditioner, eps, iters, eps_t, false, config);
164-
} else {
165-
iters = solvers[FLOW_SOL]->System.BCGSTAB_LinSolver(u, v, product, *preconditioner, eps, iters, eps_t, false, config);
164+
switch (inner_solver) {
165+
case LINEAR_SOLVER_INNER::NONE:
166+
iters = solvers[FLOW_SOL]->System.FGMRES_LinSolver(u, v, product, *preconditioner, eps, iters, eps_t, false, config);
167+
break;
168+
case LINEAR_SOLVER_INNER::BCGSTAB:
169+
iters = solvers[FLOW_SOL]->System.BCGSTAB_LinSolver(u, v, product, *preconditioner, eps, iters, eps_t, false, config);
170+
break;
171+
case LINEAR_SOLVER_INNER::SMOOTHER:
172+
iters = solvers[FLOW_SOL]->System.Smoother_LinSolver(u, v, product, *preconditioner, 0, iters, eps_t, false, config);
173+
break;
166174
}
167175
eps = eps_t;
168176
return iters;

config_template.cfg

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,8 +1553,10 @@ ADJ_JST_SENSOR_COEFF= ( 0.5, 0.02 )
15531553
% BCGSTAB, FGMRES, FGCRODR, RESTARTED_FGMRES, CONJUGATE_GRADIENT (self-adjoint problems only), SMOOTHER.
15541554
LINEAR_SOLVER= FGMRES
15551555
1556-
% Inner solver used for nested preconditioning (only possible with flexible linear solvers).
1557-
% Options: NONE, BCGSTAB
1556+
% Inner solver used for nested preconditioning (BCGSTAB is only possible with flexible linear solvers).
1557+
% Options: NONE, BCGSTAB, SMOOTHER
1558+
% Inner BCGSTAB does up to the number of iterations of the outer solver or sqrt(LINEAR_SOLVER_ERROR).
1559+
% Inner SMOOTHER does max(2, sqrt(LINEAR_SOLVER_ITER))
15581560
LINEAR_SOLVER_INNER= NONE
15591561
15601562
% Same for discrete adjoint (smoothers not supported), replaces LINEAR_SOLVER in SU2_*_AD codes.

0 commit comments

Comments
 (0)