7#include <boost/algorithm/string.hpp>
24#if !defined(USE_PETSC) && !defined(USE_LIS)
29 BaseLib::RunTime time_linear_solver;
30 time_linear_solver.
start();
32 if (!linear_solver.compute(A, linear_solver_behaviour))
34 ERR(
"Picard: The linear solver failed in the compute() step.");
38 bool const iteration_succeeded = linear_solver.
solve(rhs, x);
40 INFO(
"[time] Linear solver took {:g} s.", time_linear_solver.
elapsed());
42 if (iteration_succeeded)
47 ERR(
"Picard: The linear solver failed in the solve() step.");
55 if (linear_solver_behaviour ==
60 "The performance optimization to skip the linear solver compute() "
61 "step is not implemented for PETSc or LIS linear solvers.");
65 time_linear_solver.
start();
67 bool const iteration_succeeded = linear_solver.
solve(A, rhs, x);
69 INFO(
"[time] Linear solver took {:g} s.", time_linear_solver.
elapsed());
71 if (iteration_succeeded)
76 ERR(
"Picard: The linear solver failed in the solve() step.");
84 std::vector<GlobalVector*>
const& x,
85 std::vector<GlobalVector*>
const& x_prev,
int const process_id)
92 INFO(
"Calculate non-equilibrium initial residuum.");
108 const auto selected_global_indices =
111 std::vector<double> zero_entries(selected_global_indices.size(), 0.0);
112 _r_neq->set(selected_global_indices, zero_entries);
122 std::vector<GlobalVector*>& x,
123 std::vector<GlobalVector*>
const& x_prev,
124 std::function<
void(
int,
bool, std::vector<GlobalVector*>
const&)>
const&
125 postIterationCallback,
126 int const process_id)
134 std::vector<GlobalVector*> x_new{x};
139 bool error_norms_met =
false;
147 double time_dirichlet = 0.0;
150 time_iteration.
start();
152 INFO(
"Iteration #{:d} started.", iteration);
153 timer_dirichlet.
start();
154 auto& x_new_process = *x_new[process_id];
156 sys.computeKnownSolutions(x_new_process, process_id);
157 sys.applyKnownSolutions(x_new_process);
158 time_dirichlet += timer_dirichlet.
elapsed();
160 sys.preIteration(iteration, x_new_process);
163 time_assembly.
start();
164 sys.assemble(x_new, x_prev, process_id);
166 sys.getRhs(*x_prev[process_id], rhs);
169 if (sys.requiresNormalization() &&
172 sys.getAandRhsNormalized(A, rhs);
174 "The equation system is rectangular, but the current linear "
175 "solver only supports square systems. "
176 "The system will be normalized, which lead to a squared "
177 "condition number and potential numerical issues. "
178 "It is recommended to use a solver that supports rectangular "
179 "equation systems for better numerical stability.");
182 INFO(
"[time] Assembly took {:g} s.", time_assembly.
elapsed());
190 auto const solver_needs_to_compute = sys.linearSolverNeedsToCompute();
191 bool const solver_will_compute =
194 timer_dirichlet.
start();
195 sys.applyKnownSolutionsPicard(
196 A, rhs, x_new_process,
200 FAST_INCOMPLETE_MATRIX_UPDATE);
201 time_dirichlet += timer_dirichlet.
elapsed();
202 INFO(
"[time] Applying Dirichlet BCs took {:g} s.", time_dirichlet);
206 if (!solver_will_compute)
212 "Logic error. The solver skips the compute step for a "
213 "non-linear equation system.");
224 if (iteration_succeeded)
226 if (postIterationCallback)
228 postIterationCallback(iteration, error_norms_met, x_new);
231 switch (sys.postIteration(x_new_process))
238 ERR(
"Picard: The postIteration() hook reported a "
239 "non-recoverable error.");
240 iteration_succeeded =
false;
248 "Picard: The postIteration() hook decided that this "
249 "iteration has to be repeated.");
257 if (!iteration_succeeded)
260 error_norms_met =
false;
266 error_norms_met =
true;
285 INFO(
"[time] Iteration #{:d} took {:g} s.", iteration,
303 ERR(
"Picard: Could not solve the given nonlinear system within {:d} "
312 return {error_norms_met, iteration};
317 std::vector<GlobalVector*>
const& x,
318 std::vector<GlobalVector*>
const& x_prev,
int const process_id)
325 INFO(
"Calculate non-equilibrium initial residuum.");
334 const auto selected_global_indices =
336 std::vector<double> zero_entries(selected_global_indices.size(), 0.0);
338 _r_neq->set(selected_global_indices, zero_entries);
345 std::vector<GlobalVector*>& x,
346 std::vector<GlobalVector*>
const& x_prev,
347 std::function<
void(
int,
bool, std::vector<GlobalVector*>
const&)>
const&
348 postIterationCallback,
349 int const process_id)
355 auto& minus_delta_x =
359 bool error_norms_met =
false;
368#if !defined(USE_PETSC) && !defined(USE_LIS)
369 int next_iteration_inv_jacobian_recompute = 1;
374 double time_dirichlet = 0.0;
377 INFO(
"Iteration #{:d} started.", iteration);
378 time_iteration.
start();
380 timer_dirichlet.
start();
381 sys.computeKnownSolutions(*x[process_id], process_id);
382 time_dirichlet += timer_dirichlet.
elapsed();
384 sys.preIteration(iteration, *x[process_id]);
387 time_assembly.
start();
388 bool mpi_rank_assembly_ok =
true;
391 sys.assemble(x, x_prev, process_id);
395 ERR(
"Abort nonlinear iteration. Repeating timestep. Reason: {:s}",
397 error_norms_met =
false;
399 mpi_rank_assembly_ok =
false;
405 sys.getResidual(*x[process_id], *x_prev[process_id], res);
407 INFO(
"[time] Assembly took {:g} s.", time_assembly.
elapsed());
413 minus_delta_x.setZero();
415 timer_dirichlet.
start();
416 sys.applyKnownSolutionsNewton(J, res, *x[process_id], minus_delta_x);
417 time_dirichlet += timer_dirichlet.
elapsed();
418 INFO(
"[time] Applying Dirichlet BCs took {:g} s.", time_dirichlet);
426 time_linear_solver.
start();
427#if !defined(USE_PETSC) && !defined(USE_LIS)
429 if (iteration == next_iteration_inv_jacobian_recompute)
431 linear_solver_behaviour =
433 next_iteration_inv_jacobian_recompute =
437 bool iteration_succeeded =
false;
440 ERR(
"Newton: The linear solver failed in the compute() step.");
447 bool iteration_succeeded =
_linear_solver.solve(J, res, minus_delta_x);
449 INFO(
"[time] Linear solver took {:g} s.", time_linear_solver.
elapsed());
451 if (!iteration_succeeded)
453 ERR(
"Newton: The linear solver failed.");
462 std::vector<GlobalVector*> x_new{x};
470 minus_delta_x, *x[process_id],
_damping);
479 LinAlg::axpy(*x_new[process_id], -damping, minus_delta_x);
481 if (postIterationCallback)
483 postIterationCallback(iteration, error_norms_met, x_new);
486 switch (sys.postIteration(*x_new[process_id]))
491 ERR(
"Newton: The postIteration() hook reported a "
492 "non-recoverable error.");
493 iteration_succeeded =
false;
497 "Newton: The postIteration() hook decided that this "
498 "iteration has to be repeated.");
511 if (!iteration_succeeded)
514 error_norms_met =
false;
520 error_norms_met =
true;
534 INFO(
"[time] Iteration #{:d} took {:g} s.", iteration,
552 ERR(
"Newton: Could not solve the given nonlinear system within {:d} "
561 return {error_norms_met, iteration};
573 if (type ==
"Picard")
577 return std::make_pair(
578 std::make_unique<ConcreteNLS>(linear_solver, max_iter), tag);
580 if (type ==
"Newton")
582 auto const recompute_jacobian =
591 "The damping factor for the Newon method must be positive, got "
595 auto const damping_reduction =
600 return std::make_pair(std::make_unique<ConcreteNLS>(
601 linear_solver, max_iter, recompute_jacobian,
602 damping, damping_reduction),
606 if (boost::iequals(type,
"PETScSNES"))
613 return std::make_pair(std::make_unique<ConcreteNLS>(
614 linear_solver, max_iter, std::move(prefix)),
619 OGS_FATAL(
"Unsupported nonlinear solver type '{:s}'.", type.c_str());
MathLib::EigenLisLinearSolver GlobalLinearSolver
MathLib::EigenMatrix GlobalMatrix
MathLib::EigenVector GlobalVector
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
std::optional< T > getConfigParameterOptional(std::string const ¶m) const
T getConfigParameter(std::string const ¶m) const
double elapsed() const
Get the elapsed time in seconds.
void start()
Start the timer.
bool solve(EigenMatrix &A, EigenVector &b, EigenVector &x)
GlobalLinearSolver & _linear_solver
ConvergenceCriterion * _convergence_criterion
std::optional< double > const _damping_reduction
bool _compensate_non_equilibrium_initial_residuum
std::size_t _J_id
ID of the Jacobian matrix.
std::size_t _x_new_id
ID of the vector storing .
std::size_t _res_id
ID of the residual vector.
GlobalVector * _r_neq
non-equilibrium initial residuum.
NonlinearSolver(GlobalLinearSolver &linear_solver, int const maxiter, int const recompute_jacobian=1, double const damping=1.0, std::optional< double > const damping_reduction=std::nullopt)
int const _maxiter
maximum number of iterations
int const _recompute_jacobian
System * _equation_system
std::size_t _minus_delta_x_id
ID of the vector.
std::size_t _rhs_id
ID of the right-hand side vector.
bool _compensate_non_equilibrium_initial_residuum
const int _maxiter
maximum number of iterations
GlobalVector * _r_neq
non-equilibrium initial residuum.
GlobalLinearSolver & _linear_solver
System * _equation_system
NonlinearSolver(GlobalLinearSolver &linear_solver, const int maxiter)
std::size_t _A_id
ID of the matrix.
ConvergenceCriterion * _convergence_criterion
NonlinearSolverTag
Tag used to specify which nonlinear solver will be used.
std::pair< std::unique_ptr< NonlinearSolverBase >, NonlinearSolverTag > createNonlinearSolver(GlobalLinearSolver &linear_solver, BaseLib::ConfigTree const &config)
static bool anyOf(bool const val, Mpi const &mpi=Mpi{OGS_COMM_WORLD})
void finalizeAssembly(PETScMatrix &A)
void copy(PETScVector const &x, PETScVector &y)
void setLocalAccessibleVector(PETScVector const &x)
void matMult(PETScMatrix const &A, PETScVector const &x, PETScVector &y)
void axpy(PETScVector &y, PetscScalar const a, PETScVector const &x)
DirichletBCApplicationMode
@ COMPLETE_MATRIX_UPDATE
Both A and b fully updated.
bool solvePicard(GlobalLinearSolver &linear_solver, GlobalMatrix &A, GlobalVector &rhs, GlobalVector &x, MathLib::LinearSolverBehaviour const linear_solver_behaviour)
static NUMLIB_EXPORT MatrixProvider & provider
static NUMLIB_EXPORT VectorProvider & provider
Status of the non-linear solver.