Skip to content

Commit 28d8267

Browse files
committed
Add additional solvers and preconditioners for contrasting material systems
Add some more non-symmetric krylov solvers (BiCGSTAB) Add a number of new preconditioners that should help for some highly contrasting multi-material systems such as ILU, l1-Gauss Seidel, and a Chebychev preconditioner.
1 parent 6493dac commit 28d8267

File tree

5 files changed

+51
-20
lines changed

5 files changed

+51
-20
lines changed

src/options.toml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -379,19 +379,24 @@ grain_file = "grains.txt"
379379
abs_tol = 1e-30
380380

381381
# Linear solver algorithm:
382-
# - "CG" = Conjugate Gradient (fastest for symmetric problems)
383-
# - "GMRES" = General solver (works for any problem)
384-
# - "MINRES" = Minimal Residual (good for symmetric indefinite)
385-
# Use CG for ExaCMech, GMRES if unsure
382+
# - "CG" = Conjugate Gradient (fastest for well-behaved symmetric problems)
383+
# - "GMRES" = General solver (works for any problem, reliable but uses more memory)
384+
# - "MINRES" = Minimal Residual (for symmetric problems when CG fails)
385+
# - "BiCGSTAB" = Memory-efficient alternative to GMRES (faster but less robust)
386+
# Use CG for typical material models, GMRES if unsure or have convergence issues
386387
solver = "GMRES"
387388

388389
# Preconditioner to accelerate convergence:
389390
# With multi-material systems you might find better convergence
390391
# properties by testing out different preconditioners
391392
# EA/PA will automatically run with JACOBI as the full matrix is
392393
# not constructed
393-
# - "JACOBI" = diagonal scaling (simple / fast, always works but usually increases iteration count)
394-
# - "AMG" = Algebraic MultiGrid (usually lowers iteration count and can be faster for large problems)
394+
# - "JACOBI" = diagonal scaling (simple/fast, works everywhere but slow convergence)
395+
# - "AMG" = Algebraic MultiGrid (fewer iterations but expensive setup, can fail on some problems)
396+
# - "ILU" = Incomplete factorization (good middle-ground, useful for multi-material systems)
397+
# - "L1GS" = advanced smoother (can help with multi-material systems with contrasting properties)
398+
# - "CHEBYSHEV" = polynomial smoother (good for problems with multiple material scales)
399+
# Try ILU / L1GS / CHEBYSHEV if JACOBI convergence is too slow
395400
preconditioner = "JACOBI"
396401

397402
# Output verbosity (0 = quiet, 1+ = show iterations)

src/options/option_enum.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ LinearSolverType string_to_linear_solver_type(const std::string& str) {
113113
{"CG", LinearSolverType::CG},
114114
{"PCG", LinearSolverType::CG},
115115
{"GMRES", LinearSolverType::GMRES},
116-
{"MINRES", LinearSolverType::MINRES}
116+
{"MINRES", LinearSolverType::MINRES},
117+
{"BICGSTAB", LinearSolverType::BICGSTAB}
117118
};
118119

