xref: /petsc/src/snes/tutorials/ex3.c (revision 4ad8454beace47809662cdae21ee081016eaa39a)
1 static char help[] = "Newton methods to solve u'' + u^{2} = f in parallel.\n\
2 This example employs a user-defined monitoring routine and optionally a user-defined\n\
3 routine to check candidate iterates produced by line search routines.\n\
4 The command line options include:\n\
5   -pre_check_iterates : activate checking of iterates\n\
6   -post_check_iterates : activate checking of iterates\n\
7   -check_tol <tol>: set tolerance for iterate checking\n\
8   -user_precond : activate a (trivial) user-defined preconditioner\n\n";
9 
10 /*
11    Include "petscdm.h" so that we can use data management objects (DMs)
12    Include "petscdmda.h" so that we can use distributed arrays (DMDAs).
13    Include "petscsnes.h" so that we can use SNES solvers.  Note that this
14    file automatically includes:
15      petscsys.h    - base PETSc routines
16      petscvec.h    - vectors
17      petscmat.h    - matrices
18      petscis.h     - index sets
19      petscksp.h    - Krylov subspace methods
20      petscviewer.h - viewers
21      petscpc.h     - preconditioners
22      petscksp.h    - linear solvers
23 */
24 
25 #include <petscdm.h>
26 #include <petscdmda.h>
27 #include <petscsnes.h>
28 
29 /*
30    User-defined routines.
31 */
32 PetscErrorCode FormJacobian(SNES, Vec, Mat, Mat, void *);
33 PetscErrorCode FormFunction(SNES, Vec, Vec, void *);
34 PetscErrorCode FormInitialGuess(Vec);
35 PetscErrorCode Monitor(SNES, PetscInt, PetscReal, void *);
36 PetscErrorCode PreCheck(SNESLineSearch, Vec, Vec, PetscBool *, void *);
37 PetscErrorCode PostCheck(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *);
38 PetscErrorCode PostSetSubKSP(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *);
39 PetscErrorCode MatrixFreePreconditioner(PC, Vec, Vec);
40 
41 /*
42    User-defined application context
43 */
44 typedef struct {
45   DM          da;    /* distributed array */
46   Vec         F;     /* right-hand-side of PDE */
47   PetscMPIInt rank;  /* rank of processor */
48   PetscMPIInt size;  /* size of communicator */
49   PetscReal   h;     /* mesh spacing */
50   PetscBool   sjerr; /* if or not to test jacobian domain error */
51 } ApplicationCtx;
52 
53 /*
54    User-defined context for monitoring
55 */
56 typedef struct {
57   PetscViewer viewer;
58 } MonitorCtx;
59 
60 /*
61    User-defined context for checking candidate iterates that are
62    determined by line search methods
63 */
64 typedef struct {
65   Vec             last_step; /* previous iterate */
66   PetscReal       tolerance; /* tolerance for changes between successive iterates */
67   ApplicationCtx *user;
68 } StepCheckCtx;
69 
70 typedef struct {
71   PetscInt its0; /* num of previous outer KSP iterations */
72 } SetSubKSPCtx;
73 
74 int main(int argc, char **argv)
75 {
76   SNES           snes;       /* SNES context */
77   SNESLineSearch linesearch; /* SNESLineSearch context */
78   Mat            J;          /* Jacobian matrix */
79   ApplicationCtx ctx;        /* user-defined context */
80   Vec            x, r, U, F; /* vectors */
81   MonitorCtx     monP;       /* monitoring context */
82   StepCheckCtx   checkP;     /* step-checking context */
83   SetSubKSPCtx   checkP1;
84   PetscBool      pre_check, post_check, post_setsubksp; /* flag indicating whether we're checking candidate iterates */
85   PetscScalar    xp, *FF, *UU, none = -1.0;
86   PetscInt       its, N = 5, i, maxit, maxf, xs, xm;
87   PetscReal      abstol, rtol, stol, norm;
88   PetscBool      flg, viewinitial = PETSC_FALSE;
89 
90   PetscFunctionBeginUser;
91   PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));
92   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &ctx.rank));
93   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &ctx.size));
94   PetscCall(PetscOptionsGetInt(NULL, NULL, "-n", &N, NULL));
95   ctx.h     = 1.0 / (N - 1);
96   ctx.sjerr = PETSC_FALSE;
97   PetscCall(PetscOptionsGetBool(NULL, NULL, "-test_jacobian_domain_error", &ctx.sjerr, NULL));
98   PetscCall(PetscOptionsGetBool(NULL, NULL, "-view_initial", &viewinitial, NULL));
99 
100   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
101      Create nonlinear solver context
102      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
103 
104   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
105 
106   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
107      Create vector data structures; set function evaluation routine
108      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
109 
110   /*
111      Create distributed array (DMDA) to manage parallel grid and vectors
112   */
113   PetscCall(DMDACreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, N, 1, 1, NULL, &ctx.da));
114   PetscCall(DMSetFromOptions(ctx.da));
115   PetscCall(DMSetUp(ctx.da));
116 
117   /*
118      Extract global and local vectors from DMDA; then duplicate for remaining
119      vectors that are the same types
120   */
121   PetscCall(DMCreateGlobalVector(ctx.da, &x));
122   PetscCall(VecDuplicate(x, &r));
123   PetscCall(VecDuplicate(x, &F));
124   ctx.F = F;
125   PetscCall(VecDuplicate(x, &U));
126 
127   /*
128      Set function evaluation routine and vector.  Whenever the nonlinear
129      solver needs to compute the nonlinear function, it will call this
130      routine.
131       - Note that the final routine argument is the user-defined
132         context that provides application-specific data for the
133         function evaluation routine.
134   */
135   PetscCall(SNESSetFunction(snes, r, FormFunction, &ctx));
136 
137   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
138      Create matrix data structure; set Jacobian evaluation routine
139      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
140 
141   PetscCall(MatCreate(PETSC_COMM_WORLD, &J));
142   PetscCall(MatSetSizes(J, PETSC_DECIDE, PETSC_DECIDE, N, N));
143   PetscCall(MatSetFromOptions(J));
144   PetscCall(MatSeqAIJSetPreallocation(J, 3, NULL));
145   PetscCall(MatMPIAIJSetPreallocation(J, 3, NULL, 3, NULL));
146 
147   /*
148      Set Jacobian matrix data structure and default Jacobian evaluation
149      routine.  Whenever the nonlinear solver needs to compute the
150      Jacobian matrix, it will call this routine.
151       - Note that the final routine argument is the user-defined
152         context that provides application-specific data for the
153         Jacobian evaluation routine.
154   */
155   PetscCall(SNESSetJacobian(snes, J, J, FormJacobian, &ctx));
156 
157   /*
158      Optionally allow user-provided preconditioner
159    */
160   PetscCall(PetscOptionsHasName(NULL, NULL, "-user_precond", &flg));
161   if (flg) {
162     KSP ksp;
163     PC  pc;
164     PetscCall(SNESGetKSP(snes, &ksp));
165     PetscCall(KSPGetPC(ksp, &pc));
166     PetscCall(PCSetType(pc, PCSHELL));
167     PetscCall(PCShellSetApply(pc, MatrixFreePreconditioner));
168   }
169 
170   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
171      Customize nonlinear solver; set runtime options
172    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
173 
174   /*
175      Set an optional user-defined monitoring routine
176   */
177   PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD, 0, 0, 0, 0, 400, 400, &monP.viewer));
178   PetscCall(SNESMonitorSet(snes, Monitor, &monP, 0));
179 
180   /*
181      Set names for some vectors to facilitate monitoring (optional)
182   */
183   PetscCall(PetscObjectSetName((PetscObject)x, "Approximate Solution"));
184   PetscCall(PetscObjectSetName((PetscObject)U, "Exact Solution"));
185 
186   /*
187      Set SNES/KSP/KSP/PC runtime options, e.g.,
188          -snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc>
189   */
190   PetscCall(SNESSetFromOptions(snes));
191 
192   /*
193      Set an optional user-defined routine to check the validity of candidate
194      iterates that are determined by line search methods
195   */
196   PetscCall(SNESGetLineSearch(snes, &linesearch));
197   PetscCall(PetscOptionsHasName(NULL, NULL, "-post_check_iterates", &post_check));
198 
199   if (post_check) {
200     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Activating post step checking routine\n"));
201     PetscCall(SNESLineSearchSetPostCheck(linesearch, PostCheck, &checkP));
202     PetscCall(VecDuplicate(x, &checkP.last_step));
203 
204     checkP.tolerance = 1.0;
205     checkP.user      = &ctx;
206 
207     PetscCall(PetscOptionsGetReal(NULL, NULL, "-check_tol", &checkP.tolerance, NULL));
208   }
209 
210   PetscCall(PetscOptionsHasName(NULL, NULL, "-post_setsubksp", &post_setsubksp));
211   if (post_setsubksp) {
212     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Activating post setsubksp\n"));
213     PetscCall(SNESLineSearchSetPostCheck(linesearch, PostSetSubKSP, &checkP1));
214   }
215 
216   PetscCall(PetscOptionsHasName(NULL, NULL, "-pre_check_iterates", &pre_check));
217   if (pre_check) {
218     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Activating pre step checking routine\n"));
219     PetscCall(SNESLineSearchSetPreCheck(linesearch, PreCheck, &checkP));
220   }
221 
222   /*
223      Print parameters used for convergence testing (optional) ... just
224      to demonstrate this routine; this information is also printed with
225      the option -snes_view
226   */
227   PetscCall(SNESGetTolerances(snes, &abstol, &rtol, &stol, &maxit, &maxf));
228   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "atol=%g, rtol=%g, stol=%g, maxit=%" PetscInt_FMT ", maxf=%" PetscInt_FMT "\n", (double)abstol, (double)rtol, (double)stol, maxit, maxf));
229 
230   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
231      Initialize application:
232      Store right-hand-side of PDE and exact solution
233    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
234 
235   /*
236      Get local grid boundaries (for 1-dimensional DMDA):
237        xs, xm - starting grid index, width of local grid (no ghost points)
238   */
239   PetscCall(DMDAGetCorners(ctx.da, &xs, NULL, NULL, &xm, NULL, NULL));
240 
241   /*
242      Get pointers to vector data
243   */
244   PetscCall(DMDAVecGetArray(ctx.da, F, &FF));
245   PetscCall(DMDAVecGetArray(ctx.da, U, &UU));
246 
247   /*
248      Compute local vector entries
249   */
250   xp = ctx.h * xs;
251   for (i = xs; i < xs + xm; i++) {
252     FF[i] = 6.0 * xp + PetscPowScalar(xp + 1.e-12, 6.0); /* +1.e-12 is to prevent 0^6 */
253     UU[i] = xp * xp * xp;
254     xp += ctx.h;
255   }
256 
257   /*
258      Restore vectors
259   */
260   PetscCall(DMDAVecRestoreArray(ctx.da, F, &FF));
261   PetscCall(DMDAVecRestoreArray(ctx.da, U, &UU));
262   if (viewinitial) {
263     PetscCall(VecView(U, 0));
264     PetscCall(VecView(F, 0));
265   }
266 
267   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
268      Evaluate initial guess; then solve nonlinear system
269    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
270 
271   /*
272      Note: The user should initialize the vector, x, with the initial guess
273      for the nonlinear solver prior to calling SNESSolve().  In particular,
274      to employ an initial guess of zero, the user should explicitly set
275      this vector to zero by calling VecSet().
276   */
277   PetscCall(FormInitialGuess(x));
278   PetscCall(SNESSolve(snes, NULL, x));
279   PetscCall(SNESGetIterationNumber(snes, &its));
280   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Number of SNES iterations = %" PetscInt_FMT "\n", its));
281 
282   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
283      Check solution and clean up
284    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
285 
286   /*
287      Check the error
288   */
289   PetscCall(VecAXPY(x, none, U));
290   PetscCall(VecNorm(x, NORM_2, &norm));
291   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Norm of error %g Iterations %" PetscInt_FMT "\n", (double)norm, its));
292   if (ctx.sjerr) {
293     SNESType snestype;
294     PetscCall(SNESGetType(snes, &snestype));
295     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES Type %s\n", snestype));
296   }
297 
298   /*
299      Free work space.  All PETSc objects should be destroyed when they
300      are no longer needed.
301   */
302   PetscCall(PetscViewerDestroy(&monP.viewer));
303   if (post_check) PetscCall(VecDestroy(&checkP.last_step));
304   PetscCall(VecDestroy(&x));
305   PetscCall(VecDestroy(&r));
306   PetscCall(VecDestroy(&U));
307   PetscCall(VecDestroy(&F));
308   PetscCall(MatDestroy(&J));
309   PetscCall(SNESDestroy(&snes));
310   PetscCall(DMDestroy(&ctx.da));
311   PetscCall(PetscFinalize());
312   return 0;
313 }
314 
315 /* ------------------------------------------------------------------- */
316 /*
317    FormInitialGuess - Computes initial guess.
318 
319    Input/Output Parameter:
320 .  x - the solution vector
321 */
322 PetscErrorCode FormInitialGuess(Vec x)
323 {
324   PetscScalar pfive = .50;
325 
326   PetscFunctionBeginUser;
327   PetscCall(VecSet(x, pfive));
328   PetscFunctionReturn(PETSC_SUCCESS);
329 }
330 
331 /* ------------------------------------------------------------------- */
332 /*
333    FormFunction - Evaluates nonlinear function, F(x).
334 
335    Input Parameters:
336 .  snes - the SNES context
337 .  x - input vector
338 .  ctx - optional user-defined context, as set by SNESSetFunction()
339 
340    Output Parameter:
341 .  f - function vector
342 
343    Note:
344    The user-defined context can contain any application-specific
345    data needed for the function evaluation.
346 */
347 PetscErrorCode FormFunction(SNES snes, Vec x, Vec f, void *ctx)
348 {
349   ApplicationCtx    *user = (ApplicationCtx *)ctx;
350   DM                 da   = user->da;
351   PetscScalar       *ff, d;
352   const PetscScalar *xx, *FF;
353   PetscInt           i, M, xs, xm;
354   Vec                xlocal;
355 
356   PetscFunctionBeginUser;
357   PetscCall(DMGetLocalVector(da, &xlocal));
358   /*
359      Scatter ghost points to local vector, using the 2-step process
360         DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
361      By placing code between these two statements, computations can
362      be done while messages are in transition.
363   */
364   PetscCall(DMGlobalToLocalBegin(da, x, INSERT_VALUES, xlocal));
365   PetscCall(DMGlobalToLocalEnd(da, x, INSERT_VALUES, xlocal));
366 
367   /*
368      Get pointers to vector data.
369        - The vector xlocal includes ghost point; the vectors x and f do
370          NOT include ghost points.
371        - Using DMDAVecGetArray() allows accessing the values using global ordering
372   */
373   PetscCall(DMDAVecGetArrayRead(da, xlocal, (void *)&xx));
374   PetscCall(DMDAVecGetArray(da, f, &ff));
375   PetscCall(DMDAVecGetArrayRead(da, user->F, (void *)&FF));
376 
377   /*
378      Get local grid boundaries (for 1-dimensional DMDA):
379        xs, xm  - starting grid index, width of local grid (no ghost points)
380   */
381   PetscCall(DMDAGetCorners(da, &xs, NULL, NULL, &xm, NULL, NULL));
382   PetscCall(DMDAGetInfo(da, NULL, &M, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
383 
384   /*
385      Set function values for boundary points; define local interior grid point range:
386         xsi - starting interior grid index
387         xei - ending interior grid index
388   */
389   if (xs == 0) { /* left boundary */
390     ff[0] = xx[0];
391     xs++;
392     xm--;
393   }
394   if (xs + xm == M) { /* right boundary */
395     ff[xs + xm - 1] = xx[xs + xm - 1] - 1.0;
396     xm--;
397   }
398 
399   /*
400      Compute function over locally owned part of the grid (interior points only)
401   */
402   d = 1.0 / (user->h * user->h);
403   for (i = xs; i < xs + xm; i++) ff[i] = d * (xx[i - 1] - 2.0 * xx[i] + xx[i + 1]) + xx[i] * xx[i] - FF[i];
404 
405   /*
406      Restore vectors
407   */
408   PetscCall(DMDAVecRestoreArrayRead(da, xlocal, (void *)&xx));
409   PetscCall(DMDAVecRestoreArray(da, f, &ff));
410   PetscCall(DMDAVecRestoreArrayRead(da, user->F, (void *)&FF));
411   PetscCall(DMRestoreLocalVector(da, &xlocal));
412   PetscFunctionReturn(PETSC_SUCCESS);
413 }
414 
415 /* ------------------------------------------------------------------- */
416 /*
417    FormJacobian - Evaluates Jacobian matrix.
418 
419    Input Parameters:
420 .  snes - the SNES context
421 .  x - input vector
422 .  dummy - optional user-defined context (not used here)
423 
424    Output Parameters:
425 .  jac - Jacobian matrix
426 .  B - optionally different preconditioning matrix
427 .  flag - flag indicating matrix structure
428 */
429 PetscErrorCode FormJacobian(SNES snes, Vec x, Mat jac, Mat B, void *ctx)
430 {
431   ApplicationCtx *user = (ApplicationCtx *)ctx;
432   PetscScalar    *xx, d, A[3];
433   PetscInt        i, j[3], M, xs, xm;
434   DM              da = user->da;
435 
436   PetscFunctionBeginUser;
437   if (user->sjerr) {
438     PetscCall(SNESSetJacobianDomainError(snes));
439     PetscFunctionReturn(PETSC_SUCCESS);
440   }
441   /*
442      Get pointer to vector data
443   */
444   PetscCall(DMDAVecGetArrayRead(da, x, &xx));
445   PetscCall(DMDAGetCorners(da, &xs, NULL, NULL, &xm, NULL, NULL));
446 
447   /*
448     Get range of locally owned matrix
449   */
450   PetscCall(DMDAGetInfo(da, NULL, &M, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
451 
452   /*
453      Determine starting and ending local indices for interior grid points.
454      Set Jacobian entries for boundary points.
455   */
456 
457   if (xs == 0) { /* left boundary */
458     i    = 0;
459     A[0] = 1.0;
460 
461     PetscCall(MatSetValues(jac, 1, &i, 1, &i, A, INSERT_VALUES));
462     xs++;
463     xm--;
464   }
465   if (xs + xm == M) { /* right boundary */
466     i    = M - 1;
467     A[0] = 1.0;
468     PetscCall(MatSetValues(jac, 1, &i, 1, &i, A, INSERT_VALUES));
469     xm--;
470   }
471 
472   /*
473      Interior grid points
474       - Note that in this case we set all elements for a particular
475         row at once.
476   */
477   d = 1.0 / (user->h * user->h);
478   for (i = xs; i < xs + xm; i++) {
479     j[0] = i - 1;
480     j[1] = i;
481     j[2] = i + 1;
482     A[0] = A[2] = d;
483     A[1]        = -2.0 * d + 2.0 * xx[i];
484     PetscCall(MatSetValues(jac, 1, &i, 3, j, A, INSERT_VALUES));
485   }
486 
487   /*
488      Assemble matrix, using the 2-step process:
489        MatAssemblyBegin(), MatAssemblyEnd().
490      By placing code between these two statements, computations can be
491      done while messages are in transition.
492 
493      Also, restore vector.
494   */
495 
496   PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY));
497   PetscCall(DMDAVecRestoreArrayRead(da, x, &xx));
498   PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY));
499   PetscFunctionReturn(PETSC_SUCCESS);
500 }
501 
502 /* ------------------------------------------------------------------- */
503 /*
504    Monitor - Optional user-defined monitoring routine that views the
505    current iterate with an x-window plot. Set by SNESMonitorSet().
506 
507    Input Parameters:
508    snes - the SNES context
509    its - iteration number
510    norm - 2-norm function value (may be estimated)
511    ctx - optional user-defined context for private data for the
512          monitor routine, as set by SNESMonitorSet()
513 
514    Note:
515    See the manpage for PetscViewerDrawOpen() for useful runtime options,
516    such as -nox to deactivate all x-window output.
517  */
518 PetscErrorCode Monitor(SNES snes, PetscInt its, PetscReal fnorm, void *ctx)
519 {
520   MonitorCtx *monP = (MonitorCtx *)ctx;
521   Vec         x;
522 
523   PetscFunctionBeginUser;
524   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "iter = %" PetscInt_FMT ",SNES Function norm %g\n", its, (double)fnorm));
525   PetscCall(SNESGetSolution(snes, &x));
526   PetscCall(VecView(x, monP->viewer));
527   PetscFunctionReturn(PETSC_SUCCESS);
528 }
529 
530 /* ------------------------------------------------------------------- */
531 /*
532    PreCheck - Optional user-defined routine that checks the validity of
533    candidate steps of a line search method.  Set by SNESLineSearchSetPreCheck().
534 
535    Input Parameters:
536    snes - the SNES context
537    xcurrent - current solution
538    y - search direction and length
539 
540    Output Parameters:
541    y         - proposed step (search direction and length) (possibly changed)
542    changed_y - tells if the step has changed or not
543  */
544 PetscErrorCode PreCheck(SNESLineSearch linesearch, Vec xcurrent, Vec y, PetscBool *changed_y, void *ctx)
545 {
546   PetscFunctionBeginUser;
547   *changed_y = PETSC_FALSE;
548   PetscFunctionReturn(PETSC_SUCCESS);
549 }
550 
551 /* ------------------------------------------------------------------- */
552 /*
553    PostCheck - Optional user-defined routine that checks the validity of
554    candidate steps of a line search method.  Set by SNESLineSearchSetPostCheck().
555 
556    Input Parameters:
557    snes - the SNES context
558    ctx  - optional user-defined context for private data for the
559           monitor routine, as set by SNESLineSearchSetPostCheck()
560    xcurrent - current solution
561    y - search direction and length
562    x    - the new candidate iterate
563 
564    Output Parameters:
565    y    - proposed step (search direction and length) (possibly changed)
566    x    - current iterate (possibly modified)
567 
568  */
569 PetscErrorCode PostCheck(SNESLineSearch linesearch, Vec xcurrent, Vec y, Vec x, PetscBool *changed_y, PetscBool *changed_x, void *ctx)
570 {
571   PetscInt        i, iter, xs, xm;
572   StepCheckCtx   *check;
573   ApplicationCtx *user;
574   PetscScalar    *xa, *xa_last, tmp;
575   PetscReal       rdiff;
576   DM              da;
577   SNES            snes;
578 
579   PetscFunctionBeginUser;
580   *changed_x = PETSC_FALSE;
581   *changed_y = PETSC_FALSE;
582 
583   PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
584   check = (StepCheckCtx *)ctx;
585   user  = check->user;
586   PetscCall(SNESGetIterationNumber(snes, &iter));
587 
588   /* iteration 1 indicates we are working on the second iteration */
589   if (iter > 0) {
590     da = user->da;
591     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Checking candidate step at iteration %" PetscInt_FMT " with tolerance %g\n", iter, (double)check->tolerance));
592 
593     /* Access local array data */
594     PetscCall(DMDAVecGetArray(da, check->last_step, &xa_last));
595     PetscCall(DMDAVecGetArray(da, x, &xa));
596     PetscCall(DMDAGetCorners(da, &xs, NULL, NULL, &xm, NULL, NULL));
597 
598     /*
599        If we fail the user-defined check for validity of the candidate iterate,
600        then modify the iterate as we like.  (Note that the particular modification
601        below is intended simply to demonstrate how to manipulate this data, not
602        as a meaningful or appropriate choice.)
603     */
604     for (i = xs; i < xs + xm; i++) {
605       if (!PetscAbsScalar(xa[i])) rdiff = 2 * check->tolerance;
606       else rdiff = PetscAbsScalar((xa[i] - xa_last[i]) / xa[i]);
607       if (rdiff > check->tolerance) {
608         tmp        = xa[i];
609         xa[i]      = .5 * (xa[i] + xa_last[i]);
610         *changed_x = PETSC_TRUE;
611         PetscCall(PetscPrintf(PETSC_COMM_WORLD, "  Altering entry %" PetscInt_FMT ": x=%g, x_last=%g, diff=%g, x_new=%g\n", i, (double)PetscAbsScalar(tmp), (double)PetscAbsScalar(xa_last[i]), (double)rdiff, (double)PetscAbsScalar(xa[i])));
612       }
613     }
614     PetscCall(DMDAVecRestoreArray(da, check->last_step, &xa_last));
615     PetscCall(DMDAVecRestoreArray(da, x, &xa));
616   }
617   PetscCall(VecCopy(x, check->last_step));
618   PetscFunctionReturn(PETSC_SUCCESS);
619 }
620 
621 /* ------------------------------------------------------------------- */
622 /*
623    PostSetSubKSP - Optional user-defined routine that reset SubKSP options when hierarchical bjacobi PC is used
624    e.g,
625      mpiexec -n 8 ./ex3 -nox -n 10000 -ksp_type fgmres -pc_type bjacobi -pc_bjacobi_blocks 4 -sub_ksp_type gmres -sub_ksp_max_it 3 -post_setsubksp -sub_ksp_rtol 1.e-16
626    Set by SNESLineSearchSetPostCheck().
627 
628    Input Parameters:
629    linesearch - the LineSearch context
630    xcurrent - current solution
631    y - search direction and length
632    x    - the new candidate iterate
633 
634    Output Parameters:
635    y    - proposed step (search direction and length) (possibly changed)
636    x    - current iterate (possibly modified)
637 
638  */
639 PetscErrorCode PostSetSubKSP(SNESLineSearch linesearch, Vec xcurrent, Vec y, Vec x, PetscBool *changed_y, PetscBool *changed_x, void *ctx)
640 {
641   SetSubKSPCtx *check;
642   PetscInt      iter, its, sub_its, maxit;
643   KSP           ksp, sub_ksp, *sub_ksps;
644   PC            pc;
645   PetscReal     ksp_ratio;
646   SNES          snes;
647 
648   PetscFunctionBeginUser;
649   PetscCall(SNESLineSearchGetSNES(linesearch, &snes));
650   check = (SetSubKSPCtx *)ctx;
651   PetscCall(SNESGetIterationNumber(snes, &iter));
652   PetscCall(SNESGetKSP(snes, &ksp));
653   PetscCall(KSPGetPC(ksp, &pc));
654   PetscCall(PCBJacobiGetSubKSP(pc, NULL, NULL, &sub_ksps));
655   sub_ksp = sub_ksps[0];
656   PetscCall(KSPGetIterationNumber(ksp, &its));         /* outer KSP iteration number */
657   PetscCall(KSPGetIterationNumber(sub_ksp, &sub_its)); /* inner KSP iteration number */
658 
659   if (iter) {
660     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "    ...PostCheck snes iteration %" PetscInt_FMT ", ksp_it %" PetscInt_FMT " %" PetscInt_FMT ", subksp_it %" PetscInt_FMT "\n", iter, check->its0, its, sub_its));
661     ksp_ratio = ((PetscReal)(its)) / check->its0;
662     maxit     = (PetscInt)(ksp_ratio * sub_its + 0.5);
663     if (maxit < 2) maxit = 2;
664     PetscCall(KSPSetTolerances(sub_ksp, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, maxit));
665     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "    ...ksp_ratio %g, new maxit %" PetscInt_FMT "\n\n", (double)ksp_ratio, maxit));
666   }
667   check->its0 = its; /* save current outer KSP iteration number */
668   PetscFunctionReturn(PETSC_SUCCESS);
669 }
670 
671 /* ------------------------------------------------------------------- */
672 /*
673    MatrixFreePreconditioner - This routine demonstrates the use of a
674    user-provided preconditioner.  This code implements just the null
675    preconditioner, which of course is not recommended for general use.
676 
677    Input Parameters:
678 +  pc - preconditioner
679 -  x - input vector
680 
681    Output Parameter:
682 .  y - preconditioned vector
683 */
684 PetscErrorCode MatrixFreePreconditioner(PC pc, Vec x, Vec y)
685 {
686   PetscFunctionBeginUser;
687   PetscCall(VecCopy(x, y));
688   PetscFunctionReturn(PETSC_SUCCESS);
689 }
690 
691 /*TEST
692 
693    test:
694       args: -nox -snes_monitor_cancel -snes_monitor_short -ksp_gmres_cgs_refinement_type refine_always
695 
696    test:
697       suffix: 2
698       nsize: 3
699       args: -nox -pc_type asm -mat_type mpiaij -snes_monitor_cancel -snes_monitor_short -ksp_gmres_cgs_refinement_type refine_always
700 
701    test:
702       suffix: 3
703       nsize: 2
704       args: -nox -snes_monitor_cancel -snes_monitor_short -ksp_gmres_cgs_refinement_type refine_always
705 
706    test:
707       suffix: 4
708       args: -nox -pre_check_iterates -post_check_iterates
709 
710    test:
711       suffix: 5
712       requires: double !complex !single
713       nsize: 2
714       args: -nox -snes_test_jacobian -snes_test_jacobian_view
715 
716    test:
717       suffix: 6
718       requires: double !complex !single
719       nsize: 4
720       args: -test_jacobian_domain_error -snes_converged_reason -snes_check_jacobian_domain_error 1
721 
722    test:
723       suffix: 7
724       requires: double !complex !single
725       nsize: 4
726       args: -test_jacobian_domain_error -snes_converged_reason -snes_type newtontr -snes_check_jacobian_domain_error 1
727 
728    test:
729       suffix: 8
730       requires: double !complex !single
731       nsize: 4
732       args: -test_jacobian_domain_error -snes_converged_reason -snes_type vinewtonrsls -snes_check_jacobian_domain_error 1
733 
734    test:
735       suffix: 9
736       requires: double !complex !single
737       nsize: 4
738       args: -test_jacobian_domain_error -snes_converged_reason -snes_type vinewtonssls -snes_check_jacobian_domain_error 1
739 
740    test:
741       suffix: 10
742       requires: double !complex !single
743       nsize: 4
744       args: -test_jacobian_domain_error -snes_converged_reason -snes_type qn -snes_qn_scale_type jacobian -snes_check_jacobian_domain_error 1
745 
746    test:
747       suffix: 11
748       requires: double !complex !single
749       nsize: 4
750       args: -test_jacobian_domain_error -snes_converged_reason -snes_type ms -snes_ms_type m62 -snes_ms_damping 0.9 -snes_check_jacobian_domain_error 1
751 
752    test:
753       suffix: 12
754       args: -view_initial
755       filter: grep -v "type:"
756 
757    test:
758       suffix: 13
759       requires: double !complex !single
760       nsize: 4
761       args: -test_jacobian_domain_error -snes_converged_reason -snes_type newtontrdc -snes_check_jacobian_domain_error 1
762 
763 TEST*/
764