OGS
NumLib::NonlinearSolver< NonlinearSolverTag::Picard > Class Referencefinal

Detailed Description

Find a solution to a nonlinear equation using the Picard fixpoint iteration method.

Notation used throughout this class and its documentation: \( x_k \) is the current iterate and \( g \) is the Picard fixpoint map, i.e. \( g(x_k) \) is the solution of the linearized system \( A(x_k)\,x = b(x_k) \) (the result of one linear solve). A converged iteration is a fixpoint \( x = g(x) \), and one iteration reads \( x_{k+1} = g(x_k) \).

With an under-relaxation (damping) coefficient \( \beta \in (0, 1] \) the iteration becomes \( x_{k+1} = (1-\beta)\,x_k + \beta\,g(x_k) \); the value \( \beta = 1 \) recovers the plain Picard update above.

Definition at line 186 of file NonlinearSolver.h.

#include <NonlinearSolver.h>

Inheritance diagram for NumLib::NonlinearSolver< NonlinearSolverTag::Picard >:
[legend]
Collaboration diagram for NumLib::NonlinearSolver< NonlinearSolverTag::Picard >:
[legend]

Public Types

using System = NonlinearSystem<NonlinearSolverTag::Picard>
 Type of the nonlinear equation system to be solved.

Public Member Functions

 NonlinearSolver (GlobalLinearSolver &linear_solver, const int maxiter, const double damping)
 ~NonlinearSolver ()
void setEquationSystem (System &eq, ConvergenceCriterion &conv_crit)
void calculateNonEquilibriumInitialResiduum (std::vector< GlobalVector * > const &x, std::vector< GlobalVector * > const &x_prev, int const process_id) override
NonlinearSolverStatus solve (std::vector< GlobalVector * > &x, std::vector< GlobalVector * > const &x_prev, std::function< void(int, bool, std::vector< GlobalVector * > const &)> const &postIterationCallback, int const process_id) override
void compensateNonEquilibriumInitialResiduum (bool const value)
Public Member Functions inherited from NumLib::NonlinearSolverBase
virtual ~NonlinearSolverBase ()=default

Private Attributes

GlobalLinearSolver_linear_solver
System_equation_system = nullptr
ConvergenceCriterion_convergence_criterion = nullptr
double const _damping
const int _maxiter
 maximum number of iterations
GlobalVector_r_neq = nullptr
 non-equilibrium initial residuum.
std::size_t _A_id = 0u
 ID of the \( A \) matrix.
std::size_t _rhs_id = 0u
 ID of the right-hand side vector.
std::size_t _x_new_id = 0u
std::size_t _r_neq_id = 0u
bool _compensate_non_equilibrium_initial_residuum = false

Member Typedef Documentation

◆ System

Type of the nonlinear equation system to be solved.

Definition at line 191 of file NonlinearSolver.h.

Constructor & Destructor Documentation

◆ NonlinearSolver()

NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::NonlinearSolver ( GlobalLinearSolver & linear_solver,
const int maxiter,
const double damping )
inlineexplicit

Constructs a new instance.

Parameters
linear_solverthe linear solver used by this nonlinear solver.
maxiterthe maximum number of iterations used to solve the equation.
dampingunder-relaxation coefficient \( \beta \in (0, 1] \) applied to the Picard update (see class description); \( \beta = 1 \) disables damping.

Definition at line 202 of file NonlinearSolver.h.

References _damping, _linear_solver, and _maxiter.

Referenced by ~NonlinearSolver(), calculateNonEquilibriumInitialResiduum(), and solve().

◆ ~NonlinearSolver()

Definition at line 632 of file NonlinearSolver.cpp.

633{
634 if (_r_neq != nullptr)
635 {
637 }
638}
GlobalVector * _r_neq
non-equilibrium initial residuum.

References NonlinearSolver(), _r_neq, and NumLib::GlobalVectorProvider::provider.

Member Function Documentation

◆ calculateNonEquilibriumInitialResiduum()

void NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::calculateNonEquilibriumInitialResiduum ( std::vector< GlobalVector * > const & x,
std::vector< GlobalVector * > const & x_prev,
int const process_id )
overridevirtual

