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