14#include <boost/algorithm/string.hpp>
31#if !defined(USE_PETSC) && !defined(USE_LIS)
36 BaseLib::RunTime time_linear_solver;
37 time_linear_solver.
start();
39 if (!linear_solver.compute(A, linear_solver_behaviour))
41 ERR(
"Picard: The linear solver failed in the compute() step.");
45 bool const iteration_succeeded = linear_solver.
solve(rhs, x);
47 INFO(
"[time] Linear solver took {:g} s.", time_linear_solver.
elapsed());
49 if (iteration_succeeded)
54 ERR(
"Picard: The linear solver failed in the solve() step.");
62 if (linear_solver_behaviour ==
67 "The performance optimization to skip the linear solver compute() "
68 "step is not implemented for PETSc or LIS linear solvers.");
72 time_linear_solver.
start();
74 bool const iteration_succeeded = linear_solver.
solve(A, rhs, x);
76 INFO(
"[time] Linear solver took {:g} s.", time_linear_solver.
elapsed());
78 if (iteration_succeeded)
83 ERR(
"Picard: The linear solver failed in the solve() step.");
91 std::vector<GlobalVector*>
const& x,
92 std::vector<GlobalVector*>
const& x_prev,
int const process_id)
99 INFO(
"Calculate non-equilibrium initial residuum.");
115 const auto selected_global_indices =
118 std::vector<double> zero_entries(selected_global_indices.size(), 0.0);
119 _r_neq->set(selected_global_indices, zero_entries);
129 std::vector<GlobalVector*>& x,
130 std::vector<GlobalVector*>
const& x_prev,
131 std::function<
void(
int,
bool, std::vector<GlobalVector*>
const&)>
const&
132 postIterationCallback,
133 int const process_id)
141 std::vector<GlobalVector*> x_new{x};
146 bool error_norms_met =
false;
154 double time_dirichlet = 0.0;
157 time_iteration.
start();
159 INFO(
"Iteration #{:d} started.", iteration);
160 timer_dirichlet.
start();
161 auto& x_new_process = *x_new[process_id];
163 sys.computeKnownSolutions(x_new_process, process_id);
164 sys.applyKnownSolutions(x_new_process);
165 time_dirichlet += timer_dirichlet.
elapsed();
167 sys.preIteration(iteration, x_new_process);
170 time_assembly.
start();
171 sys.assemble(x_new, x_prev, process_id);
173 sys.getRhs(*x_prev[process_id], rhs);
176 if (sys.requiresNormalization() &&
179 sys.getAandRhsNormalized(A, rhs);
181 "The equation system is rectangular, but the current linear "
182 "solver only supports square systems. "
183 "The system will be normalized, which lead to a squared "
184 "condition number and potential numerical issues. "
185 "It is recommended to use a solver that supports rectangular "
186 "equation systems for better numerical stability.");
189 INFO(
"[time] Assembly took {:g} s.", time_assembly.
elapsed());
197 auto const solver_needs_to_compute = sys.linearSolverNeedsToCompute();
198 bool const solver_will_compute =
201 timer_dirichlet.
start();
202 sys.applyKnownSolutionsPicard(
203 A, rhs, x_new_process,
207 FAST_INCOMPLETE_MATRIX_UPDATE);
208 time_dirichlet += timer_dirichlet.
elapsed();
209 INFO(
"[time] Applying Dirichlet BCs took {:g} s.", time_dirichlet);
213 if (!solver_will_compute)
219 "Logic error. The solver skips the compute step for a "
220 "non-linear equation system.");
231 if (iteration_succeeded)
233 if (postIterationCallback)
235 postIterationCallback(iteration, error_norms_met, x_new);
238 switch (sys.postIteration(x_new_process))
245 ERR(
"Picard: The postIteration() hook reported a "
246 "non-recoverable error.");
247 iteration_succeeded =
false;
255 "Picard: The postIteration() hook decided that this "
256 "iteration has to be repeated.");
264 if (!iteration_succeeded)
267 error_norms_met =
false;
273 error_norms_met =
true;
292 INFO(
"[time] Iteration #{:d} took {:g} s.", iteration,
310 ERR(
"Picard: Could not solve the given nonlinear system within {:d} "
319 return {error_norms_met, iteration};
324 std::vector<GlobalVector*>
const& x,
325 std::vector<GlobalVector*>
const& x_prev,
int const process_id)
332 INFO(
"Calculate non-equilibrium initial residuum.");
341 const auto selected_global_indices =
343 std::vector<double> zero_entries(selected_global_indices.size(), 0.0);
345 _r_neq->set(selected_global_indices, zero_entries);
352 std::vector<GlobalVector*>& x,
353 std::vector<GlobalVector*>
const& x_prev,
354 std::function<
void(
int,
bool, std::vector<GlobalVector*>
const&)>
const&
355 postIterationCallback,
356 int const process_id)
362 auto& minus_delta_x =
366 bool error_norms_met =
false;
375#if !defined(USE_PETSC) && !defined(USE_LIS)
376 int next_iteration_inv_jacobian_recompute = 1;
381 double time_dirichlet = 0.0;
384 INFO(
"Iteration #{:d} started.", iteration);
385 time_iteration.
start();
387 timer_dirichlet.
start();
388 sys.computeKnownSolutions(*x[process_id], process_id);
389 time_dirichlet += timer_dirichlet.
elapsed();
391 sys.preIteration(iteration, *x[process_id]);
394 time_assembly.
start();
395 bool mpi_rank_assembly_ok =
true;
398 sys.assemble(x, x_prev, process_id);
402 ERR(
"Abort nonlinear iteration. Repeating timestep. Reason: {:s}",
404 error_norms_met =
false;
406 mpi_rank_assembly_ok =
false;
412 sys.getResidual(*x[process_id], *x_prev[process_id], res);
414 INFO(
"[time] Assembly took {:g} s.", time_assembly.
elapsed());
420 minus_delta_x.setZero();
422 timer_dirichlet.
start();
423 sys.applyKnownSolutionsNewton(J, res, *x[process_id], minus_delta_x);
424 time_dirichlet += timer_dirichlet.
elapsed();
425 INFO(
"[time] Applying Dirichlet BCs took {:g} s.", time_dirichlet);
433 time_linear_solver.
start();
434#if !defined(USE_PETSC) && !defined(USE_LIS)
436 if (iteration == next_iteration_inv_jacobian_recompute)
438 linear_solver_behaviour =
440 next_iteration_inv_jacobian_recompute =
444 bool iteration_succeeded =
false;
447 ERR(
"Newton: The linear solver failed in the compute() step.");
454 bool iteration_succeeded =
_linear_solver.solve(J, res, minus_delta_x);
456 INFO(
"[time] Linear solver took {:g} s.", time_linear_solver.
elapsed());
458 if (!iteration_succeeded)
460 ERR(
"Newton: The linear solver failed.");
469 std::vector<GlobalVector*> x_new{x};
477 minus_delta_x, *x[process_id],
_damping);
486 LinAlg::axpy(*x_new[process_id], -damping, minus_delta_x);
488 if (postIterationCallback)
490 postIterationCallback(iteration, error_norms_met, x_new);
493 switch (sys.postIteration(*x_new[process_id]))
498 ERR(
"Newton: The postIteration() hook reported a "
499 "non-recoverable error.");
500 iteration_succeeded =
false;
504 "Newton: The postIteration() hook decided that this "
505 "iteration has to be repeated.");
518 if (!iteration_succeeded)
521 error_norms_met =
false;
527 error_norms_met =
true;
541 INFO(
"[time] Iteration #{:d} took {:g} s.", iteration,
559 ERR(
"Newton: Could not solve the given nonlinear system within {:d} "
568 return {error_norms_met, iteration};
580 if (type ==
"Picard")
584 return std::make_pair(
585 std::make_unique<ConcreteNLS>(linear_solver, max_iter), tag);
587 if (type ==
"Newton")
589 auto const recompute_jacobian =
598 "The damping factor for the Newon method must be positive, got "
602 auto const damping_reduction =
607 return std::make_pair(std::make_unique<ConcreteNLS>(
608 linear_solver, max_iter, recompute_jacobian,
609 damping, damping_reduction),
613 if (boost::iequals(type,
"PETScSNES"))
620 return std::make_pair(std::make_unique<ConcreteNLS>(
621 linear_solver, max_iter, std::move(prefix)),
626 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)
Definition of the RunTime class.
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.