Implements NumLib::NonlinearSolverBase.

Definition at line 81 of file NonlinearSolver.cpp.

85{
87 {
88 return;
89 }
90
91 INFO("Calculate non-equilibrium initial residuum.");
92
96 _equation_system->getA(A);
98
99 // r_neq = A * x - rhs
102 MathLib::LinAlg::axpy(*_r_neq, -1.0, rhs); // res -= rhs
103
104 // Set the values of the selected entries of _r_neq, which are associated
105 // with the equations that do not need initial residual compensation, to
106 // zero.
108 _equation_system->getIndicesOfResiduumWithoutInitialCompensation();
109
110#ifdef USE_PETSC
111 // Ghost entry with global index 0 is encoded as -global_size
112 // After abs(), it appears as global_size and must be converted back to 0
113 auto const global_size = _r_neq->size();
114 for (auto& idx : selected_global_indices)
115 {
116 if (idx == global_size)
117 {
118 idx = 0;
119 }
120 }
121#endif
122
125 _equation_system->setReleaseNodalForces(_r_neq, process_id);
126
128
131}
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
std::size_t _rhs_id
ID of the right-hand side vector.
void finalizeAssembly(PETScMatrix &A)
Definition LinAlg.cpp:191
void matMult(PETScMatrix const &A, PETScVector const &x, PETScVector &y)
Definition LinAlg.cpp:142
void axpy(PETScVector &y, PetscScalar const a, PETScVector const &x)
Definition LinAlg.cpp:50

References NonlinearSolver(), _A_id, _compensate_non_equilibrium_initial_residuum, _equation_system, _r_neq, _r_neq_id, _rhs_id, MathLib::LinAlg::axpy(), MathLib::LinAlg::finalizeAssembly(), INFO(), MathLib::LinAlg::matMult(), NumLib::GlobalMatrixProvider::provider, and NumLib::GlobalVectorProvider::provider.

◆ compensateNonEquilibriumInitialResiduum()

void NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::compensateNonEquilibriumInitialResiduum ( bool const value)
inline

◆ setEquationSystem()

void NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::setEquationSystem ( System & eq,
ConvergenceCriterion & conv_crit )
inline

Set the nonlinear equation system that will be solved. TODO doc

Definition at line 212 of file NonlinearSolver.h.

References _convergence_criterion, and _equation_system.

◆ solve()

NonlinearSolverStatus NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::solve ( std::vector< GlobalVector * > & x,
std::vector< GlobalVector * > const & x_prev,
std::function< void(int, bool, std::vector< GlobalVector * > const &)> const & postIterationCallback,
int const process_id )
overridevirtual

Assemble and solve the equation system.

Parameters
xin: the initial guess, out: the solution.
x_prevprevious time step solution.
postIterationCallbackcalled after each iteration if set.
process_idusually used in staggered schemes.
Return values
trueif the equation system could be solved
falseotherwise

Implements NumLib::NonlinearSolverBase.

Definition at line 133 of file NonlinearSolver.cpp.

