1 #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/
2 #include <petsc/private/linesearchimpl.h> /*I "petscsnes.h" I*/
3 #include <petscdmshell.h>
4 #include <petscdraw.h>
5 #include <petscds.h>
6 #include <petscdmadaptor.h>
7 #include <petscconvest.h>
8
9 PetscBool SNESRegisterAllCalled = PETSC_FALSE;
10 PetscFunctionList SNESList = NULL;
11
12 /* Logging support */
13 PetscClassId SNES_CLASSID, DMSNES_CLASSID;
14 PetscLogEvent SNES_Solve, SNES_SetUp, SNES_FunctionEval, SNES_JacobianEval, SNES_NGSEval, SNES_NGSFuncEval, SNES_NewtonALEval, SNES_NPCSolve, SNES_ObjectiveEval;
15
16 /*@
17 SNESSetErrorIfNotConverged - Causes `SNESSolve()` to generate an error immediately if the solver has not converged.
18
19 Logically Collective
20
21 Input Parameters:
22 + snes - iterative context obtained from `SNESCreate()`
23 - flg - `PETSC_TRUE` indicates you want the error generated
24
25 Options Database Key:
26 . -snes_error_if_not_converged <true,false> - cause an immediate error condition and stop the program if the solver does not converge
27
28 Level: intermediate
29
30 Note:
31 Normally PETSc continues if a solver fails to converge, you can call `SNESGetConvergedReason()` after a `SNESSolve()`
32 to determine if it has converged. Otherwise the solution may be inaccurate or wrong
33
34 .seealso: [](ch_snes), `SNES`, `SNESGetErrorIfNotConverged()`, `KSPGetErrorIfNotConverged()`, `KSPSetErrorIfNotConverged()`
35 @*/
SNESSetErrorIfNotConverged(SNES snes,PetscBool flg)36 PetscErrorCode SNESSetErrorIfNotConverged(SNES snes, PetscBool flg)
37 {
38 PetscFunctionBegin;
39 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
40 PetscValidLogicalCollectiveBool(snes, flg, 2);
41 snes->errorifnotconverged = flg;
42 PetscFunctionReturn(PETSC_SUCCESS);
43 }
44
45 /*@
46 SNESGetErrorIfNotConverged - Indicates if `SNESSolve()` will generate an error if the solver does not converge?
47
48 Not Collective
49
50 Input Parameter:
51 . snes - iterative context obtained from `SNESCreate()`
52
53 Output Parameter:
54 . flag - `PETSC_TRUE` if it will generate an error, else `PETSC_FALSE`
55
56 Level: intermediate
57
58 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESSetErrorIfNotConverged()`, `KSPGetErrorIfNotConverged()`, `KSPSetErrorIfNotConverged()`
59 @*/
SNESGetErrorIfNotConverged(SNES snes,PetscBool * flag)60 PetscErrorCode SNESGetErrorIfNotConverged(SNES snes, PetscBool *flag)
61 {
62 PetscFunctionBegin;
63 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
64 PetscAssertPointer(flag, 2);
65 *flag = snes->errorifnotconverged;
66 PetscFunctionReturn(PETSC_SUCCESS);
67 }
68
69 /*@
70 SNESSetAlwaysComputesFinalResidual - tells the `SNES` to always compute the residual (nonlinear function value) at the final solution
71
72 Logically Collective
73
74 Input Parameters:
75 + snes - the shell `SNES`
76 - flg - `PETSC_TRUE` to always compute the residual
77
78 Level: advanced
79
80 Note:
81 Some solvers (such as smoothers in a `SNESFAS`) do not need the residual computed at the final solution so skip computing it
82 to save time.
83
84 .seealso: [](ch_snes), `SNES`, `SNESFAS`, `SNESSolve()`, `SNESGetAlwaysComputesFinalResidual()`
85 @*/
SNESSetAlwaysComputesFinalResidual(SNES snes,PetscBool flg)86 PetscErrorCode SNESSetAlwaysComputesFinalResidual(SNES snes, PetscBool flg)
87 {
88 PetscFunctionBegin;
89 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
90 snes->alwayscomputesfinalresidual = flg;
91 PetscFunctionReturn(PETSC_SUCCESS);
92 }
93
94 /*@
95 SNESGetAlwaysComputesFinalResidual - checks if the `SNES` always computes the residual at the final solution
96
97 Logically Collective
98
99 Input Parameter:
100 . snes - the `SNES` context
101
102 Output Parameter:
103 . flg - `PETSC_TRUE` if the residual is computed
104
105 Level: advanced
106
107 .seealso: [](ch_snes), `SNES`, `SNESFAS`, `SNESSolve()`, `SNESSetAlwaysComputesFinalResidual()`
108 @*/
SNESGetAlwaysComputesFinalResidual(SNES snes,PetscBool * flg)109 PetscErrorCode SNESGetAlwaysComputesFinalResidual(SNES snes, PetscBool *flg)
110 {
111 PetscFunctionBegin;
112 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
113 *flg = snes->alwayscomputesfinalresidual;
114 PetscFunctionReturn(PETSC_SUCCESS);
115 }
116
117 /*@
118 SNESSetFunctionDomainError - tells `SNES` that the input vector, a proposed new solution, to your function you provided to `SNESSetFunction()` is not
119 in the function's domain. For example, a step with negative pressure.
120
121 Not Collective
122
123 Input Parameter:
124 . snes - the `SNES` context
125
126 Level: advanced
127
128 Notes:
129 This does not need to be called by all processes in the `SNES` MPI communicator.
130
131 A few solvers will try to cut the step size to avoid the domain error but for other solvers `SNESSolve()` stops iterating and and
132 returns with a `SNESConvergedReason` of `SNES_DIVERGED_FUNCTION_DOMAIN`
133
134 You can direct `SNES` to avoid certain steps by using `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()` or
135 `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`
136
137 You should always call `SNESGetConvergedReason()` after each `SNESSolve()` and verify if the iteration converged (positive result) or diverged (negative result).
138
139 You can call `SNESSetJacobianDomainError()` during a Jacobian computation to indicate the proposed solution is not in the domain.
140
141 Developer Note:
142 This value is used by `SNESCheckFunctionDomainError()` to determine if the `SNESConvergedReason` is set to `SNES_DIVERGED_FUNCTION_DOMAIN`
143
144 .seealso: [](ch_snes), `SNESCreate()`, `SNESSetFunction()`, `SNESFunctionFn`, `SNESSetJacobianDomainError()`, `SNESVISetVariableBounds()`,
145 `SNESVISetComputeVariableBounds()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESConvergedReason`, `SNESGetConvergedReason()`,
146 `SNES_DIVERGED_FUNCTION_DOMAIN`, `SNESSetObjectiveDomainError()`
147 @*/
SNESSetFunctionDomainError(SNES snes)148 PetscErrorCode SNESSetFunctionDomainError(SNES snes)
149 {
150 PetscFunctionBegin;
151 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
152 snes->functiondomainerror = PETSC_TRUE;
153 PetscFunctionReturn(PETSC_SUCCESS);
154 }
155
156 /*@
157 SNESSetObjectiveDomainError - tells `SNES` that the input vector, a proposed new solution, to your function you provided to `SNESSetObjective()` is not
158 in the function's domain. For example, a step with negative pressure.
159
160 Not Collective
161
162 Input Parameter:
163 . snes - the `SNES` context
164
165 Level: advanced
166
167 Notes:
168 This does not need to be called by all processes in the `SNES` MPI communicator.
169
170 A few solvers will try to cut the step size to avoid the domain error but for other solvers `SNESSolve()` stops iterating and and
171 returns with a `SNESConvergedReason` of `SNES_DIVERGED_FUNCTION_DOMAIN`
172
173 You can direct `SNES` to avoid certain steps by using `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()` or
174 `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`
175
176 You should always call `SNESGetConvergedReason()` after each `SNESSolve()` and verify if the iteration converged (positive result) or diverged (negative result).
177
178 You can call `SNESSetJacobianDomainError()` during a Jacobian computation to indicate the proposed solution is not in the domain.
179
180 Developer Note:
181 This value is used by `SNESCheckFunctionDomainError()` to determine if the `SNESConvergedReason` is set to `SNES_DIVERGED_FUNCTION_DOMAIN`
182
183 .seealso: [](ch_snes), `SNESCreate()`, `SNESSetFunction()`, `SNESFunctionFn`, `SNESSetJacobianDomainError()`, `SNESVISetVariableBounds()`,
184 `SNESVISetComputeVariableBounds()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESConvergedReason`, `SNESGetConvergedReason()`,
185 `SNES_DIVERGED_FUNCTION_DOMAIN`, `SNESSetFunctionDomainError()`
186 @*/
SNESSetObjectiveDomainError(SNES snes)187 PetscErrorCode SNESSetObjectiveDomainError(SNES snes)
188 {
189 PetscFunctionBegin;
190 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
191 snes->objectivedomainerror = PETSC_TRUE;
192 PetscFunctionReturn(PETSC_SUCCESS);
193 }
194
195 /*@
196 SNESSetJacobianDomainError - tells `SNES` that the function you provided to `SNESSetJacobian()` at the proposed step. For example there is a negative element transformation.
197
198 Logically Collective
199
200 Input Parameter:
201 . snes - the `SNES` context
202
203 Level: advanced
204
205 Notes:
206 If this is called the `SNESSolve()` stops iterating and returns with a `SNESConvergedReason` of `SNES_DIVERGED_FUNCTION_DOMAIN`
207
208 You should always call `SNESGetConvergedReason()` after each `SNESSolve()` and verify if the iteration converged (positive result) or diverged (negative result).
209
210 You can direct `SNES` to avoid certain steps by using `SNESVISetVariableBounds()`, `SNESVISetComputeVariableBounds()` or
211 `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`
212
213 .seealso: [](ch_snes), `SNESCreate()`, `SNESSetFunction()`, `SNESFunctionFn`, `SNESSetFunctionDomainError()`, `SNESVISetVariableBounds()`,
214 `SNESVISetComputeVariableBounds()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESConvergedReason`, `SNESGetConvergedReason()`
215 @*/
SNESSetJacobianDomainError(SNES snes)216 PetscErrorCode SNESSetJacobianDomainError(SNES snes)
217 {
218 PetscFunctionBegin;
219 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
220 PetscCheck(!snes->errorifnotconverged, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "User code indicates computeJacobian does not make sense");
221 snes->jacobiandomainerror = PETSC_TRUE;
222 PetscFunctionReturn(PETSC_SUCCESS);
223 }
224
225 /*@
226 SNESSetCheckJacobianDomainError - tells `SNESSolve()` whether to check if the user called `SNESSetJacobianDomainError()` to indicate a Jacobian domain error after
227 each Jacobian evaluation.
228
229 Logically Collective
230
231 Input Parameters:
232 + snes - the `SNES` context
233 - flg - indicates if or not to check Jacobian domain error after each Jacobian evaluation
234
235 Level: advanced
236
237 Notes:
238 By default, it checks for the Jacobian domain error in the debug mode, and does not check it in the optimized mode.
239
240 Checks require one extra parallel synchronization for each Jacobian evaluation
241
242 .seealso: [](ch_snes), `SNES`, `SNESConvergedReason`, `SNESCreate()`, `SNESSetFunction()`, `SNESFunctionFn`, `SNESSetFunctionDomainError()`, `SNESGetCheckJacobianDomainError()`
243 @*/
SNESSetCheckJacobianDomainError(SNES snes,PetscBool flg)244 PetscErrorCode SNESSetCheckJacobianDomainError(SNES snes, PetscBool flg)
245 {
246 PetscFunctionBegin;
247 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
248 snes->checkjacdomainerror = flg;
249 PetscFunctionReturn(PETSC_SUCCESS);
250 }
251
252 /*@
253 SNESGetCheckJacobianDomainError - Get an indicator whether or not `SNES` is checking Jacobian domain errors after each Jacobian evaluation.
254
255 Logically Collective
256
257 Input Parameter:
258 . snes - the `SNES` context
259
260 Output Parameter:
261 . flg - `PETSC_FALSE` indicates that it is not checking Jacobian domain errors after each Jacobian evaluation
262
263 Level: advanced
264
265 .seealso: [](ch_snes), `SNES`, `SNESCreate()`, `SNESSetFunction()`, `SNESFunctionFn`, `SNESSetFunctionDomainError()`, `SNESSetCheckJacobianDomainError()`
266 @*/
SNESGetCheckJacobianDomainError(SNES snes,PetscBool * flg)267 PetscErrorCode SNESGetCheckJacobianDomainError(SNES snes, PetscBool *flg)
268 {
269 PetscFunctionBegin;
270 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
271 PetscAssertPointer(flg, 2);
272 *flg = snes->checkjacdomainerror;
273 PetscFunctionReturn(PETSC_SUCCESS);
274 }
275
276 /*@
277 SNESLoad - Loads a `SNES` that has been stored in `PETSCVIEWERBINARY` with `SNESView()`.
278
279 Collective
280
281 Input Parameters:
282 + snes - the newly loaded `SNES`, this needs to have been created with `SNESCreate()` or
283 some related function before a call to `SNESLoad()`.
284 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()`
285
286 Level: intermediate
287
288 Note:
289 The `SNESType` is determined by the data in the file, any type set into the `SNES` before this call is ignored.
290
291 .seealso: [](ch_snes), `SNES`, `PetscViewer`, `SNESCreate()`, `SNESType`, `PetscViewerBinaryOpen()`, `SNESView()`, `MatLoad()`, `VecLoad()`
292 @*/
SNESLoad(SNES snes,PetscViewer viewer)293 PetscErrorCode SNESLoad(SNES snes, PetscViewer viewer)
294 {
295 PetscBool isbinary;
296 PetscInt classid;
297 char type[256];
298 KSP ksp;
299 DM dm;
300 DMSNES dmsnes;
301
302 PetscFunctionBegin;
303 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
304 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
305 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
306 PetscCheck(isbinary, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen()");
307
308 PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT));
309 PetscCheck(classid == SNES_FILE_CLASSID, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONG, "Not SNES next in file");
310 PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
311 PetscCall(SNESSetType(snes, type));
312 PetscTryTypeMethod(snes, load, viewer);
313 PetscCall(SNESGetDM(snes, &dm));
314 PetscCall(DMGetDMSNES(dm, &dmsnes));
315 PetscCall(DMSNESLoad(dmsnes, viewer));
316 PetscCall(SNESGetKSP(snes, &ksp));
317 PetscCall(KSPLoad(ksp, viewer));
318 PetscFunctionReturn(PETSC_SUCCESS);
319 }
320
321 #include <petscdraw.h>
322 #if defined(PETSC_HAVE_SAWS)
323 #include <petscviewersaws.h>
324 #endif
325
326 /*@
327 SNESViewFromOptions - View a `SNES` based on values in the options database
328
329 Collective
330
331 Input Parameters:
332 + A - the `SNES` context
333 . obj - Optional object that provides the options prefix for the checks
334 - name - command line option
335
336 Level: intermediate
337
338 .seealso: [](ch_snes), `SNES`, `SNESView`, `PetscObjectViewFromOptions()`, `SNESCreate()`
339 @*/
SNESViewFromOptions(SNES A,PetscObject obj,const char name[])340 PetscErrorCode SNESViewFromOptions(SNES A, PetscObject obj, const char name[])
341 {
342 PetscFunctionBegin;
343 PetscValidHeaderSpecific(A, SNES_CLASSID, 1);
344 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
345 PetscFunctionReturn(PETSC_SUCCESS);
346 }
347
348 PETSC_EXTERN PetscErrorCode SNESComputeJacobian_DMDA(SNES, Vec, Mat, Mat, void *);
349
350 /*@
351 SNESView - Prints or visualizes the `SNES` data structure.
352
353 Collective
354
355 Input Parameters:
356 + snes - the `SNES` context
357 - viewer - the `PetscViewer`
358
359 Options Database Key:
360 . -snes_view - Calls `SNESView()` at end of `SNESSolve()`
361
362 Level: beginner
363
364 Notes:
365 The available visualization contexts include
366 + `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
367 - `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
368 output where only the first processor opens
369 the file. All other processors send their
370 data to the first processor to print.
371
372 The available formats include
373 + `PETSC_VIEWER_DEFAULT` - standard output (default)
374 - `PETSC_VIEWER_ASCII_INFO_DETAIL` - more verbose output for `SNESNASM`
375
376 The user can open an alternative visualization context with
377 `PetscViewerASCIIOpen()` - output to a specified file.
378
379 In the debugger you can do "call `SNESView`(snes,0)" to display the `SNES` solver. (The same holds for any PETSc object viewer).
380
381 .seealso: [](ch_snes), `SNES`, `SNESLoad()`, `SNESCreate()`, `PetscViewerASCIIOpen()`
382 @*/
SNESView(SNES snes,PetscViewer viewer)383 PetscErrorCode SNESView(SNES snes, PetscViewer viewer)
384 {
385 SNESKSPEW *kctx;
386 KSP ksp;
387 SNESLineSearch linesearch;
388 PetscBool isascii, isstring, isbinary, isdraw;
389 DMSNES dmsnes;
390 #if defined(PETSC_HAVE_SAWS)
391 PetscBool issaws;
392 #endif
393
394 PetscFunctionBegin;
395 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
396 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)snes), &viewer));
397 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
398 PetscCheckSameComm(snes, 1, viewer, 2);
399
400 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
401 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
402 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
403 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
404 #if defined(PETSC_HAVE_SAWS)
405 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
406 #endif
407 if (isascii) {
408 SNESNormSchedule normschedule;
409 DM dm;
410 SNESJacobianFn *cJ;
411 void *ctx;
412 const char *pre = "";
413
414 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)snes, viewer));
415 if (!snes->setupcalled) PetscCall(PetscViewerASCIIPrintf(viewer, " SNES has not been set up so information may be incomplete\n"));
416 if (snes->ops->view) {
417 PetscCall(PetscViewerASCIIPushTab(viewer));
418 PetscUseTypeMethod(snes, view, viewer);
419 PetscCall(PetscViewerASCIIPopTab(viewer));
420 }
421 if (snes->max_funcs == PETSC_UNLIMITED) {
422 PetscCall(PetscViewerASCIIPrintf(viewer, " maximum iterations=%" PetscInt_FMT ", maximum function evaluations=unlimited\n", snes->max_its));
423 } else {
424 PetscCall(PetscViewerASCIIPrintf(viewer, " maximum iterations=%" PetscInt_FMT ", maximum function evaluations=%" PetscInt_FMT "\n", snes->max_its, snes->max_funcs));
425 }
426 PetscCall(PetscViewerASCIIPrintf(viewer, " tolerances: relative=%g, absolute=%g, solution=%g\n", (double)snes->rtol, (double)snes->abstol, (double)snes->stol));
427 if (snes->usesksp) PetscCall(PetscViewerASCIIPrintf(viewer, " total number of linear solver iterations=%" PetscInt_FMT "\n", snes->linear_its));
428 PetscCall(PetscViewerASCIIPrintf(viewer, " total number of function evaluations=%" PetscInt_FMT "\n", snes->nfuncs));
429 PetscCall(SNESGetNormSchedule(snes, &normschedule));
430 if (normschedule > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " norm schedule %s\n", SNESNormSchedules[normschedule]));
431 if (snes->gridsequence) PetscCall(PetscViewerASCIIPrintf(viewer, " total number of grid sequence refinements=%" PetscInt_FMT "\n", snes->gridsequence));
432 if (snes->ksp_ewconv) {
433 kctx = (SNESKSPEW *)snes->kspconvctx;
434 if (kctx) {
435 PetscCall(PetscViewerASCIIPrintf(viewer, " Eisenstat-Walker computation of KSP relative tolerance (version %" PetscInt_FMT ")\n", kctx->version));
436 PetscCall(PetscViewerASCIIPrintf(viewer, " rtol_0=%g, rtol_max=%g, threshold=%g\n", (double)kctx->rtol_0, (double)kctx->rtol_max, (double)kctx->threshold));
437 PetscCall(PetscViewerASCIIPrintf(viewer, " gamma=%g, alpha=%g, alpha2=%g\n", (double)kctx->gamma, (double)kctx->alpha, (double)kctx->alpha2));
438 }
439 }
440 if (snes->lagpreconditioner == -1) {
441 PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioned is never rebuilt\n"));
442 } else if (snes->lagpreconditioner > 1) {
443 PetscCall(PetscViewerASCIIPrintf(viewer, " Preconditioned is rebuilt every %" PetscInt_FMT " new Jacobians\n", snes->lagpreconditioner));
444 }
445 if (snes->lagjacobian == -1) {
446 PetscCall(PetscViewerASCIIPrintf(viewer, " Jacobian is never rebuilt\n"));
447 } else if (snes->lagjacobian > 1) {
448 PetscCall(PetscViewerASCIIPrintf(viewer, " Jacobian is rebuilt every %" PetscInt_FMT " SNES iterations\n", snes->lagjacobian));
449 }
450 PetscCall(SNESGetDM(snes, &dm));
451 PetscCall(DMSNESGetJacobian(dm, &cJ, &ctx));
452 if (snes->mf_operator) {
453 PetscCall(PetscViewerASCIIPrintf(viewer, " Jacobian is applied matrix-free with differencing\n"));
454 pre = "Preconditioning ";
455 }
456 if (cJ == SNESComputeJacobianDefault) {
457 PetscCall(PetscViewerASCIIPrintf(viewer, " %sJacobian is built using finite differences one column at a time\n", pre));
458 } else if (cJ == SNESComputeJacobianDefaultColor) {
459 PetscCall(PetscViewerASCIIPrintf(viewer, " %sJacobian is built using finite differences with coloring\n", pre));
460 /* it slightly breaks data encapsulation for access the DMDA information directly */
461 } else if (cJ == SNESComputeJacobian_DMDA) {
462 MatFDColoring fdcoloring;
463 PetscCall(PetscObjectQuery((PetscObject)dm, "DMDASNES_FDCOLORING", (PetscObject *)&fdcoloring));
464 if (fdcoloring) {
465 PetscCall(PetscViewerASCIIPrintf(viewer, " %sJacobian is built using colored finite differences on a DMDA\n", pre));
466 } else {
467 PetscCall(PetscViewerASCIIPrintf(viewer, " %sJacobian is built using a DMDA local Jacobian\n", pre));
468 }
469 } else if (snes->mf && !snes->mf_operator) {
470 PetscCall(PetscViewerASCIIPrintf(viewer, " Jacobian is applied matrix-free with differencing, no explicit Jacobian\n"));
471 }
472 } else if (isstring) {
473 const char *type;
474 PetscCall(SNESGetType(snes, &type));
475 PetscCall(PetscViewerStringSPrintf(viewer, " SNESType: %-7.7s", type));
476 PetscTryTypeMethod(snes, view, viewer);
477 } else if (isbinary) {
478 PetscInt classid = SNES_FILE_CLASSID;
479 MPI_Comm comm;
480 PetscMPIInt rank;
481 char type[256];
482
483 PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
484 PetscCallMPI(MPI_Comm_rank(comm, &rank));
485 if (rank == 0) {
486 PetscCall(PetscViewerBinaryWrite(viewer, &classid, 1, PETSC_INT));
487 PetscCall(PetscStrncpy(type, ((PetscObject)snes)->type_name, sizeof(type)));
488 PetscCall(PetscViewerBinaryWrite(viewer, type, sizeof(type), PETSC_CHAR));
489 }
490 PetscTryTypeMethod(snes, view, viewer);
491 } else if (isdraw) {
492 PetscDraw draw;
493 char str[36];
494 PetscReal x, y, bottom, h;
495
496 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
497 PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
498 PetscCall(PetscStrncpy(str, "SNES: ", sizeof(str)));
499 PetscCall(PetscStrlcat(str, ((PetscObject)snes)->type_name, sizeof(str)));
500 PetscCall(PetscDrawStringBoxed(draw, x, y, PETSC_DRAW_BLUE, PETSC_DRAW_BLACK, str, NULL, &h));
501 bottom = y - h;
502 PetscCall(PetscDrawPushCurrentPoint(draw, x, bottom));
503 PetscTryTypeMethod(snes, view, viewer);
504 #if defined(PETSC_HAVE_SAWS)
505 } else if (issaws) {
506 PetscMPIInt rank;
507 const char *name;
508
509 PetscCall(PetscObjectGetName((PetscObject)snes, &name));
510 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
511 if (!((PetscObject)snes)->amsmem && rank == 0) {
512 char dir[1024];
513
514 PetscCall(PetscObjectViewSAWs((PetscObject)snes, viewer));
515 PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Objects/%s/its", name));
516 PetscCallSAWs(SAWs_Register, (dir, &snes->iter, 1, SAWs_READ, SAWs_INT));
517 if (!snes->conv_hist) PetscCall(SNESSetConvergenceHistory(snes, NULL, NULL, PETSC_DECIDE, PETSC_TRUE));
518 PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Objects/%s/conv_hist", name));
519 PetscCallSAWs(SAWs_Register, (dir, snes->conv_hist, 10, SAWs_READ, SAWs_DOUBLE));
520 }
521 #endif
522 }
523 if (snes->linesearch) {
524 PetscCall(SNESGetLineSearch(snes, &linesearch));
525 PetscCall(PetscViewerASCIIPushTab(viewer));
526 PetscCall(SNESLineSearchView(linesearch, viewer));
527 PetscCall(PetscViewerASCIIPopTab(viewer));
528 }
529 if (snes->npc && snes->usesnpc) {
530 PetscCall(PetscViewerASCIIPushTab(viewer));
531 PetscCall(SNESView(snes->npc, viewer));
532 PetscCall(PetscViewerASCIIPopTab(viewer));
533 }
534 PetscCall(PetscViewerASCIIPushTab(viewer));
535 PetscCall(DMGetDMSNES(snes->dm, &dmsnes));
536 PetscCall(DMSNESView(dmsnes, viewer));
537 PetscCall(PetscViewerASCIIPopTab(viewer));
538 if (snes->usesksp) {
539 PetscCall(SNESGetKSP(snes, &ksp));
540 PetscCall(PetscViewerASCIIPushTab(viewer));
541 PetscCall(KSPView(ksp, viewer));
542 PetscCall(PetscViewerASCIIPopTab(viewer));
543 }
544 if (isdraw) {
545 PetscDraw draw;
546 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
547 PetscCall(PetscDrawPopCurrentPoint(draw));
548 }
549 PetscFunctionReturn(PETSC_SUCCESS);
550 }
551
552 /*
553 We retain a list of functions that also take SNES command
554 line options. These are called at the end SNESSetFromOptions()
555 */
556 #define MAXSETFROMOPTIONS 5
557 static PetscInt numberofsetfromoptions;
558 static PetscErrorCode (*othersetfromoptions[MAXSETFROMOPTIONS])(SNES);
559
560 /*@C
561 SNESAddOptionsChecker - Adds an additional function to check for `SNES` options.
562
563 Not Collective
564
565 Input Parameter:
566 . snescheck - function that checks for options
567
568 Calling sequence of `snescheck`:
569 . snes - the `SNES` object for which it is checking options
570
571 Level: developer
572
573 .seealso: [](ch_snes), `SNES`, `SNESSetFromOptions()`
574 @*/
SNESAddOptionsChecker(PetscErrorCode (* snescheck)(SNES snes))575 PetscErrorCode SNESAddOptionsChecker(PetscErrorCode (*snescheck)(SNES snes))
576 {
577 PetscFunctionBegin;
578 PetscCheck(numberofsetfromoptions < MAXSETFROMOPTIONS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many options checkers, only %d allowed", MAXSETFROMOPTIONS);
579 othersetfromoptions[numberofsetfromoptions++] = snescheck;
580 PetscFunctionReturn(PETSC_SUCCESS);
581 }
582
SNESSetUpMatrixFree_Private(SNES snes,PetscBool hasOperator,PetscInt version)583 static PetscErrorCode SNESSetUpMatrixFree_Private(SNES snes, PetscBool hasOperator, PetscInt version)
584 {
585 Mat J;
586 MatNullSpace nullsp;
587
588 PetscFunctionBegin;
589 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
590
591 if (!snes->vec_func && (snes->jacobian || snes->jacobian_pre)) {
592 Mat A = snes->jacobian, B = snes->jacobian_pre;
593 PetscCall(MatCreateVecs(A ? A : B, NULL, &snes->vec_func));
594 }
595
596 PetscCheck(version == 1 || version == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "matrix-free operator routines, only version 1 and 2");
597 if (version == 1) {
598 PetscCall(MatCreateSNESMF(snes, &J));
599 PetscCall(MatMFFDSetOptionsPrefix(J, ((PetscObject)snes)->prefix));
600 PetscCall(MatSetFromOptions(J));
601 /* TODO: the version 2 code should be merged into the MatCreateSNESMF() and MatCreateMFFD() infrastructure and then removed */
602 } else /* if (version == 2) */ {
603 PetscCheck(snes->vec_func, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "SNESSetFunction() must be called first");
604 #if !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_REAL_SINGLE) && !defined(PETSC_USE_REAL___FLOAT128) && !defined(PETSC_USE_REAL___FP16)
605 PetscCall(MatCreateSNESMFMore(snes, snes->vec_func, &J));
606 #else
607 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "matrix-free operator routines (version 2)");
608 #endif
609 }
610
611 /* attach any user provided null space that was on Amat to the newly created matrix-free matrix */
612 if (snes->jacobian) {
613 PetscCall(MatGetNullSpace(snes->jacobian, &nullsp));
614 if (nullsp) PetscCall(MatSetNullSpace(J, nullsp));
615 }
616
617 PetscCall(PetscInfo(snes, "Setting default matrix-free operator routines (version %" PetscInt_FMT ")\n", version));
618 if (hasOperator) {
619 /* This version replaces the user provided Jacobian matrix with a
620 matrix-free version but still employs the user-provided matrix used for computing the preconditioner. */
621 PetscCall(SNESSetJacobian(snes, J, NULL, NULL, NULL));
622 } else {
623 /* This version replaces both the user-provided Jacobian and the user-
624 provided preconditioner Jacobian with the default matrix-free version. */
625 if (snes->npcside == PC_LEFT && snes->npc) {
626 if (!snes->jacobian) PetscCall(SNESSetJacobian(snes, J, NULL, NULL, NULL));
627 } else {
628 KSP ksp;
629 PC pc;
630 PetscBool match;
631
632 PetscCall(SNESSetJacobian(snes, J, J, MatMFFDComputeJacobian, NULL));
633 /* Force no preconditioner */
634 PetscCall(SNESGetKSP(snes, &ksp));
635 PetscCall(KSPGetPC(ksp, &pc));
636 PetscCall(PetscObjectTypeCompareAny((PetscObject)pc, &match, PCSHELL, PCH2OPUS, ""));
637 if (!match) {
638 PetscCall(PetscInfo(snes, "Setting default matrix-free preconditioner routines\nThat is no preconditioner is being used\n"));
639 PetscCall(PCSetType(pc, PCNONE));
640 }
641 }
642 }
643 PetscCall(MatDestroy(&J));
644 PetscFunctionReturn(PETSC_SUCCESS);
645 }
646
DMRestrictHook_SNESVecSol(DM dmfine,Mat Restrict,Vec Rscale,Mat Inject,DM dmcoarse,PetscCtx ctx)647 static PetscErrorCode DMRestrictHook_SNESVecSol(DM dmfine, Mat Restrict, Vec Rscale, Mat Inject, DM dmcoarse, PetscCtx ctx)
648 {
649 SNES snes = (SNES)ctx;
650 Vec Xfine, Xfine_named = NULL, Xcoarse;
651
652 PetscFunctionBegin;
653 if (PetscLogPrintInfo) {
654 PetscInt finelevel, coarselevel, fineclevel, coarseclevel;
655 PetscCall(DMGetRefineLevel(dmfine, &finelevel));
656 PetscCall(DMGetCoarsenLevel(dmfine, &fineclevel));
657 PetscCall(DMGetRefineLevel(dmcoarse, &coarselevel));
658 PetscCall(DMGetCoarsenLevel(dmcoarse, &coarseclevel));
659 PetscCall(PetscInfo(dmfine, "Restricting SNES solution vector from level %" PetscInt_FMT "-%" PetscInt_FMT " to level %" PetscInt_FMT "-%" PetscInt_FMT "\n", finelevel, fineclevel, coarselevel, coarseclevel));
660 }
661 if (dmfine == snes->dm) Xfine = snes->vec_sol;
662 else {
663 PetscCall(DMGetNamedGlobalVector(dmfine, "SNESVecSol", &Xfine_named));
664 Xfine = Xfine_named;
665 }
666 PetscCall(DMGetNamedGlobalVector(dmcoarse, "SNESVecSol", &Xcoarse));
667 if (Inject) {
668 PetscCall(MatRestrict(Inject, Xfine, Xcoarse));
669 } else {
670 PetscCall(MatRestrict(Restrict, Xfine, Xcoarse));
671 PetscCall(VecPointwiseMult(Xcoarse, Xcoarse, Rscale));
672 }
673 PetscCall(DMRestoreNamedGlobalVector(dmcoarse, "SNESVecSol", &Xcoarse));
674 if (Xfine_named) PetscCall(DMRestoreNamedGlobalVector(dmfine, "SNESVecSol", &Xfine_named));
675 PetscFunctionReturn(PETSC_SUCCESS);
676 }
677
DMCoarsenHook_SNESVecSol(DM dm,DM dmc,PetscCtx ctx)678 static PetscErrorCode DMCoarsenHook_SNESVecSol(DM dm, DM dmc, PetscCtx ctx)
679 {
680 PetscFunctionBegin;
681 PetscCall(DMCoarsenHookAdd(dmc, DMCoarsenHook_SNESVecSol, DMRestrictHook_SNESVecSol, ctx));
682 PetscFunctionReturn(PETSC_SUCCESS);
683 }
684
685 /* This may be called to rediscretize the operator on levels of linear multigrid. The DM shuffle is so the user can
686 * safely call SNESGetDM() in their residual evaluation routine. */
KSPComputeOperators_SNES(KSP ksp,Mat A,Mat B,PetscCtx ctx)687 static PetscErrorCode KSPComputeOperators_SNES(KSP ksp, Mat A, Mat B, PetscCtx ctx)
688 {
689 SNES snes = (SNES)ctx;
690 DMSNES sdm;
691 Vec X, Xnamed = NULL;
692 DM dmsave;
693 void *ctxsave;
694 SNESJacobianFn *jac = NULL;
695
696 PetscFunctionBegin;
697 dmsave = snes->dm;
698 PetscCall(KSPGetDM(ksp, &snes->dm));
699 if (dmsave == snes->dm) X = snes->vec_sol; /* We are on the finest level */
700 else {
701 PetscBool has;
702
703 /* We are on a coarser level, this vec was initialized using a DM restrict hook */
704 PetscCall(DMHasNamedGlobalVector(snes->dm, "SNESVecSol", &has));
705 PetscCheck(has, PetscObjectComm((PetscObject)snes->dm), PETSC_ERR_PLIB, "Missing SNESVecSol");
706 PetscCall(DMGetNamedGlobalVector(snes->dm, "SNESVecSol", &Xnamed));
707 X = Xnamed;
708 PetscCall(SNESGetJacobian(snes, NULL, NULL, &jac, &ctxsave));
709 /* If the DM's don't match up, the MatFDColoring context needed for the jacobian won't match up either -- fixit. */
710 if (jac == SNESComputeJacobianDefaultColor) PetscCall(SNESSetJacobian(snes, NULL, NULL, SNESComputeJacobianDefaultColor, NULL));
711 }
712
713 /* Compute the operators */
714 PetscCall(DMGetDMSNES(snes->dm, &sdm));
715 if (Xnamed && sdm->ops->computefunction) {
716 /* The SNES contract with the user is that ComputeFunction is always called before ComputeJacobian.
717 We make sure of this here. Disable affine shift since it is for the finest level */
718 Vec F, saverhs = snes->vec_rhs;
719
720 snes->vec_rhs = NULL;
721 PetscCall(DMGetGlobalVector(snes->dm, &F));
722 PetscCall(SNESComputeFunction(snes, X, F));
723 PetscCall(DMRestoreGlobalVector(snes->dm, &F));
724 snes->vec_rhs = saverhs;
725 snes->nfuncs--; /* Do not log coarser level evaluations */
726 }
727 /* Make sure KSP DM has the Jacobian computation routine */
728 if (!sdm->ops->computejacobian) PetscCall(DMCopyDMSNES(dmsave, snes->dm));
729 PetscCall(SNESComputeJacobian(snes, X, A, B)); /* cannot handle previous SNESSetJacobianDomainError() calls */
730
731 /* Put the previous context back */
732 if (snes->dm != dmsave && jac == SNESComputeJacobianDefaultColor) PetscCall(SNESSetJacobian(snes, NULL, NULL, jac, ctxsave));
733
734 if (Xnamed) PetscCall(DMRestoreNamedGlobalVector(snes->dm, "SNESVecSol", &Xnamed));
735 snes->dm = dmsave;
736 PetscFunctionReturn(PETSC_SUCCESS);
737 }
738
739 /*@
740 SNESSetUpMatrices - ensures that matrices are available for `SNES` Newton-like methods, this is called by `SNESSetUp_XXX()`
741
742 Collective
743
744 Input Parameter:
745 . snes - `SNES` object to configure
746
747 Level: developer
748
749 Note:
750 If the matrices do not yet exist it attempts to create them based on options previously set for the `SNES` such as `-snes_mf`
751
752 Developer Note:
753 The functionality of this routine overlaps in a confusing way with the functionality of `SNESSetUpMatrixFree_Private()` which is called by
754 `SNESSetUp()` but sometimes `SNESSetUpMatrices()` is called without `SNESSetUp()` being called. A refactorization to simplify the
755 logic that handles the matrix-free case is desirable.
756
757 .seealso: [](ch_snes), `SNES`, `SNESSetUp()`
758 @*/
SNESSetUpMatrices(SNES snes)759 PetscErrorCode SNESSetUpMatrices(SNES snes)
760 {
761 DM dm;
762 DMSNES sdm;
763
764 PetscFunctionBegin;
765 PetscCall(SNESGetDM(snes, &dm));
766 PetscCall(DMGetDMSNES(dm, &sdm));
767 if (!snes->jacobian && snes->mf && !snes->mf_operator && !snes->jacobian_pre) {
768 Mat J;
769 void *functx;
770 PetscCall(MatCreateSNESMF(snes, &J));
771 PetscCall(MatMFFDSetOptionsPrefix(J, ((PetscObject)snes)->prefix));
772 PetscCall(MatSetFromOptions(J));
773 PetscCall(SNESGetFunction(snes, NULL, NULL, &functx));
774 PetscCall(SNESSetJacobian(snes, J, J, NULL, NULL));
775 PetscCall(MatDestroy(&J));
776 } else if (snes->mf_operator && !snes->jacobian_pre && !snes->jacobian) {
777 Mat J, B;
778 PetscCall(MatCreateSNESMF(snes, &J));
779 PetscCall(MatMFFDSetOptionsPrefix(J, ((PetscObject)snes)->prefix));
780 PetscCall(MatSetFromOptions(J));
781 PetscCall(DMCreateMatrix(snes->dm, &B));
782 /* sdm->computejacobian was already set to reach here */
783 PetscCall(SNESSetJacobian(snes, J, B, NULL, NULL));
784 PetscCall(MatDestroy(&J));
785 PetscCall(MatDestroy(&B));
786 } else if (!snes->jacobian_pre) {
787 PetscDS prob;
788 Mat J, B;
789 PetscBool hasPrec = PETSC_FALSE;
790
791 J = snes->jacobian;
792 PetscCall(DMGetDS(dm, &prob));
793 if (prob) PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec));
794 if (J) PetscCall(PetscObjectReference((PetscObject)J));
795 else if (hasPrec) PetscCall(DMCreateMatrix(snes->dm, &J));
796 PetscCall(DMCreateMatrix(snes->dm, &B));
797 PetscCall(SNESSetJacobian(snes, J ? J : B, B, NULL, NULL));
798 PetscCall(MatDestroy(&J));
799 PetscCall(MatDestroy(&B));
800 }
801 {
802 KSP ksp;
803 PetscCall(SNESGetKSP(snes, &ksp));
804 PetscCall(KSPSetComputeOperators(ksp, KSPComputeOperators_SNES, snes));
805 PetscCall(DMCoarsenHookAdd(snes->dm, DMCoarsenHook_SNESVecSol, DMRestrictHook_SNESVecSol, snes));
806 }
807 PetscFunctionReturn(PETSC_SUCCESS);
808 }
809
810 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode PetscMonitorPauseFinal_Internal(PetscInt, void *);
811
SNESMonitorPauseFinal_Internal(SNES snes)812 static PetscErrorCode SNESMonitorPauseFinal_Internal(SNES snes)
813 {
814 PetscFunctionBegin;
815 if (!snes->pauseFinal) PetscFunctionReturn(PETSC_SUCCESS);
816 PetscCall(PetscMonitorPauseFinal_Internal(snes->numbermonitors, snes->monitorcontext));
817 PetscFunctionReturn(PETSC_SUCCESS);
818 }
819
820 /*@C
821 SNESMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
822
823 Collective
824
825 Input Parameters:
826 + snes - `SNES` object you wish to monitor
827 . name - the monitor type one is seeking
828 . help - message indicating what monitoring is done
829 . manual - manual page for the monitor
830 . monitor - the monitor function, this must use a `PetscViewerFormat` as its context
831 - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `SNES` or `PetscViewer` objects
832
833 Calling sequence of `monitor`:
834 + snes - the nonlinear solver context
835 . it - the current iteration
836 . r - the current function norm
837 - vf - a `PetscViewerAndFormat` struct that contains the `PetscViewer` and `PetscViewerFormat` to use
838
839 Calling sequence of `monitorsetup`:
840 + snes - the nonlinear solver context
841 - vf - a `PetscViewerAndFormat` struct that contains the `PetscViewer` and `PetscViewerFormat` to use
842
843 Options Database Key:
844 . -name - trigger the use of this monitor in `SNESSetFromOptions()`
845
846 Level: advanced
847
848 .seealso: [](ch_snes), `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
849 `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
850 `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
851 `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
852 `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
853 `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
854 `PetscOptionsFList()`, `PetscOptionsEList()`
855 @*/
SNESMonitorSetFromOptions(SNES snes,const char name[],const char help[],const char manual[],PetscErrorCode (* monitor)(SNES snes,PetscInt it,PetscReal r,PetscViewerAndFormat * vf),PetscErrorCode (* monitorsetup)(SNES snes,PetscViewerAndFormat * vf))856 PetscErrorCode SNESMonitorSetFromOptions(SNES snes, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(SNES snes, PetscInt it, PetscReal r, PetscViewerAndFormat *vf), PetscErrorCode (*monitorsetup)(SNES snes, PetscViewerAndFormat *vf))
857 {
858 PetscViewer viewer;
859 PetscViewerFormat format;
860 PetscBool flg;
861
862 PetscFunctionBegin;
863 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, name, &viewer, &format, &flg));
864 if (flg) {
865 PetscViewerAndFormat *vf;
866 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
867 PetscCall(PetscViewerDestroy(&viewer));
868 if (monitorsetup) PetscCall((*monitorsetup)(snes, vf));
869 PetscCall(SNESMonitorSet(snes, (PetscErrorCode (*)(SNES, PetscInt, PetscReal, PetscCtx))monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
870 }
871 PetscFunctionReturn(PETSC_SUCCESS);
872 }
873
SNESEWSetFromOptions_Private(SNESKSPEW * kctx,PetscBool print_api,MPI_Comm comm,const char * prefix)874 PetscErrorCode SNESEWSetFromOptions_Private(SNESKSPEW *kctx, PetscBool print_api, MPI_Comm comm, const char *prefix)
875 {
876 const char *api = print_api ? "SNESKSPSetParametersEW" : NULL;
877
878 PetscFunctionBegin;
879 PetscOptionsBegin(comm, prefix, "Eisenstat and Walker type forcing options", "KSP");
880 PetscCall(PetscOptionsInt("-ksp_ew_version", "Version 1, 2 or 3", api, kctx->version, &kctx->version, NULL));
881 PetscCall(PetscOptionsReal("-ksp_ew_rtol0", "0 <= rtol0 < 1", api, kctx->rtol_0, &kctx->rtol_0, NULL));
882 kctx->rtol_max = PetscMax(kctx->rtol_0, kctx->rtol_max);
883 PetscCall(PetscOptionsReal("-ksp_ew_rtolmax", "0 <= rtolmax < 1", api, kctx->rtol_max, &kctx->rtol_max, NULL));
884 PetscCall(PetscOptionsReal("-ksp_ew_gamma", "0 <= gamma <= 1", api, kctx->gamma, &kctx->gamma, NULL));
885 PetscCall(PetscOptionsReal("-ksp_ew_alpha", "1 < alpha <= 2", api, kctx->alpha, &kctx->alpha, NULL));
886 PetscCall(PetscOptionsReal("-ksp_ew_alpha2", "alpha2", NULL, kctx->alpha2, &kctx->alpha2, NULL));
887 PetscCall(PetscOptionsReal("-ksp_ew_threshold", "0 < threshold < 1", api, kctx->threshold, &kctx->threshold, NULL));
888 PetscCall(PetscOptionsReal("-ksp_ew_v4_p1", "p1", NULL, kctx->v4_p1, &kctx->v4_p1, NULL));
889 PetscCall(PetscOptionsReal("-ksp_ew_v4_p2", "p2", NULL, kctx->v4_p2, &kctx->v4_p2, NULL));
890 PetscCall(PetscOptionsReal("-ksp_ew_v4_p3", "p3", NULL, kctx->v4_p3, &kctx->v4_p3, NULL));
891 PetscCall(PetscOptionsReal("-ksp_ew_v4_m1", "Scaling when rk-1 in [p2,p3)", NULL, kctx->v4_m1, &kctx->v4_m1, NULL));
892 PetscCall(PetscOptionsReal("-ksp_ew_v4_m2", "Scaling when rk-1 in [p3,+infty)", NULL, kctx->v4_m2, &kctx->v4_m2, NULL));
893 PetscCall(PetscOptionsReal("-ksp_ew_v4_m3", "Threshold for successive rtol (0.1 in Eq.7)", NULL, kctx->v4_m3, &kctx->v4_m3, NULL));
894 PetscCall(PetscOptionsReal("-ksp_ew_v4_m4", "Adaptation scaling (0.5 in Eq.7)", NULL, kctx->v4_m4, &kctx->v4_m4, NULL));
895 PetscOptionsEnd();
896 PetscFunctionReturn(PETSC_SUCCESS);
897 }
898
899 /*@
900 SNESSetFromOptions - Sets various `SNES` and `KSP` parameters from user options.
901
902 Collective
903
904 Input Parameter:
905 . snes - the `SNES` context
906
907 Options Database Keys:
908 + -snes_type <type> - newtonls, newtontr, ngmres, ncg, nrichardson, qn, vi, fas, `SNESType` for complete list
909 . -snes_rtol <rtol> - relative decrease in tolerance norm from initial
910 . -snes_atol <abstol> - absolute tolerance of residual norm
911 . -snes_stol <stol> - convergence tolerance in terms of the norm of the change in the solution between steps
912 . -snes_divergence_tolerance <divtol> - if the residual goes above divtol*rnorm0, exit with divergence
913 . -snes_max_it <max_it> - maximum number of iterations
914 . -snes_max_funcs <max_funcs> - maximum number of function evaluations
915 . -snes_force_iteration <force> - force `SNESSolve()` to take at least one iteration
916 . -snes_max_fail <max_fail> - maximum number of line search failures allowed before stopping, default is none
917 . -snes_max_linear_solve_fail - number of linear solver failures before SNESSolve() stops
918 . -snes_lag_preconditioner <lag> - how often preconditioner is rebuilt (use -1 to never rebuild)
919 . -snes_lag_preconditioner_persists <true,false> - retains the -snes_lag_preconditioner information across multiple SNESSolve()
920 . -snes_lag_jacobian <lag> - how often Jacobian is rebuilt (use -1 to never rebuild)
921 . -snes_lag_jacobian_persists <true,false> - retains the -snes_lag_jacobian information across multiple SNESSolve()
922 . -snes_convergence_test <default,skip,correct_pressure> - convergence test in nonlinear solver. default `SNESConvergedDefault()`. skip `SNESConvergedSkip()` means continue iterating until max_it or some other criterion is reached, saving expense of convergence test. correct_pressure `SNESConvergedCorrectPressure()` has special handling of a pressure null space.
923 . -snes_monitor [ascii][:filename][:viewer format] - prints residual norm at each iteration. if no filename given prints to stdout
924 . -snes_monitor_solution [ascii binary draw][:filename][:viewer format] - plots solution at each iteration
925 . -snes_monitor_residual [ascii binary draw][:filename][:viewer format] - plots residual (not its norm) at each iteration
926 . -snes_monitor_solution_update [ascii binary draw][:filename][:viewer format] - plots update to solution at each iteration
927 . -snes_monitor_lg_residualnorm - plots residual norm at each iteration
928 . -snes_monitor_lg_range - plots residual norm at each iteration
929 . -snes_monitor_pause_final - Pauses all monitor drawing after the solver ends
930 . -snes_fd - use finite differences to compute Jacobian; very slow, only for testing
931 . -snes_fd_color - use finite differences with coloring to compute Jacobian
932 . -snes_mf_ksp_monitor - if using matrix-free multiply then print h at each `KSP` iteration
933 . -snes_converged_reason - print the reason for convergence/divergence after each solve
934 . -npc_snes_type <type> - the `SNES` type to use as a nonlinear preconditioner
935 . -snes_test_jacobian <optional threshold> - compare the user provided Jacobian with one computed via finite differences to check for errors. If a threshold is given, display only those entries whose difference is greater than the threshold.
936 - -snes_test_jacobian_view - display the user provided Jacobian, the finite difference Jacobian and the difference between them to help users detect the location of errors in the user provided Jacobian.
937
938 Options Database Keys for Eisenstat-Walker method:
939 + -snes_ksp_ew - use Eisenstat-Walker method for determining linear system convergence
940 . -snes_ksp_ew_version ver - version of Eisenstat-Walker method
941 . -snes_ksp_ew_rtol0 <rtol0> - Sets rtol0
942 . -snes_ksp_ew_rtolmax <rtolmax> - Sets rtolmax
943 . -snes_ksp_ew_gamma <gamma> - Sets gamma
944 . -snes_ksp_ew_alpha <alpha> - Sets alpha
945 . -snes_ksp_ew_alpha2 <alpha2> - Sets alpha2
946 - -snes_ksp_ew_threshold <threshold> - Sets threshold
947
948 Level: beginner
949
950 Notes:
951 To see all options, run your program with the -help option or consult the users manual
952
953 `SNES` supports three approaches for computing (approximate) Jacobians: user provided via `SNESSetJacobian()`, matrix-free using `MatCreateSNESMF()`,
954 and computing explicitly with
955 finite differences and coloring using `MatFDColoring`. It is also possible to use automatic differentiation and the `MatFDColoring` object.
956
957 .seealso: [](ch_snes), `SNESType`, `SNESSetOptionsPrefix()`, `SNESResetFromOptions()`, `SNES`, `SNESCreate()`, `MatCreateSNESMF()`, `MatFDColoring`
958 @*/
SNESSetFromOptions(SNES snes)959 PetscErrorCode SNESSetFromOptions(SNES snes)
960 {
961 PetscBool flg, pcset, persist, set;
962 PetscInt i, indx, lag, grids, max_its, max_funcs;
963 const char *deft = SNESNEWTONLS;
964 const char *convtests[] = {"default", "skip", "correct_pressure"};
965 SNESKSPEW *kctx = NULL;
966 char type[256], monfilename[PETSC_MAX_PATH_LEN], ewprefix[256];
967 PCSide pcside;
968 const char *optionsprefix;
969 PetscReal rtol, abstol, stol;
970
971 PetscFunctionBegin;
972 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
973 PetscCall(SNESRegisterAll());
974 PetscObjectOptionsBegin((PetscObject)snes);
975 if (((PetscObject)snes)->type_name) deft = ((PetscObject)snes)->type_name;
976 PetscCall(PetscOptionsFList("-snes_type", "Nonlinear solver method", "SNESSetType", SNESList, deft, type, 256, &flg));
977 if (flg) {
978 PetscCall(SNESSetType(snes, type));
979 } else if (!((PetscObject)snes)->type_name) {
980 PetscCall(SNESSetType(snes, deft));
981 }
982
983 abstol = snes->abstol;
984 rtol = snes->rtol;
985 stol = snes->stol;
986 max_its = snes->max_its;
987 max_funcs = snes->max_funcs;
988 PetscCall(PetscOptionsReal("-snes_rtol", "Stop if decrease in function norm less than", "SNESSetTolerances", snes->rtol, &rtol, NULL));
989 PetscCall(PetscOptionsReal("-snes_atol", "Stop if function norm less than", "SNESSetTolerances", snes->abstol, &abstol, NULL));
990 PetscCall(PetscOptionsReal("-snes_stol", "Stop if step length less than", "SNESSetTolerances", snes->stol, &stol, NULL));
991 PetscCall(PetscOptionsInt("-snes_max_it", "Maximum iterations", "SNESSetTolerances", snes->max_its, &max_its, NULL));
992 PetscCall(PetscOptionsInt("-snes_max_funcs", "Maximum function evaluations", "SNESSetTolerances", snes->max_funcs, &max_funcs, NULL));
993 PetscCall(SNESSetTolerances(snes, abstol, rtol, stol, max_its, max_funcs));
994
995 PetscCall(PetscOptionsReal("-snes_divergence_tolerance", "Stop if residual norm increases by this factor", "SNESSetDivergenceTolerance", snes->divtol, &snes->divtol, &flg));
996 if (flg) PetscCall(SNESSetDivergenceTolerance(snes, snes->divtol));
997
998 PetscCall(PetscOptionsInt("-snes_max_fail", "Maximum nonlinear step failures", "SNESSetMaxNonlinearStepFailures", snes->maxFailures, &snes->maxFailures, &flg));
999 if (flg) PetscCall(SNESSetMaxNonlinearStepFailures(snes, snes->maxFailures));
1000
1001 PetscCall(PetscOptionsInt("-snes_max_linear_solve_fail", "Maximum failures in linear solves allowed", "SNESSetMaxLinearSolveFailures", snes->maxLinearSolveFailures, &snes->maxLinearSolveFailures, &flg));
1002 if (flg) PetscCall(SNESSetMaxLinearSolveFailures(snes, snes->maxLinearSolveFailures));
1003
1004 PetscCall(PetscOptionsBool("-snes_error_if_not_converged", "Generate error if solver does not converge", "SNESSetErrorIfNotConverged", snes->errorifnotconverged, &snes->errorifnotconverged, NULL));
1005 PetscCall(PetscOptionsBool("-snes_force_iteration", "Force SNESSolve() to take at least one iteration", "SNESSetForceIteration", snes->forceiteration, &snes->forceiteration, NULL));
1006 PetscCall(PetscOptionsBool("-snes_check_jacobian_domain_error", "Check Jacobian domain error after Jacobian evaluation", "SNESCheckJacobianDomainError", snes->checkjacdomainerror, &snes->checkjacdomainerror, NULL));
1007
1008 PetscCall(PetscOptionsInt("-snes_lag_preconditioner", "How often to rebuild preconditioner", "SNESSetLagPreconditioner", snes->lagpreconditioner, &lag, &flg));
1009 if (flg) {
1010 PetscCheck(lag != -1, PetscObjectComm((PetscObject)snes), PETSC_ERR_USER, "Cannot set the lag to -1 from the command line since the preconditioner must be built as least once, perhaps you mean -2");
1011 PetscCall(SNESSetLagPreconditioner(snes, lag));
1012 }
1013 PetscCall(PetscOptionsBool("-snes_lag_preconditioner_persists", "Preconditioner lagging through multiple SNES solves", "SNESSetLagPreconditionerPersists", snes->lagjac_persist, &persist, &flg));
1014 if (flg) PetscCall(SNESSetLagPreconditionerPersists(snes, persist));
1015 PetscCall(PetscOptionsInt("-snes_lag_jacobian", "How often to rebuild Jacobian", "SNESSetLagJacobian", snes->lagjacobian, &lag, &flg));
1016 if (flg) {
1017 PetscCheck(lag != -1, PetscObjectComm((PetscObject)snes), PETSC_ERR_USER, "Cannot set the lag to -1 from the command line since the Jacobian must be built as least once, perhaps you mean -2");
1018 PetscCall(SNESSetLagJacobian(snes, lag));
1019 }
1020 PetscCall(PetscOptionsBool("-snes_lag_jacobian_persists", "Jacobian lagging through multiple SNES solves", "SNESSetLagJacobianPersists", snes->lagjac_persist, &persist, &flg));
1021 if (flg) PetscCall(SNESSetLagJacobianPersists(snes, persist));
1022
1023 PetscCall(PetscOptionsInt("-snes_grid_sequence", "Use grid sequencing to generate initial guess", "SNESSetGridSequence", snes->gridsequence, &grids, &flg));
1024 if (flg) PetscCall(SNESSetGridSequence(snes, grids));
1025
1026 PetscCall(PetscOptionsEList("-snes_convergence_test", "Convergence test", "SNESSetConvergenceTest", convtests, PETSC_STATIC_ARRAY_LENGTH(convtests), "default", &indx, &flg));
1027 if (flg) {
1028 switch (indx) {
1029 case 0:
1030 PetscCall(SNESSetConvergenceTest(snes, SNESConvergedDefault, NULL, NULL));
1031 break;
1032 case 1:
1033 PetscCall(SNESSetConvergenceTest(snes, SNESConvergedSkip, NULL, NULL));
1034 break;
1035 case 2:
1036 PetscCall(SNESSetConvergenceTest(snes, SNESConvergedCorrectPressure, NULL, NULL));
1037 break;
1038 }
1039 }
1040
1041 PetscCall(PetscOptionsEList("-snes_norm_schedule", "SNES Norm schedule", "SNESSetNormSchedule", SNESNormSchedules, 5, "function", &indx, &flg));
1042 if (flg) PetscCall(SNESSetNormSchedule(snes, (SNESNormSchedule)indx));
1043
1044 PetscCall(PetscOptionsEList("-snes_function_type", "SNES Norm schedule", "SNESSetFunctionType", SNESFunctionTypes, 2, "unpreconditioned", &indx, &flg));
1045 if (flg) PetscCall(SNESSetFunctionType(snes, (SNESFunctionType)indx));
1046
1047 kctx = (SNESKSPEW *)snes->kspconvctx;
1048
1049 PetscCall(PetscOptionsBool("-snes_ksp_ew", "Use Eisentat-Walker linear system convergence test", "SNESKSPSetUseEW", snes->ksp_ewconv, &snes->ksp_ewconv, NULL));
1050
1051 PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix));
1052 PetscCall(PetscSNPrintf(ewprefix, sizeof(ewprefix), "%s%s", optionsprefix ? optionsprefix : "", "snes_"));
1053 PetscCall(SNESEWSetFromOptions_Private(kctx, PETSC_TRUE, PetscObjectComm((PetscObject)snes), ewprefix));
1054
1055 flg = PETSC_FALSE;
1056 PetscCall(PetscOptionsBool("-snes_monitor_cancel", "Remove all monitors", "SNESMonitorCancel", flg, &flg, &set));
1057 if (set && flg) PetscCall(SNESMonitorCancel(snes));
1058
1059 PetscCall(SNESMonitorSetFromOptions(snes, "-snes_monitor", "Monitor norm of function", "SNESMonitorDefault", SNESMonitorDefault, SNESMonitorDefaultSetUp));
1060 PetscCall(SNESMonitorSetFromOptions(snes, "-snes_monitor_short", "Monitor norm of function with fewer digits", "SNESMonitorDefaultShort", SNESMonitorDefaultShort, NULL));
1061 PetscCall(SNESMonitorSetFromOptions(snes, "-snes_monitor_range", "Monitor range of elements of function", "SNESMonitorRange", SNESMonitorRange, NULL));
1062
1063 PetscCall(SNESMonitorSetFromOptions(snes, "-snes_monitor_ratio", "Monitor ratios of the norm of function for consecutive steps", "SNESMonitorRatio", SNESMonitorRatio, SNESMonitorRatioSetUp));
1064 PetscCall(SNESMonitorSetFromOptions(snes, "-snes_monitor_field", "Monitor norm of function (split into fields)", "SNESMonitorDefaultField", SNESMonitorDefaultField, NULL));
1065 PetscCall(SNESMonitorSetFromOptions(snes, "-snes_monitor_solution", "View solution at each iteration", "SNESMonitorSolution", SNESMonitorSolution, NULL));
1066 PetscCall(SNESMonitorSetFromOptions(snes, "-snes_monitor_solution_update", "View correction at each iteration", "SNESMonitorSolutionUpdate", SNESMonitorSolutionUpdate, NULL));
1067 PetscCall(SNESMonitorSetFromOptions(snes, "-snes_monitor_residual", "View residual at each iteration", "SNESMonitorResidual", SNESMonitorResidual, NULL));
1068 PetscCall(SNESMonitorSetFromOptions(snes, "-snes_monitor_jacupdate_spectrum", "Print the change in the spectrum of the Jacobian", "SNESMonitorJacUpdateSpectrum", SNESMonitorJacUpdateSpectrum, NULL));
1069 PetscCall(SNESMonitorSetFromOptions(snes, "-snes_monitor_fields", "Monitor norm of function per field", "SNESMonitorSet", SNESMonitorFields, NULL));
1070 PetscCall(PetscOptionsBool("-snes_monitor_pause_final", "Pauses all draw monitors at the final iterate", "SNESMonitorPauseFinal_Internal", PETSC_FALSE, &snes->pauseFinal, NULL));
1071
1072 PetscCall(PetscOptionsString("-snes_monitor_python", "Use Python function", "SNESMonitorSet", NULL, monfilename, sizeof(monfilename), &flg));
1073 if (flg) PetscCall(PetscPythonMonitorSet((PetscObject)snes, monfilename));
1074
1075 flg = PETSC_FALSE;
1076 PetscCall(PetscOptionsBool("-snes_monitor_lg_range", "Plot function range at each iteration", "SNESMonitorLGRange", flg, &flg, NULL));
1077 if (flg) {
1078 PetscViewer ctx;
1079
1080 PetscCall(PetscViewerDrawOpen(PetscObjectComm((PetscObject)snes), NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 400, 300, &ctx));
1081 PetscCall(SNESMonitorSet(snes, SNESMonitorLGRange, ctx, (PetscCtxDestroyFn *)PetscViewerDestroy));
1082 }
1083
1084 PetscCall(PetscViewerDestroy(&snes->convergedreasonviewer));
1085 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_converged_reason", &snes->convergedreasonviewer, &snes->convergedreasonformat, NULL));
1086 flg = PETSC_FALSE;
1087 PetscCall(PetscOptionsBool("-snes_converged_reason_view_cancel", "Remove all converged reason viewers", "SNESConvergedReasonViewCancel", flg, &flg, &set));
1088 if (set && flg) PetscCall(SNESConvergedReasonViewCancel(snes));
1089
1090 flg = PETSC_FALSE;
1091 PetscCall(PetscOptionsBool("-snes_fd", "Use finite differences (slow) to compute Jacobian", "SNESComputeJacobianDefault", flg, &flg, NULL));
1092 if (flg) {
1093 void *functx;
1094 DM dm;
1095 PetscCall(SNESGetDM(snes, &dm));
1096 PetscCall(DMSNESUnsetJacobianContext_Internal(dm));
1097 PetscCall(SNESGetFunction(snes, NULL, NULL, &functx));
1098 PetscCall(SNESSetJacobian(snes, snes->jacobian, snes->jacobian_pre, SNESComputeJacobianDefault, functx));
1099 PetscCall(PetscInfo(snes, "Setting default finite difference Jacobian matrix\n"));
1100 }
1101
1102 flg = PETSC_FALSE;
1103 PetscCall(PetscOptionsBool("-snes_fd_function", "Use finite differences (slow) to compute function from user objective", "SNESObjectiveComputeFunctionDefaultFD", flg, &flg, NULL));
1104 if (flg) PetscCall(SNESSetFunction(snes, NULL, SNESObjectiveComputeFunctionDefaultFD, NULL));
1105
1106 flg = PETSC_FALSE;
1107 PetscCall(PetscOptionsBool("-snes_fd_color", "Use finite differences with coloring to compute Jacobian", "SNESComputeJacobianDefaultColor", flg, &flg, NULL));
1108 if (flg) {
1109 DM dm;
1110 PetscCall(SNESGetDM(snes, &dm));
1111 PetscCall(DMSNESUnsetJacobianContext_Internal(dm));
1112 PetscCall(SNESSetJacobian(snes, snes->jacobian, snes->jacobian_pre, SNESComputeJacobianDefaultColor, NULL));
1113 PetscCall(PetscInfo(snes, "Setting default finite difference coloring Jacobian matrix\n"));
1114 }
1115
1116 flg = PETSC_FALSE;
1117 PetscCall(PetscOptionsBool("-snes_mf_operator", "Use a Matrix-Free Jacobian with user-provided matrix for computing the preconditioner", "SNESSetUseMatrixFree", PETSC_FALSE, &snes->mf_operator, &flg));
1118 if (flg && snes->mf_operator) {
1119 snes->mf_operator = PETSC_TRUE;
1120 snes->mf = PETSC_TRUE;
1121 }
1122 flg = PETSC_FALSE;
1123 PetscCall(PetscOptionsBool("-snes_mf", "Use a Matrix-Free Jacobian with no matrix for computing the preconditioner", "SNESSetUseMatrixFree", PETSC_FALSE, &snes->mf, &flg));
1124 if (!flg && snes->mf_operator) snes->mf = PETSC_TRUE;
1125 PetscCall(PetscOptionsInt("-snes_mf_version", "Matrix-Free routines version 1 or 2", "None", snes->mf_version, &snes->mf_version, NULL));
1126
1127 PetscCall(PetscOptionsName("-snes_test_function", "Compare hand-coded and finite difference functions", "None", &snes->testFunc));
1128 PetscCall(PetscOptionsName("-snes_test_jacobian", "Compare hand-coded and finite difference Jacobians", "None", &snes->testJac));
1129
1130 flg = PETSC_FALSE;
1131 PetscCall(SNESGetNPCSide(snes, &pcside));
1132 PetscCall(PetscOptionsEnum("-snes_npc_side", "SNES nonlinear preconditioner side", "SNESSetNPCSide", PCSides, (PetscEnum)pcside, (PetscEnum *)&pcside, &flg));
1133 if (flg) PetscCall(SNESSetNPCSide(snes, pcside));
1134
1135 #if defined(PETSC_HAVE_SAWS)
1136 /*
1137 Publish convergence information using SAWs
1138 */
1139 flg = PETSC_FALSE;
1140 PetscCall(PetscOptionsBool("-snes_monitor_saws", "Publish SNES progress using SAWs", "SNESMonitorSet", flg, &flg, NULL));
1141 if (flg) {
1142 PetscCtx ctx;
1143 PetscCall(SNESMonitorSAWsCreate(snes, &ctx));
1144 PetscCall(SNESMonitorSet(snes, SNESMonitorSAWs, ctx, SNESMonitorSAWsDestroy));
1145 }
1146 #endif
1147 #if defined(PETSC_HAVE_SAWS)
1148 {
1149 PetscBool set;
1150 flg = PETSC_FALSE;
1151 PetscCall(PetscOptionsBool("-snes_saws_block", "Block for SAWs at end of SNESSolve", "PetscObjectSAWsBlock", ((PetscObject)snes)->amspublishblock, &flg, &set));
1152 if (set) PetscCall(PetscObjectSAWsSetBlock((PetscObject)snes, flg));
1153 }
1154 #endif
1155
1156 for (i = 0; i < numberofsetfromoptions; i++) PetscCall((*othersetfromoptions[i])(snes));
1157
1158 PetscTryTypeMethod(snes, setfromoptions, PetscOptionsObject);
1159
1160 /* process any options handlers added with PetscObjectAddOptionsHandler() */
1161 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)snes, PetscOptionsObject));
1162 PetscOptionsEnd();
1163
1164 if (snes->linesearch) {
1165 PetscCall(SNESGetLineSearch(snes, &snes->linesearch));
1166 PetscCall(SNESLineSearchSetFromOptions(snes->linesearch));
1167 }
1168
1169 if (snes->usesksp) {
1170 if (!snes->ksp) PetscCall(SNESGetKSP(snes, &snes->ksp));
1171 PetscCall(KSPSetOperators(snes->ksp, snes->jacobian, snes->jacobian_pre));
1172 PetscCall(KSPSetFromOptions(snes->ksp));
1173 }
1174
1175 /* if user has set the SNES NPC type via options database, create it. */
1176 PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix));
1177 PetscCall(PetscOptionsHasName(((PetscObject)snes)->options, optionsprefix, "-npc_snes_type", &pcset));
1178 if (pcset && (!snes->npc)) PetscCall(SNESGetNPC(snes, &snes->npc));
1179 if (snes->npc) PetscCall(SNESSetFromOptions(snes->npc));
1180 snes->setfromoptionscalled++;
1181 PetscFunctionReturn(PETSC_SUCCESS);
1182 }
1183
1184 /*@
1185 SNESResetFromOptions - Sets various `SNES` and `KSP` parameters from user options ONLY if the `SNESSetFromOptions()` was previously called
1186
1187 Collective
1188
1189 Input Parameter:
1190 . snes - the `SNES` context
1191
1192 Level: advanced
1193
1194 .seealso: [](ch_snes), `SNES`, `SNESSetFromOptions()`, `SNESSetOptionsPrefix()`
1195 @*/
SNESResetFromOptions(SNES snes)1196 PetscErrorCode SNESResetFromOptions(SNES snes)
1197 {
1198 PetscFunctionBegin;
1199 if (snes->setfromoptionscalled) PetscCall(SNESSetFromOptions(snes));
1200 PetscFunctionReturn(PETSC_SUCCESS);
1201 }
1202
1203 /*@C
1204 SNESSetComputeApplicationContext - Sets an optional function to compute a user-defined context for
1205 the nonlinear solvers.
1206
1207 Logically Collective; No Fortran Support
1208
1209 Input Parameters:
1210 + snes - the `SNES` context
1211 . compute - function to compute the context
1212 - destroy - function to destroy the context, see `PetscCtxDestroyFn` for the calling sequence
1213
1214 Calling sequence of `compute`:
1215 + snes - the `SNES` context
1216 - ctx - context to be computed
1217
1218 Level: intermediate
1219
1220 Note:
1221 This routine is useful if you are performing grid sequencing or using `SNESFAS` and need the appropriate context generated for each level.
1222
1223 Use `SNESSetApplicationContext()` to see the context immediately
1224
1225 .seealso: [](ch_snes), `SNESGetApplicationContext()`, `SNESSetApplicationContext()`, `PetscCtxDestroyFn`
1226 @*/
SNESSetComputeApplicationContext(SNES snes,PetscErrorCode (* compute)(SNES snes,PetscCtxRt ctx),PetscCtxDestroyFn * destroy)1227 PetscErrorCode SNESSetComputeApplicationContext(SNES snes, PetscErrorCode (*compute)(SNES snes, PetscCtxRt ctx), PetscCtxDestroyFn *destroy)
1228 {
1229 PetscFunctionBegin;
1230 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1231 snes->ops->ctxcompute = compute;
1232 snes->ops->ctxdestroy = destroy;
1233 PetscFunctionReturn(PETSC_SUCCESS);
1234 }
1235
1236 /*@
1237 SNESSetApplicationContext - Sets the optional user-defined context for the nonlinear solvers.
1238
1239 Logically Collective
1240
1241 Input Parameters:
1242 + snes - the `SNES` context
1243 - ctx - the user context
1244
1245 Level: intermediate
1246
1247 Notes:
1248 Users can provide a context when constructing the `SNES` options and then access it inside their function, Jacobian computation, or other evaluation function
1249 with `SNESGetApplicationContext()`
1250
1251 To provide a function that computes the context for you use `SNESSetComputeApplicationContext()`
1252
1253 Fortran Note:
1254 This only works when `ctx` is a Fortran derived type (it cannot be a `PetscObject`), we recommend writing a Fortran interface definition for this
1255 function that tells the Fortran compiler the derived data type that is passed in as the `ctx` argument. See `SNESGetApplicationContext()` for
1256 an example.
1257
1258 .seealso: [](ch_snes), `SNES`, `SNESSetComputeApplicationContext()`, `SNESGetApplicationContext()`
1259 @*/
SNESSetApplicationContext(SNES snes,PetscCtx ctx)1260 PetscErrorCode SNESSetApplicationContext(SNES snes, PetscCtx ctx)
1261 {
1262 KSP ksp;
1263
1264 PetscFunctionBegin;
1265 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1266 PetscCall(SNESGetKSP(snes, &ksp));
1267 PetscCall(KSPSetApplicationContext(ksp, ctx));
1268 snes->ctx = ctx;
1269 PetscFunctionReturn(PETSC_SUCCESS);
1270 }
1271
1272 /*@
1273 SNESGetApplicationContext - Gets the user-defined context for the
1274 nonlinear solvers set with `SNESGetApplicationContext()` or `SNESSetComputeApplicationContext()`
1275
1276 Not Collective
1277
1278 Input Parameter:
1279 . snes - `SNES` context
1280
1281 Output Parameter:
1282 . ctx - the application context
1283
1284 Level: intermediate
1285
1286 Fortran Notes:
1287 This only works when the context is a Fortran derived type or a `PetscObject`. Declare `ctx` with
1288 .vb
1289 type(tUsertype), pointer :: ctx
1290 .ve
1291
1292 .seealso: [](ch_snes), `SNESSetApplicationContext()`, `SNESSetComputeApplicationContext()`
1293 @*/
SNESGetApplicationContext(SNES snes,PetscCtxRt ctx)1294 PetscErrorCode SNESGetApplicationContext(SNES snes, PetscCtxRt ctx)
1295 {
1296 PetscFunctionBegin;
1297 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1298 *(void **)ctx = snes->ctx;
1299 PetscFunctionReturn(PETSC_SUCCESS);
1300 }
1301
1302 /*@
1303 SNESSetUseMatrixFree - indicates that `SNES` should use matrix-free finite difference matrix-vector products to apply the Jacobian.
1304
1305 Logically Collective
1306
1307 Input Parameters:
1308 + snes - `SNES` context
1309 . mf_operator - use matrix-free only for the Amat used by `SNESSetJacobian()`, this means the user provided Pmat will continue to be used
1310 - mf - use matrix-free for both the Amat and Pmat used by `SNESSetJacobian()`, both the Amat and Pmat set in `SNESSetJacobian()` will be ignored. With
1311 this option no matrix-element based preconditioners can be used in the linear solve since the matrix won't be explicitly available
1312
1313 Options Database Keys:
1314 + -snes_mf_operator - use matrix-free only for the mat operator
1315 . -snes_mf - use matrix-free for both the mat and pmat operator
1316 . -snes_fd_color - compute the Jacobian via coloring and finite differences.
1317 - -snes_fd - compute the Jacobian via finite differences (slow)
1318
1319 Level: intermediate
1320
1321 Note:
1322 `SNES` supports three approaches for computing (approximate) Jacobians: user provided via `SNESSetJacobian()`, matrix-free using `MatCreateSNESMF()`,
1323 and computing explicitly with
1324 finite differences and coloring using `MatFDColoring`. It is also possible to use automatic differentiation and the `MatFDColoring` object.
1325
1326 .seealso: [](ch_snes), `SNES`, `SNESGetUseMatrixFree()`, `MatCreateSNESMF()`, `SNESComputeJacobianDefaultColor()`, `MatFDColoring`
1327 @*/
SNESSetUseMatrixFree(SNES snes,PetscBool mf_operator,PetscBool mf)1328 PetscErrorCode SNESSetUseMatrixFree(SNES snes, PetscBool mf_operator, PetscBool mf)
1329 {
1330 PetscFunctionBegin;
1331 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1332 PetscValidLogicalCollectiveBool(snes, mf_operator, 2);
1333 PetscValidLogicalCollectiveBool(snes, mf, 3);
1334 snes->mf = mf_operator ? PETSC_TRUE : mf;
1335 snes->mf_operator = mf_operator;
1336 PetscFunctionReturn(PETSC_SUCCESS);
1337 }
1338
1339 /*@
1340 SNESGetUseMatrixFree - indicates if the `SNES` uses matrix-free finite difference matrix vector products to apply the Jacobian.
1341
1342 Not Collective, but the resulting flags will be the same on all MPI processes
1343
1344 Input Parameter:
1345 . snes - `SNES` context
1346
1347 Output Parameters:
1348 + mf_operator - use matrix-free only for the Amat used by `SNESSetJacobian()`, this means the user provided Pmat will continue to be used
1349 - mf - use matrix-free for both the Amat and Pmat used by `SNESSetJacobian()`, both the Amat and Pmat set in `SNESSetJacobian()` will be ignored
1350
1351 Level: intermediate
1352
1353 .seealso: [](ch_snes), `SNES`, `SNESSetUseMatrixFree()`, `MatCreateSNESMF()`
1354 @*/
SNESGetUseMatrixFree(SNES snes,PetscBool * mf_operator,PetscBool * mf)1355 PetscErrorCode SNESGetUseMatrixFree(SNES snes, PetscBool *mf_operator, PetscBool *mf)
1356 {
1357 PetscFunctionBegin;
1358 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1359 if (mf) *mf = snes->mf;
1360 if (mf_operator) *mf_operator = snes->mf_operator;
1361 PetscFunctionReturn(PETSC_SUCCESS);
1362 }
1363
1364 /*@
1365 SNESGetIterationNumber - Gets the number of nonlinear iterations completed in the current or most recent `SNESSolve()`
1366
1367 Not Collective
1368
1369 Input Parameter:
1370 . snes - `SNES` context
1371
1372 Output Parameter:
1373 . iter - iteration number
1374
1375 Level: intermediate
1376
1377 Notes:
1378 For example, during the computation of iteration 2 this would return 1.
1379
1380 This is useful for using lagged Jacobians (where one does not recompute the
1381 Jacobian at each `SNES` iteration). For example, the code
1382 .vb
1383 ierr = SNESGetIterationNumber(snes,&it);
1384 if (!(it % 2)) {
1385 [compute Jacobian here]
1386 }
1387 .ve
1388 can be used in your function that computes the Jacobian to cause the Jacobian to be
1389 recomputed every second `SNES` iteration. See also `SNESSetLagJacobian()`
1390
1391 After the `SNES` solve is complete this will return the number of nonlinear iterations used.
1392
1393 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESSetLagJacobian()`, `SNESGetLinearSolveIterations()`, `SNESSetMonitor()`
1394 @*/
SNESGetIterationNumber(SNES snes,PetscInt * iter)1395 PetscErrorCode SNESGetIterationNumber(SNES snes, PetscInt *iter)
1396 {
1397 PetscFunctionBegin;
1398 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1399 PetscAssertPointer(iter, 2);
1400 *iter = snes->iter;
1401 PetscFunctionReturn(PETSC_SUCCESS);
1402 }
1403
1404 /*@
1405 SNESSetIterationNumber - Sets the current iteration number.
1406
1407 Not Collective
1408
1409 Input Parameters:
1410 + snes - `SNES` context
1411 - iter - iteration number
1412
1413 Level: developer
1414
1415 Note:
1416 This should only be called inside a `SNES` nonlinear solver.
1417
1418 .seealso: [](ch_snes), `SNESGetLinearSolveIterations()`
1419 @*/
SNESSetIterationNumber(SNES snes,PetscInt iter)1420 PetscErrorCode SNESSetIterationNumber(SNES snes, PetscInt iter)
1421 {
1422 PetscFunctionBegin;
1423 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1424 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
1425 snes->iter = iter;
1426 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
1427 PetscFunctionReturn(PETSC_SUCCESS);
1428 }
1429
1430 /*@
1431 SNESGetNonlinearStepFailures - Gets the number of unsuccessful steps
1432 taken by the nonlinear solver in the current or most recent `SNESSolve()` .
1433
1434 Not Collective
1435
1436 Input Parameter:
1437 . snes - `SNES` context
1438
1439 Output Parameter:
1440 . nfails - number of unsuccessful steps attempted
1441
1442 Level: intermediate
1443
1444 Notes:
1445 A failed step is a step that was generated and taken but did not satisfy the requested step criteria. For example,
1446 the `SNESLineSearchApply()` could not generate a sufficient decrease in the function norm (in fact it may have produced an increase).
1447
1448 Taken steps that produce a infinity or NaN in the function evaluation or generate a `SNESSetFunctionDomainError()`
1449 will always immediately terminate the `SNESSolve()` regardless of the value of `maxFails`.
1450
1451 `SNESSetMaxNonlinearStepFailures()` determines how many unsuccessful steps are allowed before the `SNESSolve()` terminates
1452
1453 This counter is reset to zero for each successive call to `SNESSolve()`.
1454
1455 .seealso: [](ch_snes), `SNES`, `SNESGetMaxLinearSolveFailures()`, `SNESGetLinearSolveIterations()`, `SNESSetMaxLinearSolveFailures()`, `SNESGetLinearSolveFailures()`,
1456 `SNESSetMaxNonlinearStepFailures()`, `SNESGetMaxNonlinearStepFailures()`
1457 @*/
SNESGetNonlinearStepFailures(SNES snes,PetscInt * nfails)1458 PetscErrorCode SNESGetNonlinearStepFailures(SNES snes, PetscInt *nfails)
1459 {
1460 PetscFunctionBegin;
1461 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1462 PetscAssertPointer(nfails, 2);
1463 *nfails = snes->numFailures;
1464 PetscFunctionReturn(PETSC_SUCCESS);
1465 }
1466
1467 /*@
1468 SNESSetMaxNonlinearStepFailures - Sets the maximum number of unsuccessful steps
1469 attempted by the nonlinear solver before it gives up and returns unconverged or generates an error
1470
1471 Not Collective
1472
1473 Input Parameters:
1474 + snes - `SNES` context
1475 - maxFails - maximum of unsuccessful steps allowed, use `PETSC_UNLIMITED` to have no limit on the number of failures
1476
1477 Options Database Key:
1478 . -snes_max_fail <n> - maximum number of unsuccessful steps allowed
1479
1480 Level: intermediate
1481
1482 Note:
1483 A failed step is a step that was generated and taken but did not satisfy the requested criteria. For example,
1484 the `SNESLineSearchApply()` could not generate a sufficient decrease in the function norm (in fact it may have produced an increase).
1485
1486 Taken steps that produce a infinity or NaN in the function evaluation or generate a `SNESSetFunctionDomainError()`
1487 will always immediately terminate the `SNESSolve()` regardless of the value of `maxFails`.
1488
1489 Developer Note:
1490 The options database key is wrong for this function name
1491
1492 .seealso: [](ch_snes), `SNESSetErrorIfNotConverged()`, `SNESGetMaxLinearSolveFailures()`, `SNESGetLinearSolveIterations()`, `SNESSetMaxLinearSolveFailures()`,
1493 `SNESGetLinearSolveFailures()`, `SNESGetMaxNonlinearStepFailures()`, `SNESGetNonlinearStepFailures()`, `SNESCheckLineSearchFailure()`
1494 @*/
SNESSetMaxNonlinearStepFailures(SNES snes,PetscInt maxFails)1495 PetscErrorCode SNESSetMaxNonlinearStepFailures(SNES snes, PetscInt maxFails)
1496 {
1497 PetscFunctionBegin;
1498 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1499
1500 if (maxFails == PETSC_UNLIMITED) {
1501 snes->maxFailures = PETSC_INT_MAX;
1502 } else {
1503 PetscCheck(maxFails >= 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have a negative maximum number of failures");
1504 snes->maxFailures = maxFails;
1505 }
1506 PetscFunctionReturn(PETSC_SUCCESS);
1507 }
1508
1509 /*@
1510 SNESGetMaxNonlinearStepFailures - Gets the maximum number of unsuccessful steps
1511 attempted by the nonlinear solver before it gives up and returns unconverged or generates an error
1512
1513 Not Collective
1514
1515 Input Parameter:
1516 . snes - `SNES` context
1517
1518 Output Parameter:
1519 . maxFails - maximum of unsuccessful steps
1520
1521 Level: intermediate
1522
1523 .seealso: [](ch_snes), `SNESSetErrorIfNotConverged()`, `SNESGetMaxLinearSolveFailures()`, `SNESGetLinearSolveIterations()`, `SNESSetMaxLinearSolveFailures()`, `SNESGetLinearSolveFailures()`,
1524 `SNESSetMaxNonlinearStepFailures()`, `SNESGetNonlinearStepFailures()`
1525 @*/
SNESGetMaxNonlinearStepFailures(SNES snes,PetscInt * maxFails)1526 PetscErrorCode SNESGetMaxNonlinearStepFailures(SNES snes, PetscInt *maxFails)
1527 {
1528 PetscFunctionBegin;
1529 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1530 PetscAssertPointer(maxFails, 2);
1531 *maxFails = snes->maxFailures;
1532 PetscFunctionReturn(PETSC_SUCCESS);
1533 }
1534
1535 /*@
1536 SNESGetNumberFunctionEvals - Gets the number of user provided function evaluations
1537 done by the `SNES` object in the current or most recent `SNESSolve()`
1538
1539 Not Collective
1540
1541 Input Parameter:
1542 . snes - `SNES` context
1543
1544 Output Parameter:
1545 . nfuncs - number of evaluations
1546
1547 Level: intermediate
1548
1549 Note:
1550 Reset every time `SNESSolve()` is called unless `SNESSetCountersReset()` is used.
1551
1552 .seealso: [](ch_snes), `SNES`, `SNESGetMaxLinearSolveFailures()`, `SNESGetLinearSolveIterations()`, `SNESSetMaxLinearSolveFailures()`, `SNESGetLinearSolveFailures()`, `SNESSetCountersReset()`
1553 @*/
SNESGetNumberFunctionEvals(SNES snes,PetscInt * nfuncs)1554 PetscErrorCode SNESGetNumberFunctionEvals(SNES snes, PetscInt *nfuncs)
1555 {
1556 PetscFunctionBegin;
1557 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1558 PetscAssertPointer(nfuncs, 2);
1559 *nfuncs = snes->nfuncs;
1560 PetscFunctionReturn(PETSC_SUCCESS);
1561 }
1562
1563 /*@
1564 SNESGetLinearSolveFailures - Gets the number of failed (non-converged)
1565 linear solvers in the current or most recent `SNESSolve()`
1566
1567 Not Collective
1568
1569 Input Parameter:
1570 . snes - `SNES` context
1571
1572 Output Parameter:
1573 . nfails - number of failed solves
1574
1575 Options Database Key:
1576 . -snes_max_linear_solve_fail <num> - The number of failures before the solve is terminated
1577
1578 Level: intermediate
1579
1580 Note:
1581 This counter is reset to zero for each successive call to `SNESSolve()`.
1582
1583 .seealso: [](ch_snes), `SNESGetMaxLinearSolveFailures()`, `SNESGetLinearSolveIterations()`, `SNESSetMaxLinearSolveFailures()`
1584 @*/
SNESGetLinearSolveFailures(SNES snes,PetscInt * nfails)1585 PetscErrorCode SNESGetLinearSolveFailures(SNES snes, PetscInt *nfails)
1586 {
1587 PetscFunctionBegin;
1588 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1589 PetscAssertPointer(nfails, 2);
1590 *nfails = snes->numLinearSolveFailures;
1591 PetscFunctionReturn(PETSC_SUCCESS);
1592 }
1593
1594 /*@
1595 SNESSetMaxLinearSolveFailures - the number of failed linear solve attempts
1596 allowed before `SNES` returns with a diverged reason of `SNES_DIVERGED_LINEAR_SOLVE`
1597
1598 Logically Collective
1599
1600 Input Parameters:
1601 + snes - `SNES` context
1602 - maxFails - maximum allowed linear solve failures, use `PETSC_UNLIMITED` to have no limit on the number of failures
1603
1604 Options Database Key:
1605 . -snes_max_linear_solve_fail <num> - The number of failures before the solve is terminated
1606
1607 Level: intermediate
1608
1609 Note:
1610 By default this is 0; that is `SNES` returns on the first failed linear solve
1611
1612 Developer Note:
1613 The options database key is wrong for this function name
1614
1615 .seealso: [](ch_snes), `SNESSetErrorIfNotConverged()`, `SNESGetLinearSolveFailures()`, `SNESGetMaxLinearSolveFailures()`, `SNESGetLinearSolveIterations()`
1616 @*/
SNESSetMaxLinearSolveFailures(SNES snes,PetscInt maxFails)1617 PetscErrorCode SNESSetMaxLinearSolveFailures(SNES snes, PetscInt maxFails)
1618 {
1619 PetscFunctionBegin;
1620 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1621 PetscValidLogicalCollectiveInt(snes, maxFails, 2);
1622
1623 if (maxFails == PETSC_UNLIMITED) {
1624 snes->maxLinearSolveFailures = PETSC_INT_MAX;
1625 } else {
1626 PetscCheck(maxFails >= 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "Cannot have a negative maximum number of failures");
1627 snes->maxLinearSolveFailures = maxFails;
1628 }
1629 PetscFunctionReturn(PETSC_SUCCESS);
1630 }
1631
1632 /*@
1633 SNESGetMaxLinearSolveFailures - gets the maximum number of linear solve failures that
1634 are allowed before `SNES` returns as unsuccessful
1635
1636 Not Collective
1637
1638 Input Parameter:
1639 . snes - `SNES` context
1640
1641 Output Parameter:
1642 . maxFails - maximum of unsuccessful solves allowed
1643
1644 Level: intermediate
1645
1646 Note:
1647 By default this is 1; that is `SNES` returns on the first failed linear solve
1648
1649 .seealso: [](ch_snes), `SNESSetErrorIfNotConverged()`, `SNESGetLinearSolveFailures()`, `SNESGetLinearSolveIterations()`, `SNESSetMaxLinearSolveFailures()`,
1650 @*/
SNESGetMaxLinearSolveFailures(SNES snes,PetscInt * maxFails)1651 PetscErrorCode SNESGetMaxLinearSolveFailures(SNES snes, PetscInt *maxFails)
1652 {
1653 PetscFunctionBegin;
1654 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1655 PetscAssertPointer(maxFails, 2);
1656 *maxFails = snes->maxLinearSolveFailures;
1657 PetscFunctionReturn(PETSC_SUCCESS);
1658 }
1659
1660 /*@
1661 SNESGetLinearSolveIterations - Gets the total number of linear iterations
1662 used by the nonlinear solver in the most recent `SNESSolve()`
1663
1664 Not Collective
1665
1666 Input Parameter:
1667 . snes - `SNES` context
1668
1669 Output Parameter:
1670 . lits - number of linear iterations
1671
1672 Level: intermediate
1673
1674 Notes:
1675 This counter is reset to zero for each successive call to `SNESSolve()` unless `SNESSetCountersReset()` is used.
1676
1677 If the linear solver fails inside the `SNESSolve()` the iterations for that call to the linear solver are not included. If you wish to count them
1678 then call `KSPGetIterationNumber()` after the failed solve.
1679
1680 .seealso: [](ch_snes), `SNES`, `SNESGetIterationNumber()`, `SNESGetLinearSolveFailures()`, `SNESGetMaxLinearSolveFailures()`, `SNESSetCountersReset()`
1681 @*/
SNESGetLinearSolveIterations(SNES snes,PetscInt * lits)1682 PetscErrorCode SNESGetLinearSolveIterations(SNES snes, PetscInt *lits)
1683 {
1684 PetscFunctionBegin;
1685 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1686 PetscAssertPointer(lits, 2);
1687 *lits = snes->linear_its;
1688 PetscFunctionReturn(PETSC_SUCCESS);
1689 }
1690
1691 /*@
1692 SNESSetCountersReset - Sets whether or not the counters for linear iterations and function evaluations
1693 are reset every time `SNESSolve()` is called.
1694
1695 Logically Collective
1696
1697 Input Parameters:
1698 + snes - `SNES` context
1699 - reset - whether to reset the counters or not, defaults to `PETSC_TRUE`
1700
1701 Level: developer
1702
1703 .seealso: [](ch_snes), `SNESGetNumberFunctionEvals()`, `SNESGetLinearSolveIterations()`, `SNESGetNPC()`
1704 @*/
SNESSetCountersReset(SNES snes,PetscBool reset)1705 PetscErrorCode SNESSetCountersReset(SNES snes, PetscBool reset)
1706 {
1707 PetscFunctionBegin;
1708 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1709 PetscValidLogicalCollectiveBool(snes, reset, 2);
1710 snes->counters_reset = reset;
1711 PetscFunctionReturn(PETSC_SUCCESS);
1712 }
1713
1714 /*@
1715 SNESResetCounters - Reset counters for linear iterations and function evaluations.
1716
1717 Logically Collective
1718
1719 Input Parameters:
1720 . snes - `SNES` context
1721
1722 Level: developer
1723
1724 Note:
1725 It honors the flag set with `SNESSetCountersReset()`
1726
1727 .seealso: [](ch_snes), `SNESGetNumberFunctionEvals()`, `SNESGetLinearSolveIterations()`, `SNESGetNPC()`
1728 @*/
SNESResetCounters(SNES snes)1729 PetscErrorCode SNESResetCounters(SNES snes)
1730 {
1731 PetscFunctionBegin;
1732 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1733 if (snes->counters_reset) {
1734 snes->nfuncs = 0;
1735 snes->linear_its = 0;
1736 snes->numFailures = 0;
1737 }
1738 PetscFunctionReturn(PETSC_SUCCESS);
1739 }
1740
1741 /*@
1742 SNESSetKSP - Sets a `KSP` context for the `SNES` object to use
1743
1744 Not Collective, but the `SNES` and `KSP` objects must live on the same `MPI_Comm`
1745
1746 Input Parameters:
1747 + snes - the `SNES` context
1748 - ksp - the `KSP` context
1749
1750 Level: developer
1751
1752 Notes:
1753 The `SNES` object already has its `KSP` object, you can obtain with `SNESGetKSP()`
1754 so this routine is rarely needed.
1755
1756 The `KSP` object that is already in the `SNES` object has its reference count
1757 decreased by one when this is called.
1758
1759 .seealso: [](ch_snes), `SNES`, `KSP`, `KSPGetPC()`, `SNESCreate()`, `KSPCreate()`
1760 @*/
SNESSetKSP(SNES snes,KSP ksp)1761 PetscErrorCode SNESSetKSP(SNES snes, KSP ksp)
1762 {
1763 PetscFunctionBegin;
1764 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1765 PetscValidHeaderSpecific(ksp, KSP_CLASSID, 2);
1766 PetscCheckSameComm(snes, 1, ksp, 2);
1767 PetscCall(PetscObjectReference((PetscObject)ksp));
1768 if (snes->ksp) PetscCall(PetscObjectDereference((PetscObject)snes->ksp));
1769 snes->ksp = ksp;
1770 PetscFunctionReturn(PETSC_SUCCESS);
1771 }
1772
1773 /*@
1774 SNESParametersInitialize - Sets all the parameters in `snes` to their default value (when `SNESCreate()` was called) if they
1775 currently contain default values
1776
1777 Collective
1778
1779 Input Parameter:
1780 . snes - the `SNES` object
1781
1782 Level: developer
1783
1784 Developer Note:
1785 This is called by all the `SNESCreate_XXX()` routines.
1786
1787 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESDestroy()`, `SNESSetLagPreconditioner()`, `SNESSetLagJacobian()`,
1788 `PetscObjectParameterSetDefault()`
1789 @*/
SNESParametersInitialize(SNES snes)1790 PetscErrorCode SNESParametersInitialize(SNES snes)
1791 {
1792 PetscObjectParameterSetDefault(snes, max_its, 50);
1793 PetscObjectParameterSetDefault(snes, max_funcs, 10000);
1794 PetscObjectParameterSetDefault(snes, rtol, PetscDefined(USE_REAL_SINGLE) ? 1.e-5 : 1.e-8);
1795 PetscObjectParameterSetDefault(snes, abstol, PetscDefined(USE_REAL_SINGLE) ? 1.e-25 : 1.e-50);
1796 PetscObjectParameterSetDefault(snes, stol, PetscDefined(USE_REAL_SINGLE) ? 1.e-5 : 1.e-8);
1797 PetscObjectParameterSetDefault(snes, divtol, 1.e4);
1798 return PETSC_SUCCESS;
1799 }
1800
1801 /*@
1802 SNESCreate - Creates a nonlinear solver context used to manage a set of nonlinear solves
1803
1804 Collective
1805
1806 Input Parameter:
1807 . comm - MPI communicator
1808
1809 Output Parameter:
1810 . outsnes - the new `SNES` context
1811
1812 Options Database Keys:
1813 + -snes_mf - Activates default matrix-free Jacobian-vector products, and no matrix to construct a preconditioner
1814 . -snes_mf_operator - Activates default matrix-free Jacobian-vector products, and a user-provided matrix as set by `SNESSetJacobian()`
1815 . -snes_fd_coloring - uses a relative fast computation of the Jacobian using finite differences and a graph coloring
1816 - -snes_fd - Uses (slow!) finite differences to compute Jacobian
1817
1818 Level: beginner
1819
1820 Developer Notes:
1821 `SNES` always creates a `KSP` object even though many `SNES` methods do not use it. This is
1822 unfortunate and should be fixed at some point. The flag snes->usesksp indicates if the
1823 particular method does use `KSP` and regulates if the information about the `KSP` is printed
1824 in `SNESView()`.
1825
1826 `TSSetFromOptions()` does call `SNESSetFromOptions()` which can lead to users being confused
1827 by help messages about meaningless `SNES` options.
1828
1829 `SNES` always creates the `snes->kspconvctx` even though it is used by only one type. This should be fixed.
1830
1831 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESDestroy()`, `SNESSetLagPreconditioner()`, `SNESSetLagJacobian()`
1832 @*/
SNESCreate(MPI_Comm comm,SNES * outsnes)1833 PetscErrorCode SNESCreate(MPI_Comm comm, SNES *outsnes)
1834 {
1835 SNES snes;
1836 SNESKSPEW *kctx;
1837
1838 PetscFunctionBegin;
1839 PetscAssertPointer(outsnes, 2);
1840 PetscCall(SNESInitializePackage());
1841
1842 PetscCall(PetscHeaderCreate(snes, SNES_CLASSID, "SNES", "Nonlinear solver", "SNES", comm, SNESDestroy, SNESView));
1843 snes->ops->converged = SNESConvergedDefault;
1844 snes->usesksp = PETSC_TRUE;
1845 snes->norm = 0.0;
1846 snes->xnorm = 0.0;
1847 snes->ynorm = 0.0;
1848 snes->normschedule = SNES_NORM_ALWAYS;
1849 snes->functype = SNES_FUNCTION_DEFAULT;
1850 snes->ttol = 0.0;
1851
1852 snes->rnorm0 = 0;
1853 snes->nfuncs = 0;
1854 snes->numFailures = 0;
1855 snes->maxFailures = 1;
1856 snes->linear_its = 0;
1857 snes->lagjacobian = 1;
1858 snes->jac_iter = 0;
1859 snes->lagjac_persist = PETSC_FALSE;
1860 snes->lagpreconditioner = 1;
1861 snes->pre_iter = 0;
1862 snes->lagpre_persist = PETSC_FALSE;
1863 snes->numbermonitors = 0;
1864 snes->numberreasonviews = 0;
1865 snes->data = NULL;
1866 snes->setupcalled = PETSC_FALSE;
1867 snes->ksp_ewconv = PETSC_FALSE;
1868 snes->nwork = 0;
1869 snes->work = NULL;
1870 snes->nvwork = 0;
1871 snes->vwork = NULL;
1872 snes->conv_hist_len = 0;
1873 snes->conv_hist_max = 0;
1874 snes->conv_hist = NULL;
1875 snes->conv_hist_its = NULL;
1876 snes->conv_hist_reset = PETSC_TRUE;
1877 snes->counters_reset = PETSC_TRUE;
1878 snes->vec_func_init_set = PETSC_FALSE;
1879 snes->reason = SNES_CONVERGED_ITERATING;
1880 snes->npcside = PC_RIGHT;
1881 snes->setfromoptionscalled = 0;
1882
1883 snes->mf = PETSC_FALSE;
1884 snes->mf_operator = PETSC_FALSE;
1885 snes->mf_version = 1;
1886
1887 snes->numLinearSolveFailures = 0;
1888 snes->maxLinearSolveFailures = 1;
1889
1890 snes->vizerotolerance = 1.e-8;
1891 snes->checkjacdomainerror = PetscDefined(USE_DEBUG) ? PETSC_TRUE : PETSC_FALSE;
1892
1893 /* Set this to true if the implementation of SNESSolve_XXX does compute the residual at the final solution. */
1894 snes->alwayscomputesfinalresidual = PETSC_FALSE;
1895
1896 /* Create context to compute Eisenstat-Walker relative tolerance for KSP */
1897 PetscCall(PetscNew(&kctx));
1898
1899 snes->kspconvctx = kctx;
1900 kctx->version = 2;
1901 kctx->rtol_0 = 0.3; /* Eisenstat and Walker suggest rtol_0=.5, but
1902 this was too large for some test cases */
1903 kctx->rtol_last = 0.0;
1904 kctx->rtol_max = 0.9;
1905 kctx->gamma = 1.0;
1906 kctx->alpha = 0.5 * (1.0 + PetscSqrtReal(5.0));
1907 kctx->alpha2 = kctx->alpha;
1908 kctx->threshold = 0.1;
1909 kctx->lresid_last = 0.0;
1910 kctx->norm_last = 0.0;
1911
1912 kctx->rk_last = 0.0;
1913 kctx->rk_last_2 = 0.0;
1914 kctx->rtol_last_2 = 0.0;
1915 kctx->v4_p1 = 0.1;
1916 kctx->v4_p2 = 0.4;
1917 kctx->v4_p3 = 0.7;
1918 kctx->v4_m1 = 0.8;
1919 kctx->v4_m2 = 0.5;
1920 kctx->v4_m3 = 0.1;
1921 kctx->v4_m4 = 0.5;
1922
1923 PetscCall(SNESParametersInitialize(snes));
1924 *outsnes = snes;
1925 PetscFunctionReturn(PETSC_SUCCESS);
1926 }
1927
1928 /*@C
1929 SNESSetFunction - Sets the function evaluation routine and function
1930 vector for use by the `SNES` routines in solving systems of nonlinear
1931 equations.
1932
1933 Logically Collective
1934
1935 Input Parameters:
1936 + snes - the `SNES` context
1937 . r - vector to store function values, may be `NULL`
1938 . f - function evaluation routine; for calling sequence see `SNESFunctionFn`
1939 - ctx - [optional] user-defined context for private data for the
1940 function evaluation routine (may be `NULL`)
1941
1942 Level: beginner
1943
1944 .seealso: [](ch_snes), `SNES`, `SNESGetFunction()`, `SNESComputeFunction()`, `SNESSetJacobian()`, `SNESSetPicard()`, `SNESFunctionFn`
1945 @*/
SNESSetFunction(SNES snes,Vec r,SNESFunctionFn * f,PetscCtx ctx)1946 PetscErrorCode SNESSetFunction(SNES snes, Vec r, SNESFunctionFn *f, PetscCtx ctx)
1947 {
1948 DM dm;
1949
1950 PetscFunctionBegin;
1951 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1952 if (r) {
1953 PetscValidHeaderSpecific(r, VEC_CLASSID, 2);
1954 PetscCheckSameComm(snes, 1, r, 2);
1955 PetscCall(PetscObjectReference((PetscObject)r));
1956 PetscCall(VecDestroy(&snes->vec_func));
1957 snes->vec_func = r;
1958 }
1959 PetscCall(SNESGetDM(snes, &dm));
1960 PetscCall(DMSNESSetFunction(dm, f, ctx));
1961 if (f == SNESPicardComputeFunction) PetscCall(DMSNESSetMFFunction(dm, SNESPicardComputeMFFunction, ctx));
1962 PetscFunctionReturn(PETSC_SUCCESS);
1963 }
1964
1965 /*@C
1966 SNESSetInitialFunction - Set an already computed function evaluation at the initial guess to be reused by `SNESSolve()`.
1967
1968 Logically Collective
1969
1970 Input Parameters:
1971 + snes - the `SNES` context
1972 - f - vector to store function value
1973
1974 Level: developer
1975
1976 Notes:
1977 This should not be modified during the solution procedure.
1978
1979 This is used extensively in the `SNESFAS` hierarchy and in nonlinear preconditioning.
1980
1981 .seealso: [](ch_snes), `SNES`, `SNESFAS`, `SNESSetFunction()`, `SNESComputeFunction()`, `SNESSetInitialFunctionNorm()`
1982 @*/
SNESSetInitialFunction(SNES snes,Vec f)1983 PetscErrorCode SNESSetInitialFunction(SNES snes, Vec f)
1984 {
1985 Vec vec_func;
1986
1987 PetscFunctionBegin;
1988 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1989 PetscValidHeaderSpecific(f, VEC_CLASSID, 2);
1990 PetscCheckSameComm(snes, 1, f, 2);
1991 if (snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
1992 snes->vec_func_init_set = PETSC_FALSE;
1993 PetscFunctionReturn(PETSC_SUCCESS);
1994 }
1995 PetscCall(SNESGetFunction(snes, &vec_func, NULL, NULL));
1996 PetscCall(VecCopy(f, vec_func));
1997
1998 snes->vec_func_init_set = PETSC_TRUE;
1999 PetscFunctionReturn(PETSC_SUCCESS);
2000 }
2001
2002 /*@
2003 SNESSetNormSchedule - Sets the `SNESNormSchedule` used in convergence and monitoring
2004 of the `SNES` method, when norms are computed in the solving process
2005
2006 Logically Collective
2007
2008 Input Parameters:
2009 + snes - the `SNES` context
2010 - normschedule - the frequency of norm computation
2011
2012 Options Database Key:
2013 . -snes_norm_schedule <none, always, initialonly, finalonly, initialfinalonly> - set the schedule
2014
2015 Level: advanced
2016
2017 Notes:
2018 Only certain `SNES` methods support certain `SNESNormSchedules`. Most require evaluation
2019 of the nonlinear function and the taking of its norm at every iteration to
2020 even ensure convergence at all. However, methods such as custom Gauss-Seidel methods
2021 `SNESNGS` and the like do not require the norm of the function to be computed, and therefore
2022 may either be monitored for convergence or not. As these are often used as nonlinear
2023 preconditioners, monitoring the norm of their error is not a useful enterprise within
2024 their solution.
2025
2026 .seealso: [](ch_snes), `SNESNormSchedule`, `SNESGetNormSchedule()`, `SNESComputeFunction()`, `VecNorm()`, `SNESSetFunction()`, `SNESSetInitialFunction()`
2027 @*/
SNESSetNormSchedule(SNES snes,SNESNormSchedule normschedule)2028 PetscErrorCode SNESSetNormSchedule(SNES snes, SNESNormSchedule normschedule)
2029 {
2030 PetscFunctionBegin;
2031 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2032 snes->normschedule = normschedule;
2033 PetscFunctionReturn(PETSC_SUCCESS);
2034 }
2035
2036 /*@
2037 SNESGetNormSchedule - Gets the `SNESNormSchedule` used in convergence and monitoring
2038 of the `SNES` method.
2039
2040 Logically Collective
2041
2042 Input Parameters:
2043 + snes - the `SNES` context
2044 - normschedule - the type of the norm used
2045
2046 Level: advanced
2047
2048 .seealso: [](ch_snes), `SNES`, `SNESSetNormSchedule()`, `SNESComputeFunction()`, `VecNorm()`, `SNESSetFunction()`, `SNESSetInitialFunction()`, `SNESNormSchedule`
2049 @*/
SNESGetNormSchedule(SNES snes,SNESNormSchedule * normschedule)2050 PetscErrorCode SNESGetNormSchedule(SNES snes, SNESNormSchedule *normschedule)
2051 {
2052 PetscFunctionBegin;
2053 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2054 *normschedule = snes->normschedule;
2055 PetscFunctionReturn(PETSC_SUCCESS);
2056 }
2057
2058 /*@
2059 SNESSetFunctionNorm - Sets the last computed residual norm.
2060
2061 Logically Collective
2062
2063 Input Parameters:
2064 + snes - the `SNES` context
2065 - norm - the value of the norm
2066
2067 Level: developer
2068
2069 .seealso: [](ch_snes), `SNES`, `SNESGetNormSchedule()`, `SNESComputeFunction()`, `VecNorm()`, `SNESSetFunction()`, `SNESSetInitialFunction()`, `SNESNormSchedule`
2070 @*/
SNESSetFunctionNorm(SNES snes,PetscReal norm)2071 PetscErrorCode SNESSetFunctionNorm(SNES snes, PetscReal norm)
2072 {
2073 PetscFunctionBegin;
2074 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2075 snes->norm = norm;
2076 PetscFunctionReturn(PETSC_SUCCESS);
2077 }
2078
2079 /*@
2080 SNESGetFunctionNorm - Gets the last computed norm of the residual
2081
2082 Not Collective
2083
2084 Input Parameter:
2085 . snes - the `SNES` context
2086
2087 Output Parameter:
2088 . norm - the last computed residual norm
2089
2090 Level: developer
2091
2092 .seealso: [](ch_snes), `SNES`, `SNESSetNormSchedule()`, `SNESComputeFunction()`, `VecNorm()`, `SNESSetFunction()`, `SNESSetInitialFunction()`, `SNESNormSchedule`
2093 @*/
SNESGetFunctionNorm(SNES snes,PetscReal * norm)2094 PetscErrorCode SNESGetFunctionNorm(SNES snes, PetscReal *norm)
2095 {
2096 PetscFunctionBegin;
2097 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2098 PetscAssertPointer(norm, 2);
2099 *norm = snes->norm;
2100 PetscFunctionReturn(PETSC_SUCCESS);
2101 }
2102
2103 /*@
2104 SNESGetUpdateNorm - Gets the last computed norm of the solution update
2105
2106 Not Collective
2107
2108 Input Parameter:
2109 . snes - the `SNES` context
2110
2111 Output Parameter:
2112 . ynorm - the last computed update norm
2113
2114 Level: developer
2115
2116 Note:
2117 The new solution is the current solution plus the update, so this norm is an indication of the size of the update
2118
2119 .seealso: [](ch_snes), `SNES`, `SNESSetNormSchedule()`, `SNESComputeFunction()`, `SNESGetFunctionNorm()`
2120 @*/
SNESGetUpdateNorm(SNES snes,PetscReal * ynorm)2121 PetscErrorCode SNESGetUpdateNorm(SNES snes, PetscReal *ynorm)
2122 {
2123 PetscFunctionBegin;
2124 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2125 PetscAssertPointer(ynorm, 2);
2126 *ynorm = snes->ynorm;
2127 PetscFunctionReturn(PETSC_SUCCESS);
2128 }
2129
2130 /*@
2131 SNESGetSolutionNorm - Gets the last computed norm of the solution
2132
2133 Not Collective
2134
2135 Input Parameter:
2136 . snes - the `SNES` context
2137
2138 Output Parameter:
2139 . xnorm - the last computed solution norm
2140
2141 Level: developer
2142
2143 .seealso: [](ch_snes), `SNES`, `SNESSetNormSchedule()`, `SNESComputeFunction()`, `SNESGetFunctionNorm()`, `SNESGetUpdateNorm()`
2144 @*/
SNESGetSolutionNorm(SNES snes,PetscReal * xnorm)2145 PetscErrorCode SNESGetSolutionNorm(SNES snes, PetscReal *xnorm)
2146 {
2147 PetscFunctionBegin;
2148 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2149 PetscAssertPointer(xnorm, 2);
2150 *xnorm = snes->xnorm;
2151 PetscFunctionReturn(PETSC_SUCCESS);
2152 }
2153
2154 /*@
2155 SNESSetFunctionType - Sets the `SNESFunctionType`
2156 of the `SNES` method.
2157
2158 Logically Collective
2159
2160 Input Parameters:
2161 + snes - the `SNES` context
2162 - type - the function type
2163
2164 Level: developer
2165
2166 Values of the function type\:
2167 + `SNES_FUNCTION_DEFAULT` - the default for the given `SNESType`
2168 . `SNES_FUNCTION_UNPRECONDITIONED` - an unpreconditioned function evaluation (this is the function provided with `SNESSetFunction()`
2169 - `SNES_FUNCTION_PRECONDITIONED` - a transformation of the function provided with `SNESSetFunction()`
2170
2171 Note:
2172 Different `SNESType`s use this value in different ways
2173
2174 .seealso: [](ch_snes), `SNES`, `SNESFunctionType`, `SNESGetNormSchedule()`, `SNESComputeFunction()`, `VecNorm()`, `SNESSetFunction()`, `SNESSetInitialFunction()`, `SNESNormSchedule`
2175 @*/
SNESSetFunctionType(SNES snes,SNESFunctionType type)2176 PetscErrorCode SNESSetFunctionType(SNES snes, SNESFunctionType type)
2177 {
2178 PetscFunctionBegin;
2179 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2180 snes->functype = type;
2181 PetscFunctionReturn(PETSC_SUCCESS);
2182 }
2183
2184 /*@
2185 SNESGetFunctionType - Gets the `SNESFunctionType` used in convergence and monitoring set with `SNESSetFunctionType()`
2186 of the SNES method.
2187
2188 Logically Collective
2189
2190 Input Parameters:
2191 + snes - the `SNES` context
2192 - type - the type of the function evaluation, see `SNESSetFunctionType()`
2193
2194 Level: advanced
2195
2196 .seealso: [](ch_snes), `SNESSetFunctionType()`, `SNESFunctionType`, `SNESSetNormSchedule()`, `SNESComputeFunction()`, `VecNorm()`, `SNESSetFunction()`, `SNESSetInitialFunction()`, `SNESNormSchedule`
2197 @*/
SNESGetFunctionType(SNES snes,SNESFunctionType * type)2198 PetscErrorCode SNESGetFunctionType(SNES snes, SNESFunctionType *type)
2199 {
2200 PetscFunctionBegin;
2201 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2202 *type = snes->functype;
2203 PetscFunctionReturn(PETSC_SUCCESS);
2204 }
2205
2206 /*@C
2207 SNESSetNGS - Sets the user nonlinear Gauss-Seidel routine for
2208 use with composed nonlinear solvers.
2209
2210 Input Parameters:
2211 + snes - the `SNES` context, usually of the `SNESType` `SNESNGS`
2212 . f - function evaluation routine to apply Gauss-Seidel, see `SNESNGSFn` for calling sequence
2213 - ctx - [optional] user-defined context for private data for the smoother evaluation routine (may be `NULL`)
2214
2215 Level: intermediate
2216
2217 Note:
2218 The `SNESNGS` routines are used by the composed nonlinear solver to generate
2219 a problem appropriate update to the solution, particularly `SNESFAS`.
2220
2221 .seealso: [](ch_snes), `SNESNGS`, `SNESGetNGS()`, `SNESNCG`, `SNESGetFunction()`, `SNESComputeNGS()`, `SNESNGSFn`
2222 @*/
SNESSetNGS(SNES snes,SNESNGSFn * f,PetscCtx ctx)2223 PetscErrorCode SNESSetNGS(SNES snes, SNESNGSFn *f, PetscCtx ctx)
2224 {
2225 DM dm;
2226
2227 PetscFunctionBegin;
2228 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2229 PetscCall(SNESGetDM(snes, &dm));
2230 PetscCall(DMSNESSetNGS(dm, f, ctx));
2231 PetscFunctionReturn(PETSC_SUCCESS);
2232 }
2233
2234 /*
2235 This is used for -snes_mf_operator; it uses a duplicate of snes->jacobian_pre because snes->jacobian_pre cannot be
2236 changed during the KSPSolve()
2237 */
SNESPicardComputeMFFunction(SNES snes,Vec x,Vec f,PetscCtx ctx)2238 PetscErrorCode SNESPicardComputeMFFunction(SNES snes, Vec x, Vec f, PetscCtx ctx)
2239 {
2240 DM dm;
2241 DMSNES sdm;
2242
2243 PetscFunctionBegin;
2244 PetscCall(SNESGetDM(snes, &dm));
2245 PetscCall(DMGetDMSNES(dm, &sdm));
2246 /* A(x)*x - b(x) */
2247 if (sdm->ops->computepfunction) {
2248 PetscCallBack("SNES Picard callback function", (*sdm->ops->computepfunction)(snes, x, f, sdm->pctx));
2249 PetscCall(VecScale(f, -1.0));
2250 /* Cannot share nonzero pattern because of the possible use of SNESComputeJacobianDefault() */
2251 if (!snes->picard) PetscCall(MatDuplicate(snes->jacobian_pre, MAT_DO_NOT_COPY_VALUES, &snes->picard));
2252 PetscCallBack("SNES Picard callback Jacobian", (*sdm->ops->computepjacobian)(snes, x, snes->picard, snes->picard, sdm->pctx));
2253 PetscCall(MatMultAdd(snes->picard, x, f, f));
2254 } else {
2255 PetscCallBack("SNES Picard callback Jacobian", (*sdm->ops->computepjacobian)(snes, x, snes->picard, snes->picard, sdm->pctx));
2256 PetscCall(MatMult(snes->picard, x, f));
2257 }
2258 PetscFunctionReturn(PETSC_SUCCESS);
2259 }
2260
SNESPicardComputeFunction(SNES snes,Vec x,Vec f,PetscCtx ctx)2261 PetscErrorCode SNESPicardComputeFunction(SNES snes, Vec x, Vec f, PetscCtx ctx)
2262 {
2263 DM dm;
2264 DMSNES sdm;
2265
2266 PetscFunctionBegin;
2267 PetscCall(SNESGetDM(snes, &dm));
2268 PetscCall(DMGetDMSNES(dm, &sdm));
2269 /* A(x)*x - b(x) */
2270 if (sdm->ops->computepfunction) {
2271 PetscCallBack("SNES Picard callback function", (*sdm->ops->computepfunction)(snes, x, f, sdm->pctx));
2272 PetscCall(VecScale(f, -1.0));
2273 PetscCallBack("SNES Picard callback Jacobian", (*sdm->ops->computepjacobian)(snes, x, snes->jacobian, snes->jacobian_pre, sdm->pctx));
2274 PetscCall(MatMultAdd(snes->jacobian_pre, x, f, f));
2275 } else {
2276 PetscCallBack("SNES Picard callback Jacobian", (*sdm->ops->computepjacobian)(snes, x, snes->jacobian, snes->jacobian_pre, sdm->pctx));
2277 PetscCall(MatMult(snes->jacobian_pre, x, f));
2278 }
2279 PetscFunctionReturn(PETSC_SUCCESS);
2280 }
2281
SNESPicardComputeJacobian(SNES snes,Vec x1,Mat J,Mat B,PetscCtx ctx)2282 PetscErrorCode SNESPicardComputeJacobian(SNES snes, Vec x1, Mat J, Mat B, PetscCtx ctx)
2283 {
2284 PetscFunctionBegin;
2285 /* the jacobian matrix should be pre-filled in SNESPicardComputeFunction */
2286 /* must assembly if matrix-free to get the last SNES solution */
2287 PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
2288 PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
2289 PetscFunctionReturn(PETSC_SUCCESS);
2290 }
2291
2292 /*@C
2293 SNESSetPicard - Use `SNES` to solve the system $A(x) x = bp(x) + b $ via a Picard type iteration (Picard linearization)
2294
2295 Logically Collective
2296
2297 Input Parameters:
2298 + snes - the `SNES` context
2299 . r - vector to store function values, may be `NULL`
2300 . bp - function evaluation routine, may be `NULL`, for the calling sequence see `SNESFunctionFn`
2301 . Amat - matrix with which $A(x) x - bp(x) - b$ is to be computed
2302 . Pmat - matrix from which preconditioner is computed (usually the same as `Amat`)
2303 . J - function to compute matrix values, for the calling sequence see `SNESJacobianFn`
2304 - ctx - [optional] user-defined context for private data for the function evaluation routine (may be `NULL`)
2305
2306 Level: intermediate
2307
2308 Notes:
2309 It is often better to provide the nonlinear function $F()$ and some approximation to its Jacobian directly and use
2310 an approximate Newton solver. This interface is provided to allow porting/testing a previous Picard based code in PETSc before converting it to approximate Newton.
2311
2312 One can call `SNESSetPicard()` or `SNESSetFunction()` (and possibly `SNESSetJacobian()`) but cannot call both
2313
2314 Solves the equation $A(x) x = bp(x) - b$ via the defect correction algorithm $A(x^{n}) (x^{n+1} - x^{n}) = bp(x^{n}) + b - A(x^{n})x^{n}$.
2315 When an exact solver is used this corresponds to the "classic" Picard $A(x^{n}) x^{n+1} = bp(x^{n}) + b$ iteration.
2316
2317 Run with `-snes_mf_operator` to solve the system with Newton's method using $A(x^{n})$ to construct the preconditioner.
2318
2319 We implement the defect correction form of the Picard iteration because it converges much more generally when inexact linear solvers are used then
2320 the direct Picard iteration $A(x^n) x^{n+1} = bp(x^n) + b$
2321
2322 There is some controversity over the definition of a Picard iteration for nonlinear systems but almost everyone agrees that it involves a linear solve and some
2323 believe it is the iteration $A(x^{n}) x^{n+1} = b(x^{n})$ hence we use the name Picard. If anyone has an authoritative reference that defines the Picard iteration
2324 different please contact us at petsc-dev@mcs.anl.gov and we'll have an entirely new argument \:-).
2325
2326 When used with `-snes_mf_operator` this will run matrix-free Newton's method where the matrix-vector product is of the true Jacobian of $A(x)x - bp(x) - b$ and
2327 $A(x^{n})$ is used to build the preconditioner
2328
2329 When used with `-snes_fd` this will compute the true Jacobian (very slowly one column at a time) and thus represent Newton's method.
2330
2331 When used with `-snes_fd_coloring` this will compute the Jacobian via coloring and thus represent a faster implementation of Newton's method. But the
2332 the nonzero structure of the Jacobian is, in general larger than that of the Picard matrix $A$ so you must provide in $A$ the needed nonzero structure for the correct
2333 coloring. When using `DMDA` this may mean creating the matrix $A$ with `DMCreateMatrix()` using a wider stencil than strictly needed for $A$ or with a `DMDA_STENCIL_BOX`.
2334 See the comment in src/snes/tutorials/ex15.c.
2335
2336 .seealso: [](ch_snes), `SNES`, `SNESGetFunction()`, `SNESSetFunction()`, `SNESComputeFunction()`, `SNESSetJacobian()`, `SNESGetPicard()`, `SNESLineSearchPreCheckPicard()`,
2337 `SNESFunctionFn`, `SNESJacobianFn`
2338 @*/
SNESSetPicard(SNES snes,Vec r,SNESFunctionFn * bp,Mat Amat,Mat Pmat,SNESJacobianFn * J,PetscCtx ctx)2339 PetscErrorCode SNESSetPicard(SNES snes, Vec r, SNESFunctionFn *bp, Mat Amat, Mat Pmat, SNESJacobianFn *J, PetscCtx ctx)
2340 {
2341 DM dm;
2342
2343 PetscFunctionBegin;
2344 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2345 PetscCall(SNESGetDM(snes, &dm));
2346 PetscCall(DMSNESSetPicard(dm, bp, J, ctx));
2347 PetscCall(DMSNESSetMFFunction(dm, SNESPicardComputeMFFunction, ctx));
2348 PetscCall(SNESSetFunction(snes, r, SNESPicardComputeFunction, ctx));
2349 PetscCall(SNESSetJacobian(snes, Amat, Pmat, SNESPicardComputeJacobian, ctx));
2350 PetscFunctionReturn(PETSC_SUCCESS);
2351 }
2352
2353 /*@C
2354 SNESGetPicard - Returns the context for the Picard iteration
2355
2356 Not Collective, but `Vec` is parallel if `SNES` is parallel. Collective if `Vec` is requested, but has not been created yet.
2357
2358 Input Parameter:
2359 . snes - the `SNES` context
2360
2361 Output Parameters:
2362 + r - the function (or `NULL`)
2363 . f - the function (or `NULL`); for calling sequence see `SNESFunctionFn`
2364 . Amat - the matrix used to defined the operation A(x) x - b(x) (or `NULL`)
2365 . Pmat - the matrix from which the preconditioner will be constructed (or `NULL`)
2366 . J - the function for matrix evaluation (or `NULL`); for calling sequence see `SNESJacobianFn`
2367 - ctx - the function context (or `NULL`)
2368
2369 Level: advanced
2370
2371 .seealso: [](ch_snes), `SNESSetFunction()`, `SNESSetPicard()`, `SNESGetFunction()`, `SNESGetJacobian()`, `SNESGetDM()`, `SNESFunctionFn`, `SNESJacobianFn`
2372 @*/
SNESGetPicard(SNES snes,Vec * r,SNESFunctionFn ** f,Mat * Amat,Mat * Pmat,SNESJacobianFn ** J,PetscCtxRt ctx)2373 PetscErrorCode SNESGetPicard(SNES snes, Vec *r, SNESFunctionFn **f, Mat *Amat, Mat *Pmat, SNESJacobianFn **J, PetscCtxRt ctx)
2374 {
2375 DM dm;
2376
2377 PetscFunctionBegin;
2378 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2379 PetscCall(SNESGetFunction(snes, r, NULL, NULL));
2380 PetscCall(SNESGetJacobian(snes, Amat, Pmat, NULL, NULL));
2381 PetscCall(SNESGetDM(snes, &dm));
2382 PetscCall(DMSNESGetPicard(dm, f, J, ctx));
2383 PetscFunctionReturn(PETSC_SUCCESS);
2384 }
2385
2386 /*@C
2387 SNESSetComputeInitialGuess - Sets a routine used to compute an initial guess for the nonlinear problem
2388
2389 Logically Collective
2390
2391 Input Parameters:
2392 + snes - the `SNES` context
2393 . func - function evaluation routine, see `SNESInitialGuessFn` for the calling sequence
2394 - ctx - [optional] user-defined context for private data for the
2395 function evaluation routine (may be `NULL`)
2396
2397 Level: intermediate
2398
2399 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESSetFunction()`, `SNESGetFunction()`, `SNESComputeFunction()`, `SNESSetJacobian()`, `SNESInitialGuessFn`
2400 @*/
SNESSetComputeInitialGuess(SNES snes,SNESInitialGuessFn * func,PetscCtx ctx)2401 PetscErrorCode SNESSetComputeInitialGuess(SNES snes, SNESInitialGuessFn *func, PetscCtx ctx)
2402 {
2403 PetscFunctionBegin;
2404 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2405 if (func) snes->ops->computeinitialguess = func;
2406 if (ctx) snes->initialguessP = ctx;
2407 PetscFunctionReturn(PETSC_SUCCESS);
2408 }
2409
2410 /*@C
2411 SNESGetRhs - Gets the vector for solving F(x) = `rhs`. If `rhs` is not set
2412 it assumes a zero right-hand side.
2413
2414 Logically Collective
2415
2416 Input Parameter:
2417 . snes - the `SNES` context
2418
2419 Output Parameter:
2420 . rhs - the right-hand side vector or `NULL` if there is no right-hand side vector
2421
2422 Level: intermediate
2423
2424 .seealso: [](ch_snes), `SNES`, `SNESGetSolution()`, `SNESGetFunction()`, `SNESComputeFunction()`, `SNESSetJacobian()`, `SNESSetFunction()`
2425 @*/
SNESGetRhs(SNES snes,Vec * rhs)2426 PetscErrorCode SNESGetRhs(SNES snes, Vec *rhs)
2427 {
2428 PetscFunctionBegin;
2429 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2430 PetscAssertPointer(rhs, 2);
2431 *rhs = snes->vec_rhs;
2432 PetscFunctionReturn(PETSC_SUCCESS);
2433 }
2434
2435 /*@
2436 SNESComputeFunction - Calls the function that has been set with `SNESSetFunction()`.
2437
2438 Collective
2439
2440 Input Parameters:
2441 + snes - the `SNES` context
2442 - x - input vector
2443
2444 Output Parameter:
2445 . f - function vector, as set by `SNESSetFunction()`
2446
2447 Level: developer
2448
2449 Notes:
2450 `SNESComputeFunction()` is typically used within nonlinear solvers
2451 implementations, so users would not generally call this routine themselves.
2452
2453 When solving for $F(x) = b$, this routine computes $f = F(x) - b$.
2454
2455 This function usually appears in the pattern.
2456 .vb
2457 SNESComputeFunction(snes, x, f);
2458 VecNorm(f, &fnorm);
2459 SNESCheckFunctionDomainError(snes, fnorm); or SNESLineSearchCheckFunctionDomainError(ls, fnorm);
2460 .ve
2461 to collectively handle the use of `SNESSetFunctionDomainError()` in the provided callback function.
2462
2463 .seealso: [](ch_snes), `SNES`, `SNESSetFunction()`, `SNESGetFunction()`, `SNESComputeMFFunction()`, `SNESSetFunctionDomainError()`
2464 @*/
SNESComputeFunction(SNES snes,Vec x,Vec f)2465 PetscErrorCode SNESComputeFunction(SNES snes, Vec x, Vec f)
2466 {
2467 DM dm;
2468 DMSNES sdm;
2469
2470 PetscFunctionBegin;
2471 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2472 PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2473 PetscValidHeaderSpecific(f, VEC_CLASSID, 3);
2474 PetscCheckSameComm(snes, 1, x, 2);
2475 PetscCheckSameComm(snes, 1, f, 3);
2476 PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2477
2478 PetscCall(SNESGetDM(snes, &dm));
2479 PetscCall(DMGetDMSNES(dm, &sdm));
2480 PetscCheck(sdm->ops->computefunction || snes->vec_rhs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call SNESSetFunction() or SNESSetDM() before SNESComputeFunction(), likely called from SNESSolve().");
2481 if (sdm->ops->computefunction) {
2482 if (sdm->ops->computefunction != SNESObjectiveComputeFunctionDefaultFD) PetscCall(PetscLogEventBegin(SNES_FunctionEval, snes, x, f, 0));
2483 PetscCall(VecLockReadPush(x));
2484 /* ensure domainerror is false prior to computefunction evaluation (may not have been reset) */
2485 snes->functiondomainerror = PETSC_FALSE;
2486 {
2487 void *ctx;
2488 SNESFunctionFn *computefunction;
2489 PetscCall(DMSNESGetFunction(dm, &computefunction, &ctx));
2490 PetscCallBack("SNES callback function", (*computefunction)(snes, x, f, ctx));
2491 }
2492 PetscCall(VecLockReadPop(x));
2493 if (sdm->ops->computefunction != SNESObjectiveComputeFunctionDefaultFD) PetscCall(PetscLogEventEnd(SNES_FunctionEval, snes, x, f, 0));
2494 } else /* if (snes->vec_rhs) */ {
2495 PetscCall(MatMult(snes->jacobian, x, f));
2496 }
2497 if (snes->vec_rhs) PetscCall(VecAXPY(f, -1.0, snes->vec_rhs));
2498 snes->nfuncs++;
2499 /*
2500 domainerror might not be set on all processes; so we tag vector locally with infinity and the next inner product or norm will
2501 propagate the value to all processes
2502 */
2503 PetscCall(VecFlag(f, snes->functiondomainerror));
2504 PetscFunctionReturn(PETSC_SUCCESS);
2505 }
2506
2507 /*@
2508 SNESComputeMFFunction - Calls the function that has been set with `DMSNESSetMFFunction()`.
2509
2510 Collective
2511
2512 Input Parameters:
2513 + snes - the `SNES` context
2514 - x - input vector
2515
2516 Output Parameter:
2517 . y - output vector
2518
2519 Level: developer
2520
2521 Notes:
2522 `SNESComputeMFFunction()` is used within the matrix-vector products called by the matrix created with `MatCreateSNESMF()`
2523 so users would not generally call this routine themselves.
2524
2525 Since this function is intended for use with finite differencing it does not subtract the right-hand side vector provided with `SNESSolve()`
2526 while `SNESComputeFunction()` does. As such, this routine cannot be used with `MatMFFDSetBase()` with a provided F function value even if it applies the
2527 same function as `SNESComputeFunction()` if a `SNESSolve()` right-hand side vector is use because the two functions difference would include this right hand side function.
2528
2529 .seealso: [](ch_snes), `SNES`, `SNESSetFunction()`, `SNESGetFunction()`, `SNESComputeFunction()`, `MatCreateSNESMF()`, `DMSNESSetMFFunction()`
2530 @*/
SNESComputeMFFunction(SNES snes,Vec x,Vec y)2531 PetscErrorCode SNESComputeMFFunction(SNES snes, Vec x, Vec y)
2532 {
2533 DM dm;
2534 DMSNES sdm;
2535
2536 PetscFunctionBegin;
2537 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2538 PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2539 PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2540 PetscCheckSameComm(snes, 1, x, 2);
2541 PetscCheckSameComm(snes, 1, y, 3);
2542 PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2543
2544 PetscCall(SNESGetDM(snes, &dm));
2545 PetscCall(DMGetDMSNES(dm, &sdm));
2546 PetscCall(PetscLogEventBegin(SNES_FunctionEval, snes, x, y, 0));
2547 PetscCall(VecLockReadPush(x));
2548 /* ensure domainerror is false prior to computefunction evaluation (may not have been reset) */
2549 snes->functiondomainerror = PETSC_FALSE;
2550 PetscCallBack("SNES callback function", (*sdm->ops->computemffunction)(snes, x, y, sdm->mffunctionctx));
2551 PetscCall(VecLockReadPop(x));
2552 PetscCall(PetscLogEventEnd(SNES_FunctionEval, snes, x, y, 0));
2553 snes->nfuncs++;
2554 /*
2555 domainerror might not be set on all processes; so we tag vector locally with infinity and the next inner product or norm will
2556 propagate the value to all processes
2557 */
2558 PetscCall(VecFlag(y, snes->functiondomainerror));
2559 PetscFunctionReturn(PETSC_SUCCESS);
2560 }
2561
2562 /*@
2563 SNESComputeNGS - Calls the Gauss-Seidel function that has been set with `SNESSetNGS()`.
2564
2565 Collective
2566
2567 Input Parameters:
2568 + snes - the `SNES` context
2569 . x - input vector
2570 - b - rhs vector
2571
2572 Output Parameter:
2573 . x - new solution vector
2574
2575 Level: developer
2576
2577 Note:
2578 `SNESComputeNGS()` is typically used within composed nonlinear solver
2579 implementations, so most users would not generally call this routine
2580 themselves.
2581
2582 .seealso: [](ch_snes), `SNESNGSFn`, `SNESSetNGS()`, `SNESComputeFunction()`, `SNESNGS`
2583 @*/
SNESComputeNGS(SNES snes,Vec b,Vec x)2584 PetscErrorCode SNESComputeNGS(SNES snes, Vec b, Vec x)
2585 {
2586 DM dm;
2587 DMSNES sdm;
2588
2589 PetscFunctionBegin;
2590 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2591 PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
2592 if (b) PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
2593 PetscCheckSameComm(snes, 1, x, 3);
2594 if (b) PetscCheckSameComm(snes, 1, b, 2);
2595 if (b) PetscCall(VecValidValues_Internal(b, 2, PETSC_TRUE));
2596 PetscCall(PetscLogEventBegin(SNES_NGSEval, snes, x, b, 0));
2597 PetscCall(SNESGetDM(snes, &dm));
2598 PetscCall(DMGetDMSNES(dm, &sdm));
2599 PetscCheck(sdm->ops->computegs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call SNESSetNGS() before SNESComputeNGS(), likely called from SNESSolve().");
2600 if (b) PetscCall(VecLockReadPush(b));
2601 PetscCallBack("SNES callback NGS", (*sdm->ops->computegs)(snes, x, b, sdm->gsctx));
2602 if (b) PetscCall(VecLockReadPop(b));
2603 PetscCall(PetscLogEventEnd(SNES_NGSEval, snes, x, b, 0));
2604 PetscFunctionReturn(PETSC_SUCCESS);
2605 }
2606
SNESComputeFunction_FD(SNES snes,Vec Xin,Vec G)2607 static PetscErrorCode SNESComputeFunction_FD(SNES snes, Vec Xin, Vec G)
2608 {
2609 Vec X;
2610 PetscScalar *g;
2611 PetscReal f, f2;
2612 PetscInt low, high, N, i;
2613 PetscBool flg;
2614 PetscReal h = .5 * PETSC_SQRT_MACHINE_EPSILON;
2615
2616 PetscFunctionBegin;
2617 PetscCall(PetscOptionsGetReal(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_fd_delta", &h, &flg));
2618 PetscCall(VecDuplicate(Xin, &X));
2619 PetscCall(VecCopy(Xin, X));
2620 PetscCall(VecGetSize(X, &N));
2621 PetscCall(VecGetOwnershipRange(X, &low, &high));
2622 PetscCall(VecSetOption(X, VEC_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE));
2623 PetscCall(VecGetArray(G, &g));
2624 for (i = 0; i < N; i++) {
2625 PetscCall(VecSetValue(X, i, -h, ADD_VALUES));
2626 PetscCall(VecAssemblyBegin(X));
2627 PetscCall(VecAssemblyEnd(X));
2628 PetscCall(SNESComputeObjective(snes, X, &f));
2629 PetscCall(VecSetValue(X, i, 2.0 * h, ADD_VALUES));
2630 PetscCall(VecAssemblyBegin(X));
2631 PetscCall(VecAssemblyEnd(X));
2632 PetscCall(SNESComputeObjective(snes, X, &f2));
2633 PetscCall(VecSetValue(X, i, -h, ADD_VALUES));
2634 PetscCall(VecAssemblyBegin(X));
2635 PetscCall(VecAssemblyEnd(X));
2636 if (i >= low && i < high) g[i - low] = (f2 - f) / (2.0 * h);
2637 }
2638 PetscCall(VecRestoreArray(G, &g));
2639 PetscCall(VecDestroy(&X));
2640 PetscFunctionReturn(PETSC_SUCCESS);
2641 }
2642
2643 /*@
2644 SNESTestFunction - Computes the difference between the computed and finite-difference functions
2645
2646 Collective
2647
2648 Input Parameter:
2649 . snes - the `SNES` context
2650
2651 Options Database Keys:
2652 + -snes_test_function - compare the user provided function with one compute via finite differences to check for errors.
2653 - -snes_test_function_view - display the user provided function, the finite difference function and the difference
2654
2655 Level: developer
2656
2657 .seealso: [](ch_snes), `SNESTestJacobian()`, `SNESSetFunction()`, `SNESComputeFunction()`
2658 @*/
SNESTestFunction(SNES snes)2659 PetscErrorCode SNESTestFunction(SNES snes)
2660 {
2661 Vec x, g1, g2, g3;
2662 PetscBool complete_print = PETSC_FALSE;
2663 PetscReal hcnorm, fdnorm, hcmax, fdmax, diffmax, diffnorm;
2664 PetscScalar dot;
2665 MPI_Comm comm;
2666 PetscViewer viewer, mviewer;
2667 PetscViewerFormat format;
2668 PetscInt tabs;
2669 static PetscBool directionsprinted = PETSC_FALSE;
2670 SNESObjectiveFn *objective;
2671
2672 PetscFunctionBegin;
2673 PetscCall(SNESGetObjective(snes, &objective, NULL));
2674 if (!objective) PetscFunctionReturn(PETSC_SUCCESS);
2675
2676 PetscObjectOptionsBegin((PetscObject)snes);
2677 PetscCall(PetscOptionsViewer("-snes_test_function_view", "View difference between hand-coded and finite difference function element entries", "None", &mviewer, &format, &complete_print));
2678 PetscOptionsEnd();
2679
2680 PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
2681 PetscCall(PetscViewerASCIIGetStdout(comm, &viewer));
2682 PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
2683 PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)snes)->tablevel));
2684 PetscCall(PetscViewerASCIIPrintf(viewer, " ---------- Testing Function -------------\n"));
2685 if (!complete_print && !directionsprinted) {
2686 PetscCall(PetscViewerASCIIPrintf(viewer, " Run with -snes_test_function_view and optionally -snes_test_function <threshold> to show difference\n"));
2687 PetscCall(PetscViewerASCIIPrintf(viewer, " of hand-coded and finite difference function entries greater than <threshold>.\n"));
2688 }
2689 if (!directionsprinted) {
2690 PetscCall(PetscViewerASCIIPrintf(viewer, " Testing hand-coded Function, if (for double precision runs) ||F - Ffd||/||F|| is\n"));
2691 PetscCall(PetscViewerASCIIPrintf(viewer, " O(1.e-8), the hand-coded Function is probably correct.\n"));
2692 directionsprinted = PETSC_TRUE;
2693 }
2694 if (complete_print) PetscCall(PetscViewerPushFormat(mviewer, format));
2695
2696 PetscCall(SNESGetSolution(snes, &x));
2697 PetscCall(VecDuplicate(x, &g1));
2698 PetscCall(VecDuplicate(x, &g2));
2699 PetscCall(VecDuplicate(x, &g3));
2700 PetscCall(SNESComputeFunction(snes, x, g1)); /* does not handle use of SNESSetFunctionDomainError() corrrectly */
2701 PetscCall(SNESComputeFunction_FD(snes, x, g2));
2702
2703 PetscCall(VecNorm(g2, NORM_2, &fdnorm));
2704 PetscCall(VecNorm(g1, NORM_2, &hcnorm));
2705 PetscCall(VecNorm(g2, NORM_INFINITY, &fdmax));
2706 PetscCall(VecNorm(g1, NORM_INFINITY, &hcmax));
2707 PetscCall(VecDot(g1, g2, &dot));
2708 PetscCall(VecCopy(g1, g3));
2709 PetscCall(VecAXPY(g3, -1.0, g2));
2710 PetscCall(VecNorm(g3, NORM_2, &diffnorm));
2711 PetscCall(VecNorm(g3, NORM_INFINITY, &diffmax));
2712 PetscCall(PetscViewerASCIIPrintf(viewer, " ||Ffd|| %g, ||F|| = %g, angle cosine = (Ffd'F)/||Ffd||||F|| = %g\n", (double)fdnorm, (double)hcnorm, (double)(PetscRealPart(dot) / (fdnorm * hcnorm))));
2713 PetscCall(PetscViewerASCIIPrintf(viewer, " 2-norm ||F - Ffd||/||F|| = %g, ||F - Ffd|| = %g\n", (double)(diffnorm / PetscMax(hcnorm, fdnorm)), (double)diffnorm));
2714 PetscCall(PetscViewerASCIIPrintf(viewer, " max-norm ||F - Ffd||/||F|| = %g, ||F - Ffd|| = %g\n", (double)(diffmax / PetscMax(hcmax, fdmax)), (double)diffmax));
2715
2716 if (complete_print) {
2717 PetscCall(PetscViewerASCIIPrintf(viewer, " Hand-coded function ----------\n"));
2718 PetscCall(VecView(g1, mviewer));
2719 PetscCall(PetscViewerASCIIPrintf(viewer, " Finite difference function ----------\n"));
2720 PetscCall(VecView(g2, mviewer));
2721 PetscCall(PetscViewerASCIIPrintf(viewer, " Hand-coded minus finite-difference function ----------\n"));
2722 PetscCall(VecView(g3, mviewer));
2723 }
2724 PetscCall(VecDestroy(&g1));
2725 PetscCall(VecDestroy(&g2));
2726 PetscCall(VecDestroy(&g3));
2727
2728 if (complete_print) {
2729 PetscCall(PetscViewerPopFormat(mviewer));
2730 PetscCall(PetscViewerDestroy(&mviewer));
2731 }
2732 PetscCall(PetscViewerASCIISetTab(viewer, tabs));
2733 PetscFunctionReturn(PETSC_SUCCESS);
2734 }
2735
2736 /*@
2737 SNESTestJacobian - Computes the difference between the computed and finite-difference Jacobians
2738
2739 Collective
2740
2741 Input Parameter:
2742 . snes - the `SNES` context
2743
2744 Output Parameters:
2745 + Jnorm - the Frobenius norm of the computed Jacobian, or `NULL`
2746 - diffNorm - the Frobenius norm of the difference of the computed and finite-difference Jacobians, or `NULL`
2747
2748 Options Database Keys:
2749 + -snes_test_jacobian <optional threshold> - compare the user provided Jacobian with one compute via finite differences to check for errors. If a threshold is given, display only those entries whose difference is greater than the threshold.
2750 - -snes_test_jacobian_view - display the user provided Jacobian, the finite difference Jacobian and the difference
2751
2752 Level: developer
2753
2754 Note:
2755 Directions and norms are printed to stdout if `diffNorm` is `NULL`.
2756
2757 .seealso: [](ch_snes), `SNESTestFunction()`, `SNESSetJacobian()`, `SNESComputeJacobian()`
2758 @*/
SNESTestJacobian(SNES snes,PetscReal * Jnorm,PetscReal * diffNorm)2759 PetscErrorCode SNESTestJacobian(SNES snes, PetscReal *Jnorm, PetscReal *diffNorm)
2760 {
2761 Mat A, B, C, D, jacobian;
2762 Vec x = snes->vec_sol, f;
2763 PetscReal nrm, gnorm;
2764 PetscReal threshold = 1.e-5;
2765 MatType mattype;
2766 PetscInt m, n, M, N;
2767 void *functx;
2768 PetscBool complete_print = PETSC_FALSE, threshold_print = PETSC_FALSE, flg, istranspose;
2769 PetscBool silent = diffNorm != PETSC_NULLPTR ? PETSC_TRUE : PETSC_FALSE;
2770 PetscViewer viewer, mviewer;
2771 MPI_Comm comm;
2772 PetscInt tabs;
2773 static PetscBool directionsprinted = PETSC_FALSE;
2774 PetscViewerFormat format;
2775
2776 PetscFunctionBegin;
2777 PetscObjectOptionsBegin((PetscObject)snes);
2778 PetscCall(PetscOptionsReal("-snes_test_jacobian", "Threshold for element difference between hand-coded and finite difference being meaningful", "None", threshold, &threshold, NULL));
2779 PetscCall(PetscOptionsDeprecated("-snes_test_jacobian_display", "-snes_test_jacobian_view", "3.13", NULL));
2780 PetscCall(PetscOptionsViewer("-snes_test_jacobian_view", "View difference between hand-coded and finite difference Jacobians element entries", "None", &mviewer, &format, &complete_print));
2781 PetscCall(PetscOptionsDeprecated("-snes_test_jacobian_display_threshold", "-snes_test_jacobian", "3.13", "-snes_test_jacobian accepts an optional threshold (since v3.10)"));
2782 PetscCall(PetscOptionsReal("-snes_test_jacobian_display_threshold", "Display difference between hand-coded and finite difference Jacobians which exceed input threshold", "None", threshold, &threshold, &threshold_print));
2783 PetscOptionsEnd();
2784
2785 PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
2786 PetscCall(PetscViewerASCIIGetStdout(comm, &viewer));
2787 PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
2788 PetscCall(PetscViewerASCIISetTab(viewer, ((PetscObject)snes)->tablevel));
2789 if (!silent) PetscCall(PetscViewerASCIIPrintf(viewer, " ---------- Testing Jacobian -------------\n"));
2790 if (!complete_print && !silent && !directionsprinted) {
2791 PetscCall(PetscViewerASCIIPrintf(viewer, " Run with -snes_test_jacobian_view and optionally -snes_test_jacobian <threshold> to show difference\n"));
2792 PetscCall(PetscViewerASCIIPrintf(viewer, " of hand-coded and finite difference Jacobian entries greater than <threshold>.\n"));
2793 }
2794 if (!directionsprinted && !silent) {
2795 PetscCall(PetscViewerASCIIPrintf(viewer, " Testing hand-coded Jacobian, if (for double precision runs) ||J - Jfd||_F/||J||_F is\n"));
2796 PetscCall(PetscViewerASCIIPrintf(viewer, " O(1.e-8), the hand-coded Jacobian is probably correct.\n"));
2797 directionsprinted = PETSC_TRUE;
2798 }
2799 if (complete_print) PetscCall(PetscViewerPushFormat(mviewer, format));
2800
2801 PetscCall(PetscObjectTypeCompare((PetscObject)snes->jacobian, MATMFFD, &flg));
2802 if (!flg) jacobian = snes->jacobian;
2803 else jacobian = snes->jacobian_pre;
2804
2805 if (!x) PetscCall(MatCreateVecs(jacobian, &x, NULL));
2806 else PetscCall(PetscObjectReference((PetscObject)x));
2807 PetscCall(VecDuplicate(x, &f));
2808
2809 /* evaluate the function at this point because SNESComputeJacobianDefault() assumes that the function has been evaluated and put into snes->vec_func */
2810 PetscCall(SNESComputeFunction(snes, x, f));
2811 PetscCall(VecDestroy(&f));
2812 PetscCall(PetscObjectTypeCompare((PetscObject)snes, SNESKSPTRANSPOSEONLY, &istranspose));
2813 while (jacobian) {
2814 Mat JT = NULL, Jsave = NULL;
2815
2816 if (istranspose) {
2817 PetscCall(MatCreateTranspose(jacobian, &JT));
2818 Jsave = jacobian;
2819 jacobian = JT;
2820 }
2821 PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)jacobian, &flg, MATSEQAIJ, MATMPIAIJ, MATSEQDENSE, MATMPIDENSE, MATSEQBAIJ, MATMPIBAIJ, MATSEQSBAIJ, MATMPISBAIJ, ""));
2822 if (flg) {
2823 A = jacobian;
2824 PetscCall(PetscObjectReference((PetscObject)A));
2825 } else {
2826 PetscCall(MatComputeOperator(jacobian, MATAIJ, &A));
2827 }
2828
2829 PetscCall(MatGetType(A, &mattype));
2830 PetscCall(MatGetSize(A, &M, &N));
2831 PetscCall(MatGetLocalSize(A, &m, &n));
2832 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
2833 PetscCall(MatSetType(B, mattype));
2834 PetscCall(MatSetSizes(B, m, n, M, N));
2835 PetscCall(MatSetBlockSizesFromMats(B, A, A));
2836 PetscCall(MatSetUp(B));
2837 PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
2838
2839 PetscCall(SNESGetFunction(snes, NULL, NULL, &functx));
2840 PetscCall(SNESComputeJacobianDefault(snes, x, B, B, functx));
2841
2842 PetscCall(MatDuplicate(B, MAT_COPY_VALUES, &D));
2843 PetscCall(MatAYPX(D, -1.0, A, DIFFERENT_NONZERO_PATTERN));
2844 PetscCall(MatNorm(D, NORM_FROBENIUS, &nrm));
2845 PetscCall(MatNorm(A, NORM_FROBENIUS, &gnorm));
2846 PetscCall(MatDestroy(&D));
2847 if (!gnorm) gnorm = 1; /* just in case */
2848 if (!silent) PetscCall(PetscViewerASCIIPrintf(viewer, " ||J - Jfd||_F/||J||_F = %g, ||J - Jfd||_F = %g\n", (double)(nrm / gnorm), (double)nrm));
2849 if (complete_print) {
2850 PetscCall(PetscViewerASCIIPrintf(viewer, " Hand-coded Jacobian ----------\n"));
2851 PetscCall(MatView(A, mviewer));
2852 PetscCall(PetscViewerASCIIPrintf(viewer, " Finite difference Jacobian ----------\n"));
2853 PetscCall(MatView(B, mviewer));
2854 }
2855
2856 if (threshold_print || complete_print) {
2857 PetscInt Istart, Iend, *ccols, bncols, cncols, j, row;
2858 PetscScalar *cvals;
2859 const PetscInt *bcols;
2860 const PetscScalar *bvals;
2861
2862 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C));
2863 PetscCall(MatSetType(C, mattype));
2864 PetscCall(MatSetSizes(C, m, n, M, N));
2865 PetscCall(MatSetBlockSizesFromMats(C, A, A));
2866 PetscCall(MatSetUp(C));
2867 PetscCall(MatSetOption(C, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
2868
2869 PetscCall(MatAYPX(B, -1.0, A, DIFFERENT_NONZERO_PATTERN));
2870 PetscCall(MatGetOwnershipRange(B, &Istart, &Iend));
2871
2872 for (row = Istart; row < Iend; row++) {
2873 PetscCall(MatGetRow(B, row, &bncols, &bcols, &bvals));
2874 PetscCall(PetscMalloc2(bncols, &ccols, bncols, &cvals));
2875 for (j = 0, cncols = 0; j < bncols; j++) {
2876 if (PetscAbsScalar(bvals[j]) > threshold) {
2877 ccols[cncols] = bcols[j];
2878 cvals[cncols] = bvals[j];
2879 cncols += 1;
2880 }
2881 }
2882 if (cncols) PetscCall(MatSetValues(C, 1, &row, cncols, ccols, cvals, INSERT_VALUES));
2883 PetscCall(MatRestoreRow(B, row, &bncols, &bcols, &bvals));
2884 PetscCall(PetscFree2(ccols, cvals));
2885 }
2886 PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
2887 PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
2888 PetscCall(PetscViewerASCIIPrintf(viewer, " Hand-coded minus finite-difference Jacobian with tolerance %g ----------\n", (double)threshold));
2889 PetscCall(MatView(C, complete_print ? mviewer : viewer));
2890 PetscCall(MatDestroy(&C));
2891 }
2892 PetscCall(MatDestroy(&A));
2893 PetscCall(MatDestroy(&B));
2894 PetscCall(MatDestroy(&JT));
2895 if (Jsave) jacobian = Jsave;
2896 if (jacobian != snes->jacobian_pre) {
2897 jacobian = snes->jacobian_pre;
2898 if (!silent) PetscCall(PetscViewerASCIIPrintf(viewer, " ---------- Testing Jacobian for preconditioner -------------\n"));
2899 } else jacobian = NULL;
2900 }
2901 PetscCall(VecDestroy(&x));
2902 if (complete_print) PetscCall(PetscViewerPopFormat(mviewer));
2903 if (mviewer) PetscCall(PetscViewerDestroy(&mviewer));
2904 PetscCall(PetscViewerASCIISetTab(viewer, tabs));
2905
2906 if (Jnorm) *Jnorm = gnorm;
2907 if (diffNorm) *diffNorm = nrm;
2908 PetscFunctionReturn(PETSC_SUCCESS);
2909 }
2910
2911 /*@
2912 SNESComputeJacobian - Computes the Jacobian matrix that has been set with `SNESSetJacobian()`.
2913
2914 Collective
2915
2916 Input Parameters:
2917 + snes - the `SNES` context
2918 - X - input vector
2919
2920 Output Parameters:
2921 + A - Jacobian matrix
2922 - B - optional matrix for building the preconditioner, usually the same as `A`
2923
2924 Options Database Keys:
2925 + -snes_lag_preconditioner <lag> - how often to rebuild preconditioner
2926 . -snes_lag_jacobian <lag> - how often to rebuild Jacobian
2927 . -snes_test_jacobian <optional threshold> - compare the user provided Jacobian with one compute via finite differences to check for errors. If a threshold is given, display only those entries whose difference is greater than the threshold.
2928 . -snes_test_jacobian_view - display the user provided Jacobian, the finite difference Jacobian and the difference between them to help users detect the location of errors in the user provided Jacobian
2929 . -snes_compare_explicit - Compare the computed Jacobian to the finite difference Jacobian and output the differences
2930 . -snes_compare_explicit_draw - Compare the computed Jacobian to the finite difference Jacobian and draw the result
2931 . -snes_compare_explicit_contour - Compare the computed Jacobian to the finite difference Jacobian and draw a contour plot with the result
2932 . -snes_compare_operator - Make the comparison options above use the operator instead of the matrix used to construct the preconditioner
2933 . -snes_compare_coloring - Compute the finite difference Jacobian using coloring and display norms of difference
2934 . -snes_compare_coloring_display - Compute the finite difference Jacobian using coloring and display verbose differences
2935 . -snes_compare_coloring_threshold - Display only those matrix entries that differ by more than a given threshold
2936 . -snes_compare_coloring_threshold_atol - Absolute tolerance for difference in matrix entries to be displayed by `-snes_compare_coloring_threshold`
2937 . -snes_compare_coloring_threshold_rtol - Relative tolerance for difference in matrix entries to be displayed by `-snes_compare_coloring_threshold`
2938 . -snes_compare_coloring_draw - Compute the finite difference Jacobian using coloring and draw differences
2939 - -snes_compare_coloring_draw_contour - Compute the finite difference Jacobian using coloring and show contours of matrices and differences
2940
2941 Level: developer
2942
2943 Note:
2944 Most users should not need to explicitly call this routine, as it
2945 is used internally within the nonlinear solvers.
2946
2947 Developer Note:
2948 This has duplicative ways of checking the accuracy of the user provided Jacobian (see the options above). This is for historical reasons, the routine `SNESTestJacobian()` use to used
2949 with the `SNESType` of test that has been removed.
2950
2951 .seealso: [](ch_snes), `SNESSetJacobian()`, `KSPSetOperators()`, `MatStructure`, `SNESSetLagPreconditioner()`, `SNESSetLagJacobian()`,
2952 `SNESSetJacobianDomainError()`, `SNESCheckJacobianDomainError()`, `SNESSetCheckJacobianDomainError()`
2953 @*/
SNESComputeJacobian(SNES snes,Vec X,Mat A,Mat B)2954 PetscErrorCode SNESComputeJacobian(SNES snes, Vec X, Mat A, Mat B)
2955 {
2956 PetscBool flag;
2957 DM dm;
2958 DMSNES sdm;
2959 KSP ksp;
2960
2961 PetscFunctionBegin;
2962 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
2963 PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
2964 PetscCheckSameComm(snes, 1, X, 2);
2965 PetscCall(VecValidValues_Internal(X, 2, PETSC_TRUE));
2966 PetscCall(SNESGetDM(snes, &dm));
2967 PetscCall(DMGetDMSNES(dm, &sdm));
2968
2969 /* make sure that MatAssemblyBegin/End() is called on A matrix if it is matrix-free */
2970 if (snes->lagjacobian == -2) {
2971 snes->lagjacobian = -1;
2972
2973 PetscCall(PetscInfo(snes, "Recomputing Jacobian/preconditioner because lag is -2 (means compute Jacobian, but then never again) \n"));
2974 } else if (snes->lagjacobian == -1) {
2975 PetscCall(PetscInfo(snes, "Reusing Jacobian/preconditioner because lag is -1\n"));
2976 PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMFFD, &flag));
2977 if (flag) {
2978 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2979 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
2980 }
2981 PetscFunctionReturn(PETSC_SUCCESS);
2982 } else if (snes->lagjacobian > 1 && (snes->iter + snes->jac_iter) % snes->lagjacobian) {
2983 PetscCall(PetscInfo(snes, "Reusing Jacobian/preconditioner because lag is %" PetscInt_FMT " and SNES iteration is %" PetscInt_FMT "\n", snes->lagjacobian, snes->iter));
2984 PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMFFD, &flag));
2985 if (flag) {
2986 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2987 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
2988 }
2989 PetscFunctionReturn(PETSC_SUCCESS);
2990 }
2991 if (snes->npc && snes->npcside == PC_LEFT) {
2992 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
2993 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
2994 PetscFunctionReturn(PETSC_SUCCESS);
2995 }
2996
2997 PetscCall(PetscLogEventBegin(SNES_JacobianEval, snes, X, A, B));
2998 PetscCall(VecLockReadPush(X));
2999 {
3000 void *ctx;
3001 SNESJacobianFn *J;
3002 PetscCall(DMSNESGetJacobian(dm, &J, &ctx));
3003 PetscCallBack("SNES callback Jacobian", (*J)(snes, X, A, B, ctx));
3004 }
3005 PetscCall(VecLockReadPop(X));
3006 PetscCall(PetscLogEventEnd(SNES_JacobianEval, snes, X, A, B));
3007
3008 /* attach latest linearization point to the matrix used to construct the preconditioner */
3009 PetscCall(PetscObjectCompose((PetscObject)B, "__SNES_latest_X", (PetscObject)X));
3010
3011 /* the next line ensures that snes->ksp exists */
3012 PetscCall(SNESGetKSP(snes, &ksp));
3013 if (snes->lagpreconditioner == -2) {
3014 PetscCall(PetscInfo(snes, "Rebuilding preconditioner exactly once since lag is -2\n"));
3015 PetscCall(KSPSetReusePreconditioner(snes->ksp, PETSC_FALSE));
3016 snes->lagpreconditioner = -1;
3017 } else if (snes->lagpreconditioner == -1) {
3018 PetscCall(PetscInfo(snes, "Reusing preconditioner because lag is -1\n"));
3019 PetscCall(KSPSetReusePreconditioner(snes->ksp, PETSC_TRUE));
3020 } else if (snes->lagpreconditioner > 1 && (snes->iter + snes->pre_iter) % snes->lagpreconditioner) {
3021 PetscCall(PetscInfo(snes, "Reusing preconditioner because lag is %" PetscInt_FMT " and SNES iteration is %" PetscInt_FMT "\n", snes->lagpreconditioner, snes->iter));
3022 PetscCall(KSPSetReusePreconditioner(snes->ksp, PETSC_TRUE));
3023 } else {
3024 PetscCall(PetscInfo(snes, "Rebuilding preconditioner\n"));
3025 PetscCall(KSPSetReusePreconditioner(snes->ksp, PETSC_FALSE));
3026 }
3027
3028 /* monkey business to allow testing Jacobians in multilevel solvers.
3029 This is needed because the SNESTestXXX interface does not accept vectors and matrices */
3030 {
3031 Vec xsave = snes->vec_sol;
3032 Mat jacobiansave = snes->jacobian;
3033 Mat jacobian_presave = snes->jacobian_pre;
3034
3035 snes->vec_sol = X;
3036 snes->jacobian = A;
3037 snes->jacobian_pre = B;
3038 if (snes->testFunc) PetscCall(SNESTestFunction(snes));
3039 if (snes->testJac) PetscCall(SNESTestJacobian(snes, NULL, NULL));
3040
3041 snes->vec_sol = xsave;
3042 snes->jacobian = jacobiansave;
3043 snes->jacobian_pre = jacobian_presave;
3044 }
3045
3046 {
3047 PetscBool flag = PETSC_FALSE, flag_draw = PETSC_FALSE, flag_contour = PETSC_FALSE, flag_operator = PETSC_FALSE;
3048 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_compare_explicit", NULL, NULL, &flag));
3049 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_compare_explicit_draw", NULL, NULL, &flag_draw));
3050 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_compare_explicit_draw_contour", NULL, NULL, &flag_contour));
3051 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_compare_operator", NULL, NULL, &flag_operator));
3052 if (flag || flag_draw || flag_contour) {
3053 Mat Bexp_mine = NULL, Bexp, FDexp;
3054 PetscViewer vdraw, vstdout;
3055 PetscBool flg;
3056 if (flag_operator) {
3057 PetscCall(MatComputeOperator(A, MATAIJ, &Bexp_mine));
3058 Bexp = Bexp_mine;
3059 } else {
3060 /* See if the matrix used to construct the preconditioner can be viewed and added directly */
3061 PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)B, &flg, MATSEQAIJ, MATMPIAIJ, MATSEQDENSE, MATMPIDENSE, MATSEQBAIJ, MATMPIBAIJ, MATSEQSBAIJ, MATMPISBAIJ, ""));
3062 if (flg) Bexp = B;
3063 else {
3064 /* If the "preconditioning" matrix is itself MATSHELL or some other type without direct support */
3065 PetscCall(MatComputeOperator(B, MATAIJ, &Bexp_mine));
3066 Bexp = Bexp_mine;
3067 }
3068 }
3069 PetscCall(MatConvert(Bexp, MATSAME, MAT_INITIAL_MATRIX, &FDexp));
3070 PetscCall(SNESComputeJacobianDefault(snes, X, FDexp, FDexp, NULL));
3071 PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)snes), &vstdout));
3072 if (flag_draw || flag_contour) {
3073 PetscCall(PetscViewerDrawOpen(PetscObjectComm((PetscObject)snes), NULL, "Explicit Jacobians", PETSC_DECIDE, PETSC_DECIDE, 300, 300, &vdraw));
3074 if (flag_contour) PetscCall(PetscViewerPushFormat(vdraw, PETSC_VIEWER_DRAW_CONTOUR));
3075 } else vdraw = NULL;
3076 PetscCall(PetscViewerASCIIPrintf(vstdout, "Explicit %s\n", flag_operator ? "Jacobian" : "preconditioning Jacobian"));
3077 if (flag) PetscCall(MatView(Bexp, vstdout));
3078 if (vdraw) PetscCall(MatView(Bexp, vdraw));
3079 PetscCall(PetscViewerASCIIPrintf(vstdout, "Finite difference Jacobian\n"));
3080 if (flag) PetscCall(MatView(FDexp, vstdout));
3081 if (vdraw) PetscCall(MatView(FDexp, vdraw));
3082 PetscCall(MatAYPX(FDexp, -1.0, Bexp, SAME_NONZERO_PATTERN));
3083 PetscCall(PetscViewerASCIIPrintf(vstdout, "User-provided matrix minus finite difference Jacobian\n"));
3084 if (flag) PetscCall(MatView(FDexp, vstdout));
3085 if (vdraw) { /* Always use contour for the difference */
3086 PetscCall(PetscViewerPushFormat(vdraw, PETSC_VIEWER_DRAW_CONTOUR));
3087 PetscCall(MatView(FDexp, vdraw));
3088 PetscCall(PetscViewerPopFormat(vdraw));
3089 }
3090 if (flag_contour) PetscCall(PetscViewerPopFormat(vdraw));
3091 PetscCall(PetscViewerDestroy(&vdraw));
3092 PetscCall(MatDestroy(&Bexp_mine));
3093 PetscCall(MatDestroy(&FDexp));
3094 }
3095 }
3096 {
3097 PetscBool flag = PETSC_FALSE, flag_display = PETSC_FALSE, flag_draw = PETSC_FALSE, flag_contour = PETSC_FALSE, flag_threshold = PETSC_FALSE;
3098 PetscReal threshold_atol = PETSC_SQRT_MACHINE_EPSILON, threshold_rtol = 10 * PETSC_SQRT_MACHINE_EPSILON;
3099 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_compare_coloring", NULL, NULL, &flag));
3100 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_compare_coloring_display", NULL, NULL, &flag_display));
3101 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_compare_coloring_draw", NULL, NULL, &flag_draw));
3102 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_compare_coloring_draw_contour", NULL, NULL, &flag_contour));
3103 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_compare_coloring_threshold", NULL, NULL, &flag_threshold));
3104 if (flag_threshold) {
3105 PetscCall(PetscOptionsGetReal(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_compare_coloring_threshold_rtol", &threshold_rtol, NULL));
3106 PetscCall(PetscOptionsGetReal(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_compare_coloring_threshold_atol", &threshold_atol, NULL));
3107 }
3108 if (flag || flag_display || flag_draw || flag_contour || flag_threshold) {
3109 Mat Bfd;
3110 PetscViewer vdraw, vstdout;
3111 MatColoring coloring;
3112 ISColoring iscoloring;
3113 MatFDColoring matfdcoloring;
3114 SNESFunctionFn *func;
3115 void *funcctx;
3116 PetscReal norm1, norm2, normmax;
3117
3118 PetscCall(MatDuplicate(B, MAT_DO_NOT_COPY_VALUES, &Bfd));
3119 PetscCall(MatColoringCreate(Bfd, &coloring));
3120 PetscCall(MatColoringSetType(coloring, MATCOLORINGSL));
3121 PetscCall(MatColoringSetFromOptions(coloring));
3122 PetscCall(MatColoringApply(coloring, &iscoloring));
3123 PetscCall(MatColoringDestroy(&coloring));
3124 PetscCall(MatFDColoringCreate(Bfd, iscoloring, &matfdcoloring));
3125 PetscCall(MatFDColoringSetFromOptions(matfdcoloring));
3126 PetscCall(MatFDColoringSetUp(Bfd, iscoloring, matfdcoloring));
3127 PetscCall(ISColoringDestroy(&iscoloring));
3128
3129 /* This method of getting the function is currently unreliable since it doesn't work for DM local functions. */
3130 PetscCall(SNESGetFunction(snes, NULL, &func, &funcctx));
3131 PetscCall(MatFDColoringSetFunction(matfdcoloring, (MatFDColoringFn *)func, funcctx));
3132 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)matfdcoloring, ((PetscObject)snes)->prefix));
3133 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)matfdcoloring, "coloring_"));
3134 PetscCall(MatFDColoringSetFromOptions(matfdcoloring));
3135 PetscCall(MatFDColoringApply(Bfd, matfdcoloring, X, snes));
3136 PetscCall(MatFDColoringDestroy(&matfdcoloring));
3137
3138 PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)snes), &vstdout));
3139 if (flag_draw || flag_contour) {
3140 PetscCall(PetscViewerDrawOpen(PetscObjectComm((PetscObject)snes), NULL, "Colored Jacobians", PETSC_DECIDE, PETSC_DECIDE, 300, 300, &vdraw));
3141 if (flag_contour) PetscCall(PetscViewerPushFormat(vdraw, PETSC_VIEWER_DRAW_CONTOUR));
3142 } else vdraw = NULL;
3143 PetscCall(PetscViewerASCIIPrintf(vstdout, "Explicit preconditioning Jacobian\n"));
3144 if (flag_display) PetscCall(MatView(B, vstdout));
3145 if (vdraw) PetscCall(MatView(B, vdraw));
3146 PetscCall(PetscViewerASCIIPrintf(vstdout, "Colored Finite difference Jacobian\n"));
3147 if (flag_display) PetscCall(MatView(Bfd, vstdout));
3148 if (vdraw) PetscCall(MatView(Bfd, vdraw));
3149 PetscCall(MatAYPX(Bfd, -1.0, B, SAME_NONZERO_PATTERN));
3150 PetscCall(MatNorm(Bfd, NORM_1, &norm1));
3151 PetscCall(MatNorm(Bfd, NORM_FROBENIUS, &norm2));
3152 PetscCall(MatNorm(Bfd, NORM_MAX, &normmax));
3153 PetscCall(PetscViewerASCIIPrintf(vstdout, "User-provided matrix minus finite difference Jacobian, norm1=%g normFrob=%g normmax=%g\n", (double)norm1, (double)norm2, (double)normmax));
3154 if (flag_display) PetscCall(MatView(Bfd, vstdout));
3155 if (vdraw) { /* Always use contour for the difference */
3156 PetscCall(PetscViewerPushFormat(vdraw, PETSC_VIEWER_DRAW_CONTOUR));
3157 PetscCall(MatView(Bfd, vdraw));
3158 PetscCall(PetscViewerPopFormat(vdraw));
3159 }
3160 if (flag_contour) PetscCall(PetscViewerPopFormat(vdraw));
3161
3162 if (flag_threshold) {
3163 PetscInt bs, rstart, rend, i;
3164 PetscCall(MatGetBlockSize(B, &bs));
3165 PetscCall(MatGetOwnershipRange(B, &rstart, &rend));
3166 for (i = rstart; i < rend; i++) {
3167 const PetscScalar *ba, *ca;
3168 const PetscInt *bj, *cj;
3169 PetscInt bn, cn, j, maxentrycol = -1, maxdiffcol = -1, maxrdiffcol = -1;
3170 PetscReal maxentry = 0, maxdiff = 0, maxrdiff = 0;
3171 PetscCall(MatGetRow(B, i, &bn, &bj, &ba));
3172 PetscCall(MatGetRow(Bfd, i, &cn, &cj, &ca));
3173 PetscCheck(bn == cn, ((PetscObject)A)->comm, PETSC_ERR_PLIB, "Unexpected different nonzero pattern in -snes_compare_coloring_threshold");
3174 for (j = 0; j < bn; j++) {
3175 PetscReal rdiff = PetscAbsScalar(ca[j]) / (threshold_atol + threshold_rtol * PetscAbsScalar(ba[j]));
3176 if (PetscAbsScalar(ba[j]) > PetscAbs(maxentry)) {
3177 maxentrycol = bj[j];
3178 maxentry = PetscRealPart(ba[j]);
3179 }
3180 if (PetscAbsScalar(ca[j]) > PetscAbs(maxdiff)) {
3181 maxdiffcol = bj[j];
3182 maxdiff = PetscRealPart(ca[j]);
3183 }
3184 if (rdiff > maxrdiff) {
3185 maxrdiffcol = bj[j];
3186 maxrdiff = rdiff;
3187 }
3188 }
3189 if (maxrdiff > 1) {
3190 PetscCall(PetscViewerASCIIPrintf(vstdout, "row %" PetscInt_FMT " (maxentry=%g at %" PetscInt_FMT ", maxdiff=%g at %" PetscInt_FMT ", maxrdiff=%g at %" PetscInt_FMT "):", i, (double)maxentry, maxentrycol, (double)maxdiff, maxdiffcol, (double)maxrdiff, maxrdiffcol));
3191 for (j = 0; j < bn; j++) {
3192 PetscReal rdiff;
3193 rdiff = PetscAbsScalar(ca[j]) / (threshold_atol + threshold_rtol * PetscAbsScalar(ba[j]));
3194 if (rdiff > 1) PetscCall(PetscViewerASCIIPrintf(vstdout, " (%" PetscInt_FMT ",%g:%g)", bj[j], (double)PetscRealPart(ba[j]), (double)PetscRealPart(ca[j])));
3195 }
3196 PetscCall(PetscViewerASCIIPrintf(vstdout, "\n"));
3197 }
3198 PetscCall(MatRestoreRow(B, i, &bn, &bj, &ba));
3199 PetscCall(MatRestoreRow(Bfd, i, &cn, &cj, &ca));
3200 }
3201 }
3202 PetscCall(PetscViewerDestroy(&vdraw));
3203 PetscCall(MatDestroy(&Bfd));
3204 }
3205 }
3206 PetscFunctionReturn(PETSC_SUCCESS);
3207 }
3208
3209 /*@C
3210 SNESSetJacobian - Sets the function to compute Jacobian as well as the
3211 location to store the matrix.
3212
3213 Logically Collective
3214
3215 Input Parameters:
3216 + snes - the `SNES` context
3217 . Amat - the matrix that defines the (approximate) Jacobian
3218 . Pmat - the matrix to be used in constructing the preconditioner, usually the same as `Amat`.
3219 . J - Jacobian evaluation routine (if `NULL` then `SNES` retains any previously set value), see `SNESJacobianFn` for details
3220 - ctx - [optional] user-defined context for private data for the
3221 Jacobian evaluation routine (may be `NULL`) (if `NULL` then `SNES` retains any previously set value)
3222
3223 Level: beginner
3224
3225 Notes:
3226 If the `Amat` matrix and `Pmat` matrix are different you must call `MatAssemblyBegin()`/`MatAssemblyEnd()` on
3227 each matrix.
3228
3229 If you know the operator `Amat` has a null space you can use `MatSetNullSpace()` and `MatSetTransposeNullSpace()` to supply the null
3230 space to `Amat` and the `KSP` solvers will automatically use that null space as needed during the solution process.
3231
3232 If using `SNESComputeJacobianDefaultColor()` to assemble a Jacobian, the `ctx` argument
3233 must be a `MatFDColoring`.
3234
3235 Other defect-correction schemes can be used by computing a different matrix in place of the Jacobian. One common
3236 example is to use the "Picard linearization" which only differentiates through the highest order parts of each term using `SNESSetPicard()`
3237
3238 .seealso: [](ch_snes), `SNES`, `KSPSetOperators()`, `SNESSetFunction()`, `MatMFFDComputeJacobian()`, `SNESComputeJacobianDefaultColor()`, `MatStructure`,
3239 `SNESSetPicard()`, `SNESJacobianFn`, `SNESFunctionFn`
3240 @*/
SNESSetJacobian(SNES snes,Mat Amat,Mat Pmat,SNESJacobianFn * J,PetscCtx ctx)3241 PetscErrorCode SNESSetJacobian(SNES snes, Mat Amat, Mat Pmat, SNESJacobianFn *J, PetscCtx ctx)
3242 {
3243 DM dm;
3244
3245 PetscFunctionBegin;
3246 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3247 if (Amat) PetscValidHeaderSpecific(Amat, MAT_CLASSID, 2);
3248 if (Pmat) PetscValidHeaderSpecific(Pmat, MAT_CLASSID, 3);
3249 if (Amat) PetscCheckSameComm(snes, 1, Amat, 2);
3250 if (Pmat) PetscCheckSameComm(snes, 1, Pmat, 3);
3251 PetscCall(SNESGetDM(snes, &dm));
3252 PetscCall(DMSNESSetJacobian(dm, J, ctx));
3253 if (Amat) {
3254 PetscCall(PetscObjectReference((PetscObject)Amat));
3255 PetscCall(MatDestroy(&snes->jacobian));
3256
3257 snes->jacobian = Amat;
3258 }
3259 if (Pmat) {
3260 PetscCall(PetscObjectReference((PetscObject)Pmat));
3261 PetscCall(MatDestroy(&snes->jacobian_pre));
3262
3263 snes->jacobian_pre = Pmat;
3264 }
3265 PetscFunctionReturn(PETSC_SUCCESS);
3266 }
3267
3268 /*@C
3269 SNESGetJacobian - Returns the Jacobian matrix and optionally the user
3270 provided context for evaluating the Jacobian.
3271
3272 Not Collective, but `Mat` object will be parallel if `SNES` is
3273
3274 Input Parameter:
3275 . snes - the nonlinear solver context
3276
3277 Output Parameters:
3278 + Amat - location to stash (approximate) Jacobian matrix (or `NULL`)
3279 . Pmat - location to stash matrix used to compute the preconditioner (or `NULL`)
3280 . J - location to put Jacobian function (or `NULL`), for calling sequence see `SNESJacobianFn`
3281 - ctx - location to stash Jacobian ctx (or `NULL`)
3282
3283 Level: advanced
3284
3285 .seealso: [](ch_snes), `SNES`, `Mat`, `SNESSetJacobian()`, `SNESComputeJacobian()`, `SNESJacobianFn`, `SNESGetFunction()`
3286 @*/
SNESGetJacobian(SNES snes,Mat * Amat,Mat * Pmat,SNESJacobianFn ** J,PetscCtxRt ctx)3287 PetscErrorCode SNESGetJacobian(SNES snes, Mat *Amat, Mat *Pmat, SNESJacobianFn **J, PetscCtxRt ctx)
3288 {
3289 DM dm;
3290
3291 PetscFunctionBegin;
3292 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3293 if (Amat) *Amat = snes->jacobian;
3294 if (Pmat) *Pmat = snes->jacobian_pre;
3295 PetscCall(SNESGetDM(snes, &dm));
3296 PetscCall(DMSNESGetJacobian(dm, J, ctx));
3297 PetscFunctionReturn(PETSC_SUCCESS);
3298 }
3299
SNESSetDefaultComputeJacobian(SNES snes)3300 static PetscErrorCode SNESSetDefaultComputeJacobian(SNES snes)
3301 {
3302 DM dm;
3303 DMSNES sdm;
3304
3305 PetscFunctionBegin;
3306 PetscCall(SNESGetDM(snes, &dm));
3307 PetscCall(DMGetDMSNES(dm, &sdm));
3308 if (!sdm->ops->computejacobian && snes->jacobian_pre) {
3309 DM dm;
3310 PetscBool isdense, ismf;
3311
3312 PetscCall(SNESGetDM(snes, &dm));
3313 PetscCall(PetscObjectTypeCompareAny((PetscObject)snes->jacobian_pre, &isdense, MATSEQDENSE, MATMPIDENSE, MATDENSE, NULL));
3314 PetscCall(PetscObjectTypeCompareAny((PetscObject)snes->jacobian_pre, &ismf, MATMFFD, MATSHELL, NULL));
3315 if (isdense) {
3316 PetscCall(DMSNESSetJacobian(dm, SNESComputeJacobianDefault, NULL));
3317 } else if (!ismf) {
3318 PetscCall(DMSNESSetJacobian(dm, SNESComputeJacobianDefaultColor, NULL));
3319 }
3320 }
3321 PetscFunctionReturn(PETSC_SUCCESS);
3322 }
3323
3324 /*@
3325 SNESSetUp - Sets up the internal data structures for the later use
3326 of a nonlinear solver `SNESSolve()`.
3327
3328 Collective
3329
3330 Input Parameter:
3331 . snes - the `SNES` context
3332
3333 Level: advanced
3334
3335 Note:
3336 For basic use of the `SNES` solvers the user does not need to explicitly call
3337 `SNESSetUp()`, since these actions will automatically occur during
3338 the call to `SNESSolve()`. However, if one wishes to control this
3339 phase separately, `SNESSetUp()` should be called after `SNESCreate()`
3340 and optional routines of the form SNESSetXXX(), but before `SNESSolve()`.
3341
3342 .seealso: [](ch_snes), `SNES`, `SNESCreate()`, `SNESSolve()`, `SNESDestroy()`, `SNESSetFromOptions()`
3343 @*/
SNESSetUp(SNES snes)3344 PetscErrorCode SNESSetUp(SNES snes)
3345 {
3346 DM dm;
3347 DMSNES sdm;
3348 SNESLineSearch linesearch, pclinesearch;
3349 void *lsprectx, *lspostctx;
3350 PetscBool mf_operator, mf;
3351 Vec f, fpc;
3352 void *funcctx;
3353 void *jacctx, *appctx;
3354 Mat j, jpre;
3355 PetscErrorCode (*precheck)(SNESLineSearch, Vec, Vec, PetscBool *, void *);
3356 PetscErrorCode (*postcheck)(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *);
3357 SNESFunctionFn *func;
3358 SNESJacobianFn *jac;
3359
3360 PetscFunctionBegin;
3361 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3362 if (snes->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
3363 PetscCall(PetscLogEventBegin(SNES_SetUp, snes, 0, 0, 0));
3364
3365 if (!((PetscObject)snes)->type_name) PetscCall(SNESSetType(snes, SNESNEWTONLS));
3366
3367 PetscCall(SNESGetFunction(snes, &snes->vec_func, NULL, NULL));
3368
3369 PetscCall(SNESGetDM(snes, &dm));
3370 PetscCall(DMGetDMSNES(dm, &sdm));
3371 PetscCall(SNESSetDefaultComputeJacobian(snes));
3372
3373 if (!snes->vec_func) PetscCall(DMCreateGlobalVector(dm, &snes->vec_func));
3374
3375 if (!snes->ksp) PetscCall(SNESGetKSP(snes, &snes->ksp));
3376
3377 if (snes->linesearch) {
3378 PetscCall(SNESGetLineSearch(snes, &snes->linesearch));
3379 PetscCall(SNESLineSearchSetFunction(snes->linesearch, SNESComputeFunction));
3380 }
3381
3382 PetscCall(SNESGetUseMatrixFree(snes, &mf_operator, &mf));
3383 if (snes->npc && snes->npcside == PC_LEFT) {
3384 snes->mf = PETSC_TRUE;
3385 snes->mf_operator = PETSC_FALSE;
3386 }
3387
3388 if (snes->npc) {
3389 /* copy the DM over */
3390 PetscCall(SNESGetDM(snes, &dm));
3391 PetscCall(SNESSetDM(snes->npc, dm));
3392
3393 PetscCall(SNESGetFunction(snes, &f, &func, &funcctx));
3394 PetscCall(VecDuplicate(f, &fpc));
3395 PetscCall(SNESSetFunction(snes->npc, fpc, func, funcctx));
3396 PetscCall(SNESGetJacobian(snes, &j, &jpre, &jac, &jacctx));
3397 PetscCall(SNESSetJacobian(snes->npc, j, jpre, jac, jacctx));
3398 PetscCall(SNESGetApplicationContext(snes, &appctx));
3399 PetscCall(SNESSetApplicationContext(snes->npc, appctx));
3400 PetscCall(SNESSetUseMatrixFree(snes->npc, mf_operator, mf));
3401 PetscCall(VecDestroy(&fpc));
3402
3403 /* copy the function pointers over */
3404 PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)snes->npc));
3405
3406 /* default to 1 iteration */
3407 PetscCall(SNESSetTolerances(snes->npc, 0.0, 0.0, 0.0, 1, snes->npc->max_funcs));
3408 if (snes->npcside == PC_RIGHT) {
3409 PetscCall(SNESSetNormSchedule(snes->npc, SNES_NORM_FINAL_ONLY));
3410 } else {
3411 PetscCall(SNESSetNormSchedule(snes->npc, SNES_NORM_NONE));
3412 }
3413 PetscCall(SNESSetFromOptions(snes->npc));
3414
3415 /* copy the line search context over */
3416 if (snes->linesearch && snes->npc->linesearch) {
3417 PetscCall(SNESGetLineSearch(snes, &linesearch));
3418 PetscCall(SNESGetLineSearch(snes->npc, &pclinesearch));
3419 PetscCall(SNESLineSearchGetPreCheck(linesearch, &precheck, &lsprectx));
3420 PetscCall(SNESLineSearchGetPostCheck(linesearch, &postcheck, &lspostctx));
3421 PetscCall(SNESLineSearchSetPreCheck(pclinesearch, precheck, lsprectx));
3422 PetscCall(SNESLineSearchSetPostCheck(pclinesearch, postcheck, lspostctx));
3423 PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)linesearch, (PetscObject)pclinesearch));
3424 }
3425 }
3426 if (snes->mf) PetscCall(SNESSetUpMatrixFree_Private(snes, snes->mf_operator, snes->mf_version));
3427 if (snes->ops->ctxcompute && !snes->ctx) PetscCallBack("SNES callback compute application context", (*snes->ops->ctxcompute)(snes, &snes->ctx));
3428
3429 snes->jac_iter = 0;
3430 snes->pre_iter = 0;
3431
3432 PetscTryTypeMethod(snes, setup);
3433
3434 PetscCall(SNESSetDefaultComputeJacobian(snes));
3435
3436 if (snes->npc && snes->npcside == PC_LEFT) {
3437 if (snes->functype == SNES_FUNCTION_PRECONDITIONED) {
3438 if (snes->linesearch) {
3439 PetscCall(SNESGetLineSearch(snes, &linesearch));
3440 PetscCall(SNESLineSearchSetFunction(linesearch, SNESComputeFunctionDefaultNPC));
3441 }
3442 }
3443 }
3444 PetscCall(PetscLogEventEnd(SNES_SetUp, snes, 0, 0, 0));
3445 snes->setupcalled = PETSC_TRUE;
3446 PetscFunctionReturn(PETSC_SUCCESS);
3447 }
3448
3449 /*@
3450 SNESReset - Resets a `SNES` context to the state it was in before `SNESSetUp()` was called and removes any allocated `Vec` and `Mat` from its data structures
3451
3452 Collective
3453
3454 Input Parameter:
3455 . snes - the nonlinear iterative solver context obtained from `SNESCreate()`
3456
3457 Level: intermediate
3458
3459 Notes:
3460 Any options set on the `SNES` object, including those set with `SNESSetFromOptions()` remain.
3461
3462 Call this if you wish to reuse a `SNES` but with different size vectors
3463
3464 Also calls the application context destroy routine set with `SNESSetComputeApplicationContext()`
3465
3466 .seealso: [](ch_snes), `SNES`, `SNESDestroy()`, `SNESCreate()`, `SNESSetUp()`, `SNESSolve()`
3467 @*/
SNESReset(SNES snes)3468 PetscErrorCode SNESReset(SNES snes)
3469 {
3470 PetscFunctionBegin;
3471 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3472 if (snes->ops->ctxdestroy && snes->ctx) {
3473 PetscCallBack("SNES callback destroy application context", (*snes->ops->ctxdestroy)(&snes->ctx));
3474 snes->ctx = NULL;
3475 }
3476 if (snes->npc) PetscCall(SNESReset(snes->npc));
3477
3478 PetscTryTypeMethod(snes, reset);
3479 if (snes->ksp) PetscCall(KSPReset(snes->ksp));
3480
3481 if (snes->linesearch) PetscCall(SNESLineSearchReset(snes->linesearch));
3482
3483 PetscCall(VecDestroy(&snes->vec_rhs));
3484 PetscCall(VecDestroy(&snes->vec_sol));
3485 PetscCall(VecDestroy(&snes->vec_sol_update));
3486 PetscCall(VecDestroy(&snes->vec_func));
3487 PetscCall(MatDestroy(&snes->jacobian));
3488 PetscCall(MatDestroy(&snes->jacobian_pre));
3489 PetscCall(MatDestroy(&snes->picard));
3490 PetscCall(VecDestroyVecs(snes->nwork, &snes->work));
3491 PetscCall(VecDestroyVecs(snes->nvwork, &snes->vwork));
3492
3493 snes->alwayscomputesfinalresidual = PETSC_FALSE;
3494
3495 snes->nwork = snes->nvwork = 0;
3496 snes->setupcalled = PETSC_FALSE;
3497 PetscFunctionReturn(PETSC_SUCCESS);
3498 }
3499
3500 /*@
3501 SNESConvergedReasonViewCancel - Clears all the reason view functions for a `SNES` object provided with `SNESConvergedReasonViewSet()` also
3502 removes the default viewer.
3503
3504 Collective
3505
3506 Input Parameter:
3507 . snes - the nonlinear iterative solver context obtained from `SNESCreate()`
3508
3509 Level: intermediate
3510
3511 .seealso: [](ch_snes), `SNES`, `SNESCreate()`, `SNESDestroy()`, `SNESReset()`, `SNESConvergedReasonViewSet()`
3512 @*/
SNESConvergedReasonViewCancel(SNES snes)3513 PetscErrorCode SNESConvergedReasonViewCancel(SNES snes)
3514 {
3515 PetscInt i;
3516
3517 PetscFunctionBegin;
3518 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3519 for (i = 0; i < snes->numberreasonviews; i++) {
3520 if (snes->reasonviewdestroy[i]) PetscCall((*snes->reasonviewdestroy[i])(&snes->reasonviewcontext[i]));
3521 }
3522 snes->numberreasonviews = 0;
3523 PetscCall(PetscViewerDestroy(&snes->convergedreasonviewer));
3524 PetscFunctionReturn(PETSC_SUCCESS);
3525 }
3526
3527 /*@
3528 SNESDestroy - Destroys the nonlinear solver context that was created
3529 with `SNESCreate()`.
3530
3531 Collective
3532
3533 Input Parameter:
3534 . snes - the `SNES` context
3535
3536 Level: beginner
3537
3538 .seealso: [](ch_snes), `SNES`, `SNESCreate()`, `SNESSolve()`
3539 @*/
SNESDestroy(SNES * snes)3540 PetscErrorCode SNESDestroy(SNES *snes)
3541 {
3542 DM dm;
3543
3544 PetscFunctionBegin;
3545 if (!*snes) PetscFunctionReturn(PETSC_SUCCESS);
3546 PetscValidHeaderSpecific(*snes, SNES_CLASSID, 1);
3547 if (--((PetscObject)*snes)->refct > 0) {
3548 *snes = NULL;
3549 PetscFunctionReturn(PETSC_SUCCESS);
3550 }
3551
3552 PetscCall(SNESReset(*snes));
3553 PetscCall(SNESDestroy(&(*snes)->npc));
3554
3555 /* if memory was published with SAWs then destroy it */
3556 PetscCall(PetscObjectSAWsViewOff((PetscObject)*snes));
3557 PetscTryTypeMethod(*snes, destroy);
3558
3559 dm = (*snes)->dm;
3560 while (dm) {
3561 PetscCall(DMCoarsenHookRemove(dm, DMCoarsenHook_SNESVecSol, DMRestrictHook_SNESVecSol, *snes));
3562 PetscCall(DMGetCoarseDM(dm, &dm));
3563 }
3564
3565 PetscCall(DMDestroy(&(*snes)->dm));
3566 PetscCall(KSPDestroy(&(*snes)->ksp));
3567 PetscCall(SNESLineSearchDestroy(&(*snes)->linesearch));
3568
3569 PetscCall(PetscFree((*snes)->kspconvctx));
3570 if ((*snes)->ops->convergeddestroy) PetscCall((*(*snes)->ops->convergeddestroy)(&(*snes)->cnvP));
3571 if ((*snes)->conv_hist_alloc) PetscCall(PetscFree2((*snes)->conv_hist, (*snes)->conv_hist_its));
3572 PetscCall(SNESMonitorCancel(*snes));
3573 PetscCall(SNESConvergedReasonViewCancel(*snes));
3574 PetscCall(PetscHeaderDestroy(snes));
3575 PetscFunctionReturn(PETSC_SUCCESS);
3576 }
3577
3578 /* ----------- Routines to set solver parameters ---------- */
3579
3580 /*@
3581 SNESSetLagPreconditioner - Sets when the preconditioner is rebuilt in the nonlinear solve `SNESSolve()`.
3582
3583 Logically Collective
3584
3585 Input Parameters:
3586 + snes - the `SNES` context
3587 - lag - 1 means rebuild every time the Jacobian is computed within a single nonlinear solve, 2 means every second time
3588 the Jacobian is built etc. -2 indicates rebuild preconditioner at next chance but then never rebuild after that
3589
3590 Options Database Keys:
3591 + -snes_lag_jacobian_persists <true,false> - sets the persistence through multiple `SNESSolve()`
3592 . -snes_lag_jacobian <-2,1,2,...> - sets the lag
3593 . -snes_lag_preconditioner_persists <true,false> - sets the persistence through multiple `SNESSolve()`
3594 - -snes_lag_preconditioner <-2,1,2,...> - sets the lag
3595
3596 Level: intermediate
3597
3598 Notes:
3599 The default is 1
3600
3601 The preconditioner is ALWAYS built in the first iteration of a nonlinear solve unless lag is -1 or `SNESSetLagPreconditionerPersists()` was called
3602
3603 `SNESSetLagPreconditionerPersists()` allows using the same uniform lagging (for example every second linear solve) across multiple nonlinear solves.
3604
3605 .seealso: [](ch_snes), `SNESGetLagPreconditioner()`, `SNESSetLagJacobian()`, `SNESGetLagJacobian()`, `SNESSetLagPreconditionerPersists()`,
3606 `SNESSetLagJacobianPersists()`, `SNES`, `SNESSolve()`
3607 @*/
SNESSetLagPreconditioner(SNES snes,PetscInt lag)3608 PetscErrorCode SNESSetLagPreconditioner(SNES snes, PetscInt lag)
3609 {
3610 PetscFunctionBegin;
3611 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3612 PetscCheck(lag >= -2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Lag must be -2, -1, 1 or greater");
3613 PetscCheck(lag, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Lag cannot be 0");
3614 PetscValidLogicalCollectiveInt(snes, lag, 2);
3615 snes->lagpreconditioner = lag;
3616 PetscFunctionReturn(PETSC_SUCCESS);
3617 }
3618
3619 /*@
3620 SNESSetGridSequence - sets the number of steps of grid sequencing that `SNES` will do
3621
3622 Logically Collective
3623
3624 Input Parameters:
3625 + snes - the `SNES` context
3626 - steps - the number of refinements to do, defaults to 0
3627
3628 Options Database Key:
3629 . -snes_grid_sequence <steps> - Use grid sequencing to generate initial guess
3630
3631 Level: intermediate
3632
3633 Notes:
3634 Once grid sequencing is turned on `SNESSolve()` will automatically perform the solve on each grid refinement.
3635
3636 Use `SNESGetSolution()` to extract the fine grid solution after grid sequencing.
3637
3638 .seealso: [](ch_snes), `SNES`, `SNESGetLagPreconditioner()`, `SNESSetLagJacobian()`, `SNESGetLagJacobian()`, `SNESGetGridSequence()`,
3639 `SNESSetDM()`, `SNESSolve()`
3640 @*/
SNESSetGridSequence(SNES snes,PetscInt steps)3641 PetscErrorCode SNESSetGridSequence(SNES snes, PetscInt steps)
3642 {
3643 PetscFunctionBegin;
3644 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3645 PetscValidLogicalCollectiveInt(snes, steps, 2);
3646 snes->gridsequence = steps;
3647 PetscFunctionReturn(PETSC_SUCCESS);
3648 }
3649
3650 /*@
3651 SNESGetGridSequence - gets the number of steps of grid sequencing that `SNES` will do
3652
3653 Logically Collective
3654
3655 Input Parameter:
3656 . snes - the `SNES` context
3657
3658 Output Parameter:
3659 . steps - the number of refinements to do, defaults to 0
3660
3661 Level: intermediate
3662
3663 .seealso: [](ch_snes), `SNESGetLagPreconditioner()`, `SNESSetLagJacobian()`, `SNESGetLagJacobian()`, `SNESSetGridSequence()`
3664 @*/
SNESGetGridSequence(SNES snes,PetscInt * steps)3665 PetscErrorCode SNESGetGridSequence(SNES snes, PetscInt *steps)
3666 {
3667 PetscFunctionBegin;
3668 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3669 *steps = snes->gridsequence;
3670 PetscFunctionReturn(PETSC_SUCCESS);
3671 }
3672
3673 /*@
3674 SNESGetLagPreconditioner - Return how often the preconditioner is rebuilt
3675
3676 Not Collective
3677
3678 Input Parameter:
3679 . snes - the `SNES` context
3680
3681 Output Parameter:
3682 . lag - -1 indicates NEVER rebuild, 1 means rebuild every time the Jacobian is computed within a single nonlinear solve, 2 means every second time
3683 the Jacobian is built etc. -2 indicates rebuild preconditioner at next chance but then never rebuild after that
3684
3685 Level: intermediate
3686
3687 Notes:
3688 The default is 1
3689
3690 The preconditioner is ALWAYS built in the first iteration of a nonlinear solve unless lag is -1
3691
3692 .seealso: [](ch_snes), `SNES`, `SNESSetLagPreconditioner()`, `SNESSetLagJacobianPersists()`, `SNESSetLagPreconditionerPersists()`
3693 @*/
SNESGetLagPreconditioner(SNES snes,PetscInt * lag)3694 PetscErrorCode SNESGetLagPreconditioner(SNES snes, PetscInt *lag)
3695 {
3696 PetscFunctionBegin;
3697 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3698 *lag = snes->lagpreconditioner;
3699 PetscFunctionReturn(PETSC_SUCCESS);
3700 }
3701
3702 /*@
3703 SNESSetLagJacobian - Set when the Jacobian is rebuilt in the nonlinear solve. See `SNESSetLagPreconditioner()` for determining how
3704 often the preconditioner is rebuilt.
3705
3706 Logically Collective
3707
3708 Input Parameters:
3709 + snes - the `SNES` context
3710 - lag - -1 indicates NEVER rebuild, 1 means rebuild every time the Jacobian is computed within a single nonlinear solve, 2 means every second time
3711 the Jacobian is built etc. -2 means rebuild at next chance but then never again
3712
3713 Options Database Keys:
3714 + -snes_lag_jacobian_persists <true,false> - sets the persistence through multiple SNES solves
3715 . -snes_lag_jacobian <-2,1,2,...> - sets the lag
3716 . -snes_lag_preconditioner_persists <true,false> - sets the persistence through multiple SNES solves
3717 - -snes_lag_preconditioner <-2,1,2,...> - sets the lag.
3718
3719 Level: intermediate
3720
3721 Notes:
3722 The default is 1
3723
3724 The Jacobian is ALWAYS built in the first iteration of a nonlinear solve unless lag is -1
3725
3726 If -1 is used before the very first nonlinear solve the CODE WILL FAIL! because no Jacobian is used, use -2 to indicate you want it recomputed
3727 at the next Newton step but never again (unless it is reset to another value)
3728
3729 .seealso: [](ch_snes), `SNES`, `SNESGetLagPreconditioner()`, `SNESSetLagPreconditioner()`, `SNESGetLagJacobianPersists()`, `SNESSetLagPreconditionerPersists()`
3730 @*/
SNESSetLagJacobian(SNES snes,PetscInt lag)3731 PetscErrorCode SNESSetLagJacobian(SNES snes, PetscInt lag)
3732 {
3733 PetscFunctionBegin;
3734 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3735 PetscCheck(lag >= -2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Lag must be -2, -1, 1 or greater");
3736 PetscCheck(lag, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Lag cannot be 0");
3737 PetscValidLogicalCollectiveInt(snes, lag, 2);
3738 snes->lagjacobian = lag;
3739 PetscFunctionReturn(PETSC_SUCCESS);
3740 }
3741
3742 /*@
3743 SNESGetLagJacobian - Get how often the Jacobian is rebuilt. See `SNESGetLagPreconditioner()` to determine when the preconditioner is rebuilt
3744
3745 Not Collective
3746
3747 Input Parameter:
3748 . snes - the `SNES` context
3749
3750 Output Parameter:
3751 . lag - -1 indicates NEVER rebuild, 1 means rebuild every time the Jacobian is computed within a single nonlinear solve, 2 means every second time
3752 the Jacobian is built etc.
3753
3754 Level: intermediate
3755
3756 Notes:
3757 The default is 1
3758
3759 The jacobian is ALWAYS built in the first iteration of a nonlinear solve unless lag is -1 or `SNESSetLagJacobianPersists()` was called.
3760
3761 .seealso: [](ch_snes), `SNES`, `SNESSetLagJacobian()`, `SNESSetLagPreconditioner()`, `SNESGetLagPreconditioner()`, `SNESSetLagJacobianPersists()`, `SNESSetLagPreconditionerPersists()`
3762
3763 @*/
SNESGetLagJacobian(SNES snes,PetscInt * lag)3764 PetscErrorCode SNESGetLagJacobian(SNES snes, PetscInt *lag)
3765 {
3766 PetscFunctionBegin;
3767 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3768 *lag = snes->lagjacobian;
3769 PetscFunctionReturn(PETSC_SUCCESS);
3770 }
3771
3772 /*@
3773 SNESSetLagJacobianPersists - Set whether or not the Jacobian lagging persists through multiple nonlinear solves
3774
3775 Logically collective
3776
3777 Input Parameters:
3778 + snes - the `SNES` context
3779 - flg - jacobian lagging persists if true
3780
3781 Options Database Keys:
3782 + -snes_lag_jacobian_persists <true,false> - sets the persistence through multiple SNES solves
3783 . -snes_lag_jacobian <-2,1,2,...> - sets the lag
3784 . -snes_lag_preconditioner_persists <true,false> - sets the persistence through multiple SNES solves
3785 - -snes_lag_preconditioner <-2,1,2,...> - sets the lag
3786
3787 Level: advanced
3788
3789 Notes:
3790 Normally when `SNESSetLagJacobian()` is used, the Jacobian is always rebuilt at the beginning of each new nonlinear solve, this removes that behavior
3791
3792 This is useful both for nonlinear preconditioning, where it's appropriate to have the Jacobian be stale by
3793 several solves, and for implicit time-stepping, where Jacobian lagging in the inner nonlinear solve over several
3794 timesteps may present huge efficiency gains.
3795
3796 .seealso: [](ch_snes), `SNES`, `SNESSetLagPreconditionerPersists()`, `SNESSetLagJacobian()`, `SNESGetLagJacobian()`, `SNESGetNPC()`
3797 @*/
SNESSetLagJacobianPersists(SNES snes,PetscBool flg)3798 PetscErrorCode SNESSetLagJacobianPersists(SNES snes, PetscBool flg)
3799 {
3800 PetscFunctionBegin;
3801 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3802 PetscValidLogicalCollectiveBool(snes, flg, 2);
3803 snes->lagjac_persist = flg;
3804 PetscFunctionReturn(PETSC_SUCCESS);
3805 }
3806
3807 /*@
3808 SNESSetLagPreconditionerPersists - Set whether or not the preconditioner lagging persists through multiple nonlinear solves
3809
3810 Logically Collective
3811
3812 Input Parameters:
3813 + snes - the `SNES` context
3814 - flg - preconditioner lagging persists if true
3815
3816 Options Database Keys:
3817 + -snes_lag_jacobian_persists <true,false> - sets the persistence through multiple SNES solves
3818 . -snes_lag_jacobian <-2,1,2,...> - sets the lag
3819 . -snes_lag_preconditioner_persists <true,false> - sets the persistence through multiple SNES solves
3820 - -snes_lag_preconditioner <-2,1,2,...> - sets the lag
3821
3822 Level: developer
3823
3824 Notes:
3825 Normally when `SNESSetLagPreconditioner()` is used, the preconditioner is always rebuilt at the beginning of each new nonlinear solve, this removes that behavior
3826
3827 This is useful both for nonlinear preconditioning, where it's appropriate to have the preconditioner be stale
3828 by several solves, and for implicit time-stepping, where preconditioner lagging in the inner nonlinear solve over
3829 several timesteps may present huge efficiency gains.
3830
3831 .seealso: [](ch_snes), `SNES`, `SNESSetLagJacobianPersists()`, `SNESSetLagJacobian()`, `SNESGetLagJacobian()`, `SNESGetNPC()`, `SNESSetLagPreconditioner()`
3832 @*/
SNESSetLagPreconditionerPersists(SNES snes,PetscBool flg)3833 PetscErrorCode SNESSetLagPreconditionerPersists(SNES snes, PetscBool flg)
3834 {
3835 PetscFunctionBegin;
3836 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3837 PetscValidLogicalCollectiveBool(snes, flg, 2);
3838 snes->lagpre_persist = flg;
3839 PetscFunctionReturn(PETSC_SUCCESS);
3840 }
3841
3842 /*@
3843 SNESSetForceIteration - force `SNESSolve()` to take at least one iteration regardless of the initial residual norm
3844
3845 Logically Collective
3846
3847 Input Parameters:
3848 + snes - the `SNES` context
3849 - force - `PETSC_TRUE` require at least one iteration
3850
3851 Options Database Key:
3852 . -snes_force_iteration <force> - Sets forcing an iteration
3853
3854 Level: intermediate
3855
3856 Note:
3857 This is used sometimes with `TS` to prevent `TS` from detecting a false steady state solution
3858
3859 .seealso: [](ch_snes), `SNES`, `TS`, `SNESSetDivergenceTolerance()`
3860 @*/
SNESSetForceIteration(SNES snes,PetscBool force)3861 PetscErrorCode SNESSetForceIteration(SNES snes, PetscBool force)
3862 {
3863 PetscFunctionBegin;
3864 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3865 snes->forceiteration = force;
3866 PetscFunctionReturn(PETSC_SUCCESS);
3867 }
3868
3869 /*@
3870 SNESGetForceIteration - Check whether or not `SNESSolve()` take at least one iteration regardless of the initial residual norm
3871
3872 Logically Collective
3873
3874 Input Parameter:
3875 . snes - the `SNES` context
3876
3877 Output Parameter:
3878 . force - `PETSC_TRUE` requires at least one iteration.
3879
3880 Level: intermediate
3881
3882 .seealso: [](ch_snes), `SNES`, `SNESSetForceIteration()`, `SNESSetDivergenceTolerance()`
3883 @*/
SNESGetForceIteration(SNES snes,PetscBool * force)3884 PetscErrorCode SNESGetForceIteration(SNES snes, PetscBool *force)
3885 {
3886 PetscFunctionBegin;
3887 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3888 *force = snes->forceiteration;
3889 PetscFunctionReturn(PETSC_SUCCESS);
3890 }
3891
3892 /*@
3893 SNESSetTolerances - Sets various parameters used in `SNES` convergence tests.
3894
3895 Logically Collective
3896
3897 Input Parameters:
3898 + snes - the `SNES` context
3899 . abstol - the absolute convergence tolerance, $ F(x^n) \le abstol $
3900 . rtol - the relative convergence tolerance, $ F(x^n) \le reltol * F(x^0) $
3901 . stol - convergence tolerance in terms of the norm of the change in the solution between steps, || delta x || < stol*|| x ||
3902 . maxit - the maximum number of iterations allowed in the solver, default 50.
3903 - maxf - the maximum number of function evaluations allowed in the solver (use `PETSC_UNLIMITED` indicates no limit), default 10,000
3904
3905 Options Database Keys:
3906 + -snes_atol <abstol> - Sets `abstol`
3907 . -snes_rtol <rtol> - Sets `rtol`
3908 . -snes_stol <stol> - Sets `stol`
3909 . -snes_max_it <maxit> - Sets `maxit`
3910 - -snes_max_funcs <maxf> - Sets `maxf` (use `unlimited` to have no maximum)
3911
3912 Level: intermediate
3913
3914 Note:
3915 All parameters must be non-negative
3916
3917 Use `PETSC_CURRENT` to retain the current value of any parameter and `PETSC_DETERMINE` to use the default value for the given `SNES`.
3918 The default value is the value in the object when its type is set.
3919
3920 Use `PETSC_UNLIMITED` on `maxit` or `maxf` to indicate there is no bound on the number of iterations or number of function evaluations.
3921
3922 Fortran Note:
3923 Use `PETSC_CURRENT_INTEGER`, `PETSC_CURRENT_REAL`, `PETSC_UNLIMITED_INTEGER`, `PETSC_DETERMINE_INTEGER`, or `PETSC_DETERMINE_REAL`
3924
3925 .seealso: [](ch_snes), `SNESSolve()`, `SNES`, `SNESSetDivergenceTolerance()`, `SNESSetForceIteration()`
3926 @*/
SNESSetTolerances(SNES snes,PetscReal abstol,PetscReal rtol,PetscReal stol,PetscInt maxit,PetscInt maxf)3927 PetscErrorCode SNESSetTolerances(SNES snes, PetscReal abstol, PetscReal rtol, PetscReal stol, PetscInt maxit, PetscInt maxf)
3928 {
3929 PetscFunctionBegin;
3930 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
3931 PetscValidLogicalCollectiveReal(snes, abstol, 2);
3932 PetscValidLogicalCollectiveReal(snes, rtol, 3);
3933 PetscValidLogicalCollectiveReal(snes, stol, 4);
3934 PetscValidLogicalCollectiveInt(snes, maxit, 5);
3935 PetscValidLogicalCollectiveInt(snes, maxf, 6);
3936
3937 if (abstol == (PetscReal)PETSC_DETERMINE) {
3938 snes->abstol = snes->default_abstol;
3939 } else if (abstol != (PetscReal)PETSC_CURRENT) {
3940 PetscCheck(abstol >= 0.0, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "Absolute tolerance %g must be non-negative", (double)abstol);
3941 snes->abstol = abstol;
3942 }
3943
3944 if (rtol == (PetscReal)PETSC_DETERMINE) {
3945 snes->rtol = snes->default_rtol;
3946 } else if (rtol != (PetscReal)PETSC_CURRENT) {
3947 PetscCheck(rtol >= 0.0 && 1.0 > rtol, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "Relative tolerance %g must be non-negative and less than 1.0", (double)rtol);
3948 snes->rtol = rtol;
3949 }
3950
3951 if (stol == (PetscReal)PETSC_DETERMINE) {
3952 snes->stol = snes->default_stol;
3953 } else if (stol != (PetscReal)PETSC_CURRENT) {
3954 PetscCheck(stol >= 0.0, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "Step tolerance %g must be non-negative", (double)stol);
3955 snes->stol = stol;
3956 }
3957
3958 if (maxit == PETSC_DETERMINE) {
3959 snes->max_its = snes->default_max_its;
3960 } else if (maxit == PETSC_UNLIMITED) {
3961 snes->max_its = PETSC_INT_MAX;
3962 } else if (maxit != PETSC_CURRENT) {
3963 PetscCheck(maxit >= 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of iterations %" PetscInt_FMT " must be non-negative", maxit);
3964 snes->max_its = maxit;
3965 }
3966
3967 if (maxf == PETSC_DETERMINE) {
3968 snes->max_funcs = snes->default_max_funcs;
3969 } else if (maxf == PETSC_UNLIMITED || maxf == -1) {
3970 snes->max_funcs = PETSC_UNLIMITED;
3971 } else if (maxf != PETSC_CURRENT) {
3972 PetscCheck(maxf >= 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "Maximum number of function evaluations %" PetscInt_FMT " must be nonnegative", maxf);
3973 snes->max_funcs = maxf;
3974 }
3975 PetscFunctionReturn(PETSC_SUCCESS);
3976 }
3977
3978 /*@
3979 SNESSetDivergenceTolerance - Sets the divergence tolerance used for the `SNES` divergence test.
3980
3981 Logically Collective
3982
3983 Input Parameters:
3984 + snes - the `SNES` context
3985 - divtol - the divergence tolerance. Use `PETSC_UNLIMITED` to deactivate the test. If the residual norm $ F(x^n) \ge divtol * F(x^0) $ the solver
3986 is stopped due to divergence.
3987
3988 Options Database Key:
3989 . -snes_divergence_tolerance <divtol> - Sets `divtol`
3990
3991 Level: intermediate
3992
3993 Notes:
3994 Use `PETSC_DETERMINE` to use the default value from when the object's type was set.
3995
3996 Fortran Note:
3997 Use ``PETSC_DETERMINE_REAL` or `PETSC_UNLIMITED_REAL`
3998
3999 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESSetTolerances()`, `SNESGetDivergenceTolerance()`
4000 @*/
SNESSetDivergenceTolerance(SNES snes,PetscReal divtol)4001 PetscErrorCode SNESSetDivergenceTolerance(SNES snes, PetscReal divtol)
4002 {
4003 PetscFunctionBegin;
4004 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4005 PetscValidLogicalCollectiveReal(snes, divtol, 2);
4006
4007 if (divtol == (PetscReal)PETSC_DETERMINE) {
4008 snes->divtol = snes->default_divtol;
4009 } else if (divtol == (PetscReal)PETSC_UNLIMITED || divtol == -1) {
4010 snes->divtol = PETSC_UNLIMITED;
4011 } else if (divtol != (PetscReal)PETSC_CURRENT) {
4012 PetscCheck(divtol >= 1.0, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "Divergence tolerance %g must be greater than 1.0", (double)divtol);
4013 snes->divtol = divtol;
4014 }
4015 PetscFunctionReturn(PETSC_SUCCESS);
4016 }
4017
4018 /*@
4019 SNESGetTolerances - Gets various parameters used in `SNES` convergence tests.
4020
4021 Not Collective
4022
4023 Input Parameter:
4024 . snes - the `SNES` context
4025
4026 Output Parameters:
4027 + atol - the absolute convergence tolerance
4028 . rtol - the relative convergence tolerance
4029 . stol - convergence tolerance in terms of the norm of the change in the solution between steps
4030 . maxit - the maximum number of iterations allowed
4031 - maxf - the maximum number of function evaluations allowed, `PETSC_UNLIMITED` indicates no bound
4032
4033 Level: intermediate
4034
4035 Notes:
4036 See `SNESSetTolerances()` for details on the parameters.
4037
4038 The user can specify `NULL` for any parameter that is not needed.
4039
4040 .seealso: [](ch_snes), `SNES`, `SNESSetTolerances()`
4041 @*/
SNESGetTolerances(SNES snes,PetscReal * atol,PetscReal * rtol,PetscReal * stol,PetscInt * maxit,PetscInt * maxf)4042 PetscErrorCode SNESGetTolerances(SNES snes, PetscReal *atol, PetscReal *rtol, PetscReal *stol, PetscInt *maxit, PetscInt *maxf)
4043 {
4044 PetscFunctionBegin;
4045 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4046 if (atol) *atol = snes->abstol;
4047 if (rtol) *rtol = snes->rtol;
4048 if (stol) *stol = snes->stol;
4049 if (maxit) *maxit = snes->max_its;
4050 if (maxf) *maxf = snes->max_funcs;
4051 PetscFunctionReturn(PETSC_SUCCESS);
4052 }
4053
4054 /*@
4055 SNESGetDivergenceTolerance - Gets divergence tolerance used in divergence test.
4056
4057 Not Collective
4058
4059 Input Parameters:
4060 + snes - the `SNES` context
4061 - divtol - divergence tolerance
4062
4063 Level: intermediate
4064
4065 .seealso: [](ch_snes), `SNES`, `SNESSetDivergenceTolerance()`
4066 @*/
SNESGetDivergenceTolerance(SNES snes,PetscReal * divtol)4067 PetscErrorCode SNESGetDivergenceTolerance(SNES snes, PetscReal *divtol)
4068 {
4069 PetscFunctionBegin;
4070 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4071 if (divtol) *divtol = snes->divtol;
4072 PetscFunctionReturn(PETSC_SUCCESS);
4073 }
4074
4075 PETSC_INTERN PetscErrorCode SNESMonitorRange_Private(SNES, PetscInt, PetscReal *);
4076
SNESMonitorLGRange(SNES snes,PetscInt n,PetscReal rnorm,void * monctx)4077 PetscErrorCode SNESMonitorLGRange(SNES snes, PetscInt n, PetscReal rnorm, void *monctx)
4078 {
4079 PetscDrawLG lg;
4080 PetscReal x, y, per;
4081 PetscViewer v = (PetscViewer)monctx;
4082 static PetscReal prev; /* should be in the context */
4083 PetscDraw draw;
4084
4085 PetscFunctionBegin;
4086 PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 4);
4087 PetscCall(PetscViewerDrawGetDrawLG(v, 0, &lg));
4088 if (!n) PetscCall(PetscDrawLGReset(lg));
4089 PetscCall(PetscDrawLGGetDraw(lg, &draw));
4090 PetscCall(PetscDrawSetTitle(draw, "Residual norm"));
4091 x = (PetscReal)n;
4092 if (rnorm > 0.0) y = PetscLog10Real(rnorm);
4093 else y = -15.0;
4094 PetscCall(PetscDrawLGAddPoint(lg, &x, &y));
4095 if (n < 20 || !(n % 5) || snes->reason) {
4096 PetscCall(PetscDrawLGDraw(lg));
4097 PetscCall(PetscDrawLGSave(lg));
4098 }
4099
4100 PetscCall(PetscViewerDrawGetDrawLG(v, 1, &lg));
4101 if (!n) PetscCall(PetscDrawLGReset(lg));
4102 PetscCall(PetscDrawLGGetDraw(lg, &draw));
4103 PetscCall(PetscDrawSetTitle(draw, "% elements > .2*max element"));
4104 PetscCall(SNESMonitorRange_Private(snes, n, &per));
4105 x = (PetscReal)n;
4106 y = 100.0 * per;
4107 PetscCall(PetscDrawLGAddPoint(lg, &x, &y));
4108 if (n < 20 || !(n % 5) || snes->reason) {
4109 PetscCall(PetscDrawLGDraw(lg));
4110 PetscCall(PetscDrawLGSave(lg));
4111 }
4112
4113 PetscCall(PetscViewerDrawGetDrawLG(v, 2, &lg));
4114 if (!n) {
4115 prev = rnorm;
4116 PetscCall(PetscDrawLGReset(lg));
4117 }
4118 PetscCall(PetscDrawLGGetDraw(lg, &draw));
4119 PetscCall(PetscDrawSetTitle(draw, "(norm -oldnorm)/oldnorm"));
4120 x = (PetscReal)n;
4121 y = (prev - rnorm) / prev;
4122 PetscCall(PetscDrawLGAddPoint(lg, &x, &y));
4123 if (n < 20 || !(n % 5) || snes->reason) {
4124 PetscCall(PetscDrawLGDraw(lg));
4125 PetscCall(PetscDrawLGSave(lg));
4126 }
4127
4128 PetscCall(PetscViewerDrawGetDrawLG(v, 3, &lg));
4129 if (!n) PetscCall(PetscDrawLGReset(lg));
4130 PetscCall(PetscDrawLGGetDraw(lg, &draw));
4131 PetscCall(PetscDrawSetTitle(draw, "(norm -oldnorm)/oldnorm*(% > .2 max)"));
4132 x = (PetscReal)n;
4133 y = (prev - rnorm) / (prev * per);
4134 if (n > 2) { /*skip initial crazy value */
4135 PetscCall(PetscDrawLGAddPoint(lg, &x, &y));
4136 }
4137 if (n < 20 || !(n % 5) || snes->reason) {
4138 PetscCall(PetscDrawLGDraw(lg));
4139 PetscCall(PetscDrawLGSave(lg));
4140 }
4141 prev = rnorm;
4142 PetscFunctionReturn(PETSC_SUCCESS);
4143 }
4144
4145 /*@
4146 SNESConverged - Run the convergence test and update the `SNESConvergedReason`.
4147
4148 Collective
4149
4150 Input Parameters:
4151 + snes - the `SNES` context
4152 . it - current iteration
4153 . xnorm - 2-norm of current iterate
4154 . snorm - 2-norm of current step
4155 - fnorm - 2-norm of function
4156
4157 Level: developer
4158
4159 Note:
4160 This routine is called by the `SNESSolve()` implementations.
4161 It does not typically need to be called by the user.
4162
4163 .seealso: [](ch_snes), `SNES`, `SNESSolve`, `SNESSetConvergenceTest()`
4164 @*/
SNESConverged(SNES snes,PetscInt it,PetscReal xnorm,PetscReal snorm,PetscReal fnorm)4165 PetscErrorCode SNESConverged(SNES snes, PetscInt it, PetscReal xnorm, PetscReal snorm, PetscReal fnorm)
4166 {
4167 PetscFunctionBegin;
4168 if (!snes->reason) {
4169 if (snes->normschedule == SNES_NORM_ALWAYS) PetscUseTypeMethod(snes, converged, it, xnorm, snorm, fnorm, &snes->reason, snes->cnvP);
4170 if (it == snes->max_its && !snes->reason) {
4171 if (snes->normschedule == SNES_NORM_ALWAYS) {
4172 PetscCall(PetscInfo(snes, "Maximum number of iterations has been reached: %" PetscInt_FMT "\n", snes->max_its));
4173 snes->reason = SNES_DIVERGED_MAX_IT;
4174 } else snes->reason = SNES_CONVERGED_ITS;
4175 }
4176 }
4177 PetscFunctionReturn(PETSC_SUCCESS);
4178 }
4179
4180 /*@
4181 SNESMonitor - runs any `SNES` monitor routines provided with `SNESMonitor()` or the options database
4182
4183 Collective
4184
4185 Input Parameters:
4186 + snes - nonlinear solver context obtained from `SNESCreate()`
4187 . iter - current iteration number
4188 - rnorm - current relative norm of the residual
4189
4190 Level: developer
4191
4192 Note:
4193 This routine is called by the `SNESSolve()` implementations.
4194 It does not typically need to be called by the user.
4195
4196 .seealso: [](ch_snes), `SNES`, `SNESMonitorSet()`
4197 @*/
SNESMonitor(SNES snes,PetscInt iter,PetscReal rnorm)4198 PetscErrorCode SNESMonitor(SNES snes, PetscInt iter, PetscReal rnorm)
4199 {
4200 PetscInt i, n = snes->numbermonitors;
4201
4202 PetscFunctionBegin;
4203 PetscCall(VecLockReadPush(snes->vec_sol));
4204 for (i = 0; i < n; i++) PetscCall((*snes->monitor[i])(snes, iter, rnorm, snes->monitorcontext[i]));
4205 PetscCall(VecLockReadPop(snes->vec_sol));
4206 PetscFunctionReturn(PETSC_SUCCESS);
4207 }
4208
4209 /* ------------ Routines to set performance monitoring options ----------- */
4210
4211 /*MC
4212 SNESMonitorFunction - functional form passed to `SNESMonitorSet()` to monitor convergence of nonlinear solver
4213
4214 Synopsis:
4215 #include <petscsnes.h>
4216 PetscErrorCode SNESMonitorFunction(SNES snes, PetscInt its, PetscReal norm, void *mctx)
4217
4218 Collective
4219
4220 Input Parameters:
4221 + snes - the `SNES` context
4222 . its - iteration number
4223 . norm - 2-norm function value (may be estimated)
4224 - mctx - [optional] monitoring context
4225
4226 Level: advanced
4227
4228 .seealso: [](ch_snes), `SNESMonitorSet()`
4229 M*/
4230
4231 /*@C
4232 SNESMonitorSet - Sets an ADDITIONAL function that is to be used at every
4233 iteration of the `SNES` nonlinear solver to display the iteration's
4234 progress.
4235
4236 Logically Collective
4237
4238 Input Parameters:
4239 + snes - the `SNES` context
4240 . f - the monitor function, for the calling sequence see `SNESMonitorFunction`
4241 . mctx - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
4242 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence
4243
4244 Options Database Keys:
4245 + -snes_monitor - sets `SNESMonitorDefault()`
4246 . -snes_monitor draw::draw_lg - sets line graph monitor,
4247 - -snes_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `SNESMonitorSet()`, but does not cancel those set via
4248 the options database.
4249
4250 Level: intermediate
4251
4252 Note:
4253 Several different monitoring routines may be set by calling
4254 `SNESMonitorSet()` multiple times; all will be called in the
4255 order in which they were set.
4256
4257 Fortran Note:
4258 Only a single monitor function can be set for each `SNES` object
4259
4260 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESMonitorDefault()`, `SNESMonitorCancel()`, `SNESMonitorFunction`, `PetscCtxDestroyFn`
4261 @*/
SNESMonitorSet(SNES snes,PetscErrorCode (* f)(SNES,PetscInt,PetscReal,PetscCtx),PetscCtx mctx,PetscCtxDestroyFn * monitordestroy)4262 PetscErrorCode SNESMonitorSet(SNES snes, PetscErrorCode (*f)(SNES, PetscInt, PetscReal, PetscCtx), PetscCtx mctx, PetscCtxDestroyFn *monitordestroy)
4263 {
4264 PetscFunctionBegin;
4265 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4266 for (PetscInt i = 0; i < snes->numbermonitors; i++) {
4267 PetscBool identical;
4268
4269 PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))(PetscVoidFn *)f, mctx, monitordestroy, (PetscErrorCode (*)(void))(PetscVoidFn *)snes->monitor[i], snes->monitorcontext[i], snes->monitordestroy[i], &identical));
4270 if (identical) PetscFunctionReturn(PETSC_SUCCESS);
4271 }
4272 PetscCheck(snes->numbermonitors < MAXSNESMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
4273 snes->monitor[snes->numbermonitors] = f;
4274 snes->monitordestroy[snes->numbermonitors] = monitordestroy;
4275 snes->monitorcontext[snes->numbermonitors++] = mctx;
4276 PetscFunctionReturn(PETSC_SUCCESS);
4277 }
4278
4279 /*@
4280 SNESMonitorCancel - Clears all the monitor functions for a `SNES` object.
4281
4282 Logically Collective
4283
4284 Input Parameter:
4285 . snes - the `SNES` context
4286
4287 Options Database Key:
4288 . -snes_monitor_cancel - cancels all monitors that have been hardwired
4289 into a code by calls to `SNESMonitorSet()`, but does not cancel those
4290 set via the options database
4291
4292 Level: intermediate
4293
4294 Note:
4295 There is no way to clear one specific monitor from a `SNES` object.
4296
4297 .seealso: [](ch_snes), `SNES`, `SNESMonitorDefault()`, `SNESMonitorSet()`
4298 @*/
SNESMonitorCancel(SNES snes)4299 PetscErrorCode SNESMonitorCancel(SNES snes)
4300 {
4301 PetscInt i;
4302
4303 PetscFunctionBegin;
4304 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4305 for (i = 0; i < snes->numbermonitors; i++) {
4306 if (snes->monitordestroy[i]) PetscCall((*snes->monitordestroy[i])(&snes->monitorcontext[i]));
4307 }
4308 snes->numbermonitors = 0;
4309 PetscFunctionReturn(PETSC_SUCCESS);
4310 }
4311
4312 /*MC
4313 SNESConvergenceTestFunction - functional form used for testing of convergence of nonlinear solver
4314
4315 Synopsis:
4316 #include <petscsnes.h>
4317 PetscErrorCode SNESConvergenceTest(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, void *cctx)
4318
4319 Collective
4320
4321 Input Parameters:
4322 + snes - the `SNES` context
4323 . it - current iteration (0 is the first and is before any Newton step)
4324 . xnorm - 2-norm of current iterate
4325 . gnorm - 2-norm of current step
4326 . f - 2-norm of function
4327 - cctx - [optional] convergence context
4328
4329 Output Parameter:
4330 . reason - reason for convergence/divergence, only needs to be set when convergence or divergence is detected
4331
4332 Level: intermediate
4333
4334 .seealso: [](ch_snes), `SNES`, `SNESSolve`, `SNESSetConvergenceTest()`
4335 M*/
4336
4337 /*@C
4338 SNESSetConvergenceTest - Sets the function that is to be used
4339 to test for convergence of the nonlinear iterative solution.
4340
4341 Logically Collective
4342
4343 Input Parameters:
4344 + snes - the `SNES` context
4345 . SNESConvergenceTestFunction - routine to test for convergence
4346 . ctx - [optional] context for private data for the convergence routine (may be `NULL`)
4347 - destroy - [optional] destructor for the context (may be `NULL`; `PETSC_NULL_FUNCTION` in Fortran)
4348
4349 Level: advanced
4350
4351 .seealso: [](ch_snes), `SNES`, `SNESConvergedDefault()`, `SNESConvergedSkip()`, `SNESConvergenceTestFunction`
4352 @*/
SNESSetConvergenceTest(SNES snes,PetscErrorCode (* SNESConvergenceTestFunction)(SNES,PetscInt,PetscReal,PetscReal,PetscReal,SNESConvergedReason *,void *),PetscCtx ctx,PetscCtxDestroyFn * destroy)4353 PetscErrorCode SNESSetConvergenceTest(SNES snes, PetscErrorCode (*SNESConvergenceTestFunction)(SNES, PetscInt, PetscReal, PetscReal, PetscReal, SNESConvergedReason *, void *), PetscCtx ctx, PetscCtxDestroyFn *destroy)
4354 {
4355 PetscFunctionBegin;
4356 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4357 if (!SNESConvergenceTestFunction) SNESConvergenceTestFunction = SNESConvergedSkip;
4358 if (snes->ops->convergeddestroy) PetscCall((*snes->ops->convergeddestroy)(&snes->cnvP));
4359 snes->ops->converged = SNESConvergenceTestFunction;
4360 snes->ops->convergeddestroy = destroy;
4361 snes->cnvP = ctx;
4362 PetscFunctionReturn(PETSC_SUCCESS);
4363 }
4364
4365 /*@
4366 SNESGetConvergedReason - Gets the reason the `SNES` iteration was stopped, which may be due to convergence, divergence, or stagnation
4367
4368 Not Collective
4369
4370 Input Parameter:
4371 . snes - the `SNES` context
4372
4373 Output Parameter:
4374 . reason - negative value indicates diverged, positive value converged, see `SNESConvergedReason` for the individual convergence tests for complete lists
4375
4376 Options Database Key:
4377 . -snes_converged_reason - prints the reason to standard out
4378
4379 Level: intermediate
4380
4381 Note:
4382 Should only be called after the call the `SNESSolve()` is complete, if it is called earlier it returns the value `SNES__CONVERGED_ITERATING`.
4383
4384 .seealso: [](ch_snes), `SNESSolve()`, `SNESSetConvergenceTest()`, `SNESSetConvergedReason()`, `SNESConvergedReason`, `SNESGetConvergedReasonString()`
4385 @*/
SNESGetConvergedReason(SNES snes,SNESConvergedReason * reason)4386 PetscErrorCode SNESGetConvergedReason(SNES snes, SNESConvergedReason *reason)
4387 {
4388 PetscFunctionBegin;
4389 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4390 PetscAssertPointer(reason, 2);
4391 *reason = snes->reason;
4392 PetscFunctionReturn(PETSC_SUCCESS);
4393 }
4394
4395 /*@C
4396 SNESGetConvergedReasonString - Return a human readable string for `SNESConvergedReason`
4397
4398 Not Collective
4399
4400 Input Parameter:
4401 . snes - the `SNES` context
4402
4403 Output Parameter:
4404 . strreason - a human readable string that describes `SNES` converged reason
4405
4406 Level: beginner
4407
4408 .seealso: [](ch_snes), `SNES`, `SNESGetConvergedReason()`
4409 @*/
SNESGetConvergedReasonString(SNES snes,const char ** strreason)4410 PetscErrorCode SNESGetConvergedReasonString(SNES snes, const char **strreason)
4411 {
4412 PetscFunctionBegin;
4413 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4414 PetscAssertPointer(strreason, 2);
4415 *strreason = SNESConvergedReasons[snes->reason];
4416 PetscFunctionReturn(PETSC_SUCCESS);
4417 }
4418
4419 /*@
4420 SNESSetConvergedReason - Sets the reason the `SNES` iteration was stopped.
4421
4422 Not Collective
4423
4424 Input Parameters:
4425 + snes - the `SNES` context
4426 - reason - negative value indicates diverged, positive value converged, see `SNESConvergedReason` or the
4427 manual pages for the individual convergence tests for complete lists
4428
4429 Level: developer
4430
4431 Developer Note:
4432 Called inside the various `SNESSolve()` implementations
4433
4434 .seealso: [](ch_snes), `SNESGetConvergedReason()`, `SNESSetConvergenceTest()`, `SNESConvergedReason`
4435 @*/
SNESSetConvergedReason(SNES snes,SNESConvergedReason reason)4436 PetscErrorCode SNESSetConvergedReason(SNES snes, SNESConvergedReason reason)
4437 {
4438 PetscFunctionBegin;
4439 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4440 PetscCheck(!snes->errorifnotconverged || reason > 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_PLIB, "SNES code should have previously errored due to negative reason");
4441 snes->reason = reason;
4442 PetscFunctionReturn(PETSC_SUCCESS);
4443 }
4444
4445 /*@
4446 SNESSetConvergenceHistory - Sets the arrays used to hold the convergence history.
4447
4448 Logically Collective
4449
4450 Input Parameters:
4451 + snes - iterative context obtained from `SNESCreate()`
4452 . a - array to hold history, this array will contain the function norms computed at each step
4453 . its - integer array holds the number of linear iterations for each solve.
4454 . na - size of `a` and `its`
4455 - reset - `PETSC_TRUE` indicates each new nonlinear solve resets the history counter to zero,
4456 else it continues storing new values for new nonlinear solves after the old ones
4457
4458 Level: intermediate
4459
4460 Notes:
4461 If 'a' and 'its' are `NULL` then space is allocated for the history. If 'na' is `PETSC_DECIDE` (or, deprecated, `PETSC_DEFAULT`) then a
4462 default array of length 1,000 is allocated.
4463
4464 This routine is useful, e.g., when running a code for purposes
4465 of accurate performance monitoring, when no I/O should be done
4466 during the section of code that is being timed.
4467
4468 If the arrays run out of space after a number of iterations then the later values are not saved in the history
4469
4470 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESGetConvergenceHistory()`
4471 @*/
SNESSetConvergenceHistory(SNES snes,PetscReal a[],PetscInt its[],PetscInt na,PetscBool reset)4472 PetscErrorCode SNESSetConvergenceHistory(SNES snes, PetscReal a[], PetscInt its[], PetscInt na, PetscBool reset)
4473 {
4474 PetscFunctionBegin;
4475 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4476 if (a) PetscAssertPointer(a, 2);
4477 if (its) PetscAssertPointer(its, 3);
4478 if (!a) {
4479 if (na == PETSC_DECIDE) na = 1000;
4480 PetscCall(PetscCalloc2(na, &a, na, &its));
4481 snes->conv_hist_alloc = PETSC_TRUE;
4482 }
4483 snes->conv_hist = a;
4484 snes->conv_hist_its = its;
4485 snes->conv_hist_max = (size_t)na;
4486 snes->conv_hist_len = 0;
4487 snes->conv_hist_reset = reset;
4488 PetscFunctionReturn(PETSC_SUCCESS);
4489 }
4490
4491 #if defined(PETSC_HAVE_MATLAB)
4492 #include <engine.h> /* MATLAB include file */
4493 #include <mex.h> /* MATLAB include file */
4494
SNESGetConvergenceHistoryMatlab(SNES snes)4495 PETSC_EXTERN mxArray *SNESGetConvergenceHistoryMatlab(SNES snes)
4496 {
4497 mxArray *mat;
4498 PetscInt i;
4499 PetscReal *ar;
4500
4501 mat = mxCreateDoubleMatrix(snes->conv_hist_len, 1, mxREAL);
4502 ar = (PetscReal *)mxGetData(mat);
4503 for (i = 0; i < snes->conv_hist_len; i++) ar[i] = snes->conv_hist[i];
4504 return mat;
4505 }
4506 #endif
4507
4508 /*@C
4509 SNESGetConvergenceHistory - Gets the arrays used to hold the convergence history.
4510
4511 Not Collective
4512
4513 Input Parameter:
4514 . snes - iterative context obtained from `SNESCreate()`
4515
4516 Output Parameters:
4517 + a - array to hold history, usually was set with `SNESSetConvergenceHistory()`
4518 . its - integer array holds the number of linear iterations (or
4519 negative if not converged) for each solve.
4520 - na - size of `a` and `its`
4521
4522 Level: intermediate
4523
4524 Note:
4525 This routine is useful, e.g., when running a code for purposes
4526 of accurate performance monitoring, when no I/O should be done
4527 during the section of code that is being timed.
4528
4529 Fortran Notes:
4530 Return the arrays with ``SNESRestoreConvergenceHistory()`
4531
4532 Use the arguments
4533 .vb
4534 PetscReal, pointer :: a(:)
4535 PetscInt, pointer :: its(:)
4536 .ve
4537
4538 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESSetConvergenceHistory()`
4539 @*/
SNESGetConvergenceHistory(SNES snes,PetscReal * a[],PetscInt * its[],PetscInt * na)4540 PetscErrorCode SNESGetConvergenceHistory(SNES snes, PetscReal *a[], PetscInt *its[], PetscInt *na)
4541 {
4542 PetscFunctionBegin;
4543 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4544 if (a) *a = snes->conv_hist;
4545 if (its) *its = snes->conv_hist_its;
4546 if (na) *na = (PetscInt)snes->conv_hist_len;
4547 PetscFunctionReturn(PETSC_SUCCESS);
4548 }
4549
4550 /*@C
4551 SNESSetUpdate - Sets the general-purpose update function called
4552 at the beginning of every iteration of the nonlinear solve. Specifically
4553 it is called just before the Jacobian is "evaluated" and after the function
4554 evaluation.
4555
4556 Logically Collective
4557
4558 Input Parameters:
4559 + snes - The nonlinear solver context
4560 - func - The update function; for calling sequence see `SNESUpdateFn`
4561
4562 Level: advanced
4563
4564 Notes:
4565 This is NOT what one uses to update the ghost points before a function evaluation, that should be done at the beginning of your function provided
4566 to `SNESSetFunction()`, or `SNESSetPicard()`
4567 This is not used by most users, and it is intended to provide a general hook that is run
4568 right before the direction step is computed.
4569
4570 Users are free to modify the current residual vector,
4571 the current linearization point, or any other vector associated to the specific solver used.
4572 If such modifications take place, it is the user responsibility to update all the relevant
4573 vectors. For example, if one is adjusting the model parameters at each Newton step their code may look like
4574 .vb
4575 PetscErrorCode update(SNES snes, PetscInt iteration)
4576 {
4577 PetscFunctionBeginUser;
4578 if (iteration > 0) {
4579 // update the model parameters here
4580 Vec x,f;
4581 PetscCall(SNESGetSolution(snes,&x));
4582 PetcCall(SNESGetFunction(snes,&f,NULL,NULL));
4583 PetscCall(SNESComputeFunction(snes,x,f));
4584 }
4585 PetscFunctionReturn(PETSC_SUCCESS);
4586 }
4587 .ve
4588
4589 There are a variety of function hooks one many set that are called at different stages of the nonlinear solution process, see the functions listed below.
4590
4591 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESSetJacobian()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchSetPostCheck()`, `SNESNewtonTRSetPreCheck()`, `SNESNewtonTRSetPostCheck()`,
4592 `SNESMonitorSet()`
4593 @*/
SNESSetUpdate(SNES snes,SNESUpdateFn * func)4594 PetscErrorCode SNESSetUpdate(SNES snes, SNESUpdateFn *func)
4595 {
4596 PetscFunctionBegin;
4597 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4598 snes->ops->update = func;
4599 PetscFunctionReturn(PETSC_SUCCESS);
4600 }
4601
4602 /*@
4603 SNESConvergedReasonView - Displays the reason a `SNES` solve converged or diverged to a viewer
4604
4605 Collective
4606
4607 Input Parameters:
4608 + snes - iterative context obtained from `SNESCreate()`
4609 - viewer - the viewer to display the reason
4610
4611 Options Database Keys:
4612 + -snes_converged_reason - print reason for converged or diverged, also prints number of iterations
4613 - -snes_converged_reason ::failed - only print reason and number of iterations when diverged
4614
4615 Level: beginner
4616
4617 Note:
4618 To change the format of the output call `PetscViewerPushFormat`(viewer,format) before this call. Use `PETSC_VIEWER_DEFAULT` for the default,
4619 use `PETSC_VIEWER_FAILED` to only display a reason if it fails.
4620
4621 .seealso: [](ch_snes), `SNESConvergedReason`, `PetscViewer`, `SNES`,
4622 `SNESCreate()`, `SNESSetUp()`, `SNESDestroy()`, `SNESSetTolerances()`, `SNESConvergedDefault()`, `SNESGetConvergedReason()`,
4623 `SNESConvergedReasonViewFromOptions()`,
4624 `PetscViewerPushFormat()`, `PetscViewerPopFormat()`
4625 @*/
SNESConvergedReasonView(SNES snes,PetscViewer viewer)4626 PetscErrorCode SNESConvergedReasonView(SNES snes, PetscViewer viewer)
4627 {
4628 PetscViewerFormat format;
4629 PetscBool isAscii;
4630
4631 PetscFunctionBegin;
4632 if (!viewer) viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));
4633 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isAscii));
4634 if (isAscii) {
4635 PetscCall(PetscViewerGetFormat(viewer, &format));
4636 PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel + 1));
4637 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
4638 DM dm;
4639 Vec u;
4640 PetscDS prob;
4641 PetscInt Nf, f;
4642 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
4643 void **exactCtx;
4644 PetscReal error;
4645
4646 PetscCall(SNESGetDM(snes, &dm));
4647 PetscCall(SNESGetSolution(snes, &u));
4648 PetscCall(DMGetDS(dm, &prob));
4649 PetscCall(PetscDSGetNumFields(prob, &Nf));
4650 PetscCall(PetscMalloc2(Nf, &exactSol, Nf, &exactCtx));
4651 for (f = 0; f < Nf; ++f) PetscCall(PetscDSGetExactSolution(prob, f, &exactSol[f], &exactCtx[f]));
4652 PetscCall(DMComputeL2Diff(dm, 0.0, exactSol, exactCtx, u, &error));
4653 PetscCall(PetscFree2(exactSol, exactCtx));
4654 if (error < 1.0e-11) PetscCall(PetscViewerASCIIPrintf(viewer, "L_2 Error: < 1.0e-11\n"));
4655 else PetscCall(PetscViewerASCIIPrintf(viewer, "L_2 Error: %g\n", (double)error));
4656 }
4657 if (snes->reason > 0 && format != PETSC_VIEWER_FAILED) {
4658 if (((PetscObject)snes)->prefix) {
4659 PetscCall(PetscViewerASCIIPrintf(viewer, "Nonlinear %s solve converged due to %s iterations %" PetscInt_FMT "\n", ((PetscObject)snes)->prefix, SNESConvergedReasons[snes->reason], snes->iter));
4660 } else {
4661 PetscCall(PetscViewerASCIIPrintf(viewer, "Nonlinear solve converged due to %s iterations %" PetscInt_FMT "\n", SNESConvergedReasons[snes->reason], snes->iter));
4662 }
4663 } else if (snes->reason <= 0) {
4664 if (((PetscObject)snes)->prefix) {
4665 PetscCall(PetscViewerASCIIPrintf(viewer, "Nonlinear %s solve did not converge due to %s iterations %" PetscInt_FMT "\n", ((PetscObject)snes)->prefix, SNESConvergedReasons[snes->reason], snes->iter));
4666 } else {
4667 PetscCall(PetscViewerASCIIPrintf(viewer, "Nonlinear solve did not converge due to %s iterations %" PetscInt_FMT "\n", SNESConvergedReasons[snes->reason], snes->iter));
4668 }
4669 }
4670 PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel + 1));
4671 }
4672 PetscFunctionReturn(PETSC_SUCCESS);
4673 }
4674
4675 /*@C
4676 SNESConvergedReasonViewSet - Sets an ADDITIONAL function that is to be used at the
4677 end of the nonlinear solver to display the convergence reason of the nonlinear solver.
4678
4679 Logically Collective
4680
4681 Input Parameters:
4682 + snes - the `SNES` context
4683 . f - the `SNESConvergedReason` view function
4684 . vctx - [optional] user-defined context for private data for the `SNESConvergedReason` view function (use `NULL` if no context is desired)
4685 - reasonviewdestroy - [optional] routine that frees the context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence
4686
4687 Calling sequence of `f`:
4688 + snes - the `SNES` context
4689 - vctx - [optional] context for private data for the function
4690
4691 Options Database Keys:
4692 + -snes_converged_reason - sets a default `SNESConvergedReasonView()`
4693 - -snes_converged_reason_view_cancel - cancels all converged reason viewers that have been hardwired into a code by
4694 calls to `SNESConvergedReasonViewSet()`, but does not cancel those set via the options database.
4695
4696 Level: intermediate
4697
4698 Note:
4699 Several different converged reason view routines may be set by calling
4700 `SNESConvergedReasonViewSet()` multiple times; all will be called in the
4701 order in which they were set.
4702
4703 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESConvergedReason`, `SNESGetConvergedReason()`, `SNESConvergedReasonView()`, `SNESConvergedReasonViewCancel()`,
4704 `PetscCtxDestroyFn`
4705 @*/
SNESConvergedReasonViewSet(SNES snes,PetscErrorCode (* f)(SNES snes,void * vctx),void * vctx,PetscCtxDestroyFn * reasonviewdestroy)4706 PetscErrorCode SNESConvergedReasonViewSet(SNES snes, PetscErrorCode (*f)(SNES snes, void *vctx), void *vctx, PetscCtxDestroyFn *reasonviewdestroy)
4707 {
4708 PetscFunctionBegin;
4709 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4710 for (PetscInt i = 0; i < snes->numberreasonviews; i++) {
4711 PetscBool identical;
4712
4713 PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))(PetscVoidFn *)f, vctx, reasonviewdestroy, (PetscErrorCode (*)(void))(PetscVoidFn *)snes->reasonview[i], snes->reasonviewcontext[i], snes->reasonviewdestroy[i], &identical));
4714 if (identical) PetscFunctionReturn(PETSC_SUCCESS);
4715 }
4716 PetscCheck(snes->numberreasonviews < MAXSNESREASONVIEWS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many SNES reasonview set");
4717 snes->reasonview[snes->numberreasonviews] = f;
4718 snes->reasonviewdestroy[snes->numberreasonviews] = reasonviewdestroy;
4719 snes->reasonviewcontext[snes->numberreasonviews++] = vctx;
4720 PetscFunctionReturn(PETSC_SUCCESS);
4721 }
4722
4723 /*@
4724 SNESConvergedReasonViewFromOptions - Processes command line options to determine if/how a `SNESConvergedReason` is to be viewed at the end of `SNESSolve()`
4725 All the user-provided viewer routines set with `SNESConvergedReasonViewSet()` will be called, if they exist.
4726
4727 Collective
4728
4729 Input Parameter:
4730 . snes - the `SNES` object
4731
4732 Level: advanced
4733
4734 .seealso: [](ch_snes), `SNES`, `SNESConvergedReason`, `SNESConvergedReasonViewSet()`, `SNESCreate()`, `SNESSetUp()`, `SNESDestroy()`,
4735 `SNESSetTolerances()`, `SNESConvergedDefault()`, `SNESGetConvergedReason()`, `SNESConvergedReasonView()`
4736 @*/
SNESConvergedReasonViewFromOptions(SNES snes)4737 PetscErrorCode SNESConvergedReasonViewFromOptions(SNES snes)
4738 {
4739 static PetscBool incall = PETSC_FALSE;
4740
4741 PetscFunctionBegin;
4742 if (incall) PetscFunctionReturn(PETSC_SUCCESS);
4743 incall = PETSC_TRUE;
4744
4745 /* All user-provided viewers are called first, if they exist. */
4746 for (PetscInt i = 0; i < snes->numberreasonviews; i++) PetscCall((*snes->reasonview[i])(snes, snes->reasonviewcontext[i]));
4747
4748 /* Call PETSc default routine if users ask for it */
4749 if (snes->convergedreasonviewer) {
4750 PetscCall(PetscViewerPushFormat(snes->convergedreasonviewer, snes->convergedreasonformat));
4751 PetscCall(SNESConvergedReasonView(snes, snes->convergedreasonviewer));
4752 PetscCall(PetscViewerPopFormat(snes->convergedreasonviewer));
4753 }
4754 incall = PETSC_FALSE;
4755 PetscFunctionReturn(PETSC_SUCCESS);
4756 }
4757
4758 /*@
4759 SNESSolve - Solves a nonlinear system $F(x) = b $ associated with a `SNES` object
4760
4761 Collective
4762
4763 Input Parameters:
4764 + snes - the `SNES` context
4765 . b - the constant part of the equation $F(x) = b$, or `NULL` to use zero.
4766 - x - the solution vector.
4767
4768 Level: beginner
4769
4770 Note:
4771 The user should initialize the vector, `x`, with the initial guess
4772 for the nonlinear solve prior to calling `SNESSolve()` .
4773
4774 .seealso: [](ch_snes), `SNES`, `SNESCreate()`, `SNESDestroy()`, `SNESSetFunction()`, `SNESSetJacobian()`, `SNESSetGridSequence()`, `SNESGetSolution()`,
4775 `SNESNewtonTRSetPreCheck()`, `SNESNewtonTRGetPreCheck()`, `SNESNewtonTRSetPostCheck()`, `SNESNewtonTRGetPostCheck()`,
4776 `SNESLineSearchSetPostCheck()`, `SNESLineSearchGetPostCheck()`, `SNESLineSearchSetPreCheck()`, `SNESLineSearchGetPreCheck()`
4777 @*/
SNESSolve(SNES snes,Vec b,Vec x)4778 PetscErrorCode SNESSolve(SNES snes, Vec b, Vec x)
4779 {
4780 PetscBool flg;
4781 PetscInt grid;
4782 Vec xcreated = NULL;
4783 DM dm;
4784
4785 PetscFunctionBegin;
4786 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
4787 if (x) PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
4788 if (x) PetscCheckSameComm(snes, 1, x, 3);
4789 if (b) PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4790 if (b) PetscCheckSameComm(snes, 1, b, 2);
4791
4792 /* High level operations using the nonlinear solver */
4793 {
4794 PetscViewer viewer;
4795 PetscViewerFormat format;
4796 PetscInt num;
4797 PetscBool flg;
4798 static PetscBool incall = PETSC_FALSE;
4799
4800 if (!incall) {
4801 /* Estimate the convergence rate of the discretization */
4802 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_convergence_estimate", &viewer, &format, &flg));
4803 if (flg) {
4804 PetscConvEst conv;
4805 DM dm;
4806 PetscReal *alpha; /* Convergence rate of the solution error for each field in the L_2 norm */
4807 PetscInt Nf;
4808
4809 incall = PETSC_TRUE;
4810 PetscCall(SNESGetDM(snes, &dm));
4811 PetscCall(DMGetNumFields(dm, &Nf));
4812 PetscCall(PetscCalloc1(Nf, &alpha));
4813 PetscCall(PetscConvEstCreate(PetscObjectComm((PetscObject)snes), &conv));
4814 PetscCall(PetscConvEstSetSolver(conv, (PetscObject)snes));
4815 PetscCall(PetscConvEstSetFromOptions(conv));
4816 PetscCall(PetscConvEstSetUp(conv));
4817 PetscCall(PetscConvEstGetConvRate(conv, alpha));
4818 PetscCall(PetscViewerPushFormat(viewer, format));
4819 PetscCall(PetscConvEstRateView(conv, alpha, viewer));
4820 PetscCall(PetscViewerPopFormat(viewer));
4821 PetscCall(PetscViewerDestroy(&viewer));
4822 PetscCall(PetscConvEstDestroy(&conv));
4823 PetscCall(PetscFree(alpha));
4824 incall = PETSC_FALSE;
4825 }
4826 /* Adaptively refine the initial grid */
4827 num = 1;
4828 PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)snes)->prefix, "-snes_adapt_initial", &num, &flg));
4829 if (flg) {
4830 DMAdaptor adaptor;
4831
4832 incall = PETSC_TRUE;
4833 PetscCall(DMAdaptorCreate(PetscObjectComm((PetscObject)snes), &adaptor));
4834 PetscCall(DMAdaptorSetSolver(adaptor, snes));
4835 PetscCall(DMAdaptorSetSequenceLength(adaptor, num));
4836 PetscCall(DMAdaptorSetFromOptions(adaptor));
4837 PetscCall(DMAdaptorSetUp(adaptor));
4838 PetscCall(DMAdaptorAdapt(adaptor, x, DM_ADAPTATION_INITIAL, &dm, &x));
4839 PetscCall(DMAdaptorDestroy(&adaptor));
4840 incall = PETSC_FALSE;
4841 }
4842 /* Use grid sequencing to adapt */
4843 num = 0;
4844 PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)snes)->prefix, "-snes_adapt_sequence", &num, NULL));
4845 if (num) {
4846 DMAdaptor adaptor;
4847 const char *prefix;
4848
4849 incall = PETSC_TRUE;
4850 PetscCall(DMAdaptorCreate(PetscObjectComm((PetscObject)snes), &adaptor));
4851 PetscCall(SNESGetOptionsPrefix(snes, &prefix));
4852 PetscCall(DMAdaptorSetOptionsPrefix(adaptor, prefix));
4853 PetscCall(DMAdaptorSetSolver(adaptor, snes));
4854 PetscCall(DMAdaptorSetSequenceLength(adaptor, num));
4855 PetscCall(DMAdaptorSetFromOptions(adaptor));
4856 PetscCall(DMAdaptorSetUp(adaptor));
4857 PetscCall(PetscObjectViewFromOptions((PetscObject)adaptor, NULL, "-snes_adapt_view"));
4858 PetscCall(DMAdaptorAdapt(adaptor, x, DM_ADAPTATION_SEQUENTIAL, &dm, &x));
4859 PetscCall(DMAdaptorDestroy(&adaptor));
4860 incall = PETSC_FALSE;
4861 }
4862 }
4863 }
4864 if (!x) x = snes->vec_sol;
4865 if (!x) {
4866 PetscCall(SNESGetDM(snes, &dm));
4867 PetscCall(DMCreateGlobalVector(dm, &xcreated));
4868 x = xcreated;
4869 }
4870 PetscCall(SNESViewFromOptions(snes, NULL, "-snes_view_pre"));
4871
4872 for (grid = 0; grid < snes->gridsequence; grid++) PetscCall(PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes))));
4873 for (grid = 0; grid < snes->gridsequence + 1; grid++) {
4874 /* set solution vector */
4875 if (!grid) PetscCall(PetscObjectReference((PetscObject)x));
4876 PetscCall(VecDestroy(&snes->vec_sol));
4877 snes->vec_sol = x;
4878 PetscCall(SNESGetDM(snes, &dm));
4879
4880 /* set affine vector if provided */
4881 if (b) PetscCall(PetscObjectReference((PetscObject)b));
4882 PetscCall(VecDestroy(&snes->vec_rhs));
4883 snes->vec_rhs = b;
4884
4885 if (snes->vec_rhs) PetscCheck(snes->vec_func != snes->vec_rhs, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "Right hand side vector cannot be function vector");
4886 PetscCheck(snes->vec_func != snes->vec_sol, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "Solution vector cannot be function vector");
4887 PetscCheck(snes->vec_rhs != snes->vec_sol, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "Solution vector cannot be right-hand side vector");
4888 if (!snes->vec_sol_update /* && snes->vec_sol */) PetscCall(VecDuplicate(snes->vec_sol, &snes->vec_sol_update));
4889 PetscCall(DMShellSetGlobalVector(dm, snes->vec_sol));
4890 PetscCall(SNESSetUp(snes));
4891
4892 if (!grid) {
4893 if (snes->ops->computeinitialguess) PetscCallBack("SNES callback compute initial guess", (*snes->ops->computeinitialguess)(snes, snes->vec_sol, snes->initialguessP));
4894 }
4895
4896 if (snes->conv_hist_reset) snes->conv_hist_len = 0;
4897 PetscCall(SNESResetCounters(snes));
4898 snes->reason = SNES_CONVERGED_ITERATING;
4899 PetscCall(PetscLogEventBegin(SNES_Solve, snes, 0, 0, 0));
4900 PetscUseTypeMethod(snes, solve);
4901 PetscCall(PetscLogEventEnd(SNES_Solve, snes, 0, 0, 0));
4902 PetscCheck(snes->reason, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Internal error, solver %s returned without setting converged reason", ((PetscObject)snes)->type_name);
4903 snes->functiondomainerror = PETSC_FALSE; /* clear the flag if it has been set */
4904 snes->objectivedomainerror = PETSC_FALSE; /* clear the flag if it has been set */
4905 snes->jacobiandomainerror = PETSC_FALSE; /* clear the flag if it has been set */
4906
4907 if (snes->lagjac_persist) snes->jac_iter += snes->iter;
4908 if (snes->lagpre_persist) snes->pre_iter += snes->iter;
4909
4910 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_test_local_min", NULL, NULL, &flg));
4911 if (flg && !PetscPreLoadingOn) PetscCall(SNESTestLocalMin(snes));
4912 /* Call converged reason views. This may involve user-provided viewers as well */
4913 PetscCall(SNESConvergedReasonViewFromOptions(snes));
4914
4915 if (snes->errorifnotconverged) {
4916 if (snes->reason < 0) PetscCall(SNESMonitorCancel(snes));
4917 PetscCheck(snes->reason >= 0, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESSolve has not converged");
4918 }
4919 if (snes->reason < 0) break;
4920 if (grid < snes->gridsequence) {
4921 DM fine;
4922 Vec xnew;
4923 Mat interp;
4924
4925 PetscCall(DMRefine(snes->dm, PetscObjectComm((PetscObject)snes), &fine));
4926 PetscCheck(fine, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_INCOMP, "DMRefine() did not perform any refinement, cannot continue grid sequencing");
4927 PetscCall(DMGetCoordinatesLocalSetUp(fine));
4928 PetscCall(DMCreateInterpolation(snes->dm, fine, &interp, NULL));
4929 PetscCall(DMCreateGlobalVector(fine, &xnew));
4930 PetscCall(MatInterpolate(interp, x, xnew));
4931 PetscCall(DMInterpolate(snes->dm, interp, fine));
4932 PetscCall(MatDestroy(&interp));
4933 x = xnew;
4934
4935 PetscCall(SNESReset(snes));
4936 PetscCall(SNESSetDM(snes, fine));
4937 PetscCall(SNESResetFromOptions(snes));
4938 PetscCall(DMDestroy(&fine));
4939 PetscCall(PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes))));
4940 }
4941 }
4942 PetscCall(SNESViewFromOptions(snes, NULL, "-snes_view"));
4943 PetscCall(VecViewFromOptions(snes->vec_sol, (PetscObject)snes, "-snes_view_solution"));
4944 PetscCall(DMMonitor(snes->dm));
4945 PetscCall(SNESMonitorPauseFinal_Internal(snes));
4946
4947 PetscCall(VecDestroy(&xcreated));
4948 PetscCall(PetscObjectSAWsBlock((PetscObject)snes));
4949 PetscFunctionReturn(PETSC_SUCCESS);
4950 }
4951
4952 /* --------- Internal routines for SNES Package --------- */
4953
4954 /*@
4955 SNESSetType - Sets the algorithm/method to be used to solve the nonlinear system with the given `SNES`
4956
4957 Collective
4958
4959 Input Parameters:
4960 + snes - the `SNES` context
4961 - type - a known method
4962
4963 Options Database Key:
4964 . -snes_type <type> - Sets the method; use -help for a list
4965 of available methods (for instance, newtonls or newtontr)
4966
4967 Level: intermediate
4968
4969 Notes:
4970 See `SNESType` for available methods (for instance)
4971 + `SNESNEWTONLS` - Newton's method with line search
4972 (systems of nonlinear equations)
4973 - `SNESNEWTONTR` - Newton's method with trust region
4974 (systems of nonlinear equations)
4975
4976 Normally, it is best to use the `SNESSetFromOptions()` command and then
4977 set the `SNES` solver type from the options database rather than by using
4978 this routine. Using the options database provides the user with
4979 maximum flexibility in evaluating the many nonlinear solvers.
4980 The `SNESSetType()` routine is provided for those situations where it
4981 is necessary to set the nonlinear solver independently of the command
4982 line or options database. This might be the case, for example, when
4983 the choice of solver changes during the execution of the program,
4984 and the user's application is taking responsibility for choosing the
4985 appropriate method.
4986
4987 Developer Note:
4988 `SNESRegister()` adds a constructor for a new `SNESType` to `SNESList`, `SNESSetType()` locates
4989 the constructor in that list and calls it to create the specific object.
4990
4991 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESType`, `SNESCreate()`, `SNESDestroy()`, `SNESGetType()`, `SNESSetFromOptions()`
4992 @*/
SNESSetType(SNES snes,SNESType type)4993 PetscErrorCode SNESSetType(SNES snes, SNESType type)
4994 {
4995 PetscBool match;
4996 PetscErrorCode (*r)(SNES);
4997
4998 PetscFunctionBegin;
4999 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5000 PetscAssertPointer(type, 2);
5001
5002 PetscCall(PetscObjectTypeCompare((PetscObject)snes, type, &match));
5003 if (match) PetscFunctionReturn(PETSC_SUCCESS);
5004
5005 PetscCall(PetscFunctionListFind(SNESList, type, &r));
5006 PetscCheck(r, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested SNES type %s", type);
5007 /* Destroy the previous private SNES context */
5008 PetscTryTypeMethod(snes, destroy);
5009 /* Reinitialize type-specific function pointers in SNESOps structure */
5010 snes->ops->reset = NULL;
5011 snes->ops->setup = NULL;
5012 snes->ops->solve = NULL;
5013 snes->ops->view = NULL;
5014 snes->ops->setfromoptions = NULL;
5015 snes->ops->destroy = NULL;
5016
5017 /* It may happen the user has customized the line search before calling SNESSetType */
5018 if (((PetscObject)snes)->type_name) PetscCall(SNESLineSearchDestroy(&snes->linesearch));
5019
5020 /* Call the SNESCreate_XXX routine for this particular Nonlinear solver */
5021 snes->setupcalled = PETSC_FALSE;
5022
5023 PetscCall(PetscObjectChangeTypeName((PetscObject)snes, type));
5024 PetscCall((*r)(snes));
5025 PetscFunctionReturn(PETSC_SUCCESS);
5026 }
5027
5028 /*@
5029 SNESGetType - Gets the `SNES` method type and name (as a string).
5030
5031 Not Collective
5032
5033 Input Parameter:
5034 . snes - nonlinear solver context
5035
5036 Output Parameter:
5037 . type - `SNES` method (a character string)
5038
5039 Level: intermediate
5040
5041 .seealso: [](ch_snes), `SNESSetType()`, `SNESType`, `SNESSetFromOptions()`, `SNES`
5042 @*/
SNESGetType(SNES snes,SNESType * type)5043 PetscErrorCode SNESGetType(SNES snes, SNESType *type)
5044 {
5045 PetscFunctionBegin;
5046 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5047 PetscAssertPointer(type, 2);
5048 *type = ((PetscObject)snes)->type_name;
5049 PetscFunctionReturn(PETSC_SUCCESS);
5050 }
5051
5052 /*@
5053 SNESSetSolution - Sets the solution vector for use by the `SNES` routines.
5054
5055 Logically Collective
5056
5057 Input Parameters:
5058 + snes - the `SNES` context obtained from `SNESCreate()`
5059 - u - the solution vector
5060
5061 Level: beginner
5062
5063 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESGetSolution()`, `Vec`
5064 @*/
SNESSetSolution(SNES snes,Vec u)5065 PetscErrorCode SNESSetSolution(SNES snes, Vec u)
5066 {
5067 DM dm;
5068
5069 PetscFunctionBegin;
5070 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5071 PetscValidHeaderSpecific(u, VEC_CLASSID, 2);
5072 PetscCall(PetscObjectReference((PetscObject)u));
5073 PetscCall(VecDestroy(&snes->vec_sol));
5074
5075 snes->vec_sol = u;
5076
5077 PetscCall(SNESGetDM(snes, &dm));
5078 PetscCall(DMShellSetGlobalVector(dm, u));
5079 PetscFunctionReturn(PETSC_SUCCESS);
5080 }
5081
5082 /*@
5083 SNESGetSolution - Returns the vector where the approximate solution is
5084 stored. This is the fine grid solution when using `SNESSetGridSequence()`.
5085
5086 Not Collective, but `x` is parallel if `snes` is parallel
5087
5088 Input Parameter:
5089 . snes - the `SNES` context
5090
5091 Output Parameter:
5092 . x - the solution
5093
5094 Level: intermediate
5095
5096 .seealso: [](ch_snes), `SNESSetSolution()`, `SNESSolve()`, `SNES`, `SNESGetSolutionUpdate()`, `SNESGetFunction()`
5097 @*/
SNESGetSolution(SNES snes,Vec * x)5098 PetscErrorCode SNESGetSolution(SNES snes, Vec *x)
5099 {
5100 PetscFunctionBegin;
5101 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5102 PetscAssertPointer(x, 2);
5103 *x = snes->vec_sol;
5104 PetscFunctionReturn(PETSC_SUCCESS);
5105 }
5106
5107 /*@
5108 SNESGetSolutionUpdate - Returns the vector where the solution update is
5109 stored.
5110
5111 Not Collective, but `x` is parallel if `snes` is parallel
5112
5113 Input Parameter:
5114 . snes - the `SNES` context
5115
5116 Output Parameter:
5117 . x - the solution update
5118
5119 Level: advanced
5120
5121 .seealso: [](ch_snes), `SNES`, `SNESGetSolution()`, `SNESGetFunction()`
5122 @*/
SNESGetSolutionUpdate(SNES snes,Vec * x)5123 PetscErrorCode SNESGetSolutionUpdate(SNES snes, Vec *x)
5124 {
5125 PetscFunctionBegin;
5126 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5127 PetscAssertPointer(x, 2);
5128 *x = snes->vec_sol_update;
5129 PetscFunctionReturn(PETSC_SUCCESS);
5130 }
5131
5132 /*@C
5133 SNESGetFunction - Returns the function that defines the nonlinear system set with `SNESSetFunction()`
5134
5135 Not Collective, but `r` is parallel if `snes` is parallel. Collective if `r` is requested, but has not been created yet.
5136
5137 Input Parameter:
5138 . snes - the `SNES` context
5139
5140 Output Parameters:
5141 + r - the vector that is used to store residuals (or `NULL` if you don't want it)
5142 . f - the function (or `NULL` if you don't want it); for calling sequence see `SNESFunctionFn`
5143 - ctx - the function context (or `NULL` if you don't want it)
5144
5145 Level: advanced
5146
5147 Note:
5148 The vector `r` DOES NOT, in general, contain the current value of the `SNES` nonlinear function
5149
5150 .seealso: [](ch_snes), `SNES`, `SNESSolve()`, `SNESSetFunction()`, `SNESGetSolution()`, `SNESFunctionFn`
5151 @*/
SNESGetFunction(SNES snes,Vec * r,SNESFunctionFn ** f,PetscCtxRt ctx)5152 PetscErrorCode SNESGetFunction(SNES snes, Vec *r, SNESFunctionFn **f, PetscCtxRt ctx)
5153 {
5154 DM dm;
5155
5156 PetscFunctionBegin;
5157 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5158 if (r) {
5159 if (!snes->vec_func) {
5160 if (snes->vec_rhs) {
5161 PetscCall(VecDuplicate(snes->vec_rhs, &snes->vec_func));
5162 } else if (snes->vec_sol) {
5163 PetscCall(VecDuplicate(snes->vec_sol, &snes->vec_func));
5164 } else if (snes->dm) {
5165 PetscCall(DMCreateGlobalVector(snes->dm, &snes->vec_func));
5166 }
5167 }
5168 *r = snes->vec_func;
5169 }
5170 PetscCall(SNESGetDM(snes, &dm));
5171 PetscCall(DMSNESGetFunction(dm, f, ctx));
5172 PetscFunctionReturn(PETSC_SUCCESS);
5173 }
5174
5175 /*@C
5176 SNESGetNGS - Returns the function and context set with `SNESSetNGS()`
5177
5178 Input Parameter:
5179 . snes - the `SNES` context
5180
5181 Output Parameters:
5182 + f - the function (or `NULL`) see `SNESNGSFn` for calling sequence
5183 - ctx - the function context (or `NULL`)
5184
5185 Level: advanced
5186
5187 .seealso: [](ch_snes), `SNESSetNGS()`, `SNESGetFunction()`, `SNESNGSFn`
5188 @*/
SNESGetNGS(SNES snes,SNESNGSFn ** f,PetscCtxRt ctx)5189 PetscErrorCode SNESGetNGS(SNES snes, SNESNGSFn **f, PetscCtxRt ctx)
5190 {
5191 DM dm;
5192
5193 PetscFunctionBegin;
5194 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5195 PetscCall(SNESGetDM(snes, &dm));
5196 PetscCall(DMSNESGetNGS(dm, f, ctx));
5197 PetscFunctionReturn(PETSC_SUCCESS);
5198 }
5199
5200 /*@
5201 SNESSetOptionsPrefix - Sets the prefix used for searching for all
5202 `SNES` options in the database.
5203
5204 Logically Collective
5205
5206 Input Parameters:
5207 + snes - the `SNES` context
5208 - prefix - the prefix to prepend to all option names
5209
5210 Level: advanced
5211
5212 Note:
5213 A hyphen (-) must NOT be given at the beginning of the prefix name.
5214 The first character of all runtime options is AUTOMATICALLY the hyphen.
5215
5216 .seealso: [](ch_snes), `SNES`, `SNESSetFromOptions()`, `SNESAppendOptionsPrefix()`
5217 @*/
SNESSetOptionsPrefix(SNES snes,const char prefix[])5218 PetscErrorCode SNESSetOptionsPrefix(SNES snes, const char prefix[])
5219 {
5220 PetscFunctionBegin;
5221 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5222 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)snes, prefix));
5223 if (!snes->ksp) PetscCall(SNESGetKSP(snes, &snes->ksp));
5224 if (snes->linesearch) {
5225 PetscCall(SNESGetLineSearch(snes, &snes->linesearch));
5226 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)snes->linesearch, prefix));
5227 }
5228 PetscCall(KSPSetOptionsPrefix(snes->ksp, prefix));
5229 PetscFunctionReturn(PETSC_SUCCESS);
5230 }
5231
5232 /*@
5233 SNESAppendOptionsPrefix - Appends to the prefix used for searching for all
5234 `SNES` options in the database.
5235
5236 Logically Collective
5237
5238 Input Parameters:
5239 + snes - the `SNES` context
5240 - prefix - the prefix to prepend to all option names
5241
5242 Level: advanced
5243
5244 Note:
5245 A hyphen (-) must NOT be given at the beginning of the prefix name.
5246 The first character of all runtime options is AUTOMATICALLY the hyphen.
5247
5248 .seealso: [](ch_snes), `SNESGetOptionsPrefix()`, `SNESSetOptionsPrefix()`
5249 @*/
SNESAppendOptionsPrefix(SNES snes,const char prefix[])5250 PetscErrorCode SNESAppendOptionsPrefix(SNES snes, const char prefix[])
5251 {
5252 PetscFunctionBegin;
5253 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5254 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)snes, prefix));
5255 if (!snes->ksp) PetscCall(SNESGetKSP(snes, &snes->ksp));
5256 if (snes->linesearch) {
5257 PetscCall(SNESGetLineSearch(snes, &snes->linesearch));
5258 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)snes->linesearch, prefix));
5259 }
5260 PetscCall(KSPAppendOptionsPrefix(snes->ksp, prefix));
5261 PetscFunctionReturn(PETSC_SUCCESS);
5262 }
5263
5264 /*@
5265 SNESGetOptionsPrefix - Gets the prefix used for searching for all
5266 `SNES` options in the database.
5267
5268 Not Collective
5269
5270 Input Parameter:
5271 . snes - the `SNES` context
5272
5273 Output Parameter:
5274 . prefix - pointer to the prefix string used
5275
5276 Level: advanced
5277
5278 .seealso: [](ch_snes), `SNES`, `SNESSetOptionsPrefix()`, `SNESAppendOptionsPrefix()`
5279 @*/
SNESGetOptionsPrefix(SNES snes,const char * prefix[])5280 PetscErrorCode SNESGetOptionsPrefix(SNES snes, const char *prefix[])
5281 {
5282 PetscFunctionBegin;
5283 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5284 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)snes, prefix));
5285 PetscFunctionReturn(PETSC_SUCCESS);
5286 }
5287
5288 /*@C
5289 SNESRegister - Adds a method to the nonlinear solver package.
5290
5291 Not Collective
5292
5293 Input Parameters:
5294 + sname - name of a new user-defined solver
5295 - function - routine to create method context
5296
5297 Level: advanced
5298
5299 Note:
5300 `SNESRegister()` may be called multiple times to add several user-defined solvers.
5301
5302 Example Usage:
5303 .vb
5304 SNESRegister("my_solver", MySolverCreate);
5305 .ve
5306
5307 Then, your solver can be chosen with the procedural interface via
5308 .vb
5309 SNESSetType(snes, "my_solver")
5310 .ve
5311 or at runtime via the option
5312 .vb
5313 -snes_type my_solver
5314 .ve
5315
5316 .seealso: [](ch_snes), `SNESRegisterAll()`, `SNESRegisterDestroy()`
5317 @*/
SNESRegister(const char sname[],PetscErrorCode (* function)(SNES))5318 PetscErrorCode SNESRegister(const char sname[], PetscErrorCode (*function)(SNES))
5319 {
5320 PetscFunctionBegin;
5321 PetscCall(SNESInitializePackage());
5322 PetscCall(PetscFunctionListAdd(&SNESList, sname, function));
5323 PetscFunctionReturn(PETSC_SUCCESS);
5324 }
5325
SNESTestLocalMin(SNES snes)5326 PetscErrorCode SNESTestLocalMin(SNES snes)
5327 {
5328 PetscInt N, i, j;
5329 Vec u, uh, fh;
5330 PetscScalar value;
5331 PetscReal norm;
5332
5333 PetscFunctionBegin;
5334 PetscCall(SNESGetSolution(snes, &u));
5335 PetscCall(VecDuplicate(u, &uh));
5336 PetscCall(VecDuplicate(u, &fh));
5337
5338 /* currently only works for sequential */
5339 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)snes), "Testing FormFunction() for local min\n"));
5340 PetscCall(VecGetSize(u, &N));
5341 for (i = 0; i < N; i++) {
5342 PetscCall(VecCopy(u, uh));
5343 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)snes), "i = %" PetscInt_FMT "\n", i));
5344 for (j = -10; j < 11; j++) {
5345 value = PetscSign(j) * PetscExpReal(PetscAbs(j) - 10.0);
5346 PetscCall(VecSetValue(uh, i, value, ADD_VALUES));
5347 PetscCall(SNESComputeFunction(snes, uh, fh));
5348 PetscCall(VecNorm(fh, NORM_2, &norm)); /* does not handle use of SNESSetFunctionDomainError() correctly */
5349 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)snes), " j norm %" PetscInt_FMT " %18.16e\n", j, (double)norm));
5350 value = -value;
5351 PetscCall(VecSetValue(uh, i, value, ADD_VALUES));
5352 }
5353 }
5354 PetscCall(VecDestroy(&uh));
5355 PetscCall(VecDestroy(&fh));
5356 PetscFunctionReturn(PETSC_SUCCESS);
5357 }
5358
5359 /*@
5360 SNESGetLineSearch - Returns the line search associated with the `SNES`.
5361
5362 Not Collective
5363
5364 Input Parameter:
5365 . snes - iterative context obtained from `SNESCreate()`
5366
5367 Output Parameter:
5368 . linesearch - linesearch context
5369
5370 Level: beginner
5371
5372 Notes:
5373 It creates a default line search instance which can be configured as needed in case it has not been already set with `SNESSetLineSearch()`.
5374
5375 You can also use the options database keys `-snes_linesearch_*` to configure the line search. See `SNESLineSearchSetFromOptions()` for the possible options.
5376
5377 .seealso: [](ch_snes), `SNESLineSearch`, `SNESSetLineSearch()`, `SNESLineSearchCreate()`, `SNESLineSearchSetFromOptions()`
5378 @*/
SNESGetLineSearch(SNES snes,SNESLineSearch * linesearch)5379 PetscErrorCode SNESGetLineSearch(SNES snes, SNESLineSearch *linesearch)
5380 {
5381 const char *optionsprefix;
5382
5383 PetscFunctionBegin;
5384 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5385 PetscAssertPointer(linesearch, 2);
5386 if (!snes->linesearch) {
5387 PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix));
5388 PetscCall(SNESLineSearchCreate(PetscObjectComm((PetscObject)snes), &snes->linesearch));
5389 PetscCall(SNESLineSearchSetSNES(snes->linesearch, snes));
5390 PetscCall(SNESLineSearchAppendOptionsPrefix(snes->linesearch, optionsprefix));
5391 PetscCall(PetscObjectIncrementTabLevel((PetscObject)snes->linesearch, (PetscObject)snes, 1));
5392 }
5393 *linesearch = snes->linesearch;
5394 PetscFunctionReturn(PETSC_SUCCESS);
5395 }
5396
5397 /*@
5398 SNESKSPSetUseEW - Sets `SNES` to the use Eisenstat-Walker method for
5399 computing relative tolerance for linear solvers within an inexact
5400 Newton method.
5401
5402 Logically Collective
5403
5404 Input Parameters:
5405 + snes - `SNES` context
5406 - flag - `PETSC_TRUE` or `PETSC_FALSE`
5407
5408 Options Database Keys:
5409 + -snes_ksp_ew - use Eisenstat-Walker method for determining linear system convergence
5410 . -snes_ksp_ew_version ver - version of Eisenstat-Walker method
5411 . -snes_ksp_ew_rtol0 <rtol0> - Sets rtol0
5412 . -snes_ksp_ew_rtolmax <rtolmax> - Sets rtolmax
5413 . -snes_ksp_ew_gamma <gamma> - Sets gamma
5414 . -snes_ksp_ew_alpha <alpha> - Sets alpha
5415 . -snes_ksp_ew_alpha2 <alpha2> - Sets alpha2
5416 - -snes_ksp_ew_threshold <threshold> - Sets threshold
5417
5418 Level: advanced
5419
5420 Note:
5421 The default is to use a constant relative tolerance for
5422 the inner linear solvers. Alternatively, one can use the
5423 Eisenstat-Walker method {cite}`ew96`, where the relative convergence tolerance
5424 is reset at each Newton iteration according progress of the nonlinear
5425 solver.
5426
5427 .seealso: [](ch_snes), `KSP`, `SNES`, `SNESKSPGetUseEW()`, `SNESKSPGetParametersEW()`, `SNESKSPSetParametersEW()`
5428 @*/
SNESKSPSetUseEW(SNES snes,PetscBool flag)5429 PetscErrorCode SNESKSPSetUseEW(SNES snes, PetscBool flag)
5430 {
5431 PetscFunctionBegin;
5432 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5433 PetscValidLogicalCollectiveBool(snes, flag, 2);
5434 snes->ksp_ewconv = flag;
5435 PetscFunctionReturn(PETSC_SUCCESS);
5436 }
5437
5438 /*@
5439 SNESKSPGetUseEW - Gets if `SNES` is using Eisenstat-Walker method
5440 for computing relative tolerance for linear solvers within an
5441 inexact Newton method.
5442
5443 Not Collective
5444
5445 Input Parameter:
5446 . snes - `SNES` context
5447
5448 Output Parameter:
5449 . flag - `PETSC_TRUE` or `PETSC_FALSE`
5450
5451 Level: advanced
5452
5453 .seealso: [](ch_snes), `SNESKSPSetUseEW()`, `SNESKSPGetParametersEW()`, `SNESKSPSetParametersEW()`
5454 @*/
SNESKSPGetUseEW(SNES snes,PetscBool * flag)5455 PetscErrorCode SNESKSPGetUseEW(SNES snes, PetscBool *flag)
5456 {
5457 PetscFunctionBegin;
5458 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5459 PetscAssertPointer(flag, 2);
5460 *flag = snes->ksp_ewconv;
5461 PetscFunctionReturn(PETSC_SUCCESS);
5462 }
5463
5464 /*@
5465 SNESKSPSetParametersEW - Sets parameters for Eisenstat-Walker
5466 convergence criteria for the linear solvers within an inexact
5467 Newton method.
5468
5469 Logically Collective
5470
5471 Input Parameters:
5472 + snes - `SNES` context
5473 . version - version 1, 2 (default is 2), 3 or 4
5474 . rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
5475 . rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
5476 . gamma - multiplicative factor for version 2 rtol computation
5477 (0 <= gamma2 <= 1)
5478 . alpha - power for version 2 rtol computation (1 < alpha <= 2)
5479 . alpha2 - power for safeguard
5480 - threshold - threshold for imposing safeguard (0 < threshold < 1)
5481
5482 Level: advanced
5483
5484 Notes:
5485 Version 3 was contributed by Luis Chacon, June 2006.
5486
5487 Use `PETSC_CURRENT` to retain the default for any of the parameters.
5488
5489 .seealso: [](ch_snes), `SNES`, `SNESKSPSetUseEW()`, `SNESKSPGetUseEW()`, `SNESKSPGetParametersEW()`
5490 @*/
SNESKSPSetParametersEW(SNES snes,PetscInt version,PetscReal rtol_0,PetscReal rtol_max,PetscReal gamma,PetscReal alpha,PetscReal alpha2,PetscReal threshold)5491 PetscErrorCode SNESKSPSetParametersEW(SNES snes, PetscInt version, PetscReal rtol_0, PetscReal rtol_max, PetscReal gamma, PetscReal alpha, PetscReal alpha2, PetscReal threshold)
5492 {
5493 SNESKSPEW *kctx;
5494
5495 PetscFunctionBegin;
5496 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5497 kctx = (SNESKSPEW *)snes->kspconvctx;
5498 PetscCheck(kctx, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "No Eisenstat-Walker context existing");
5499 PetscValidLogicalCollectiveInt(snes, version, 2);
5500 PetscValidLogicalCollectiveReal(snes, rtol_0, 3);
5501 PetscValidLogicalCollectiveReal(snes, rtol_max, 4);
5502 PetscValidLogicalCollectiveReal(snes, gamma, 5);
5503 PetscValidLogicalCollectiveReal(snes, alpha, 6);
5504 PetscValidLogicalCollectiveReal(snes, alpha2, 7);
5505 PetscValidLogicalCollectiveReal(snes, threshold, 8);
5506
5507 if (version != PETSC_CURRENT) kctx->version = version;
5508 if (rtol_0 != (PetscReal)PETSC_CURRENT) kctx->rtol_0 = rtol_0;
5509 if (rtol_max != (PetscReal)PETSC_CURRENT) kctx->rtol_max = rtol_max;
5510 if (gamma != (PetscReal)PETSC_CURRENT) kctx->gamma = gamma;
5511 if (alpha != (PetscReal)PETSC_CURRENT) kctx->alpha = alpha;
5512 if (alpha2 != (PetscReal)PETSC_CURRENT) kctx->alpha2 = alpha2;
5513 if (threshold != (PetscReal)PETSC_CURRENT) kctx->threshold = threshold;
5514
5515 PetscCheck(kctx->version >= 1 && kctx->version <= 4, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Only versions 1 to 4 are supported: %" PetscInt_FMT, kctx->version);
5516 PetscCheck(kctx->rtol_0 >= 0.0 && kctx->rtol_0 < 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "0.0 <= rtol_0 < 1.0: %g", (double)kctx->rtol_0);
5517 PetscCheck(kctx->rtol_max >= 0.0 && kctx->rtol_max < 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "0.0 <= rtol_max (%g) < 1.0", (double)kctx->rtol_max);
5518 PetscCheck(kctx->gamma >= 0.0 && kctx->gamma <= 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "0.0 <= gamma (%g) <= 1.0", (double)kctx->gamma);
5519 PetscCheck(kctx->alpha > 1.0 && kctx->alpha <= 2.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "1.0 < alpha (%g) <= 2.0", (double)kctx->alpha);
5520 PetscCheck(kctx->threshold > 0.0 && kctx->threshold < 1.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "0.0 < threshold (%g) < 1.0", (double)kctx->threshold);
5521 PetscFunctionReturn(PETSC_SUCCESS);
5522 }
5523
5524 /*@
5525 SNESKSPGetParametersEW - Gets parameters for Eisenstat-Walker
5526 convergence criteria for the linear solvers within an inexact
5527 Newton method.
5528
5529 Not Collective
5530
5531 Input Parameter:
5532 . snes - `SNES` context
5533
5534 Output Parameters:
5535 + version - version 1, 2 (default is 2), 3 or 4
5536 . rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
5537 . rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
5538 . gamma - multiplicative factor for version 2 rtol computation (0 <= gamma2 <= 1)
5539 . alpha - power for version 2 rtol computation (1 < alpha <= 2)
5540 . alpha2 - power for safeguard
5541 - threshold - threshold for imposing safeguard (0 < threshold < 1)
5542
5543 Level: advanced
5544
5545 .seealso: [](ch_snes), `SNES`, `SNESKSPSetUseEW()`, `SNESKSPGetUseEW()`, `SNESKSPSetParametersEW()`
5546 @*/
SNESKSPGetParametersEW(SNES snes,PetscInt * version,PetscReal * rtol_0,PetscReal * rtol_max,PetscReal * gamma,PetscReal * alpha,PetscReal * alpha2,PetscReal * threshold)5547 PetscErrorCode SNESKSPGetParametersEW(SNES snes, PetscInt *version, PetscReal *rtol_0, PetscReal *rtol_max, PetscReal *gamma, PetscReal *alpha, PetscReal *alpha2, PetscReal *threshold)
5548 {
5549 SNESKSPEW *kctx;
5550
5551 PetscFunctionBegin;
5552 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5553 kctx = (SNESKSPEW *)snes->kspconvctx;
5554 PetscCheck(kctx, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "No Eisenstat-Walker context existing");
5555 if (version) *version = kctx->version;
5556 if (rtol_0) *rtol_0 = kctx->rtol_0;
5557 if (rtol_max) *rtol_max = kctx->rtol_max;
5558 if (gamma) *gamma = kctx->gamma;
5559 if (alpha) *alpha = kctx->alpha;
5560 if (alpha2) *alpha2 = kctx->alpha2;
5561 if (threshold) *threshold = kctx->threshold;
5562 PetscFunctionReturn(PETSC_SUCCESS);
5563 }
5564
KSPPreSolve_SNESEW(KSP ksp,Vec b,Vec x,PetscCtx ctx)5565 PetscErrorCode KSPPreSolve_SNESEW(KSP ksp, Vec b, Vec x, PetscCtx ctx)
5566 {
5567 SNES snes = (SNES)ctx;
5568 SNESKSPEW *kctx = (SNESKSPEW *)snes->kspconvctx;
5569 PetscReal rtol = PETSC_CURRENT, stol;
5570
5571 PetscFunctionBegin;
5572 if (!snes->ksp_ewconv) PetscFunctionReturn(PETSC_SUCCESS);
5573 if (!snes->iter) {
5574 rtol = kctx->rtol_0; /* first time in, so use the original user rtol */
5575 PetscCall(VecNorm(snes->vec_func, NORM_2, &kctx->norm_first));
5576 } else {
5577 PetscCheck(kctx->version >= 1 && kctx->version <= 4, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Only versions 1-4 are supported: %" PetscInt_FMT, kctx->version);
5578 if (kctx->version == 1) {
5579 rtol = PetscAbsReal(snes->norm - kctx->lresid_last) / kctx->norm_last;
5580 stol = PetscPowReal(kctx->rtol_last, kctx->alpha2);
5581 if (stol > kctx->threshold) rtol = PetscMax(rtol, stol);
5582 } else if (kctx->version == 2) {
5583 rtol = kctx->gamma * PetscPowReal(snes->norm / kctx->norm_last, kctx->alpha);
5584 stol = kctx->gamma * PetscPowReal(kctx->rtol_last, kctx->alpha);
5585 if (stol > kctx->threshold) rtol = PetscMax(rtol, stol);
5586 } else if (kctx->version == 3) { /* contributed by Luis Chacon, June 2006. */
5587 rtol = kctx->gamma * PetscPowReal(snes->norm / kctx->norm_last, kctx->alpha);
5588 /* safeguard: avoid sharp decrease of rtol */
5589 stol = kctx->gamma * PetscPowReal(kctx->rtol_last, kctx->alpha);
5590 stol = PetscMax(rtol, stol);
5591 rtol = PetscMin(kctx->rtol_0, stol);
5592 /* safeguard: avoid oversolving */
5593 stol = kctx->gamma * (kctx->norm_first * snes->rtol) / snes->norm;
5594 stol = PetscMax(rtol, stol);
5595 rtol = PetscMin(kctx->rtol_0, stol);
5596 } else /* if (kctx->version == 4) */ {
5597 /* H.-B. An et al. Journal of Computational and Applied Mathematics 200 (2007) 47-60 */
5598 PetscReal ared = PetscAbsReal(kctx->norm_last - snes->norm);
5599 PetscReal pred = PetscAbsReal(kctx->norm_last - kctx->lresid_last);
5600 PetscReal rk = ared / pred;
5601 if (rk < kctx->v4_p1) rtol = 1. - 2. * kctx->v4_p1;
5602 else if (rk < kctx->v4_p2) rtol = kctx->rtol_last;
5603 else if (rk < kctx->v4_p3) rtol = kctx->v4_m1 * kctx->rtol_last;
5604 else rtol = kctx->v4_m2 * kctx->rtol_last;
5605
5606 if (kctx->rtol_last_2 > kctx->v4_m3 && kctx->rtol_last > kctx->v4_m3 && kctx->rk_last_2 < kctx->v4_p1 && kctx->rk_last < kctx->v4_p1) rtol = kctx->v4_m4 * kctx->rtol_last;
5607 kctx->rtol_last_2 = kctx->rtol_last;
5608 kctx->rk_last_2 = kctx->rk_last;
5609 kctx->rk_last = rk;
5610 }
5611 }
5612 /* safeguard: avoid rtol greater than rtol_max */
5613 rtol = PetscMin(rtol, kctx->rtol_max);
5614 PetscCall(KSPSetTolerances(ksp, rtol, PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT));
5615 PetscCall(PetscInfo(snes, "iter %" PetscInt_FMT ", Eisenstat-Walker (version %" PetscInt_FMT ") KSP rtol=%g\n", snes->iter, kctx->version, (double)rtol));
5616 PetscFunctionReturn(PETSC_SUCCESS);
5617 }
5618
KSPPostSolve_SNESEW(KSP ksp,Vec b,Vec x,PetscCtx ctx)5619 PetscErrorCode KSPPostSolve_SNESEW(KSP ksp, Vec b, Vec x, PetscCtx ctx)
5620 {
5621 SNES snes = (SNES)ctx;
5622 SNESKSPEW *kctx = (SNESKSPEW *)snes->kspconvctx;
5623 PCSide pcside;
5624 Vec lres;
5625
5626 PetscFunctionBegin;
5627 if (!snes->ksp_ewconv) PetscFunctionReturn(PETSC_SUCCESS);
5628 PetscCall(KSPGetTolerances(ksp, &kctx->rtol_last, NULL, NULL, NULL));
5629 kctx->norm_last = snes->norm;
5630 if (kctx->version == 1 || kctx->version == 4) {
5631 PC pc;
5632 PetscBool getRes;
5633
5634 PetscCall(KSPGetPC(ksp, &pc));
5635 PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCNONE, &getRes));
5636 if (!getRes) {
5637 KSPNormType normtype;
5638
5639 PetscCall(KSPGetNormType(ksp, &normtype));
5640 getRes = (PetscBool)(normtype == KSP_NORM_UNPRECONDITIONED);
5641 }
5642 PetscCall(KSPGetPCSide(ksp, &pcside));
5643 if (pcside == PC_RIGHT || getRes) { /* KSP residual is true linear residual */
5644 PetscCall(KSPGetResidualNorm(ksp, &kctx->lresid_last));
5645 } else {
5646 /* KSP residual is preconditioned residual */
5647 /* compute true linear residual norm */
5648 Mat J;
5649 PetscCall(KSPGetOperators(ksp, &J, NULL));
5650 PetscCall(VecDuplicate(b, &lres));
5651 PetscCall(MatMult(J, x, lres));
5652 PetscCall(VecAYPX(lres, -1.0, b));
5653 PetscCall(VecNorm(lres, NORM_2, &kctx->lresid_last));
5654 PetscCall(VecDestroy(&lres));
5655 }
5656 }
5657 PetscFunctionReturn(PETSC_SUCCESS);
5658 }
5659
5660 /*@
5661 SNESGetKSP - Returns the `KSP` context for a `SNES` solver.
5662
5663 Not Collective, but if `snes` is parallel, then `ksp` is parallel
5664
5665 Input Parameter:
5666 . snes - the `SNES` context
5667
5668 Output Parameter:
5669 . ksp - the `KSP` context
5670
5671 Level: beginner
5672
5673 Notes:
5674 The user can then directly manipulate the `KSP` context to set various
5675 options, etc. Likewise, the user can then extract and manipulate the
5676 `PC` contexts as well.
5677
5678 Some `SNESType`s do not use a `KSP` but a `KSP` is still returned by this function, changes to that `KSP` will have no effect.
5679
5680 .seealso: [](ch_snes), `SNES`, `KSP`, `PC`, `KSPGetPC()`, `SNESCreate()`, `KSPCreate()`, `SNESSetKSP()`
5681 @*/
SNESGetKSP(SNES snes,KSP * ksp)5682 PetscErrorCode SNESGetKSP(SNES snes, KSP *ksp)
5683 {
5684 PetscFunctionBegin;
5685 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5686 PetscAssertPointer(ksp, 2);
5687
5688 if (!snes->ksp) {
5689 PetscCall(KSPCreate(PetscObjectComm((PetscObject)snes), &snes->ksp));
5690 PetscCall(PetscObjectIncrementTabLevel((PetscObject)snes->ksp, (PetscObject)snes, 1));
5691
5692 PetscCall(KSPSetPreSolve(snes->ksp, KSPPreSolve_SNESEW, snes));
5693 PetscCall(KSPSetPostSolve(snes->ksp, KSPPostSolve_SNESEW, snes));
5694
5695 PetscCall(KSPMonitorSetFromOptions(snes->ksp, "-snes_monitor_ksp", "snes_preconditioned_residual", snes));
5696 PetscCall(PetscObjectSetOptions((PetscObject)snes->ksp, ((PetscObject)snes)->options));
5697 }
5698 *ksp = snes->ksp;
5699 PetscFunctionReturn(PETSC_SUCCESS);
5700 }
5701
5702 #include <petsc/private/dmimpl.h>
5703 /*@
5704 SNESSetDM - Sets the `DM` that may be used by some `SNES` nonlinear solvers or their underlying preconditioners
5705
5706 Logically Collective
5707
5708 Input Parameters:
5709 + snes - the nonlinear solver context
5710 - dm - the `DM`, cannot be `NULL`
5711
5712 Level: intermediate
5713
5714 Note:
5715 A `DM` can only be used for solving one problem at a time because information about the problem is stored on the `DM`,
5716 even when not using interfaces like `DMSNESSetFunction()`. Use `DMClone()` to get a distinct `DM` when solving different
5717 problems using the same function space.
5718
5719 .seealso: [](ch_snes), `DM`, `SNES`, `SNESGetDM()`, `KSPSetDM()`, `KSPGetDM()`
5720 @*/
SNESSetDM(SNES snes,DM dm)5721 PetscErrorCode SNESSetDM(SNES snes, DM dm)
5722 {
5723 KSP ksp;
5724 DMSNES sdm;
5725
5726 PetscFunctionBegin;
5727 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5728 PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
5729 PetscCall(PetscObjectReference((PetscObject)dm));
5730 if (snes->dm) { /* Move the DMSNES context over to the new DM unless the new DM already has one */
5731 if (snes->dm->dmsnes && !dm->dmsnes) {
5732 PetscCall(DMCopyDMSNES(snes->dm, dm));
5733 PetscCall(DMGetDMSNES(snes->dm, &sdm));
5734 if (sdm->originaldm == snes->dm) sdm->originaldm = dm; /* Grant write privileges to the replacement DM */
5735 }
5736 PetscCall(DMCoarsenHookRemove(snes->dm, DMCoarsenHook_SNESVecSol, DMRestrictHook_SNESVecSol, snes));
5737 PetscCall(DMDestroy(&snes->dm));
5738 }
5739 snes->dm = dm;
5740 snes->dmAuto = PETSC_FALSE;
5741
5742 PetscCall(SNESGetKSP(snes, &ksp));
5743 PetscCall(KSPSetDM(ksp, dm));
5744 PetscCall(KSPSetDMActive(ksp, KSP_DMACTIVE_ALL, PETSC_FALSE));
5745 if (snes->npc) {
5746 PetscCall(SNESSetDM(snes->npc, snes->dm));
5747 PetscCall(SNESSetNPCSide(snes, snes->npcside));
5748 }
5749 PetscFunctionReturn(PETSC_SUCCESS);
5750 }
5751
5752 /*@
5753 SNESGetDM - Gets the `DM` that may be used by some `SNES` nonlinear solvers/preconditioners
5754
5755 Not Collective but `dm` obtained is parallel on `snes`
5756
5757 Input Parameter:
5758 . snes - the `SNES` context
5759
5760 Output Parameter:
5761 . dm - the `DM`
5762
5763 Level: intermediate
5764
5765 .seealso: [](ch_snes), `DM`, `SNES`, `SNESSetDM()`, `KSPSetDM()`, `KSPGetDM()`
5766 @*/
SNESGetDM(SNES snes,DM * dm)5767 PetscErrorCode SNESGetDM(SNES snes, DM *dm)
5768 {
5769 PetscFunctionBegin;
5770 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5771 if (!snes->dm) {
5772 PetscCall(DMShellCreate(PetscObjectComm((PetscObject)snes), &snes->dm));
5773 snes->dmAuto = PETSC_TRUE;
5774 }
5775 *dm = snes->dm;
5776 PetscFunctionReturn(PETSC_SUCCESS);
5777 }
5778
5779 /*@
5780 SNESSetNPC - Sets the nonlinear preconditioner to be used.
5781
5782 Collective
5783
5784 Input Parameters:
5785 + snes - iterative context obtained from `SNESCreate()`
5786 - npc - the `SNES` nonlinear preconditioner object
5787
5788 Options Database Key:
5789 . -npc_snes_type <type> - set the type of the `SNES` to use as the nonlinear preconditioner
5790
5791 Level: developer
5792
5793 Notes:
5794 This is rarely used, rather use `SNESGetNPC()` to retrieve the preconditioner and configure it using the API.
5795
5796 Only some `SNESType` can use a nonlinear preconditioner
5797
5798 .seealso: [](ch_snes), `SNES`, `SNESNGS`, `SNESFAS`, `SNESGetNPC()`, `SNESHasNPC()`
5799 @*/
SNESSetNPC(SNES snes,SNES npc)5800 PetscErrorCode SNESSetNPC(SNES snes, SNES npc)
5801 {
5802 PetscFunctionBegin;
5803 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5804 PetscValidHeaderSpecific(npc, SNES_CLASSID, 2);
5805 PetscCheckSameComm(snes, 1, npc, 2);
5806 PetscCall(PetscObjectReference((PetscObject)npc));
5807 PetscCall(SNESDestroy(&snes->npc));
5808 snes->npc = npc;
5809 PetscFunctionReturn(PETSC_SUCCESS);
5810 }
5811
5812 /*@
5813 SNESGetNPC - Gets a nonlinear preconditioning solver SNES` to be used to precondition the original nonlinear solver.
5814
5815 Not Collective; but any changes to the obtained the `pc` object must be applied collectively
5816
5817 Input Parameter:
5818 . snes - iterative context obtained from `SNESCreate()`
5819
5820 Output Parameter:
5821 . pc - the `SNES` preconditioner context
5822
5823 Options Database Key:
5824 . -npc_snes_type <type> - set the type of the `SNES` to use as the nonlinear preconditioner
5825
5826 Level: advanced
5827
5828 Notes:
5829 If a `SNES` was previously set with `SNESSetNPC()` then that value is returned, otherwise a new `SNES` object is created that will
5830 be used as the nonlinear preconditioner for the current `SNES`.
5831
5832 The (preconditioner) `SNES` returned automatically inherits the same nonlinear function and Jacobian supplied to the original
5833 `SNES`. These may be overwritten if needed.
5834
5835 Use the options database prefixes `-npc_snes`, `-npc_ksp`, etc., to control the configuration of the nonlinear preconditioner
5836
5837 .seealso: [](ch_snes), `SNESSetNPC()`, `SNESHasNPC()`, `SNES`, `SNESCreate()`
5838 @*/
SNESGetNPC(SNES snes,SNES * pc)5839 PetscErrorCode SNESGetNPC(SNES snes, SNES *pc)
5840 {
5841 const char *optionsprefix;
5842
5843 PetscFunctionBegin;
5844 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5845 PetscAssertPointer(pc, 2);
5846 if (!snes->npc) {
5847 PetscCtx ctx;
5848
5849 PetscCall(SNESCreate(PetscObjectComm((PetscObject)snes), &snes->npc));
5850 PetscCall(PetscObjectIncrementTabLevel((PetscObject)snes->npc, (PetscObject)snes, 1));
5851 PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix));
5852 PetscCall(SNESSetOptionsPrefix(snes->npc, optionsprefix));
5853 PetscCall(SNESAppendOptionsPrefix(snes->npc, "npc_"));
5854 if (snes->ops->ctxcompute) {
5855 PetscCall(SNESSetComputeApplicationContext(snes, snes->ops->ctxcompute, snes->ops->ctxdestroy));
5856 } else {
5857 PetscCall(SNESGetApplicationContext(snes, &ctx));
5858 PetscCall(SNESSetApplicationContext(snes->npc, ctx));
5859 }
5860 PetscCall(SNESSetCountersReset(snes->npc, PETSC_FALSE));
5861 }
5862 *pc = snes->npc;
5863 PetscFunctionReturn(PETSC_SUCCESS);
5864 }
5865
5866 /*@
5867 SNESHasNPC - Returns whether a nonlinear preconditioner is associated with the given `SNES`
5868
5869 Not Collective
5870
5871 Input Parameter:
5872 . snes - iterative context obtained from `SNESCreate()`
5873
5874 Output Parameter:
5875 . has_npc - whether the `SNES` has a nonlinear preconditioner or not
5876
5877 Level: developer
5878
5879 .seealso: [](ch_snes), `SNESSetNPC()`, `SNESGetNPC()`
5880 @*/
SNESHasNPC(SNES snes,PetscBool * has_npc)5881 PetscErrorCode SNESHasNPC(SNES snes, PetscBool *has_npc)
5882 {
5883 PetscFunctionBegin;
5884 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5885 PetscAssertPointer(has_npc, 2);
5886 *has_npc = snes->npc ? PETSC_TRUE : PETSC_FALSE;
5887 PetscFunctionReturn(PETSC_SUCCESS);
5888 }
5889
5890 /*@
5891 SNESSetNPCSide - Sets the nonlinear preconditioning side used by the nonlinear preconditioner inside `SNES`.
5892
5893 Logically Collective
5894
5895 Input Parameter:
5896 . snes - iterative context obtained from `SNESCreate()`
5897
5898 Output Parameter:
5899 . side - the preconditioning side, where side is one of
5900 .vb
5901 PC_LEFT - left preconditioning
5902 PC_RIGHT - right preconditioning (default for most nonlinear solvers)
5903 .ve
5904
5905 Options Database Key:
5906 . -snes_npc_side <right,left> - nonlinear preconditioner side
5907
5908 Level: intermediate
5909
5910 Note:
5911 `SNESNRICHARDSON` and `SNESNCG` only support left preconditioning.
5912
5913 .seealso: [](ch_snes), `SNES`, `SNESGetNPC()`, `SNESNRICHARDSON`, `SNESNCG`, `SNESType`, `SNESGetNPCSide()`, `KSPSetPCSide()`, `PC_LEFT`, `PC_RIGHT`, `PCSide`
5914 @*/
SNESSetNPCSide(SNES snes,PCSide side)5915 PetscErrorCode SNESSetNPCSide(SNES snes, PCSide side)
5916 {
5917 PetscFunctionBegin;
5918 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5919 PetscValidLogicalCollectiveEnum(snes, side, 2);
5920 if (side == PC_SIDE_DEFAULT) side = PC_RIGHT;
5921 PetscCheck((side == PC_LEFT) || (side == PC_RIGHT), PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONG, "Only PC_LEFT and PC_RIGHT are supported");
5922 snes->npcside = side;
5923 PetscFunctionReturn(PETSC_SUCCESS);
5924 }
5925
5926 /*@
5927 SNESGetNPCSide - Gets the preconditioning side used by the nonlinear preconditioner inside `SNES`.
5928
5929 Not Collective
5930
5931 Input Parameter:
5932 . snes - iterative context obtained from `SNESCreate()`
5933
5934 Output Parameter:
5935 . side - the preconditioning side, where side is one of
5936 .vb
5937 `PC_LEFT` - left preconditioning
5938 `PC_RIGHT` - right preconditioning (default for most nonlinear solvers)
5939 .ve
5940
5941 Level: intermediate
5942
5943 .seealso: [](ch_snes), `SNES`, `SNESGetNPC()`, `SNESSetNPCSide()`, `KSPGetPCSide()`, `PC_LEFT`, `PC_RIGHT`, `PCSide`
5944 @*/
SNESGetNPCSide(SNES snes,PCSide * side)5945 PetscErrorCode SNESGetNPCSide(SNES snes, PCSide *side)
5946 {
5947 PetscFunctionBegin;
5948 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5949 PetscAssertPointer(side, 2);
5950 *side = snes->npcside;
5951 PetscFunctionReturn(PETSC_SUCCESS);
5952 }
5953
5954 /*@
5955 SNESSetLineSearch - Sets the `SNESLineSearch` to be used for a given `SNES`
5956
5957 Collective
5958
5959 Input Parameters:
5960 + snes - iterative context obtained from `SNESCreate()`
5961 - linesearch - the linesearch object
5962
5963 Level: developer
5964
5965 Note:
5966 This is almost never used, rather one uses `SNESGetLineSearch()` to retrieve the line search and set options on it
5967 to configure it using the API).
5968
5969 .seealso: [](ch_snes), `SNES`, `SNESLineSearch`, `SNESGetLineSearch()`
5970 @*/
SNESSetLineSearch(SNES snes,SNESLineSearch linesearch)5971 PetscErrorCode SNESSetLineSearch(SNES snes, SNESLineSearch linesearch)
5972 {
5973 PetscFunctionBegin;
5974 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
5975 PetscValidHeaderSpecific(linesearch, SNESLINESEARCH_CLASSID, 2);
5976 PetscCheckSameComm(snes, 1, linesearch, 2);
5977 PetscCall(PetscObjectReference((PetscObject)linesearch));
5978 PetscCall(SNESLineSearchDestroy(&snes->linesearch));
5979
5980 snes->linesearch = linesearch;
5981 PetscFunctionReturn(PETSC_SUCCESS);
5982 }
5983