Actual source code: ex17.c
petsc-3.13.6 2020-09-29
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: }
164: PetscPrintf(PETSC_COMM_SELF,"number of SNES iterations = %D\n\n",its);
166: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
167: Free work space. All PETSc objects should be destroyed when they
168: are no longer needed.
169: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
171: VecDestroy(&x); VecDestroy(&r);
172: MatDestroy(&J); SNESDestroy(&snes);
173: return(0);
174: }
176: /* ------------------------------------------------------------------- */
177: /*
178: FormFunction1 - Evaluates nonlinear function, F(x).
180: Input Parameters:
181: . snes - the SNES context
182: . x - input vector
183: . dummy - optional user-defined context (not used here)
185: Output Parameter:
186: . f - function vector
187: */
188: static PetscErrorCode FormFunction1(SNES snes,Vec x,Vec f,void *dummy)
189: {
190: PetscErrorCode ierr;
191: const PetscScalar *xx;
192: PetscScalar *ff;
195: /*
196: Get pointers to vector data.
197: - For default PETSc vectors, VecGetArray() returns a pointer to
198: the data array. Otherwise, the routine is implementation dependent.
199: - You MUST call VecRestoreArray() when you no longer need access to
200: the array.
201: */
202: VecGetArrayRead(x,&xx);
203: VecGetArray(f,&ff);
205: /*
206: Compute function
207: */
208: ff[0] = xx[0]*xx[0] + xx[0]*xx[1] - 3.0;
209: ff[1] = xx[0]*xx[1] + xx[1]*xx[1] - 6.0;
212: /*
213: Restore vectors
214: */
215: VecRestoreArrayRead(x,&xx);
216: VecRestoreArray(f,&ff);
217: return(0);
218: }
219: /* ------------------------------------------------------------------- */
220: /*
221: FormJacobian1 - Evaluates Jacobian matrix.
223: Input Parameters:
224: . snes - the SNES context
225: . x - input vector
226: . dummy - optional user-defined context (not used here)
228: Output Parameters:
229: . jac - Jacobian matrix
230: . B - optionally different preconditioning matrix
231: . flag - flag indicating matrix structure
232: */
233: static PetscErrorCode FormJacobian1(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
234: {
235: const PetscScalar *xx;
236: PetscScalar A[4];
237: PetscErrorCode ierr;
238: PetscInt idx[2] = {0,1};
241: /*
242: Get pointer to vector data
243: */
244: VecGetArrayRead(x,&xx);
246: /*
247: Compute Jacobian entries and insert into matrix.
248: - Since this is such a small problem, we set all entries for
249: the matrix at once.
250: */
251: A[0] = 2.0*xx[0] + xx[1]; A[1] = xx[0];
252: A[2] = xx[1]; A[3] = xx[0] + 2.0*xx[1];
253: MatSetValues(jac,2,idx,2,idx,A,INSERT_VALUES);
255: /*
256: Restore vector
257: */
258: VecRestoreArrayRead(x,&xx);
260: /*
261: Assemble matrix
262: */
263: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
264: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
265: return(0);
266: }
269: /* ------------------------------------------------------------------- */
270: static PetscErrorCode FormFunction2(SNES snes,Vec x,Vec f,void *dummy)
271: {
272: PetscErrorCode ierr;
273: const PetscScalar *xx;
274: PetscScalar *ff;
277: /*
278: Get pointers to vector data.
279: - For default PETSc vectors, VecGetArray() returns a pointer to
280: the data array. Otherwise, the routine is implementation dependent.
281: - You MUST call VecRestoreArray() when you no longer need access to
282: the array.
283: */
284: VecGetArrayRead(x,&xx);
285: VecGetArray(f,&ff);
287: /*
288: Compute function
289: */
290: ff[0] = PetscSinScalar(3.0*xx[0]) + xx[0];
291: ff[1] = xx[1];
293: /*
294: Restore vectors
295: */
296: VecRestoreArrayRead(x,&xx);
297: VecRestoreArray(f,&ff);
298: return(0);
299: }
301: /* ------------------------------------------------------------------- */
302: static PetscErrorCode FormJacobian2(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
303: {
304: const PetscScalar *xx;
305: PetscScalar A[4];
306: PetscErrorCode ierr;
307: PetscInt idx[2] = {0,1};
310: /*
311: Get pointer to vector data
312: */
313: VecGetArrayRead(x,&xx);
315: /*
316: Compute Jacobian entries and insert into matrix.
317: - Since this is such a small problem, we set all entries for
318: the matrix at once.
319: */
320: A[0] = 3.0*PetscCosScalar(3.0*xx[0]) + 1.0; A[1] = 0.0;
321: A[2] = 0.0; A[3] = 1.0;
322: MatSetValues(jac,2,idx,2,idx,A,INSERT_VALUES);
324: /*
325: Restore vector
326: */
327: VecRestoreArrayRead(x,&xx);
329: /*
330: Assemble matrix
331: */
332: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
333: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
334: return(0);
335: }
337: static int block_system(void)
338: {
339: SNES snes; /* nonlinear solver context */
340: KSP ksp; /* linear solver context */
341: PC pc; /* preconditioner context */
342: Vec x,r; /* solution, residual vectors */
343: Mat J; /* Jacobian matrix */
345: PetscInt its;
346: PetscScalar pfive = .5;
347: PetscBool flg;
349: Mat j11, j12, j21, j22;
350: Vec x1, x2, r1, r2;
351: Vec bv;
352: Vec bx[2];
353: Mat bA[2][2];
356: PetscPrintf(PETSC_COMM_WORLD, "\n\n========================= Block system =========================\n\n");
358: SNESCreate(PETSC_COMM_WORLD,&snes);
360: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
361: Create matrix and vector data structures; set corresponding routines
362: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
364: /*
365: Create sub vectors for solution and nonlinear function
366: */
367: VecCreateSeq(PETSC_COMM_SELF,1,&x1);
368: VecDuplicate(x1,&r1);
370: VecCreateSeq(PETSC_COMM_SELF,1,&x2);
371: VecDuplicate(x2,&r2);
373: /*
374: Create the block vectors
375: */
376: bx[0] = x1;
377: bx[1] = x2;
378: VecCreateNest(PETSC_COMM_WORLD,2,NULL,bx,&x);
379: VecAssemblyBegin(x);
380: VecAssemblyEnd(x);
381: VecDestroy(&x1);
382: VecDestroy(&x2);
384: bx[0] = r1;
385: bx[1] = r2;
386: VecCreateNest(PETSC_COMM_WORLD,2,NULL,bx,&r);
387: VecDestroy(&r1);
388: VecDestroy(&r2);
389: VecAssemblyBegin(r);
390: VecAssemblyEnd(r);
392: /*
393: Create sub Jacobian matrix data structure
394: */
395: MatCreate(PETSC_COMM_WORLD, &j11);
396: MatSetSizes(j11, 1, 1, 1, 1);
397: MatSetType(j11, MATSEQAIJ);
398: MatSetUp(j11);
400: MatCreate(PETSC_COMM_WORLD, &j12);
401: MatSetSizes(j12, 1, 1, 1, 1);
402: MatSetType(j12, MATSEQAIJ);
403: MatSetUp(j12);
405: MatCreate(PETSC_COMM_WORLD, &j21);
406: MatSetSizes(j21, 1, 1, 1, 1);
407: MatSetType(j21, MATSEQAIJ);
408: MatSetUp(j21);
410: MatCreate(PETSC_COMM_WORLD, &j22);
411: MatSetSizes(j22, PETSC_DECIDE, PETSC_DECIDE, 1, 1);
412: MatSetType(j22, MATSEQAIJ);
413: MatSetUp(j22);
414: /*
415: Create block Jacobian matrix data structure
416: */
417: bA[0][0] = j11;
418: bA[0][1] = j12;
419: bA[1][0] = j21;
420: bA[1][1] = j22;
422: MatCreateNest(PETSC_COMM_WORLD,2,NULL,2,NULL,&bA[0][0],&J);
423: MatSetUp(J);
424: MatNestSetVecType(J,VECNEST);
425: MatDestroy(&j11);
426: MatDestroy(&j12);
427: MatDestroy(&j21);
428: MatDestroy(&j22);
430: MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);
431: MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);
433: PetscOptionsHasName(NULL,NULL,"-hard",&flg);
434: if (!flg) {
435: /*
436: Set function evaluation routine and vector.
437: */
438: SNESSetFunction(snes,r,FormFunction1_block,NULL);
440: /*
441: Set Jacobian matrix data structure and Jacobian evaluation routine
442: */
443: SNESSetJacobian(snes,J,J,FormJacobian1_block,NULL);
444: } else {
445: SNESSetFunction(snes,r,FormFunction2_block,NULL);
446: SNESSetJacobian(snes,J,J,FormJacobian2_block,NULL);
447: }
449: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
450: Customize nonlinear solver; set runtime options
451: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
453: /*
454: Set linear solver defaults for this problem. By extracting the
455: KSP, KSP, and PC contexts from the SNES context, we can then
456: directly call any KSP, KSP, and PC routines to set various options.
457: */
458: SNESGetKSP(snes,&ksp);
459: KSPGetPC(ksp,&pc);
460: PCSetType(pc,PCNONE);
461: KSPSetTolerances(ksp,1.e-4,PETSC_DEFAULT,PETSC_DEFAULT,20);
463: /*
464: Set SNES/KSP/KSP/PC runtime options, e.g.,
465: -snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc>
466: These options will override those specified above as long as
467: SNESSetFromOptions() is called _after_ any other customization
468: routines.
469: */
470: SNESSetFromOptions(snes);
472: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
473: Evaluate initial guess; then solve nonlinear system
474: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
475: if (!flg) {
476: VecSet(x,pfive);
477: } else {
478: Vec *vecs;
479: VecNestGetSubVecs(x, NULL, &vecs);
480: bv = vecs[0];
481: /* VecBlockGetSubVec(x, 0, &bv); */
482: VecSetValue(bv, 0, 2.0, INSERT_VALUES); /* xx[0] = 2.0; */
483: VecAssemblyBegin(bv);
484: VecAssemblyEnd(bv);
486: /* VecBlockGetSubVec(x, 1, &bv); */
487: bv = vecs[1];
488: VecSetValue(bv, 0, 3.0, INSERT_VALUES); /* xx[1] = 3.0; */
489: VecAssemblyBegin(bv);
490: VecAssemblyEnd(bv);
491: }
492: /*
493: Note: The user should initialize the vector, x, with the initial guess
494: for the nonlinear solver prior to calling SNESSolve(). In particular,
495: to employ an initial guess of zero, the user should explicitly set
496: this vector to zero by calling VecSet().
497: */
498: SNESSolve(snes,NULL,x);
499: SNESGetIterationNumber(snes,&its);
500: if (flg) {
501: Vec f;
502: VecView(x,PETSC_VIEWER_STDOUT_WORLD);
503: SNESGetFunction(snes,&f,0,0);
504: VecView(r,PETSC_VIEWER_STDOUT_WORLD);
505: }
507: PetscPrintf(PETSC_COMM_SELF,"number of SNES iterations = %D\n\n",its);
509: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
510: Free work space. All PETSc objects should be destroyed when they
511: are no longer needed.
512: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
513: VecDestroy(&x); VecDestroy(&r);
514: MatDestroy(&J); SNESDestroy(&snes);
515: return(0);
516: }
518: /* ------------------------------------------------------------------- */
519: static PetscErrorCode FormFunction1_block(SNES snes,Vec x,Vec f,void *dummy)
520: {
521: Vec *xx, *ff, x1,x2, f1,f2;
522: PetscScalar ff_0, ff_1;
523: PetscScalar xx_0, xx_1;
524: PetscInt index,nb;
528: /* get blocks for function */
529: VecNestGetSubVecs(f, &nb, &ff);
530: f1 = ff[0]; f2 = ff[1];
532: /* get blocks for solution */
533: VecNestGetSubVecs(x, &nb, &xx);
534: x1 = xx[0]; x2 = xx[1];
536: /* get solution values */
537: index = 0;
538: VecGetValues(x1,1, &index, &xx_0);
539: VecGetValues(x2,1, &index, &xx_1);
541: /* Compute function */
542: ff_0 = xx_0*xx_0 + xx_0*xx_1 - 3.0;
543: ff_1 = xx_0*xx_1 + xx_1*xx_1 - 6.0;
545: /* set function values */
546: VecSetValue(f1, index, ff_0, INSERT_VALUES);
548: VecSetValue(f2, index, ff_1, INSERT_VALUES);
550: VecAssemblyBegin(f);
551: VecAssemblyEnd(f);
552: return(0);
553: }
555: /* ------------------------------------------------------------------- */
556: static PetscErrorCode FormJacobian1_block(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
557: {
558: Vec *xx, x1,x2;
559: PetscScalar xx_0, xx_1;
560: PetscInt index,nb;
561: PetscScalar A_00, A_01, A_10, A_11;
562: Mat j11, j12, j21, j22;
563: Mat **mats;
567: /* get blocks for solution */
568: VecNestGetSubVecs(x, &nb, &xx);
569: x1 = xx[0]; x2 = xx[1];
571: /* get solution values */
572: index = 0;
573: VecGetValues(x1,1, &index, &xx_0);
574: VecGetValues(x2,1, &index, &xx_1);
576: /* get block matrices */
577: MatNestGetSubMats(jac,NULL,NULL,&mats);
578: j11 = mats[0][0];
579: j12 = mats[0][1];
580: j21 = mats[1][0];
581: j22 = mats[1][1];
583: /* compute jacobian entries */
584: A_00 = 2.0*xx_0 + xx_1;
585: A_01 = xx_0;
586: A_10 = xx_1;
587: A_11 = xx_0 + 2.0*xx_1;
589: /* set jacobian values */
590: MatSetValue(j11, 0,0, A_00, INSERT_VALUES);
591: MatSetValue(j12, 0,0, A_01, INSERT_VALUES);
592: MatSetValue(j21, 0,0, A_10, INSERT_VALUES);
593: MatSetValue(j22, 0,0, A_11, INSERT_VALUES);
595: /* Assemble sub matrix */
596: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
597: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
598: return(0);
599: }
601: /* ------------------------------------------------------------------- */
602: static PetscErrorCode FormFunction2_block(SNES snes,Vec x,Vec f,void *dummy)
603: {
604: PetscErrorCode ierr;
605: PetscScalar *ff;
606: const PetscScalar *xx;
609: /*
610: Get pointers to vector data.
611: - For default PETSc vectors, VecGetArray() returns a pointer to
612: the data array. Otherwise, the routine is implementation dependent.
613: - You MUST call VecRestoreArray() when you no longer need access to
614: the array.
615: */
616: VecGetArrayRead(x,&xx);
617: VecGetArray(f,&ff);
619: /*
620: Compute function
621: */
622: ff[0] = PetscSinScalar(3.0*xx[0]) + xx[0];
623: ff[1] = xx[1];
625: /*
626: Restore vectors
627: */
628: VecRestoreArrayRead(x,&xx);
629: VecRestoreArray(f,&ff);
630: return(0);
631: }
633: /* ------------------------------------------------------------------- */
634: static PetscErrorCode FormJacobian2_block(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
635: {
636: const PetscScalar *xx;
637: PetscScalar A[4];
638: PetscErrorCode ierr;
639: PetscInt idx[2] = {0,1};
642: /*
643: Get pointer to vector data
644: */
645: VecGetArrayRead(x,&xx);
647: /*
648: Compute Jacobian entries and insert into matrix.
649: - Since this is such a small problem, we set all entries for
650: the matrix at once.
651: */
652: A[0] = 3.0*PetscCosScalar(3.0*xx[0]) + 1.0; A[1] = 0.0;
653: A[2] = 0.0; A[3] = 1.0;
654: MatSetValues(jac,2,idx,2,idx,A,INSERT_VALUES);
656: /*
657: Restore vector
658: */
659: VecRestoreArrayRead(x,&xx);
661: /*
662: Assemble matrix
663: */
664: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
665: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
666: return(0);
667: }
669: int main(int argc,char **argv)
670: {
671: PetscMPIInt size;
674: PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr;
676: MPI_Comm_size(PETSC_COMM_WORLD,&size);
677: if (size != 1) SETERRQ(PETSC_COMM_WORLD, 1,"This is a uniprocessor example only!");
679: assembled_system();
681: block_system();
683: PetscFinalize();
684: return ierr;
685: }
688: /*TEST
690: test:
691: args: -snes_monitor_short
692: requires: !single
694: TEST*/