23#if !defined(USE_PETSC) && !defined(USE_LIS)
28 BaseLib::RunTime time_linear_solver;
29 time_linear_solver.
start();
31 if (!linear_solver.compute(A, linear_solver_behaviour))
33 ERR(
"Picard: The linear solver failed in the compute() step.");
37 bool const iteration_succeeded = linear_solver.
solve(rhs, x);
39 INFO(
"[time] Linear solver took {:g} s.", time_linear_solver.
elapsed());
41 if (iteration_succeeded)
46 ERR(
"Picard: The linear solver failed in the solve() step.");
54 if (linear_solver_behaviour ==
59 "The performance optimization to skip the linear solver compute() "
60 "step is not implemented for PETSc or LIS linear solvers.");
64 time_linear_solver.
start();
66 bool const iteration_succeeded = linear_solver.
solve(A, rhs, x);
68 INFO(
"[time] Linear solver took {:g} s.", time_linear_solver.
elapsed());
70 if (iteration_succeeded)
75 ERR(
"Picard: The linear solver failed in the solve() step.");
83 std::vector<GlobalVector*>
const& x,
84 std::vector<GlobalVector*>
const& x_prev,
int const process_id)
91 INFO(
"Calculate non-equilibrium initial residuum.");
107 auto selected_global_indices =
113 auto const global_size =
_r_neq->size();
114 for (
auto& idx : selected_global_indices)
116 if (idx == global_size)
123 std::vector<double> zero_entries(selected_global_indices.size(), 0.0);
124 _r_neq->set(selected_global_indices, zero_entries);
134 std::vector<GlobalVector*>& x,
135 std::vector<GlobalVector*>
const& x_prev,
136 std::function<
void(
int,
bool, std::vector<GlobalVector*>
const&)>
const&
137 postIterationCallback,
138 int const process_id)
146 std::vector<GlobalVector*> x_new{x};
151 bool error_norms_met =
false;
159 double time_dirichlet = 0.0;
162 time_iteration.
start();
164 INFO(
"Iteration #{:d} started.", iteration);
165 timer_dirichlet.
start();
166 auto& x_new_process = *x_new[process_id];
168 sys.computeKnownSolutions(x_new_process, process_id);
169 sys.applyKnownSolutions(x_new_process);
170 time_dirichlet += timer_dirichlet.
elapsed();
172 sys.preIteration(iteration, x_new_process);
175 time_assembly.
start();
176 sys.assemble(x_new, x_prev, process_id);
178 sys.getRhs(*x_prev[process_id], rhs);
181 if (sys.requiresNormalization() &&
184 sys.getAandRhsNormalized(A, rhs);
186 "The equation system is rectangular, but the current linear "
187 "solver only supports square systems. "
188 "The system will be normalized, which lead to a squared "
189 "condition number and potential numerical issues. "
190 "It is recommended to use a solver that supports rectangular "
191 "equation systems for better numerical stability.");
194 INFO(
"[time] Assembly took {:g} s.", time_assembly.
elapsed());
202 auto const solver_needs_to_compute = sys.linearSolverNeedsToCompute();
203 bool const solver_will_compute =
206 timer_dirichlet.
start();
207 sys.applyKnownSolutionsPicard(
208 A, rhs, x_new_process,
212 FAST_INCOMPLETE_MATRIX_UPDATE);
213 time_dirichlet += timer_dirichlet.
elapsed();
214 INFO(
"[time] Applying Dirichlet BCs took {:g} s.", time_dirichlet);
218 if (!solver_will_compute)
224 "Logic error. The solver skips the compute step for a "
225 "non-linear equation system.");
236 if (iteration_succeeded)
238 if (postIterationCallback)
240 postIterationCallback(iteration, error_norms_met, x_new);
243 switch (sys.postIteration(x_new_process))
250 ERR(
"Picard: The postIteration() hook reported a "
251 "non-recoverable error.");
252 iteration_succeeded =
false;
260 "Picard: The postIteration() hook decided that this "
261 "iteration has to be repeated.");
269 if (!iteration_succeeded)
272 error_norms_met =
false;
278 error_norms_met =
true;
297 INFO(
"[time] Iteration #{:d} took {:g} s.", iteration,
315 ERR(
"Picard: Could not solve the given nonlinear system within {:d} "
324 return {error_norms_met, iteration};
329 std::vector<GlobalVector*>
const& x,
330 std::vector<GlobalVector*>
const& x_prev,
int const process_id)
337 INFO(
"Calculate non-equilibrium initial residuum.");
346 auto selected_global_indices =
352 auto const global_size =
_r_neq->size();
353 for (
auto& idx : selected_global_indices)
355 if (idx == global_size)
362 std::vector<double> zero_entries(selected_global_indices.size(), 0.0);
363 _r_neq->set(selected_global_indices, zero_entries);
370 std::vector<GlobalVector*>& x,
371 std::vector<GlobalVector*>
const& x_prev,
372 std::function<
void(
int,
bool, std::vector<GlobalVector*>
const&)>
const&
373 postIterationCallback,
374 int const process_id)
380 auto& minus_delta_x =
384 bool error_norms_met =
false;
395#if !defined(USE_PETSC) && !defined(USE_LIS)
396 int next_iteration_inv_jacobian_recompute = 1;
401 double time_dirichlet = 0.0;
404 INFO(
"Iteration #{:d} started.", iteration);
405 time_iteration.
start();
407 timer_dirichlet.
start();
408 sys.computeKnownSolutions(*x[process_id], process_id);
409 time_dirichlet += timer_dirichlet.
elapsed();
411 sys.preIteration(iteration, *x[process_id]);
414 time_assembly.
start();
415 bool mpi_rank_assembly_ok =
true;
418 sys.assemble(x, x_prev, process_id);
422 ERR(
"Abort nonlinear iteration. Repeating timestep. Reason: {:s}",
424 error_norms_met =
false;
426 mpi_rank_assembly_ok =
false;
432 sys.getResidual(*x[process_id], *x_prev[process_id], res);
434 INFO(
"[time] Assembly took {:g} s.", time_assembly.
elapsed());
442 minus_delta_x.setZero();
444 timer_dirichlet.
start();
445 sys.applyKnownSolutionsNewton(J, res, *x[process_id], minus_delta_x);
446 time_dirichlet += timer_dirichlet.
elapsed();
447 INFO(
"[time] Applying Dirichlet BCs took {:g} s.", time_dirichlet);
455 time_linear_solver.
start();
456#if !defined(USE_PETSC) && !defined(USE_LIS)
458 if (iteration == next_iteration_inv_jacobian_recompute)
460 linear_solver_behaviour =
462 next_iteration_inv_jacobian_recompute =
466 bool iteration_succeeded =
false;
469 ERR(
"Newton: The linear solver failed in the compute() step.");
476 bool iteration_succeeded =
_linear_solver.solve(J, res, minus_delta_x);
478 INFO(
"[time] Linear solver took {:g} s.", time_linear_solver.
elapsed());
480 if (!iteration_succeeded)
482 ERR(
"Newton: The linear solver failed.");
491 std::vector<GlobalVector*> x_new{x};
496 *x[process_id], minus_delta_x, res, J, *x_new[process_id],
497 step_ctx, iteration);
499 if (step_result.step_length != 1.0)
501 INFO(
"Step length: {:g}", step_result.step_length);
504 if (!step_result.success)
506 ERR(
"Newton: step strategy failed.");
507 iteration_succeeded =
false;
509 else if (!step_result.x_new_is_set)
514 if (postIterationCallback)
516 postIterationCallback(iteration, error_norms_met, x_new);
519 switch (sys.postIteration(*x_new[process_id]))
524 ERR(
"Newton: The postIteration() hook reported a "
525 "non-recoverable error.");
526 iteration_succeeded =
false;
530 "Newton: The postIteration() hook decided that this "
531 "iteration has to be repeated.");
544 if (!iteration_succeeded)
547 error_norms_met =
false;
553 error_norms_met =
true;
567 INFO(
"[time] Iteration #{:d} took {:g} s.", iteration,
585 ERR(
"Newton: Could not solve the given nonlinear system within {:d} "
594 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)
GlobalLinearSolver & _linear_solver
ConvergenceCriterion * _convergence_criterion
Convergence criterion used to terminate the Newton iteration.
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.
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)
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
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.