OGS
PETScNonlinearSolver.cpp
Go to the documentation of this file.
1
11#ifdef USE_PETSC
12
14
15#include <petscmat.h>
16#include <petscvec.h>
17#include <spdlog/fmt/bundled/core.h>
18
19#include "BaseLib/RunTime.h"
20
21template <>
22struct fmt::formatter<SNESConvergedReason>
23{
24 constexpr auto parse(format_parse_context& ctx) { return ctx.end(); }
25
26 template <typename FormatContext>
27 auto format(SNESConvergedReason const reason, FormatContext& ctx)
28 {
29 if (reason < 0)
30 {
31 return fmt::format_to(ctx.out(), "DIVERGED: {}",
32 SNESConvergedReasons[-reason]);
33 }
34 return fmt::format_to(ctx.out(), "CONVERGED: {}",
35 SNESConvergedReasons[reason]);
36 }
37};
38
39namespace
40{
42{
45 std::vector<GlobalVector*>& x;
46 std::vector<GlobalVector*> const& x_prev;
49 int const process_id;
50};
51
52PetscErrorCode updateResidual(SNES /*snes*/, Vec x, Vec petsc_r,
53 void* petsc_context)
54{
55 auto context = static_cast<PetscContext*>(petsc_context);
56
57 DBUG("PETScNonlinearSolver: residual callback called.");
58
59 VecCopy(x, context->x[context->process_id]->getRawVector());
60
61 // Assemble in ogs context.
62 BaseLib::RunTime time_assembly;
63 time_assembly.start();
64 context->system->assemble(context->x, context->x_prev, context->process_id);
65
66 INFO("[time] Assembly took {} s.", time_assembly.elapsed());
67 context->system->getResidual(*context->x[context->process_id],
68 *context->x_prev[context->process_id],
69 *context->r);
70 context->r->finalizeAssembly();
71 context->J->finalizeAssembly();
72
73 context->system->getJacobian(*context->J);
74 context->system->applyKnownSolutionsNewton(
75 *context->J, *context->r, *context->x[context->process_id]);
76
77 VecCopy(context->r->getRawVector(), petsc_r);
78
79 return 0;
80}
81
82PetscErrorCode updateJacobian(SNES /*snes*/, Vec /*x*/, Mat J,
83 Mat /*same as J*/, void* petsc_context)
84{
85 DBUG("PETScNonlinearSolver: jacobian callback called.");
86 // Assume the system is already assembled.
87 // Copy the results into petsc vectors.
88
89 auto context = static_cast<PetscContext*>(petsc_context);
90 MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY);
91 MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY);
92 MatCopy(context->J->getRawMatrix(), J, DIFFERENT_NONZERO_PATTERN);
93 return 0;
94}
95} // namespace
96
97namespace NumLib
98{
100 GlobalLinearSolver& /*linear_solver*/, int const maxiter,
101 std::string prefix)
102{
103 SNESCreate(PETSC_COMM_WORLD, &_snes_solver);
104 if (!prefix.empty())
105 {
106 prefix = prefix + "_";
107 SNESSetOptionsPrefix(_snes_solver, prefix.c_str());
108 }
109 // force SNESSolve() to take at least one iteration regardless of the
110 // initial residual norm
111 SNESSetForceIteration(_snes_solver, PETSC_TRUE);
112
113 // Set the maximum iterations.
114 PetscReal atol, rtol, stol;
115 PetscInt maxf;
116 SNESGetTolerances(_snes_solver, &atol, &rtol, &stol, nullptr, &maxf);
117 SNESSetTolerances(_snes_solver, atol, rtol, stol, maxiter, maxf);
118
119 SNESSetFromOptions(_snes_solver);
120#ifndef NDEBUG
121 PetscOptionsView(nullptr, PETSC_VIEWER_STDOUT_WORLD);
122#endif // NDEBUG
123}
124
126 ConvergenceCriterion& conv_crit)
127{
128 _equation_system = &eq;
129 _convergence_criterion = &conv_crit;
130}
131
133 bool const value)
134{
136}
137
139 std::vector<GlobalVector*> const& /*x*/,
140 std::vector<GlobalVector*> const& /*x_prev*/, int const /*process_id*/)
141{
143 {
144 return;
145 }
146
147 OGS_FATAL(
148 "Non-equilibrium initial residuum is not implemented for the "
149 "PETScNonlinearSolver.");
150}
151
153 std::vector<GlobalVector*>& x,
154 std::vector<GlobalVector*> const& x_prev,
155 std::function<void(
156 int,
157 std::vector<GlobalVector*> const&)> const& /*postIterationCallback*/,
158 int const process_id)
159{
160 DBUG("PETScNonlinearSolver: solve()");
161 using TimeDiscretizedSystem =
164
165 auto* system = static_cast<TimeDiscretizedSystem*>(_equation_system);
166
167 DBUG("PETScNonlinearSolver: create vectors");
168 // r and J on which the ogs assembly operates.
170 system->getMatrixSpecifications(process_id), _jacobian_id);
172 system->getMatrixSpecifications(process_id), _residual_id);
173
174 // Vectors and matrices used by SNES for solutions. These will be locked
175 // during the SNES' solve call.
177 system->getMatrixSpecifications(process_id), _petsc_jacobian_id);
178 BaseLib::RunTime timer_dirichlet;
179 double time_dirichlet = 0.0;
180
181 timer_dirichlet.start();
182 system->computeKnownSolutions(*x[process_id], process_id);
183 system->applyKnownSolutions(*x[process_id]);
184 time_dirichlet += timer_dirichlet.elapsed();
185 INFO("[time] Applying Dirichlet BCs took {} s.", time_dirichlet);
186
188 system->getMatrixSpecifications(process_id), _petsc_residual_id);
190 system->getMatrixSpecifications(process_id), _petsc_x_id);
191 MathLib::LinAlg::copy(*x[process_id], x_snes); // Initial guess.
192
193 PetscContext petsc_context{_equation_system, x, x_prev, &r, &J, process_id};
194
195 DBUG("PETScNonlinearSolver: set function");
196 SNESSetFunction(_snes_solver, r_snes.getRawVector(), updateResidual,
197 &petsc_context);
198
199 DBUG("PETScNonlinearSolver: set jacobian");
200 // The jacobian and the preconditioner matrices point to the same location.
201 SNESSetJacobian(_snes_solver, J_snes.getRawMatrix(), J_snes.getRawMatrix(),
202 updateJacobian, &petsc_context);
203
204 std::unique_ptr<GlobalVector> xl = nullptr;
205 std::unique_ptr<GlobalVector> xu = nullptr;
206
207 SNESType snes_type;
208 SNESGetType(_snes_solver, &snes_type);
209 if ((std::strcmp(snes_type, SNESVINEWTONRSLS) == 0) ||
210 (std::strcmp(snes_type, SNESVINEWTONSSLS) == 0))
211 {
212 // Set optional constraints via callback.
213 DBUG("PETScNonlinearSolver: set constraints");
215 system->getMatrixSpecifications(process_id));
217 system->getMatrixSpecifications(process_id));
218
219 system->updateConstraints(*xl, *xu, process_id);
222
223 SNESVISetVariableBounds(_snes_solver, xl->getRawVector(),
224 xu->getRawVector());
225 }
226
227 DBUG("PETScNonlinearSolver: call SNESSolve");
228 SNESSolve(_snes_solver, nullptr, x_snes.getRawVector());
229
230 SNESConvergedReason reason = SNES_CONVERGED_ITERATING;
231 SNESGetConvergedReason(_snes_solver, &reason);
232 INFO("PETSsSNES convergence reason {}.", reason);
233
234 PetscInt iterations;
235 SNESGetIterationNumber(_snes_solver, &iterations);
236 INFO("PETScSNES used {} iterations.", iterations);
237
238 // Copy back the solution.
239 MathLib::LinAlg::copy(x_snes, *x[process_id]);
240
246
247 return {reason >= 0, iterations};
248}
249
250} // namespace NumLib
251#endif // USE_PETSC
#define OGS_FATAL(...)
Definition: Error.h:26
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:35
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:30
Definition of the RunTime class.
Count the running time.
Definition: RunTime.h:29
double elapsed() const
Get the elapsed time in seconds.
Definition: RunTime.h:42
void start()
Start the timer.
Definition: RunTime.h:32
Global vector based on Eigen vector.
Definition: EigenVector.h:25
virtual void releaseMatrix(GlobalMatrix const &A)=0
virtual GlobalMatrix & getMatrix(std::size_t &id)=0
Get an uninitialized matrix with the given id.
ConvergenceCriterion * _convergence_criterion
NonlinearSolverStatus solve(std::vector< GlobalVector * > &x, std::vector< GlobalVector * > const &x_prev, std::function< void(int, std::vector< GlobalVector * > const &)> const &postIterationCallback, int const process_id) override
void setEquationSystem(System &eq, ConvergenceCriterion &conv_crit)
Set the nonlinear equation system that will be solved.
PETScNonlinearSolver(GlobalLinearSolver &linear_solver, int maxiter, std::string prefix)
std::size_t _jacobian_id
ID of the Jacobian matrix.
void compensateNonEquilibriumInitialResiduum(bool const value)
std::size_t _residual_id
ID of the residual vector.
void calculateNonEquilibriumInitialResiduum(std::vector< GlobalVector * > const &x, std::vector< GlobalVector * > const &x_prev, int const process_id) override
virtual GlobalVector & getVector(std::size_t &id)=0
Get an uninitialized vector with the given id.
virtual void releaseVector(GlobalVector const &x)=0
void copy(PETScVector const &x, PETScVector &y)
Definition: LinAlg.cpp:37
void finalizeVectorAssembly(VEC_T &)
General function to finalize the vector assembly.
PetscErrorCode updateResidual(SNES, Vec x, Vec petsc_r, void *petsc_context)
PetscErrorCode updateJacobian(SNES, Vec, Mat J, Mat, void *petsc_context)
static NUMLIB_EXPORT MatrixProvider & provider
static NUMLIB_EXPORT VectorProvider & provider
Status of the non-linear solver.
auto format(SNESConvergedReason const reason, FormatContext &ctx)
constexpr auto parse(format_parse_context &ctx)