GCC Code Coverage Report


Directory: ./
File: PETScInterface/SNESInterface.cpp
Date: 2024-04-14 07:32:34
Exec Total Coverage
Lines: 63 79 79.7%
Branches: 39 117 33.3%

Line Branch Exec Source
1 // ______ ______ _ _ _____ ______
2 // | ____| ____| | (_)/ ____| | ____|
3 // | |__ | |__ | | _| (___ ___| |__
4 // | __| | __| | | | |\___ \ / __| __|
5 // | | | |____| |____| |____) | (__| |____
6 // |_| |______|______|_|_____/ \___|______|
7 // Finite Elements for Life Sciences and Engineering
8 //
9 // License: LGL2.1 License
10 // FELiScE default license: LICENSE in root folder
11 //
12 // Main authors: Vicente Mataix Ferrandiz
13 //
14
15 // System includes
16
17 // External includes
18
19 // Project includes
20 #include "Core/mpiInfo.hpp"
21 #include "Solver/linearProblem.hpp"
22 #include "PETScInterface/SNESInterface.hpp"
23
24 namespace felisce
25 {
26 namespace { // anonymous
27 /**
28 * @brief This function is used to monitor evolution of the convergence.
29 * Is is intended to be passed to SNESMonitorSet()
30 * @param[in] snes SNES object. Not explicitly used but required by Petsc prototype.
31 * @param[in] its Index of iteration.
32 * @param[in] norm Current L^2 norm.
33 * @param[in] contextAsVoid Optional user-defined function context. In our case is is a pointer to LinearProblem object.
34 */
35 20911 PetscErrorCode snesViewerLinearProblem(
36 SNES snes,
37 PetscInt its,
38 PetscReal norm,
39 void* contextAsVoid
40 )
41 {
42 PetscFunctionBegin;
43
44
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20911 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20911 FEL_ASSERT(contextAsVoid);
45
46 20911 const LinearProblem* p_linear_problem = static_cast<const LinearProblem*>(contextAsVoid);
47
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20911 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
20911 FEL_ASSERT(p_linear_problem);
48
49 PetscReal evaluation_state_Min, evaluation_state_Max;
50
51 20911 const PetscVector& r_vector = p_linear_problem->evaluationState();
52
1/2
✓ Branch 1 taken 20911 times.
✗ Branch 2 not taken.
20911 r_vector.min(&evaluation_state_Min);
53
1/2
✓ Branch 1 taken 20911 times.
✗ Branch 2 not taken.
20911 r_vector.max(&evaluation_state_Max);
54
55 20911 PetscObject snes_object = reinterpret_cast<PetscObject>(snes);
56
57 PetscReal residual_min, residual_max;
58
1/2
✓ Branch 2 taken 20911 times.
✗ Branch 3 not taken.
20911 p_linear_problem->vector().min(&residual_min);
59
1/2
✓ Branch 2 taken 20911 times.
✗ Branch 3 not taken.
20911 p_linear_problem->vector().max(&residual_max);
60
61 int tablevel;
62
1/2
✓ Branch 1 taken 20911 times.
✗ Branch 2 not taken.
20911 PetscObjectGetTabLevel(snes_object,&tablevel);
63
2/4
✓ Branch 1 taken 20911 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20911 times.
✗ Branch 5 not taken.
20911 PetscViewerASCIIAddTab(PETSC_VIEWER_STDOUT_WORLD, tablevel);
64
2/4
✓ Branch 1 taken 20911 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20911 times.
✗ Branch 5 not taken.
20911 PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_WORLD,
65 "%d SNES Function Norm is %14.12e and displacement extrema are %8.6e and %8.6e. Residual between %8.6e and %8.6e\n",
66 its,
67 norm,
68 evaluation_state_Min, evaluation_state_Max,
69 residual_min, residual_max
70 );
71
72
2/4
✓ Branch 1 taken 20911 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20911 times.
✗ Branch 5 not taken.
20911 PetscViewerASCIISubtractTab(PETSC_VIEWER_STDOUT_WORLD, tablevel);
73
74 20911 PetscFunctionReturn(0);
75 }
76 } // namespace anonymous
77
78 /***********************************************************************************/
79 /***********************************************************************************/
80
81 518 SNESInterface::SNESInterface()
82 {
83 518 }
84
85 /***********************************************************************************/
86 /***********************************************************************************/
87
88 518 SNESInterface::~SNESInterface()
89 {
90
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 235 times.
518 if (m_doUseSNES) {
91 283 SNESDestroy(&m_SNES);
92 }
93 518 }
94
95 /***********************************************************************************/
96 /***********************************************************************************/
97
98 283 void SNESInterface::init()
99 {
100 283 init( MpiInfo::petscComm() );
101 283 }
102
103 /***********************************************************************************/
104 /***********************************************************************************/
105
106 283 void SNESInterface::init(MPI_Comm comm)
107 {
108 283 m_comm = comm;
109
110 // First case of Newton-Raphson method such as implemented by Petsc.
111 // By extracting the KSP and PC contexts from the SNES context, we can then
112 // directly call any KSP, and PC routines to set various options.
113
1/2
✓ Branch 1 taken 283 times.
✗ Branch 2 not taken.
283 SNESCreate(m_comm, &m_SNES);
114
115 // We deactivate line-search in order to use standard Newton-Raphson
116
1/2
✓ Branch 1 taken 283 times.
✗ Branch 2 not taken.
283 SNESSetType(m_SNES,SNESNEWTONLS);
117 SNESLineSearch ls;
118
1/2
✓ Branch 1 taken 283 times.
✗ Branch 2 not taken.
283 SNESGetLineSearch(m_SNES, &ls);
119
1/2
✓ Branch 1 taken 283 times.
✗ Branch 2 not taken.
283 SNESLineSearchSetType(ls,SNESLINESEARCHBASIC);
120 283 }
121
122 /***********************************************************************************/
123 /***********************************************************************************/
124
125 7242 void SNESInterface::getSolutionUpdate(PetscVector& rDeltaX)
126 {
127 Vec increment;
128 // Warning: SNESGetSolutionUpdate returns -delta U
129
1/2
✓ Branch 1 taken 7242 times.
✗ Branch 2 not taken.
7242 SNESGetSolutionUpdate(m_SNES, &increment);
130
131 // Copy to our vector
132
2/4
✓ Branch 1 taken 7242 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7242 times.
✗ Branch 5 not taken.
7242 VecCopy(increment,rDeltaX.toPetsc());
133 7242 }
134
135 /***********************************************************************************/
136 /***********************************************************************************/
137
138 247 void SNESInterface::setFunction(PetscVector& r, PetscErrorCode (*f)(SNES,Vec,Vec,void*), void* ctx)
139 {
140 247 SNESSetFunction(m_SNES, r.toPetsc(), f, ctx);
141 247 }
142
143 /***********************************************************************************/
144 /***********************************************************************************/
145
146 247 void SNESInterface::setJacobian(
147 PetscMatrix& Amat,
148 PetscMatrix& Pmat,
149 PetscErrorCode (*J)(SNES,Vec,Mat,Mat,void*),
150 void* ctx
151 )
152 {
153 247 SNESSetJacobian(m_SNES, Amat.toPetsc(), Pmat.toPetsc(), J, ctx);
154 247 }
155
156 /***********************************************************************************/
157 /***********************************************************************************/
158
159 283 void SNESInterface::getKSP(KSP* pKSP)
160 {
161 283 SNESGetKSP(m_SNES, pKSP);
162 283 }
163
164 /***********************************************************************************/
165 /***********************************************************************************/
166
167 283 void SNESInterface::setMonitorSetLinearProblem(LinearProblem* pLinearProblem)
168 {
169 283 SNESMonitorSet(m_SNES, snesViewerLinearProblem, pLinearProblem, FELISCE_PETSC_NULLPTR);
170 283 }
171
172 /***********************************************************************************/
173 /***********************************************************************************/
174
175 283 void SNESInterface::setTolerances(
176 const double absoluteTolerance,
177 const double relativeTolerance,
178 const double solutionTolerance,
179 const int maxIterationSNES,
180 const int maxFunctionEvaluatedSNES,
181 const double divergenceTolerance
182 )
183 {
184 283 SNESSetTolerances(m_SNES,
185 absoluteTolerance,
186 relativeTolerance,
187 solutionTolerance,
188 maxIterationSNES,
189 maxFunctionEvaluatedSNES
190 );
191
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 279 times.
283 if (divergenceTolerance > 0.0) {
192 4 SNESSetDivergenceTolerance(m_SNES, divergenceTolerance);
193 }
194 283 }
195
196 /***********************************************************************************/
197 /***********************************************************************************/
198
199 7095 PetscInt SNESInterface::solve(PetscVector& rX)
200 {
201
2/4
✓ Branch 1 taken 7095 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7095 times.
✗ Branch 5 not taken.
7095 SNESSolve(m_SNES, FELISCE_PETSC_NULLPTR, rX.toPetsc());
202
203 SNESConvergedReason cvg_reason;
204
1/2
✓ Branch 1 taken 7095 times.
✗ Branch 2 not taken.
7095 SNESGetConvergedReason(m_SNES,&cvg_reason);
205 PetscInt its;
206
1/2
✓ Branch 1 taken 7095 times.
✗ Branch 2 not taken.
7095 SNESGetIterationNumber(m_SNES,&its);
207
3/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 7063 times.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
7095 if (cvg_reason > 0 || cvg_reason == SNES_DIVERGED_MAX_IT) { // NOTE: See https://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/SNES/SNESConvergedReason.html
208
4/6
✓ Branch 0 taken 2226 times.
✓ Branch 1 taken 4293 times.
✓ Branch 2 taken 544 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
7095 switch (cvg_reason) {
209
1/2
✓ Branch 1 taken 2226 times.
✗ Branch 2 not taken.
2226 case SNES_CONVERGED_FNORM_ABS: PetscPrintf(m_comm, "SNES converged in %d iterations due to ||F|| < atol \n", its); break;
210
1/2
✓ Branch 1 taken 4293 times.
✗ Branch 2 not taken.
4293 case SNES_CONVERGED_FNORM_RELATIVE: PetscPrintf(m_comm, "SNES converged in %d iterations due to ||F|| < rtol*||F_initial|| \n", its); break;
211
1/2
✓ Branch 1 taken 544 times.
✗ Branch 2 not taken.
544 case SNES_CONVERGED_SNORM_RELATIVE: PetscPrintf(m_comm, "SNES converged in %d iterations due to Newton computed step size small; || delta x || < stol || x || \n", its); break;
212 case SNES_CONVERGED_ITS: PetscPrintf(m_comm, "SNES converged in %d iterations due to maximum iterations reached \n", its); break;
213
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 case SNES_DIVERGED_MAX_IT: PetscPrintf(m_comm, "SNES diverged due to SNESSolve() has reached the maximum number of iterations requested: %d. Calculations continues as normal \n", its); break;
214 default: PetscPrintf(m_comm, "SNES converged in %d iterations \n", its);
215 }
216 } else {
217 std::string error_message = "Convergence failed in SNES solver. ";
218 switch (cvg_reason) {
219 // case SNES_CONVERGED_ITERATING: error_message += "SNES diverged due to maximum iterations reached"; break;
220 case SNES_DIVERGED_FUNCTION_DOMAIN: error_message += "SNES diverged due to the new x location passed the function is not in the domain of F"; break;
221 case SNES_DIVERGED_FUNCTION_COUNT: error_message += "SNES diverged due to the user provided function has been called more times then the final argument to SNESSetTolerances() "; break;
222 case SNES_DIVERGED_LINEAR_SOLVE: error_message += "SNES diverged due to the linear solve failed"; break;
223 case SNES_DIVERGED_FNORM_NAN: error_message += "SNES diverged due to the 2-norm of the current function evaluation is not-a-number (NaN), this is usually caused by a division of 0 by 0"; break;
224 // case SNES_DIVERGED_MAX_IT: error_message += "SNES diverged due to SNESSolve() has reached the maximum number of iterations requested"; break;
225 case SNES_DIVERGED_LINE_SEARCH: error_message += "SNES diverged due to the line search failed "; break;
226 case SNES_DIVERGED_INNER: error_message += "SNES diverged due to inner solve failed"; break;
227 case SNES_DIVERGED_LOCAL_MIN: error_message += "SNES diverged due to || J^T b || is small, implies converged to local minimum of F()"; break;
228 case SNES_DIVERGED_DTOL: error_message += "SNES diverged due to || F || > divtol*||F_initial||"; break;
229 case SNES_DIVERGED_JACOBIAN_DOMAIN: error_message += "SNES diverged due to Jacobian calculation does not make sense"; break;
230 case SNES_DIVERGED_TR_DELTA: error_message += "SNES diverged due to SNES_DIVERGED_TR_DELTA"; break;
231 default: error_message += "";
232 }
233 FEL_ERROR(error_message);
234 }
235
236 7095 return its;
237 }
238
239 }
240