Actual source code: ex1.c

  1: static char help[] = "Solves the nonlinear system, the Bratu (SFI - solid fuel ignition) problem in a 2D rectangular domain.\n\
  2: This example also illustrates the use of matrix coloring.  Runtime options include:\n\
  3:   -par <parameter>, where <parameter> indicates the problem's nonlinearity\n\
  4:      problem SFI:  <parameter> = Bratu parameter (0 <= par <= 6.81)\n\
  5:   -mx <xg>, where <xg> = number of grid points in the x-direction\n\
  6:   -my <yg>, where <yg> = number of grid points in the y-direction\n\n";

  8: /*

 10:     Solid Fuel Ignition (SFI) problem.  This problem is modeled by
 11:     the partial differential equation

 13:             -Laplacian u - lambda*exp(u) = 0,  0 < x,y < 1,

 15:     with boundary conditions

 17:              u = 0  for  x = 0, x = 1, y = 0, y = 1.

 19:     A finite difference approximation with the usual 5-point stencil
 20:     is used to discretize the boundary value problem to obtain a nonlinear
 21:     system of equations.

 23:     The parallel version of this code is snes/tutorials/ex5.c

 25: */

 27: /*
 28:    Include "petscsnes.h" so that we can use SNES solvers.  Note that
 29:    this file automatically includes:
 30:      petscsys.h       - base PETSc routines   petscvec.h - vectors
 31:      petscmat.h - matrices
 32:      petscis.h     - index sets            petscksp.h - Krylov subspace methods
 33:      petscviewer.h - viewers               petscpc.h  - preconditioners
 34:      petscksp.h   - linear solvers
 35: */

 37: #include <petscsnes.h>

 39: /*
 40:    User-defined application context - contains data needed by the
 41:    application-provided call-back routines, FormJacobian() and
 42:    FormFunction().
 43: */
 44: typedef struct {
 45:   PetscReal param; /* test problem parameter */
 46:   PetscInt  mx;    /* Discretization in x-direction */
 47:   PetscInt  my;    /* Discretization in y-direction */
 48: } AppCtx;

 50: /*
 51:    User-defined routines
 52: */
 53: extern PetscErrorCode FormJacobian(SNES, Vec, Mat, Mat, void *);
 54: extern PetscErrorCode FormFunction(SNES, Vec, Vec, void *);
 55: extern PetscErrorCode FormInitialGuess(AppCtx *, Vec);
 56: extern PetscErrorCode ConvergenceTest(KSP, PetscInt, PetscReal, KSPConvergedReason *, void *);
 57: extern PetscErrorCode ConvergenceDestroy(void *);
 58: extern PetscErrorCode postcheck(SNES, Vec, Vec, Vec, PetscBool *, PetscBool *, void *);

 60: int main(int argc, char **argv)
 61: {
 62:   SNES          snes; /* nonlinear solver context */
 63:   Vec           x, r; /* solution, residual vectors */
 64:   Mat           J;    /* Jacobian matrix */
 65:   AppCtx        user; /* user-defined application context */
 66:   PetscInt      i, its, N, hist_its[50];
 67:   PetscMPIInt   size;
 68:   PetscReal     bratu_lambda_max = 6.81, bratu_lambda_min = 0., history[50];
 69:   MatFDColoring fdcoloring;
 70:   PetscBool     matrix_free = PETSC_FALSE, flg, fd_coloring = PETSC_FALSE, use_convergence_test = PETSC_FALSE, pc = PETSC_FALSE, prunejacobian = PETSC_FALSE, null_appctx = PETSC_TRUE;
 71:   KSP           ksp;
 72:   PetscInt     *testarray;

 74:   PetscFunctionBeginUser;
 75:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
 76:   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
 77:   PetscCheck(size == 1, PETSC_COMM_WORLD, PETSC_ERR_WRONG_MPI_SIZE, "This is a uniprocessor example only!");

 79:   /*
 80:      Initialize problem parameters
 81:   */
 82:   user.mx    = 4;
 83:   user.my    = 4;
 84:   user.param = 6.0;
 85:   PetscCall(PetscOptionsGetInt(NULL, NULL, "-mx", &user.mx, NULL));
 86:   PetscCall(PetscOptionsGetInt(NULL, NULL, "-my", &user.my, NULL));
 87:   PetscCall(PetscOptionsGetReal(NULL, NULL, "-par", &user.param, NULL));
 88:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-pc", &pc, NULL));
 89:   PetscCheck(user.param < bratu_lambda_max && user.param > bratu_lambda_min, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Lambda is out of range");
 90:   N = user.mx * user.my;
 91:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_convergence_test", &use_convergence_test, NULL));
 92:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-prune_jacobian", &prunejacobian, NULL));
 93:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-null_appctx", &null_appctx, NULL));

 95:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 96:      Create nonlinear solver context
 97:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 99:   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));

101:   if (pc) {
102:     PetscCall(SNESSetType(snes, SNESNEWTONTR));
103:     PetscCall(SNESNewtonTRSetPostCheck(snes, postcheck, NULL));
104:   }

106:   /* Test application context handling from Python */
107:   if (!null_appctx) { PetscCall(SNESSetApplicationContext(snes, (void *)&user)); }

109:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
110:      Create vector data structures; set function evaluation routine
111:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

113:   PetscCall(VecCreate(PETSC_COMM_WORLD, &x));
114:   PetscCall(VecSetSizes(x, PETSC_DECIDE, N));
115:   PetscCall(VecSetFromOptions(x));
116:   PetscCall(VecDuplicate(x, &r));

118:   /*
119:      Set function evaluation routine and vector.  Whenever the nonlinear
120:      solver needs to evaluate the nonlinear function, it will call this
121:      routine.
122:       - Note that the final routine argument is the user-defined
123:         context that provides application-specific data for the
124:         function evaluation routine.
125:   */
126:   PetscCall(SNESSetFunction(snes, r, FormFunction, (void *)&user));

128:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
129:      Create matrix data structure; set Jacobian evaluation routine
130:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

132:   /*
133:      Create matrix. Here we only approximately preallocate storage space
134:      for the Jacobian.  See the users manual for a discussion of better
135:      techniques for preallocating matrix memory.
136:   */
137:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-snes_mf", &matrix_free, NULL));
138:   if (!matrix_free) {
139:     PetscBool matrix_free_operator = PETSC_FALSE;
140:     PetscCall(PetscOptionsGetBool(NULL, NULL, "-snes_mf_operator", &matrix_free_operator, NULL));
141:     if (matrix_free_operator) matrix_free = PETSC_FALSE;
142:   }
143:   if (!matrix_free) PetscCall(MatCreateSeqAIJ(PETSC_COMM_WORLD, N, N, 5, NULL, &J));

145:   /*
146:      This option will cause the Jacobian to be computed via finite differences
147:     efficiently using a coloring of the columns of the matrix.
148:   */
149:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-snes_fd_coloring", &fd_coloring, NULL));
150:   PetscCheck(!matrix_free || !fd_coloring, PETSC_COMM_WORLD, PETSC_ERR_ARG_INCOMP, "Use only one of -snes_mf, -snes_fd_coloring options! You can do -snes_mf_operator -snes_fd_coloring");

152:   if (fd_coloring) {
153:     ISColoring  iscoloring;
154:     MatColoring mc;
155:     if (prunejacobian) {
156:       /* Initialize x with random nonzero values so that the nonzeros in the Jacobian
157:          can better reflect the sparsity structure of the Jacobian. */
158:       PetscRandom rctx;
159:       PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rctx));
160:       PetscCall(PetscRandomSetInterval(rctx, 1.0, 2.0));
161:       PetscCall(VecSetRandom(x, rctx));
162:       PetscCall(PetscRandomDestroy(&rctx));
163:     }

165:     /*
166:       This initializes the nonzero structure of the Jacobian. This is artificial
167:       because clearly if we had a routine to compute the Jacobian we won't need
168:       to use finite differences.
169:     */
170:     PetscCall(FormJacobian(snes, x, J, J, &user));

172:     /*
173:        Color the matrix, i.e. determine groups of columns that share no common
174:       rows. These columns in the Jacobian can all be computed simultaneously.
175:     */
176:     PetscCall(MatColoringCreate(J, &mc));
177:     PetscCall(MatColoringSetType(mc, MATCOLORINGSL));
178:     PetscCall(MatColoringSetFromOptions(mc));
179:     PetscCall(MatColoringApply(mc, &iscoloring));
180:     PetscCall(MatColoringDestroy(&mc));
181:     /*
182:        Create the data structure that SNESComputeJacobianDefaultColor() uses
183:        to compute the actual Jacobians via finite differences.
184:     */
185:     PetscCall(MatFDColoringCreate(J, iscoloring, &fdcoloring));
186:     PetscCall(MatFDColoringSetFunction(fdcoloring, (PetscErrorCode (*)(void))FormFunction, &user));
187:     PetscCall(MatFDColoringSetFromOptions(fdcoloring));
188:     PetscCall(MatFDColoringSetUp(J, iscoloring, fdcoloring));
189:     /*
190:         Tell SNES to use the routine SNESComputeJacobianDefaultColor()
191:       to compute Jacobians.
192:     */
193:     PetscCall(SNESSetJacobian(snes, J, J, SNESComputeJacobianDefaultColor, fdcoloring));
194:     PetscCall(ISColoringDestroy(&iscoloring));
195:     if (prunejacobian) PetscCall(SNESPruneJacobianColor(snes, J, J));
196:   }
197:   /*
198:      Set Jacobian matrix data structure and default Jacobian evaluation
199:      routine.  Whenever the nonlinear solver needs to compute the
200:      Jacobian matrix, it will call this routine.
201:       - Note that the final routine argument is the user-defined
202:         context that provides application-specific data for the
203:         Jacobian evaluation routine.
204:       - The user can override with:
205:          -snes_fd : default finite differencing approximation of Jacobian
206:          -snes_mf : matrix-free Newton-Krylov method with no preconditioning
207:                     (unless user explicitly sets preconditioner)
208:          -snes_mf_operator : form preconditioning matrix as set by the user,
209:                              but use matrix-free approx for Jacobian-vector
210:                              products within Newton-Krylov method
211:   */
212:   else if (!matrix_free) {
213:     PetscCall(SNESSetJacobian(snes, J, J, FormJacobian, (void *)&user));
214:   }

216:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
217:      Customize nonlinear solver; set runtime options
218:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

220:   /*
221:      Set runtime options (e.g., -snes_monitor -snes_rtol <rtol> -ksp_type <type>)
222:   */
223:   PetscCall(SNESSetFromOptions(snes));

225:   /*
226:      Set array that saves the function norms.  This array is intended
227:      when the user wants to save the convergence history for later use
228:      rather than just to view the function norms via -snes_monitor.
229:   */
230:   PetscCall(SNESSetConvergenceHistory(snes, history, hist_its, 50, PETSC_TRUE));

232:   /*
233:       Add a user provided convergence test; this is to test that SNESNEWTONTR properly calls the
234:       user provided test before the specialized test. The convergence context is just an array to
235:       test that it gets properly freed at the end
236:   */
237:   if (use_convergence_test) {
238:     PetscCall(SNESGetKSP(snes, &ksp));
239:     PetscCall(PetscMalloc1(5, &testarray));
240:     PetscCall(KSPSetConvergenceTest(ksp, ConvergenceTest, testarray, ConvergenceDestroy));
241:   }

243:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
244:      Evaluate initial guess; then solve nonlinear system
245:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
246:   /*
247:      Note: The user should initialize the vector, x, with the initial guess
248:      for the nonlinear solver prior to calling SNESSolve().  In particular,
249:      to employ an initial guess of zero, the user should explicitly set
250:      this vector to zero by calling VecSet().
251:   */
252:   PetscCall(FormInitialGuess(&user, x));
253:   PetscCall(SNESSolve(snes, NULL, x));
254:   PetscCall(SNESGetIterationNumber(snes, &its));
255:   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Number of SNES iterations = %" PetscInt_FMT "\n", its));

257:   /*
258:      Print the convergence history.  This is intended just to demonstrate
259:      use of the data attained via SNESSetConvergenceHistory().
260:   */
261:   PetscCall(PetscOptionsHasName(NULL, NULL, "-print_history", &flg));
262:   if (flg) {
263:     for (i = 0; i < its + 1; i++) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "iteration %" PetscInt_FMT ": Linear iterations %" PetscInt_FMT " Function norm = %g\n", i, hist_its[i], (double)history[i]));
264:   }

266:   /* Test NewtonTR API */
267:   PetscCall(SNESNewtonTRSetTolerances(snes, 1.0, 2.0, 3.0));
268:   PetscCall(SNESNewtonTRSetUpdateParameters(snes, 4.0, 5.0, 6.0, 7.0, 8.0));
269:   PetscCall(PetscObjectTypeCompare((PetscObject)snes, SNESNEWTONTR, &flg));
270:   if (flg) {
271:     PetscReal tmp[5];

273:     PetscCall(SNESNewtonTRGetTolerances(snes, &tmp[0], &tmp[1], &tmp[2]));
274:     PetscCheck(tmp[0] == 1.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Wrong value");
275:     PetscCheck(tmp[1] == 2.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Wrong value");
276:     PetscCheck(tmp[2] == 3.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Wrong value");
277:     PetscCall(SNESNewtonTRGetUpdateParameters(snes, &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4]));
278:     PetscCheck(tmp[0] == 4.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Wrong value");
279:     PetscCheck(tmp[1] == 5.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Wrong value");
280:     PetscCheck(tmp[2] == 6.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Wrong value");
281:     PetscCheck(tmp[3] == 7.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Wrong value");
282:     PetscCheck(tmp[4] == 8.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Wrong value");
283:   }

285:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
286:      Free work space.  All PETSc objects should be destroyed when they
287:      are no longer needed.
288:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

290:   if (!matrix_free) PetscCall(MatDestroy(&J));
291:   if (fd_coloring) PetscCall(MatFDColoringDestroy(&fdcoloring));
292:   PetscCall(VecDestroy(&x));
293:   PetscCall(VecDestroy(&r));
294:   PetscCall(SNESDestroy(&snes));
295:   PetscCall(PetscFinalize());
296:   return 0;
297: }

299: /*
300:    FormInitialGuess - Forms initial approximation.

302:    Input Parameters:
303:    user - user-defined application context
304:    X - vector

306:    Output Parameter:
307:    X - vector
308:  */
309: PetscErrorCode FormInitialGuess(AppCtx *user, Vec X)
310: {
311:   PetscInt     i, j, row, mx, my;
312:   PetscReal    lambda, temp1, temp, hx, hy;
313:   PetscScalar *x;

315:   PetscFunctionBeginUser;
316:   mx     = user->mx;
317:   my     = user->my;
318:   lambda = user->param;

320:   hx = 1.0 / (PetscReal)(mx - 1);
321:   hy = 1.0 / (PetscReal)(my - 1);

323:   /*
324:      Get a pointer to vector data.
325:        - For default PETSc vectors, VecGetArray() returns a pointer to
326:          the data array.  Otherwise, the routine is implementation dependent.
327:        - You MUST call VecRestoreArray() when you no longer need access to
328:          the array.
329:   */
330:   PetscCall(VecGetArray(X, &x));
331:   temp1 = lambda / (lambda + 1.0);
332:   for (j = 0; j < my; j++) {
333:     temp = (PetscReal)(PetscMin(j, my - j - 1)) * hy;
334:     for (i = 0; i < mx; i++) {
335:       row = i + j * mx;
336:       if (i == 0 || j == 0 || i == mx - 1 || j == my - 1) {
337:         x[row] = 0.0;
338:         continue;
339:       }
340:       x[row] = temp1 * PetscSqrtReal(PetscMin((PetscReal)(PetscMin(i, mx - i - 1)) * hx, temp));
341:     }
342:   }

344:   /*
345:      Restore vector
346:   */
347:   PetscCall(VecRestoreArray(X, &x));
348:   PetscFunctionReturn(PETSC_SUCCESS);
349: }

351: /*
352:    FormFunction - Evaluates nonlinear function, F(x).

354:    Input Parameters:
355: .  snes - the SNES context
356: .  X - input vector
357: .  ptr - optional user-defined context, as set by SNESSetFunction()

359:    Output Parameter:
360: .  F - function vector
361:  */
362: PetscErrorCode FormFunction(SNES snes, Vec X, Vec F, void *ptr)
363: {
364:   AppCtx            *user = (AppCtx *)ptr;
365:   PetscInt           i, j, row, mx, my;
366:   PetscReal          two = 2.0, one = 1.0, lambda, hx, hy, hxdhy, hydhx;
367:   PetscScalar        ut, ub, ul, ur, u, uxx, uyy, sc, *f;
368:   const PetscScalar *x;

370:   PetscFunctionBeginUser;
371:   mx     = user->mx;
372:   my     = user->my;
373:   lambda = user->param;
374:   hx     = one / (PetscReal)(mx - 1);
375:   hy     = one / (PetscReal)(my - 1);
376:   sc     = hx * hy;
377:   hxdhy  = hx / hy;
378:   hydhx  = hy / hx;

380:   /*
381:      Get pointers to vector data
382:   */
383:   PetscCall(VecGetArrayRead(X, &x));
384:   PetscCall(VecGetArray(F, &f));

386:   /*
387:      Compute function
388:   */
389:   for (j = 0; j < my; j++) {
390:     for (i = 0; i < mx; i++) {
391:       row = i + j * mx;
392:       if (i == 0 || j == 0 || i == mx - 1 || j == my - 1) {
393:         f[row] = x[row];
394:         continue;
395:       }
396:       u      = x[row];
397:       ub     = x[row - mx];
398:       ul     = x[row - 1];
399:       ut     = x[row + mx];
400:       ur     = x[row + 1];
401:       uxx    = (-ur + two * u - ul) * hydhx;
402:       uyy    = (-ut + two * u - ub) * hxdhy;
403:       f[row] = uxx + uyy - sc * lambda * PetscExpScalar(u);
404:     }
405:   }

407:   /*
408:      Restore vectors
409:   */
410:   PetscCall(VecRestoreArrayRead(X, &x));
411:   PetscCall(VecRestoreArray(F, &f));
412:   PetscFunctionReturn(PETSC_SUCCESS);
413: }

415: /*
416:    FormJacobian - Evaluates Jacobian matrix.

418:    Input Parameters:
419: .  snes - the SNES context
420: .  x - input vector
421: .  ptr - optional user-defined context, as set by SNESSetJacobian()

423:    Output Parameters:
424: .  A - Jacobian matrix
425: .  B - optionally different preconditioning matrix

427: */
428: PetscErrorCode FormJacobian(SNES snes, Vec X, Mat J, Mat jac, void *ptr)
429: {
430:   AppCtx            *user = (AppCtx *)ptr; /* user-defined application context */
431:   PetscInt           i, j, row, mx, my, col[5];
432:   PetscScalar        two = 2.0, one = 1.0, lambda, v[5], sc;
433:   const PetscScalar *x;
434:   PetscReal          hx, hy, hxdhy, hydhx;

436:   PetscFunctionBeginUser;
437:   mx     = user->mx;
438:   my     = user->my;
439:   lambda = user->param;
440:   hx     = 1.0 / (PetscReal)(mx - 1);
441:   hy     = 1.0 / (PetscReal)(my - 1);
442:   sc     = hx * hy;
443:   hxdhy  = hx / hy;
444:   hydhx  = hy / hx;

446:   /*
447:      Get pointer to vector data
448:   */
449:   PetscCall(VecGetArrayRead(X, &x));

451:   /*
452:      Compute entries of the Jacobian
453:   */
454:   for (j = 0; j < my; j++) {
455:     for (i = 0; i < mx; i++) {
456:       row = i + j * mx;
457:       if (i == 0 || j == 0 || i == mx - 1 || j == my - 1) {
458:         PetscCall(MatSetValues(jac, 1, &row, 1, &row, &one, INSERT_VALUES));
459:         continue;
460:       }
461:       v[0]   = -hxdhy;
462:       col[0] = row - mx;
463:       v[1]   = -hydhx;
464:       col[1] = row - 1;
465:       v[2]   = two * (hydhx + hxdhy) - sc * lambda * PetscExpScalar(x[row]);
466:       col[2] = row;
467:       v[3]   = -hydhx;
468:       col[3] = row + 1;
469:       v[4]   = -hxdhy;
470:       col[4] = row + mx;
471:       PetscCall(MatSetValues(jac, 1, &row, 5, col, v, INSERT_VALUES));
472:     }
473:   }

475:   /*
476:      Restore vector
477:   */
478:   PetscCall(VecRestoreArrayRead(X, &x));

480:   /*
481:      Assemble matrix
482:   */
483:   PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY));
484:   PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY));

486:   if (jac != J) {
487:     PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
488:     PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
489:   }
490:   PetscFunctionReturn(PETSC_SUCCESS);
491: }

493: PetscErrorCode ConvergenceTest(KSP ksp, PetscInt it, PetscReal nrm, KSPConvergedReason *reason, void *ctx)
494: {
495:   PetscFunctionBeginUser;
496:   *reason = KSP_CONVERGED_ITERATING;
497:   if (it > 1) {
498:     *reason = KSP_CONVERGED_ITS;
499:     PetscCall(PetscInfo(NULL, "User provided convergence test returning after 2 iterations\n"));
500:   }
501:   PetscFunctionReturn(PETSC_SUCCESS);
502: }

504: PetscErrorCode ConvergenceDestroy(void *ctx)
505: {
506:   PetscFunctionBeginUser;
507:   PetscCall(PetscInfo(NULL, "User provided convergence destroy called\n"));
508:   PetscCall(PetscFree(ctx));
509:   PetscFunctionReturn(PETSC_SUCCESS);
510: }

512: PetscErrorCode postcheck(SNES snes, Vec x, Vec y, Vec w, PetscBool *changed_y, PetscBool *changed_w, void *ctx)
513: {
514:   PetscReal norm;
515:   Vec       tmp;

517:   PetscFunctionBeginUser;
518:   PetscCall(VecDuplicate(x, &tmp));
519:   PetscCall(VecWAXPY(tmp, -1.0, x, w));
520:   PetscCall(VecNorm(tmp, NORM_2, &norm));
521:   PetscCall(VecDestroy(&tmp));
522:   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Norm of search step %g\n", (double)norm));
523:   PetscFunctionReturn(PETSC_SUCCESS);
524: }

526: /*TEST

528:    build:
529:       requires: !single

531:    test:
532:       args: -ksp_gmres_cgs_refinement_type refine_always

534:    test:
535:       suffix: 2
536:       args: -snes_monitor_short -snes_type newtontr -ksp_gmres_cgs_refinement_type refine_always

538:    test:
539:       suffix: 2a
540:       filter: grep -i KSPConvergedDefault > /dev/null && echo "Found KSPConvergedDefault"
541:       args: -snes_monitor_short -snes_type newtontr -ksp_gmres_cgs_refinement_type refine_always -info
542:       requires: defined(PETSC_USE_INFO)

544:    test:
545:       suffix: 2b
546:       filter: grep -i  "User provided convergence test" > /dev/null  && echo "Found User provided convergence test"
547:       args: -snes_monitor_short -snes_type newtontr -ksp_gmres_cgs_refinement_type refine_always -use_convergence_test -info
548:       requires: defined(PETSC_USE_INFO)

550:    test:
551:       suffix: 2c
552:       args: -snes_converged_reason -snes_type newtontr -snes_tr_qn {{same different}separate output} -pc_type mat -snes_view -snes_tr_qn_mat_type lmvmdfp -snes_tr_norm_type infinity

554:    test:
555:       suffix: 3
556:       args: -snes_monitor_short -mat_coloring_type sl -snes_fd_coloring -mx 8 -my 11 -ksp_gmres_cgs_refinement_type refine_always

558:    test:
559:       suffix: 4
560:       args: -pc -par 6.807 -snes_monitor -snes_converged_reason

562:    test:
563:       suffix: 5
564:       args: -snes_monitor_short -mat_coloring_type sl -snes_fd_coloring -mx 8 -my 11 -ksp_gmres_cgs_refinement_type refine_always -prune_jacobian
565:       output_file: output/ex1_3.out

567:    test:
568:       suffix: 6
569:       args: -snes_monitor draw:image:testfile -viewer_view

571:    test:
572:       suffix: python
573:       requires: petsc4py
574:       args: -python -snes_type python -snes_python_type ex1.py:MySNES -snes_view -null_appctx {{0 1}separate output}
575:       localrunfiles: ex1.py

577: TEST*/