139{
140 namespace LinAlg = MathLib::LinAlg;
141 auto& sys = *_equation_system;
142
143 if (_damping != 1.0 && sys.isLinear())
144 {
145 OGS_FATAL(
146 "Damping (under-relaxation) is not compatible with a linear "
147 "equation system: a single Picard step already yields the exact "
148 "solution, so the damped iterate would be accepted as converged "
149 "but wrong. Remove the 'damping' parameter for linear problems.");
150 }
151
154
158 LinAlg::copy(*x[process_id], *x_new[process_id]); // set initial guess
159
160 bool error_norms_met = false;
161
162 _convergence_criterion->preFirstIteration();
163
164 int iteration = 1;
165 for (; iteration <= _maxiter; ++iteration, _convergence_criterion->reset())
166 {
168 double time_dirichlet = 0.0;
169
171 time_iteration.start();
172
173 INFO("Iteration #{:d} started.", iteration);
174 timer_dirichlet.start();
177 sys.computeKnownSolutions(x_new_process, process_id);
178 sys.applyKnownSolutions(x_new_process);
179 time_dirichlet += timer_dirichlet.elapsed();
180
181 sys.preIteration(iteration, x_new_process);
182
184 time_assembly.start();
185 sys.assemble(x_new, x_prev, process_id);
186 sys.getA(A);
187 sys.getRhs(*x_prev[process_id], rhs);
188
189 // Normalize the linear equation system, if required
190 if (sys.requiresNormalization() &&
191 !_linear_solver.canSolveRectangular())
192 {
193 sys.getAandRhsNormalized(A, rhs);
194 WARN(
195 "The equation system is rectangular, but the current linear "
196 "solver only supports square systems. "
197 "The system will be normalized, which lead to a squared "
198 "condition number and potential numerical issues. "
199 "It is recommended to use a solver that supports rectangular "
200 "equation systems for better numerical stability.");
201 }
202
203 INFO("[time] Assembly took {:g} s.", time_assembly.elapsed());
204
205 // Subtract non-equilibrium initial residuum if set
206 if (_r_neq != nullptr)
207 {
208 LinAlg::axpy(rhs, -1, *_r_neq);
209 }
210
211 auto const solver_needs_to_compute = sys.linearSolverNeedsToCompute();
212 bool const solver_will_compute =
214
215 timer_dirichlet.start();
216 sys.applyKnownSolutionsPicard(
222 time_dirichlet += timer_dirichlet.elapsed();
223 INFO("[time] Applying Dirichlet BCs took {:g} s.", time_dirichlet);
224
225 if (!sys.isLinear() && _convergence_criterion->hasResidualCheck())
226 {
228 {
229 // !solver_will_compute means that the Dirichlet BC application
230 // is incomplete (i.e., A not properly modified) and the
231 // computed residual is wrong.
232 OGS_FATAL(
233 "Logic error. The solver skips the compute step for a "
234 "non-linear equation system.");
235 }
237 LinAlg::matMult(A, x_new_process, res); // res = A * x_new
238 LinAlg::axpy(res, -1.0, rhs); // res -= rhs
239 _convergence_criterion->checkResidual(res);
240 }
241
244
246 {
247 // Notation (see NonlinearSolver<Picard> class doc):
248 // x_k = x[process_id] (iterate entering this step)
249 // g(x_k) = x_new_process (raw Picard output, this linear
250 // solve)
251 // Under-relaxation with damping beta (active when beta != 1):
252 // x_{k+1} = x_k + beta*(g(x_k) - x_k)
253 // = (1-beta)*x_k + beta*g(x_k)
254 if (_damping != 1.0)
255 {
258 }
259
261 {
263 }
264
265 switch (sys.postIteration(x_new_process))
266 {
268 // Don't copy here. The old x might still be used further
269 // below. Although currently it is not.
270 break;
272 ERR("Picard: The postIteration() hook reported a "
273 "non-recoverable error.");
274 iteration_succeeded = false;
275 // Copy new solution to x.
276 // Thereby the failed solution can be used by the caller for
277 // debugging purposes.
279 break;
281 INFO(
282 "Picard: The postIteration() hook decided that this "
283 "iteration has to be repeated.");
285 *x[process_id],
286 x_new_process); // throw the iteration result away
287 continue;
288 }
289 }
290
292 {
293 // Don't compute error norms, break here.
294 error_norms_met = false;
295 break;
296 }
297
298 if (sys.isLinear())
299 {
300 error_norms_met = true;
301 }
302 else
303 {
304 if (_convergence_criterion->hasDeltaXCheck())
305 {
308 x_new_process); // minus_delta_x = x - x_new
311 }
312
314 }
315
316 // Update x s.t. in the next iteration we will compute the right delta x
318
319 INFO("[time] Iteration #{:d} took {:g} s.", iteration,
320 time_iteration.elapsed());
321
322 if (error_norms_met)
323 {
324 break;
325 }
326
327 // Avoid increment of the 'iteration' if the error norms are not met,
328 // but maximum number of iterations is reached.
329 if (iteration >= _maxiter)
330 {
331 break;
332 }
333 }
334
335 if (iteration > _maxiter)
336 {
337 ERR("Picard: Could not solve the given nonlinear system within {:d} "
338 "iterations",
339 _maxiter);
340 }
341
345
346 return {error_norms_met, iteration};
347}
#define OGS_FATAL(...)
Definition Error.h:21
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
void copy(PETScVector const &x, PETScVector &y)
Definition LinAlg.cpp:30
void setLocalAccessibleVector(PETScVector const &x)
Definition LinAlg.cpp:20
void scale(PETScVector &x, PetscScalar const a)
Definition LinAlg.cpp:37
bool solvePicard(GlobalLinearSolver &linear_solver, GlobalMatrix &A, GlobalVector &rhs, GlobalVector &x, MathLib::LinearSolverBehaviour const linear_solver_behaviour)