119120
return string_to_enum(str, mapping, LinearSolverType::NOTYPE, "linear solver");
@@ -141,7 +142,10 @@ NonlinearSolverType string_to_nonlinear_solver_type(const std::string& str) {
141142
PreconditionerType string_to_preconditioner_type(const std::string& str) {
142143
static const std::map<std::string, PreconditionerType> mapping = {
143144
{"JACOBI", PreconditionerType::JACOBI},
144-
{"AMG", PreconditionerType::AMG}
145+
{"AMG", PreconditionerType::AMG},
146+
{"ILU", PreconditionerType::ILU},
147+
{"L1GS", PreconditionerType::L1GS},
148+
{"CHEBYSHEV", PreconditionerType::CHEBYSHEV},
145149
};
146150

147151
return string_to_enum(str, mapping, PreconditionerType::NOTYPE, "preconditioner");

src/options/option_parser_v2.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,13 +597,17 @@ void ExaOptions::print_solver_options() const {
597597
case LinearSolverType::CG: std::cout << "Conjugate Gradient\n"; break;
598598
case LinearSolverType::GMRES: std::cout << "GMRES\n"; break;
599599
case LinearSolverType::MINRES: std::cout << "MINRES\n"; break;
600+
case LinearSolverType::BICGSTAB: std::cout << "BiCGSTAB\n"; break;
600601
default: std::cout << "Unknown\n"; break;
601602
}
602603

603604
std::cout << " Preconditioner: ";
604605
switch (solvers.linear_solver.preconditioner) {
605606
case PreconditionerType::JACOBI: std::cout << "Jacobi\n"; break;
606607
case PreconditionerType::AMG: std::cout << "AMG\n"; break;
608+
case PreconditionerType::ILU: std::cout << "ILU\n"; break;
609+
case PreconditionerType::L1GS: std::cout << "L1GS\n"; break;
610+
case PreconditionerType::CHEBYSHEV: std::cout << "CHEBYSHEV\n"; break;
607611
default: std::cout << "Unknown\n"; break;
608612
}
609613

src/options/option_parser_v2.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ enum class LinearSolverType {
8989
CG, /**< Conjugate Gradient solver */
9090
GMRES, /**< Generalized Minimal Residual solver */
9191
MINRES, /**< Minimal Residual solver */
92+
BICGSTAB, /**< BiCGSTAB Solver */
9293
NOTYPE /**< Uninitialized or invalid linear solver type */
9394
};
9495

@@ -106,7 +107,10 @@ enum class NonlinearSolverType {
106107
*/
107108
enum class PreconditionerType {
108109
JACOBI, /**< Jacobi preconditioner */
109-
AMG, /**< Algebraic multigrid preconditioner */
110+
AMG, /**< Algebraic multigrid preconditioner (Full assembly only) */
111+
ILU, /**< Incomplete LU factorization preconditioner (Full assembly only) */
112+
L1GS, /**< l1-scaled block Gauss-Seidel/SSOR preconditioner (Full assembly only) */
113+
CHEBYSHEV, /**< Chebyshev preconditioner (Full assembly only) */
110114
NOTYPE /**< Uninitialized or invalid preconditioner type */
111115
};
112116

@@ -580,7 +584,7 @@ struct LinearSolverOptions {
580584
/**
581585
* @brief Preconditioner type for linear solver acceleration
582586
*/
583-
PreconditionerType preconditioner = PreconditionerType::JACOBI;
587+
PreconditionerType preconditioner = PreconditionerType::AMG;
584588

585589
/**
586590
* @brief Absolute convergence tolerance for linear solver

src/system_driver.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ SystemDriver::SystemDriver(std::shared_ptr<SimulationState> sim_state)
253253
J_prec = mech_operator->GetPAPreconditioner();
254254
}
255255
else {
256-
if (linear_solvers.solver_type == LinearSolverType::GMRES || linear_solvers.solver_type == LinearSolverType::CG) {
256+
if (linear_solvers.preconditioner == PreconditionerType::AMG) {
257257
auto prec_amg = std::make_shared<mfem::HypreBoomerAMG>();
258258
HYPRE_Solver h_amg = (HYPRE_Solver) * prec_amg;
259259
HYPRE_Real st_val = 0.90;
@@ -280,8 +280,19 @@ SystemDriver::SystemDriver(std::shared_ptr<SimulationState> sim_state)
280280

281281
prec_amg->SetPrintLevel(linear_solvers.print_level);
282282
J_prec = prec_amg;
283-
}
284-
else {
283+
} else if (linear_solvers.preconditioner == PreconditionerType::ILU) {
284+
auto J_hypreEuclid = std::make_shared<mfem::HypreEuclid>(fe_space->GetComm());
285+
J_prec = J_hypreEuclid;
286+
} else if (linear_solvers.preconditioner == PreconditionerType::L1GS) {
287+
auto J_hypreSmoother = std::make_shared<mfem::HypreSmoother>();
288+
J_hypreSmoother->SetType(mfem::HypreSmoother::l1GS);
289+
J_hypreSmoother->SetPositiveDiagonal(true);
290+
J_prec = J_hypreSmoother;
291+
} else if (linear_solvers.preconditioner == PreconditionerType::CHEBYSHEV) {
292+
auto J_hypreSmoother = std::make_shared<mfem::HypreSmoother>();
293+
J_hypreSmoother->SetType(mfem::HypreSmoother::Chebyshev);
294+
J_prec = J_hypreSmoother;
295+
} else {
285296
auto J_hypreSmoother = std::make_shared<mfem::HypreSmoother>();
286297
J_hypreSmoother->SetType(mfem::HypreSmoother::l1Jacobi);
287298
J_hypreSmoother->SetPositiveDiagonal(true);
@@ -295,17 +306,20 @@ SystemDriver::SystemDriver(std::shared_ptr<SimulationState> sim_state)
295306
else if (linear_solvers.solver_type == LinearSolverType::CG) {
296307
J_solver = std::make_shared<mfem::CGSolver>(fe_space->GetComm());
297308
}
309+
else if (linear_solvers.solver_type == LinearSolverType::BICGSTAB) {
310+
J_solver = std::make_shared<mfem::BiCGSTABSolver>(fe_space->GetComm());
311+
}
298312
else {
299313
J_solver = std::make_shared<mfem::MINRESSolver>(fe_space->GetComm());
300314
}
301315

302-
// The relative tolerance should be at this point or smaller
303-
J_solver->SetRelTol(linear_solvers.rel_tol);
304-
// The absolute tolerance could probably get even smaller then this
305-
J_solver->SetAbsTol(linear_solvers.abs_tol);
306-
J_solver->SetMaxIter(linear_solvers.max_iter);
307-
J_solver->SetPrintLevel(linear_solvers.print_level);
308-
J_solver->SetPreconditioner(*J_prec);
316+
// The relative tolerance should be at this point or smaller
317+
J_solver->SetRelTol(linear_solvers.rel_tol);
318+
// The absolute tolerance could probably get even smaller then this
319+
J_solver->SetAbsTol(linear_solvers.abs_tol);
320+
J_solver->SetMaxIter(linear_solvers.max_iter);
321+
J_solver->SetPrintLevel(linear_solvers.print_level);
322+
J_solver->SetPreconditioner(*J_prec);
309323

310324
auto nonlinear_solver = options.solvers.nonlinear_solver;
311325
newton_iter = nonlinear_solver.iter;

0 commit comments

Comments
 (0)