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.");
96template <
typename Assemble>
99 bool mpi_rank_assembly_ok =
true;
106 ERR(
"Abort nonlinear iteration. Repeating timestep. Reason: {:s}",
108 mpi_rank_assembly_ok =
false;
116 std::vector<GlobalVector*>
const& x,
117 std::vector<GlobalVector*>
const& x_prev,
int const process_id)
124 INFO(
"Calculate non-equilibrium initial residuum.");
140 auto selected_global_indices =
146 auto const global_size =
_r_neq->size();
147 for (
auto& idx : selected_global_indices)
149 if (idx == global_size)
156 std::vector<double> zero_entries(selected_global_indices.size(), 0.0);
157 _r_neq->set(selected_global_indices, zero_entries);
167 std::vector<GlobalVector*>& x,
168 std::vector<GlobalVector*>
const& x_prev,
169 std::function<
void(
int, std::vector<GlobalVector*>
const&)>
const&
170 postIterationCallback,
171 int const process_id)
181 "Damping (under-relaxation) and Anderson acceleration are not "
182 "compatible with a linear equation system: a single Picard step "
183 "already yields the exact solution, so the mixed/damped iterate "
184 "would be accepted as converged but wrong. Remove the 'damping' "
185 "parameter and the 'anderson' subtree for linear problems.");
191 std::vector<GlobalVector*> x_new{x};
196 bool error_norms_met =
false;
211 double time_dirichlet = 0.0;
214 time_iteration.
start();
216 INFO(
"Iteration #{:d} started.", iteration);
217 timer_dirichlet.
start();
218 auto& x_new_process = *x_new[process_id];
220 sys.computeKnownSolutions(x_new_process, process_id);
221 sys.applyKnownSolutions(x_new_process);
222 time_dirichlet += timer_dirichlet.
elapsed();
224 sys.preIteration(iteration, x_new_process);
227 time_assembly.
start();
228 if (!assembledOnAllRanks([&]
229 { sys.assemble(x_new, x_prev, process_id); }))
231 error_norms_met =
false;
235 sys.getRhs(*x_prev[process_id], rhs);
238 if (sys.requiresNormalization() &&
241 sys.getAandRhsNormalized(A, rhs);
243 "The equation system is rectangular, but the current linear "
244 "solver only supports square systems. "
245 "The system will be normalized, which lead to a squared "
246 "condition number and potential numerical issues. "
247 "It is recommended to use a solver that supports rectangular "
248 "equation systems for better numerical stability.");
251 INFO(
"[time] Assembly took {:g} s.", time_assembly.
elapsed());
259 auto const solver_needs_to_compute = sys.linearSolverNeedsToCompute();
260 bool const solver_will_compute =
263 timer_dirichlet.
start();
264 sys.applyKnownSolutionsPicard(
265 A, rhs, x_new_process,
269 FAST_INCOMPLETE_MATRIX_UPDATE);
270 time_dirichlet += timer_dirichlet.
elapsed();
271 INFO(
"[time] Applying Dirichlet BCs took {:g} s.", time_dirichlet);
275 if (!solver_will_compute)
281 "Logic error. The solver skips the compute step for a "
282 "non-linear equation system.");
293 if (iteration_succeeded)
309 anderson.
accelerate(*x[process_id], x_new_process);
311 if (postIterationCallback)
313 postIterationCallback(iteration, x_new);
316 switch (sys.postIteration(x_new_process))
323 ERR(
"Picard: The postIteration() hook reported a "
324 "non-recoverable error.");
325 iteration_succeeded =
false;
333 "Picard: The postIteration() hook decided that this "
334 "iteration has to be repeated.");
343 if (!iteration_succeeded)
346 error_norms_met =
false;
352 error_norms_met =
true;
371 INFO(
"[time] Iteration #{:d} took {:g} s.", iteration,
389 ERR(
"Picard: Could not solve the given nonlinear system within {:d} "
398 return {error_norms_met, iteration};
403 std::vector<GlobalVector*>
const& x,
404 std::vector<GlobalVector*>
const& x_prev,
int const process_id)
411 INFO(
"Calculate non-equilibrium initial residuum.");
420 auto selected_global_indices =
426 auto const global_size =
_r_neq->size();
427 for (
auto& idx : selected_global_indices)
429 if (idx == global_size)
436 std::vector<double> zero_entries(selected_global_indices.size(), 0.0);
437 _r_neq->set(selected_global_indices, zero_entries);
444 std::vector<GlobalVector*>& x,
445 std::vector<GlobalVector*>
const& x_prev,
446 std::function<
void(
int, std::vector<GlobalVector*>
const&)>
const&
447 postIterationCallback,
448 int const process_id)
454 auto& minus_delta_x =
458 bool error_norms_met =
false;
469#if !defined(USE_PETSC) && !defined(USE_LIS)
470 int next_iteration_inv_jacobian_recompute = 1;
475 double time_dirichlet = 0.0;
478 INFO(
"Iteration #{:d} started.", iteration);
479 time_iteration.
start();
481 timer_dirichlet.
start();
482 sys.computeKnownSolutions(*x[process_id], process_id);
483 time_dirichlet += timer_dirichlet.
elapsed();
485 sys.preIteration(iteration, *x[process_id]);
488 time_assembly.
start();
489 if (!assembledOnAllRanks([&] { sys.assemble(x, x_prev, process_id); }))
491 error_norms_met =
false;
494 sys.getResidual(*x[process_id], *x_prev[process_id], res);
500 INFO(
"[time] Assembly took {:g} s.", time_assembly.
elapsed());
508 minus_delta_x.setZero();
510 timer_dirichlet.
start();
511 sys.applyKnownSolutionsNewton(J, res, *x[process_id], minus_delta_x);
512 time_dirichlet += timer_dirichlet.
elapsed();
513 INFO(
"[time] Applying Dirichlet BCs took {:g} s.", time_dirichlet);
521 time_linear_solver.
start();
522#if !defined(USE_PETSC) && !defined(USE_LIS)
524 if (iteration == next_iteration_inv_jacobian_recompute)
526 linear_solver_behaviour =
528 next_iteration_inv_jacobian_recompute =
537 linear_solver_behaviour =
541 bool iteration_succeeded =
false;
544 ERR(
"Newton: The linear solver failed in the compute() step.");
551 bool iteration_succeeded =
_linear_solver.solve(J, res, minus_delta_x);
553 INFO(
"[time] Linear solver took {:g} s.", time_linear_solver.
elapsed());
555 if (!iteration_succeeded)
557 ERR(
"Newton: The linear solver failed.");
566 std::vector<GlobalVector*> x_new{x};
571 *x[process_id], minus_delta_x, res, J, *x_new[process_id],
572 step_ctx, iteration);
574 if (step_result.step_length != 1.0)
576 INFO(
"Step length: {:g}", step_result.step_length);
579 if (!step_result.success)
581 ERR(
"Newton: step strategy failed.");
582 iteration_succeeded =
false;
584 else if (!step_result.x_new_is_set)
589 if (postIterationCallback)
591 postIterationCallback(iteration, x_new);
594 switch (sys.postIteration(*x_new[process_id]))
599 ERR(
"Newton: The postIteration() hook reported a "
600 "non-recoverable error.");
601 iteration_succeeded =
false;
605 "Newton: The postIteration() hook decided that this "
606 "iteration has to be repeated.");
619 if (!iteration_succeeded)
622 error_norms_met =
false;
628 error_norms_met =
true;
642 INFO(
"[time] Iteration #{:d} took {:g} s.", iteration,
660 ERR(
"Newton: Could not solve the given nonlinear system within {:d} "
669 return {error_norms_met, iteration};
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)
double elapsed() const
Get the elapsed time in seconds.
void start()
Start the timer.
bool solve(EigenMatrix &A, EigenVector &b, EigenVector &x)
void accelerate(GlobalVector const &x_old, GlobalVector &x_new)
static constexpr int min_mixing_depth
GlobalLinearSolver & _linear_solver
ConvergenceCriterion * _convergence_criterion
Convergence criterion used to terminate the Newton iteration.
bool _compensate_non_equilibrium_initial_residuum
double _tikhonov_lambda
Tikhonov regularization parameter.
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.
int const _maxiter
maximum number of iterations
int const _recompute_jacobian
Recompute Jacobian every this many steps.
std::unique_ptr< NewtonStepStrategy > _step_strategy
Globalization / step-acceptance strategy (e.g. fixed damping).
NonlinearSolver(GlobalLinearSolver &linear_solver, int const maxiter, std::unique_ptr< NewtonStepStrategy > newton_strategy, int const recompute_jacobian=1)
int _tikhonov_starting_iteration
Starting iteration for Tikhonov regularization.
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
GlobalVector * _r_neq
non-equilibrium initial residuum.
NonlinearSolver(GlobalLinearSolver &linear_solver, int const maxiter, int const anderson_depth, double const damping)
GlobalLinearSolver & _linear_solver
int const _maxiter
maximum number of iterations
int const _anderson_depth
System * _equation_system
std::size_t _A_id
ID of the matrix.
ConvergenceCriterion * _convergence_criterion
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 scale(PETScVector &x, PetscScalar const a)
void axpy(PETScVector &y, PetscScalar const a, PETScVector const &x)
DirichletBCApplicationMode
@ COMPLETE_MATRIX_UPDATE
Both A and b fully updated.
bool assembledOnAllRanks(Assemble const &assemble)
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.