References NonlinearSolver(), _A_id, _convergence_criterion, _damping, _equation_system, _linear_solver, _maxiter, _r_neq, _rhs_id, _x_new_id, MathLib::LinAlg::axpy(), MathLib::COMPLETE_MATRIX_UPDATE, MathLib::LinAlg::copy(), BaseLib::RunTime::elapsed(), ERR(), NumLib::FAILURE, INFO(), MathLib::LinAlg::matMult(), OGS_FATAL, NumLib::GlobalMatrixProvider::provider, NumLib::GlobalVectorProvider::provider, NumLib::REPEAT_ITERATION, MathLib::LinAlg::scale(), MathLib::LinAlg::setLocalAccessibleVector(), NumLib::detail::solvePicard(), BaseLib::RunTime::start(), NumLib::SUCCESS, and WARN().

Member Data Documentation

◆ _A_id

std::size_t NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::_A_id = 0u
private

ID of the \( A \) matrix.

Definition at line 250 of file NonlinearSolver.h.

Referenced by calculateNonEquilibriumInitialResiduum(), and solve().

◆ _compensate_non_equilibrium_initial_residuum

bool NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::_compensate_non_equilibrium_initial_residuum = false
private

Enables computation of the non-equilibrium initial residuum \( r_{\rm neq} \) before the first time step. The forces are zero if the external forces are in equilibrium with the initial state/initial conditions. During the simulation the new residuum reads \( \tilde r = r - r_{\rm neq} \).

Definition at line 259 of file NonlinearSolver.h.

Referenced by calculateNonEquilibriumInitialResiduum(), and compensateNonEquilibriumInitialResiduum().

◆ _convergence_criterion

ConvergenceCriterion* NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::_convergence_criterion = nullptr
private

Definition at line 240 of file NonlinearSolver.h.

Referenced by setEquationSystem(), and solve().

◆ _damping

double const NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::_damping
private

Under-relaxation (damping) coefficient beta in (0, 1] applied to the Picard update x_{k+1} = (1-beta)*x_k + beta*g(x_k); 1.0 disables damping.

Definition at line 245 of file NonlinearSolver.h.

Referenced by NonlinearSolver(), and solve().

◆ _equation_system

System* NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::_equation_system = nullptr
private

◆ _linear_solver

Definition at line 236 of file NonlinearSolver.h.

Referenced by NonlinearSolver(), and solve().

◆ _maxiter

const int NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::_maxiter
private

maximum number of iterations

Definition at line 247 of file NonlinearSolver.h.

Referenced by NonlinearSolver(), and solve().

◆ _r_neq

non-equilibrium initial residuum.

Definition at line 249 of file NonlinearSolver.h.

Referenced by ~NonlinearSolver(), calculateNonEquilibriumInitialResiduum(), and solve().

◆ _r_neq_id

std::size_t NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::_r_neq_id = 0u
private

ID of the non-equilibrium initial residuum vector.

Definition at line 254 of file NonlinearSolver.h.

Referenced by calculateNonEquilibriumInitialResiduum().

◆ _rhs_id

std::size_t NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::_rhs_id = 0u
private

ID of the right-hand side vector.

Definition at line 251 of file NonlinearSolver.h.

Referenced by calculateNonEquilibriumInitialResiduum(), and solve().

◆ _x_new_id

std::size_t NumLib::NonlinearSolver< NonlinearSolverTag::Picard >::_x_new_id = 0u
private

ID of the vector storing the solution of the linearized equation.

Definition at line 252 of file NonlinearSolver.h.

Referenced by solve().


The documentation for this class was generated from the following files: