Actual source code: ex17.c
1: static const char help[] = "Newton's method to solve a two-variable system, sequentially.\n"
2: "The same problem is solved twice - i) fully assembled system + ii) block system\n\n";
4: /*T
5: Concepts: SNES^basic uniprocessor example, block objects
6: Processors: 1
7: T*/
11: /*
12: Include "petscsnes.h" so that we can use SNES solvers. Note that this
13: file automatically includes:
14: petscsys.h - base PETSc routines petscvec.h - vectors
15: petscsys.h - system routines petscmat.h - matrices
16: petscis.h - index sets petscksp.h - Krylov subspace methods
17: petscviewer.h - viewers petscpc.h - preconditioners
18: petscksp.h - linear solvers
19: */
20: #include <petscsnes.h>
22: /*
23: This example is block version of the test found at
24: ${PETSC_DIR}/src/snes/tutorials/ex1.c
25: In this test we replace the Jacobian systems
26: [J]{x} = {F}
27: where
29: [J] = (j_00, j_01), {x} = (x_0, x_1)^T, {F} = (f_0, f_1)^T
30: (j_10, j_11)
31: where [J] \in \mathbb^{2 \times 2}, {x},{F} \in \mathbb^{2 \times 1},
33: with a block system in which each block is of length 1.
34: i.e. The block system is thus
36: [J] = ([j00], [j01]), {x} = ({x0}, {x1})^T, {F} = ({f0}, {f1})^T
37: ([j10], [j11])
38: where
39: [j00], [j01], [j10], [j11] \in \mathbb^{1 \times 1}
40: {x0}, {x1}, {f0}, {f1} \in \mathbb^{1 \times 1}
42: In practice we would not bother defing blocks of size one, and would instead assemble the
43: full system. This is just a simple test to illustrate how to manipulate the blocks and
44: to confirm the implementation is correct.
45: */
47: /*
48: User-defined routines
49: */
50: static PetscErrorCode FormJacobian1(SNES,Vec,Mat,Mat,void*);
51: static PetscErrorCode FormFunction1(SNES,Vec,Vec,void*);
52: static PetscErrorCode FormJacobian2(SNES,Vec,Mat,Mat,void*);
53: static PetscErrorCode FormFunction2(SNES,Vec,Vec,void*);
54: static PetscErrorCode FormJacobian1_block(SNES,Vec,Mat,Mat,void*);
55: static PetscErrorCode FormFunction1_block(SNES,Vec,Vec,void*);
56: static PetscErrorCode FormJacobian2_block(SNES,Vec,Mat,Mat,void*);
57: static PetscErrorCode FormFunction2_block(SNES,Vec,Vec,void*);
60: static PetscErrorCode assembled_system(void)
61: {
62: SNES snes; /* nonlinear solver context */
63: KSP ksp; /* linear solver context */
64: PC pc; /* preconditioner context */
65: Vec x,r; /* solution, residual vectors */
66: Mat J; /* Jacobian matrix */
68: PetscInt its;
69: PetscScalar pfive = .5,*xx;
70: PetscBool flg;
73: PetscPrintf(PETSC_COMM_WORLD, "\n\n========================= Assembled system =========================\n\n");
75: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
76: Create nonlinear solver context
77: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
79: SNESCreate(PETSC_COMM_WORLD,&snes);
81: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
82: Create matrix and vector data structures; set corresponding routines
83: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
85: /*
86: Create vectors for solution and nonlinear function
87: */
88: VecCreateSeq(PETSC_COMM_SELF,2,&x);
89: VecDuplicate(x,&r);
91: /*
92: Create Jacobian matrix data structure
93: */
94: MatCreate(PETSC_COMM_SELF,&J);
95: MatSetSizes(J,PETSC_DECIDE,PETSC_DECIDE,2,2);
96: MatSetFromOptions(J);
97: MatSetUp(J);
99: PetscOptionsHasName(NULL,NULL,"-hard",&flg);
100: if (!flg) {
101: /*
102: Set function evaluation routine and vector.
103: */
104: SNESSetFunction(snes,r,FormFunction1,NULL);
106: /*
107: Set Jacobian matrix data structure and Jacobian evaluation routine
108: */
109: SNESSetJacobian(snes,J,J,FormJacobian1,NULL);
110: } else {
111: SNESSetFunction(snes,r,FormFunction2,NULL);
112: SNESSetJacobian(snes,J,J,FormJacobian2,NULL);
113: }
115: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
116: Customize nonlinear solver; set runtime options
117: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
119: /*
120: Set linear solver defaults for this problem. By extracting the
121: KSP, KSP, and PC contexts from the SNES context, we can then
122: directly call any KSP, KSP, and PC routines to set various options.
123: */
124: SNESGetKSP(snes,&ksp);
125: KSPGetPC(ksp,&pc);
126: PCSetType(pc,PCNONE);
127: KSPSetTolerances(ksp,1.e-4,PETSC_DEFAULT,PETSC_DEFAULT,20);
129: /*
130: Set SNES/KSP/KSP/PC runtime options, e.g.,
131: -snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc>
132: These options will override those specified above as long as
133: SNESSetFromOptions() is called _after_ any other customization
134: routines.
135: */
136: SNESSetFromOptions(snes);
138: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
139: Evaluate initial guess; then solve nonlinear system
140: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
141: if (!flg) {
142: VecSet(x,pfive);
143: } else {
144: VecGetArray(x,&xx);
145: xx[0] = 2.0; xx[1] = 3.0;
146: VecRestoreArray(x,&xx);
147: }
148: /*
149: Note: The user should initialize the vector, x, with the initial guess
150: for the nonlinear solver prior to calling SNESSolve(). In particular,
151: to employ an initial guess of zero, the user should explicitly set
152: this vector to zero by calling VecSet().
153: */
155: SNESSolve(snes,NULL,x);
156: SNESGetIterationNumber(snes,&its);
157: if (flg) {
158: Vec f;
159: VecView(x,PETSC_VIEWER_STDOUT_WORLD);
160: SNESGetFunction(snes,&f,0,0);
161: VecView(r,PETSC_VIEWER_STDOUT_WORLD);
162: }
163: PetscPrintf(PETSC_COMM_SELF,"number of SNES iterations = %D\n\n",its);
165: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
166: Free work space. All PETSc objects should be destroyed when they
167: are no longer needed.
168: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
170: VecDestroy(&x); VecDestroy(&r);
171: MatDestroy(&J); SNESDestroy(&snes);
172: return(0);
173: }
175: /* ------------------------------------------------------------------- */
176: /*
177: FormFunction1 - Evaluates nonlinear function, F(x).
179: Input Parameters:
180: . snes - the SNES context
181: . x - input vector
182: . dummy - optional user-defined context (not used here)
184: Output Parameter:
185: . f - function vector
186: */
187: static PetscErrorCode FormFunction1(SNES snes,Vec x,Vec f,void *dummy)
188: {
189: PetscErrorCode ierr;
190: const PetscScalar *xx;
191: PetscScalar *ff;
194: /*
195: Get pointers to vector data.
196: - For default PETSc vectors, VecGetArray() returns a pointer to
197: the data array. Otherwise, the routine is implementation dependent.
198: - You MUST call VecRestoreArray() when you no longer need access to
199: the array.
200: */
201: VecGetArrayRead(x,&xx);
202: VecGetArray(f,&ff);
204: /*
205: Compute function
206: */
207: ff[0] = xx[0]*xx[0] + xx[0]*xx[1] - 3.0;
208: ff[1] = xx[0]*xx[1] + xx[1]*xx[1] - 6.0;
211: /*
212: Restore vectors
213: */
214: VecRestoreArrayRead(x,&xx);
215: VecRestoreArray(f,&ff);
216: return(0);
217: }
218: /* ------------------------------------------------------------------- */
219: /*
220: FormJacobian1 - Evaluates Jacobian matrix.
222: Input Parameters:
223: . snes - the SNES context
224: . x - input vector
225: . dummy - optional user-defined context (not used here)
227: Output Parameters:
228: . jac - Jacobian matrix
229: . B - optionally different preconditioning matrix
230: . flag - flag indicating matrix structure
231: */
232: static PetscErrorCode FormJacobian1(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
233: {
234: const PetscScalar *xx;
235: PetscScalar A[4];
236: PetscErrorCode ierr;
237: PetscInt idx[2] = {0,1};
240: /*
241: Get pointer to vector data
242: */
243: VecGetArrayRead(x,&xx);
245: /*
246: Compute Jacobian entries and insert into matrix.
247: - Since this is such a small problem, we set all entries for
248: the matrix at once.
249: */
250: A[0] = 2.0*xx[0] + xx[1]; A[1] = xx[0];
251: A[2] = xx[1]; A[3] = xx[0] + 2.0*xx[1];
252: MatSetValues(jac,2,idx,2,idx,A,INSERT_VALUES);
254: /*
255: Restore vector
256: */
257: VecRestoreArrayRead(x,&xx);
259: /*
260: Assemble matrix
261: */
262: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
263: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
264: return(0);
265: }
268: /* ------------------------------------------------------------------- */
269: static PetscErrorCode FormFunction2(SNES snes,Vec x,Vec f,void *dummy)
270: {
271: PetscErrorCode ierr;
272: const PetscScalar *xx;
273: PetscScalar *ff;
276: /*
277: Get pointers to vector data.
278: - For default PETSc vectors, VecGetArray() returns a pointer to
279: the data array. Otherwise, the routine is implementation dependent.
280: - You MUST call VecRestoreArray() when you no longer need access to
281: the array.
282: */
283: VecGetArrayRead(x,&xx);
284: VecGetArray(f,&ff);
286: /*
287: Compute function
288: */
289: ff[0] = PetscSinScalar(3.0*xx[0]) + xx[0];
290: ff[1] = xx[1];
292: /*
293: Restore vectors
294: */
295: VecRestoreArrayRead(x,&xx);
296: VecRestoreArray(f,&ff);
297: return(0);
298: }
300: /* ------------------------------------------------------------------- */
301: static PetscErrorCode FormJacobian2(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
302: {
303: const PetscScalar *xx;
304: PetscScalar A[4];
305: PetscErrorCode ierr;
306: PetscInt idx[2] = {0,1};
309: /*
310: Get pointer to vector data
311: */
312: VecGetArrayRead(x,&xx);
314: /*
315: Compute Jacobian entries and insert into matrix.
316: - Since this is such a small problem, we set all entries for
317: the matrix at once.
318: */
319: A[0] = 3.0*PetscCosScalar(3.0*xx[0]) + 1.0; A[1] = 0.0;
320: A[2] = 0.0; A[3] = 1.0;
321: MatSetValues(jac,2,idx,2,idx,A,INSERT_VALUES);
323: /*
324: Restore vector
325: */
326: VecRestoreArrayRead(x,&xx);
328: /*
329: Assemble matrix
330: */
331: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
332: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
333: return(0);
334: }
336: static PetscErrorCode block_system(void)
337: {
338: SNES snes; /* nonlinear solver context */
339: KSP ksp; /* linear solver context */
340: PC pc; /* preconditioner context */
341: Vec x,r; /* solution, residual vectors */
342: Mat J; /* Jacobian matrix */
344: PetscInt its;
345: PetscScalar pfive = .5;
346: PetscBool flg;
348: Mat j11, j12, j21, j22;
349: Vec x1, x2, r1, r2;
350: Vec bv;
351: Vec bx[2];
352: Mat bA[2][2];
355: PetscPrintf(PETSC_COMM_WORLD, "\n\n========================= Block system =========================\n\n");
357: SNESCreate(PETSC_COMM_WORLD,&snes);
359: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
360: Create matrix and vector data structures; set corresponding routines
361: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
363: /*
364: Create sub vectors for solution and nonlinear function
365: */
366: VecCreateSeq(PETSC_COMM_SELF,1,&x1);
367: VecDuplicate(x1,&r1);
369: VecCreateSeq(PETSC_COMM_SELF,1,&x2);
370: VecDuplicate(x2,&r2);
372: /*
373: Create the block vectors
374: */
375: bx[0] = x1;
376: bx[1] = x2;
377: VecCreateNest(PETSC_COMM_WORLD,2,NULL,bx,&x);
378: VecAssemblyBegin(x);
379: VecAssemblyEnd(x);
380: VecDestroy(&x1);
381: VecDestroy(&x2);
383: bx[0] = r1;
384: bx[1] = r2;
385: VecCreateNest(PETSC_COMM_WORLD,2,NULL,bx,&r);
386: VecDestroy(&r1);
387: VecDestroy(&r2);
388: VecAssemblyBegin(r);
389: VecAssemblyEnd(r);
391: /*
392: Create sub Jacobian matrix data structure
393: */
394: MatCreate(PETSC_COMM_WORLD, &j11);
395: MatSetSizes(j11, 1, 1, 1, 1);
396: MatSetType(j11, MATSEQAIJ);
397: MatSetUp(j11);
399: MatCreate(PETSC_COMM_WORLD, &j12);
400: MatSetSizes(j12, 1, 1, 1, 1);
401: MatSetType(j12, MATSEQAIJ);
402: MatSetUp(j12);
404: MatCreate(PETSC_COMM_WORLD, &j21);
405: MatSetSizes(j21, 1, 1, 1, 1);
406: MatSetType(j21, MATSEQAIJ);
407: MatSetUp(j21);
409: MatCreate(PETSC_COMM_WORLD, &j22);
410: MatSetSizes(j22, PETSC_DECIDE, PETSC_DECIDE, 1, 1);
411: MatSetType(j22, MATSEQAIJ);
412: MatSetUp(j22);
413: /*
414: Create block Jacobian matrix data structure
415: */
416: bA[0][0] = j11;
417: bA[0][1] = j12;
418: bA[1][0] = j21;
419: bA[1][1] = j22;
421: MatCreateNest(PETSC_COMM_WORLD,2,NULL,2,NULL,&bA[0][0],&J);
422: MatSetUp(J);
423: MatNestSetVecType(J,VECNEST);
424: MatDestroy(&j11);
425: MatDestroy(&j12);
426: MatDestroy(&j21);
427: MatDestroy(&j22);
429: MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);
430: MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);
432: PetscOptionsHasName(NULL,NULL,"-hard",&flg);
433: if (!flg) {
434: /*
435: Set function evaluation routine and vector.
436: */
437: SNESSetFunction(snes,r,FormFunction1_block,NULL);
439: /*
440: Set Jacobian matrix data structure and Jacobian evaluation routine
441: */
442: SNESSetJacobian(snes,J,J,FormJacobian1_block,NULL);
443: } else {
444: SNESSetFunction(snes,r,FormFunction2_block,NULL);
445: SNESSetJacobian(snes,J,J,FormJacobian2_block,NULL);
446: }
448: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
449: Customize nonlinear solver; set runtime options
450: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
452: /*
453: Set linear solver defaults for this problem. By extracting the
454: KSP, KSP, and PC contexts from the SNES context, we can then
455: directly call any KSP, KSP, and PC routines to set various options.
456: */
457: SNESGetKSP(snes,&ksp);
458: KSPGetPC(ksp,&pc);
459: PCSetType(pc,PCNONE);
460: KSPSetTolerances(ksp,1.e-4,PETSC_DEFAULT,PETSC_DEFAULT,20);
462: /*
463: Set SNES/KSP/KSP/PC runtime options, e.g.,
464: -snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc>
465: These options will override those specified above as long as
466: SNESSetFromOptions() is called _after_ any other customization
467: routines.
468: */
469: SNESSetFromOptions(snes);
471: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
472: Evaluate initial guess; then solve nonlinear system
473: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
474: if (!flg) {
475: VecSet(x,pfive);
476: } else {
477: Vec *vecs;
478: VecNestGetSubVecs(x, NULL, &vecs);
479: bv = vecs[0];
480: /* VecBlockGetSubVec(x, 0, &bv); */
481: VecSetValue(bv, 0, 2.0, INSERT_VALUES); /* xx[0] = 2.0; */
482: VecAssemblyBegin(bv);
483: VecAssemblyEnd(bv);
485: /* VecBlockGetSubVec(x, 1, &bv); */
486: bv = vecs[1];
487: VecSetValue(bv, 0, 3.0, INSERT_VALUES); /* xx[1] = 3.0; */
488: VecAssemblyBegin(bv);
489: VecAssemblyEnd(bv);
490: }
491: /*
492: Note: The user should initialize the vector, x, with the initial guess
493: for the nonlinear solver prior to calling SNESSolve(). In particular,
494: to employ an initial guess of zero, the user should explicitly set
495: this vector to zero by calling VecSet().
496: */
497: SNESSolve(snes,NULL,x);
498: SNESGetIterationNumber(snes,&its);
499: if (flg) {
500: Vec f;
501: VecView(x,PETSC_VIEWER_STDOUT_WORLD);
502: SNESGetFunction(snes,&f,0,0);
503: VecView(r,PETSC_VIEWER_STDOUT_WORLD);
504: }
506: PetscPrintf(PETSC_COMM_SELF,"number of SNES iterations = %D\n\n",its);
508: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
509: Free work space. All PETSc objects should be destroyed when they
510: are no longer needed.
511: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
512: VecDestroy(&x); VecDestroy(&r);
513: MatDestroy(&J); SNESDestroy(&snes);
514: return(0);
515: }
517: /* ------------------------------------------------------------------- */
518: static PetscErrorCode FormFunction1_block(SNES snes,Vec x,Vec f,void *dummy)
519: {
520: Vec *xx, *ff, x1,x2, f1,f2;
521: PetscScalar ff_0, ff_1;
522: PetscScalar xx_0, xx_1;
523: PetscInt index,nb;
527: /* get blocks for function */
528: VecNestGetSubVecs(f, &nb, &ff);
529: f1 = ff[0]; f2 = ff[1];
531: /* get blocks for solution */
532: VecNestGetSubVecs(x, &nb, &xx);
533: x1 = xx[0]; x2 = xx[1];
535: /* get solution values */
536: index = 0;
537: VecGetValues(x1,1, &index, &xx_0);
538: VecGetValues(x2,1, &index, &xx_1);
540: /* Compute function */
541: ff_0 = xx_0*xx_0 + xx_0*xx_1 - 3.0;
542: ff_1 = xx_0*xx_1 + xx_1*xx_1 - 6.0;
544: /* set function values */
545: VecSetValue(f1, index, ff_0, INSERT_VALUES);
547: VecSetValue(f2, index, ff_1, INSERT_VALUES);
549: VecAssemblyBegin(f);
550: VecAssemblyEnd(f);
551: return(0);
552: }
554: /* ------------------------------------------------------------------- */
555: static PetscErrorCode FormJacobian1_block(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
556: {
557: Vec *xx, x1,x2;
558: PetscScalar xx_0, xx_1;
559: PetscInt index,nb;
560: PetscScalar A_00, A_01, A_10, A_11;
561: Mat j11, j12, j21, j22;
562: Mat **mats;
566: /* get blocks for solution */
567: VecNestGetSubVecs(x, &nb, &xx);
568: x1 = xx[0]; x2 = xx[1];
570: /* get solution values */
571: index = 0;
572: VecGetValues(x1,1, &index, &xx_0);
573: VecGetValues(x2,1, &index, &xx_1);
575: /* get block matrices */
576: MatNestGetSubMats(jac,NULL,NULL,&mats);
577: j11 = mats[0][0];
578: j12 = mats[0][1];
579: j21 = mats[1][0];
580: j22 = mats[1][1];
582: /* compute jacobian entries */
583: A_00 = 2.0*xx_0 + xx_1;
584: A_01 = xx_0;
585: A_10 = xx_1;
586: A_11 = xx_0 + 2.0*xx_1;
588: /* set jacobian values */
589: MatSetValue(j11, 0,0, A_00, INSERT_VALUES);
590: MatSetValue(j12, 0,0, A_01, INSERT_VALUES);
591: MatSetValue(j21, 0,0, A_10, INSERT_VALUES);
592: MatSetValue(j22, 0,0, A_11, INSERT_VALUES);
594: /* Assemble sub matrix */
595: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
596: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
597: return(0);
598: }
600: /* ------------------------------------------------------------------- */
601: static PetscErrorCode FormFunction2_block(SNES snes,Vec x,Vec f,void *dummy)
602: {
603: PetscErrorCode ierr;
604: PetscScalar *ff;
605: const PetscScalar *xx;
608: /*
609: Get pointers to vector data.
610: - For default PETSc vectors, VecGetArray() returns a pointer to
611: the data array. Otherwise, the routine is implementation dependent.
612: - You MUST call VecRestoreArray() when you no longer need access to
613: the array.
614: */
615: VecGetArrayRead(x,&xx);
616: VecGetArray(f,&ff);
618: /*
619: Compute function
620: */
621: ff[0] = PetscSinScalar(3.0*xx[0]) + xx[0];
622: ff[1] = xx[1];
624: /*
625: Restore vectors
626: */
627: VecRestoreArrayRead(x,&xx);
628: VecRestoreArray(f,&ff);
629: return(0);
630: }
632: /* ------------------------------------------------------------------- */
633: static PetscErrorCode FormJacobian2_block(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
634: {
635: const PetscScalar *xx;
636: PetscScalar A[4];
637: PetscErrorCode ierr;
638: PetscInt idx[2] = {0,1};
641: /*
642: Get pointer to vector data
643: */
644: VecGetArrayRead(x,&xx);
646: /*
647: Compute Jacobian entries and insert into matrix.
648: - Since this is such a small problem, we set all entries for
649: the matrix at once.
650: */
651: A[0] = 3.0*PetscCosScalar(3.0*xx[0]) + 1.0; A[1] = 0.0;
652: A[2] = 0.0; A[3] = 1.0;
653: MatSetValues(jac,2,idx,2,idx,A,INSERT_VALUES);
655: /*
656: Restore vector
657: */
658: VecRestoreArrayRead(x,&xx);
660: /*
661: Assemble matrix
662: */
663: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
664: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
665: return(0);
666: }
668: int main(int argc,char **argv)
669: {
670: PetscMPIInt size;
673: PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr;
675: MPI_Comm_size(PETSC_COMM_WORLD,&size);
676: if (size != 1) SETERRQ(PETSC_COMM_WORLD, 1,"This is a uniprocessor example only!");
678: assembled_system();
680: block_system();
682: PetscFinalize();
683: return ierr;
684: }
687: /*TEST
689: test:
690: args: -snes_monitor_short
691: requires: !single
693: TEST*/