Actual source code: ex3.c
1: /*$Id: ex3.c,v 1.87 2001/08/07 21:31:17 bsmith Exp $*/
3: static char help[] = "Newton methods to solve u'' + u^{2} = f in parallel.n
4: This example employs a user-defined monitoring routine and optionally a user-definedn
5: routine to check candidate iterates produced by line search routines. This code alson
6: The command line options include:n
7: -check_iterates : activate checking of iteratesn
8: -check_tol <tol>: set tolerance for iterate checkingnn";
10: /*T
11: Concepts: SNES^basic parallel example
12: Concepts: SNES^setting a user-defined monitoring routine
13: Processors: n
14: T*/
16: /*
17: Include "petscdraw.h" so that we can use distributed arrays (DAs).
18: Include "petscdraw.h" so that we can use PETSc drawing routines.
19: Include "petscsnes.h" so that we can use SNES solvers. Note that this
20: file automatically includes:
21: petsc.h - base PETSc routines petscvec.h - vectors
22: petscsys.h - system routines petscmat.h - matrices
23: petscis.h - index sets petscksp.h - Krylov subspace methods
24: petscviewer.h - viewers petscpc.h - preconditioners
25: petscsles.h - linear solvers
26: */
28: #include petscda.h
29: #include petscsnes.h
31: /*
32: User-defined routines. Note that immediately before each routine below,
33: If defined, this macro is used in the PETSc error handlers to provide a
34: complete traceback of routine names. All PETSc library routines use this
35: macro, and users can optionally employ it as well in their application
36: codes. Note that users can get a traceback of PETSc errors regardless of
37: provides the added traceback detail of the application routine names.
38: */
39: int FormJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*);
40: int FormFunction(SNES,Vec,Vec,void*);
41: int FormInitialGuess(Vec);
42: int Monitor(SNES,int,PetscReal,void *);
43: int StepCheck(SNES,void *,Vec,PetscTruth *);
45: /*
46: User-defined application context
47: */
48: typedef struct {
49: DA da; /* distributed array */
50: Vec F; /* right-hand-side of PDE */
51: int rank; /* rank of processor */
52: int size; /* size of communicator */
53: PetscReal h; /* mesh spacing */
54: } ApplicationCtx;
56: /*
57: User-defined context for monitoring
58: */
59: typedef struct {
60: PetscViewer viewer;
61: } MonitorCtx;
63: /*
64: User-defined context for checking candidate iterates that are
65: determined by line search methods
66: */
67: typedef struct {
68: Vec last_step; /* previous iterate */
69: PetscReal tolerance; /* tolerance for changes between successive iterates */
70: } StepCheckCtx;
72: int main(int argc,char **argv)
73: {
74: SNES snes; /* SNES context */
75: Mat J; /* Jacobian matrix */
76: ApplicationCtx ctx; /* user-defined context */
77: Vec x,r,U,F; /* vectors */
78: MonitorCtx monP; /* monitoring context */
79: StepCheckCtx checkP; /* step-checking context */
80: PetscTruth step_check; /* flag indicating whether we're checking
81: candidate iterates */
82: PetscScalar xp,*FF,*UU,none = -1.0;
83: int ierr,its,N = 5,i,maxit,maxf,xs,xm;
84: PetscReal atol,rtol,stol,norm;
86: PetscInitialize(&argc,&argv,(char *)0,help);
87: MPI_Comm_rank(PETSC_COMM_WORLD,&ctx.rank);
88: MPI_Comm_size(PETSC_COMM_WORLD,&ctx.size);
89: PetscOptionsGetInt(PETSC_NULL,"-n",&N,PETSC_NULL);
90: ctx.h = 1.0/(N-1);
92: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
93: Create nonlinear solver context
94: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
96: SNESCreate(PETSC_COMM_WORLD,&snes);
98: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
99: Create vector data structures; set function evaluation routine
100: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
102: /*
103: Create distributed array (DA) to manage parallel grid and vectors
104: */
105: DACreate1d(PETSC_COMM_WORLD,DA_NONPERIODIC,N,1,1,PETSC_NULL,&ctx.da);
107: /*
108: Extract global and local vectors from DA; then duplicate for remaining
109: vectors that are the same types
110: */
111: DACreateGlobalVector(ctx.da,&x);
112: VecDuplicate(x,&r);
113: VecDuplicate(x,&F); ctx.F = F;
114: VecDuplicate(x,&U);
116: /*
117: Set function evaluation routine and vector. Whenever the nonlinear
118: solver needs to compute the nonlinear function, it will call this
119: routine.
120: - Note that the final routine argument is the user-defined
121: context that provides application-specific data for the
122: function evaluation routine.
123: */
124: SNESSetFunction(snes,r,FormFunction,&ctx);
126: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
127: Create matrix data structure; set Jacobian evaluation routine
128: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
130: MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,N,N,&J);
131: MatSetFromOptions(J);
133: /*
134: Set Jacobian matrix data structure and default Jacobian evaluation
135: routine. Whenever the nonlinear solver needs to compute the
136: Jacobian matrix, it will call this routine.
137: - Note that the final routine argument is the user-defined
138: context that provides application-specific data for the
139: Jacobian evaluation routine.
140: */
141: SNESSetJacobian(snes,J,J,FormJacobian,&ctx);
143: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
144: Customize nonlinear solver; set runtime options
145: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
147: /*
148: Set an optional user-defined monitoring routine
149: */
150: PetscViewerDrawOpen(PETSC_COMM_WORLD,0,0,0,0,400,400,&monP.viewer);
151: SNESSetMonitor(snes,Monitor,&monP,0);
153: /*
154: Set names for some vectors to facilitate monitoring (optional)
155: */
156: PetscObjectSetName((PetscObject)x,"Approximate Solution");
157: PetscObjectSetName((PetscObject)U,"Exact Solution");
159: /*
160: Set SNES/SLES/KSP/PC runtime options, e.g.,
161: -snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc>
162: */
163: SNESSetFromOptions(snes);
165: /*
166: Set an optional user-defined routine to check the validity of candidate
167: iterates that are determined by line search methods
168: */
169: PetscOptionsHasName(PETSC_NULL,"-check_iterates",&step_check);
170: if (step_check) {
171: PetscPrintf(PETSC_COMM_WORLD,"Activating step checking routinen");
172: SNESSetLineSearchCheck(snes,StepCheck,&checkP);
173: VecDuplicate(x,&(checkP.last_step));
174: checkP.tolerance = 1.0;
175: PetscOptionsGetReal(PETSC_NULL,"-check_tol",&checkP.tolerance,PETSC_NULL);
176: }
179: /*
180: Print parameters used for convergence testing (optional) ... just
181: to demonstrate this routine; this information is also printed with
182: the option -snes_view
183: */
184: SNESGetTolerances(snes,&atol,&rtol,&stol,&maxit,&maxf);
185: PetscPrintf(PETSC_COMM_WORLD,"atol=%g, rtol=%g, stol=%g, maxit=%d, maxf=%dn",atol,rtol,stol,maxit,maxf);
187: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
188: Initialize application:
189: Store right-hand-side of PDE and exact solution
190: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
192: /*
193: Get local grid boundaries (for 1-dimensional DA):
194: xs, xm - starting grid index, width of local grid (no ghost points)
195: */
196: DAGetCorners(ctx.da,&xs,PETSC_NULL,PETSC_NULL,&xm,PETSC_NULL,PETSC_NULL);
198: /*
199: Get pointers to vector data
200: */
201: DAVecGetArray(ctx.da,F,(void**)&FF);
202: DAVecGetArray(ctx.da,U,(void**)&UU);
204: /*
205: Compute local vector entries
206: */
207: xp = ctx.h*xs;
208: for (i=xs; i<xs+xm; i++) {
209: FF[i] = 6.0*xp + PetscPowScalar(xp+1.e-12,6.0); /* +1.e-12 is to prevent 0^6 */
210: UU[i] = xp*xp*xp;
211: xp += ctx.h;
212: }
214: /*
215: Restore vectors
216: */
217: DAVecRestoreArray(ctx.da,F,(void**)&FF);
218: DAVecRestoreArray(ctx.da,U,(void**)&UU);
220: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
221: Evaluate initial guess; then solve nonlinear system
222: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
224: /*
225: Note: The user should initialize the vector, x, with the initial guess
226: for the nonlinear solver prior to calling SNESSolve(). In particular,
227: to employ an initial guess of zero, the user should explicitly set
228: this vector to zero by calling VecSet().
229: */
230: FormInitialGuess(x);
231: SNESSolve(snes,x,&its);
232: PetscPrintf(PETSC_COMM_WORLD,"Number of Newton iterations = %dnn",its);
234: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
235: Check solution and clean up
236: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
238: /*
239: Check the error
240: */
241: VecAXPY(&none,U,x);
242: ierr = VecNorm(x,NORM_2,&norm);
243: PetscPrintf(PETSC_COMM_WORLD,"Norm of error %A, Iterations %dn",norm,its);
245: /*
246: Free work space. All PETSc objects should be destroyed when they
247: are no longer needed.
248: */
249: PetscViewerDestroy(monP.viewer);
250: if (step_check) {VecDestroy(checkP.last_step);}
251: VecDestroy(x);
252: VecDestroy(r);
253: VecDestroy(U);
254: VecDestroy(F);
255: MatDestroy(J);
256: SNESDestroy(snes);
257: DADestroy(ctx.da);
258: PetscFinalize();
260: return(0);
261: }
262: /* ------------------------------------------------------------------- */
263: /*
264: FormInitialGuess - Computes initial guess.
266: Input/Output Parameter:
267: . x - the solution vector
268: */
269: int FormInitialGuess(Vec x)
270: {
271: int ierr;
272: PetscScalar pfive = .50;
275: VecSet(&pfive,x);
276: return(0);
277: }
278: /* ------------------------------------------------------------------- */
279: /*
280: FormFunction - Evaluates nonlinear function, F(x).
282: Input Parameters:
283: . snes - the SNES context
284: . x - input vector
285: . ctx - optional user-defined context, as set by SNESSetFunction()
287: Output Parameter:
288: . f - function vector
290: Note:
291: The user-defined context can contain any application-specific
292: data needed for the function evaluation.
293: */
294: int FormFunction(SNES snes,Vec x,Vec f,void *ctx)
295: {
296: ApplicationCtx *user = (ApplicationCtx*) ctx;
297: DA da = user->da;
298: PetscScalar *xx,*ff,*FF,d;
299: int i,ierr,M,xs,xm;
300: Vec xlocal;
303: DAGetLocalVector(da,&xlocal);
304: /*
305: Scatter ghost points to local vector, using the 2-step process
306: DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
307: By placing code between these two statements, computations can
308: be done while messages are in transition.
309: */
310: DAGlobalToLocalBegin(da,x,INSERT_VALUES,xlocal);
311: DAGlobalToLocalEnd(da,x,INSERT_VALUES,xlocal);
313: /*
314: Get pointers to vector data.
315: - The vector xlocal includes ghost point; the vectors x and f do
316: NOT include ghost points.
317: - Using DAVecGetArray() allows accessing the values using global ordering
318: */
319: DAVecGetArray(da,xlocal,(void**)&xx);
320: DAVecGetArray(da,f,(void**)&ff);
321: DAVecGetArray(da,user->F,(void**)&FF);
323: /*
324: Get local grid boundaries (for 1-dimensional DA):
325: xs, xm - starting grid index, width of local grid (no ghost points)
326: */
327: DAGetCorners(da,&xs,PETSC_NULL,PETSC_NULL,&xm,PETSC_NULL,PETSC_NULL);
328: DAGetInfo(da,PETSC_NULL,&M,PETSC_NULL,PETSC_NULL,PETSC_NULL,PETSC_NULL,PETSC_NULL,PETSC_NULL,
329: PETSC_NULL,PETSC_NULL,PETSC_NULL);
331: /*
332: Set function values for boundary points; define local interior grid point range:
333: xsi - starting interior grid index
334: xei - ending interior grid index
335: */
336: if (xs == 0) { /* left boundary */
337: ff[0] = xx[0];
338: xs++;xm--;
339: }
340: if (xs+xm == M) { /* right boundary */
341: ff[xs+xm-1] = xx[xs+xm-1] - 1.0;
342: xm--;
343: }
345: /*
346: Compute function over locally owned part of the grid (interior points only)
347: */
348: d = 1.0/(user->h*user->h);
349: for (i=xs; i<xs+xm; i++) {
350: ff[i] = d*(xx[i-1] - 2.0*xx[i] + xx[i+1]) + xx[i]*xx[i] - FF[i];
351: }
353: /*
354: Restore vectors
355: */
356: DAVecRestoreArray(da,xlocal,(void**)&xx);
357: DAVecRestoreArray(da,f,(void**)&ff);
358: DAVecRestoreArray(da,user->F,(void**)&FF);
359: DARestoreLocalVector(da,&xlocal);
360: return(0);
361: }
362: /* ------------------------------------------------------------------- */
363: /*
364: FormJacobian - Evaluates Jacobian matrix.
366: Input Parameters:
367: . snes - the SNES context
368: . x - input vector
369: . dummy - optional user-defined context (not used here)
371: Output Parameters:
372: . jac - Jacobian matrix
373: . B - optionally different preconditioning matrix
374: . flag - flag indicating matrix structure
375: */
376: int FormJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure*flag,void *ctx)
377: {
378: ApplicationCtx *user = (ApplicationCtx*) ctx;
379: PetscScalar *xx,d,A[3];
380: int i,j[3],ierr,M,xs,xm;
381: DA da = user->da;
384: /*
385: Get pointer to vector data
386: */
387: DAVecGetArray(da,x,(void**)&xx);
388: DAGetCorners(da,&xs,PETSC_NULL,PETSC_NULL,&xm,PETSC_NULL,PETSC_NULL);
390: /*
391: Get range of locally owned matrix
392: */
393: DAGetInfo(da,PETSC_NULL,&M,PETSC_NULL,PETSC_NULL,PETSC_NULL,PETSC_NULL,PETSC_NULL,PETSC_NULL,
394: PETSC_NULL,PETSC_NULL,PETSC_NULL);
396: /*
397: Determine starting and ending local indices for interior grid points.
398: Set Jacobian entries for boundary points.
399: */
401: if (xs == 0) { /* left boundary */
402: i = 0; A[0] = 1.0;
403: MatSetValues(*jac,1,&i,1,&i,A,INSERT_VALUES);
404: xs++;xm--;
405: }
406: if (xs+xm == M) { /* right boundary */
407: i = M-1; A[0] = 1.0;
408: MatSetValues(*jac,1,&i,1,&i,A,INSERT_VALUES);
409: xm--;
410: }
412: /*
413: Interior grid points
414: - Note that in this case we set all elements for a particular
415: row at once.
416: */
417: d = 1.0/(user->h*user->h);
418: for (i=xs; i<xs+xm; i++) {
419: j[0] = i - 1; j[1] = i; j[2] = i + 1;
420: A[0] = A[2] = d; A[1] = -2.0*d + 2.0*xx[i];
421: MatSetValues(*jac,1,&i,3,j,A,INSERT_VALUES);
422: }
424: /*
425: Assemble matrix, using the 2-step process:
426: MatAssemblyBegin(), MatAssemblyEnd().
427: By placing code between these two statements, computations can be
428: done while messages are in transition.
430: Also, restore vector.
431: */
433: MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
434: DAVecRestoreArray(da,x,(void**)&xx);
435: MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);
437: *flag = SAME_NONZERO_PATTERN;
438: return(0);
439: }
440: /* ------------------------------------------------------------------- */
441: /*
442: Monitor - Optional user-defined monitoring routine that views the
443: current iterate with an x-window plot. Set by SNESSetMonitor().
445: Input Parameters:
446: snes - the SNES context
447: its - iteration number
448: norm - 2-norm function value (may be estimated)
449: ctx - optional user-defined context for private data for the
450: monitor routine, as set by SNESSetMonitor()
452: Note:
453: See the manpage for PetscViewerDrawOpen() for useful runtime options,
454: such as -nox to deactivate all x-window output.
455: */
456: int Monitor(SNES snes,int its,PetscReal fnorm,void *ctx)
457: {
458: int ierr;
459: MonitorCtx *monP = (MonitorCtx*) ctx;
460: Vec x;
463: PetscPrintf(PETSC_COMM_WORLD,"iter = %d,SNES Function norm %gn",its,fnorm);
464: SNESGetSolution(snes,&x);
465: VecView(x,monP->viewer);
466: return(0);
467: }
468: /* ------------------------------------------------------------------- */
469: /*
470: StepCheck - Optional user-defined routine that checks the validity of
471: candidate steps of a line search method. Set by SNESSetLineSearchCheck().
473: Input Parameters:
474: snes - the SNES context
475: ctx - optional user-defined context for private data for the
476: monitor routine, as set by SNESSetLineSearchCheck()
477: x - the new candidate iterate
479: Output Parameters:
480: x - current iterate (possibly modified)
481: flg - flag indicating whether x has been modified (either
482: PETSC_TRUE of PETSC_FALSE)
483: */
484: int StepCheck(SNES snes,void *ctx,Vec x,PetscTruth *flg)
485: {
486: int ierr,i,iter,xs,xm;
487: ApplicationCtx *user;
488: StepCheckCtx *check = (StepCheckCtx*) ctx;
489: PetscScalar *xa,*xa_last,tmp;
490: PetscReal rdiff;
491: DA da;
494: *flg = PETSC_FALSE;
495: SNESGetIterationNumber(snes,&iter);
497: if (iter > 1) {
498: SNESGetApplicationContext(snes,(void**)&user);
499: da = user->da;
500: PetscPrintf(PETSC_COMM_WORLD,"Checking candidate step at iteration %d with tolerance %gn",
501: iter,check->tolerance);
503: /* Access local array data */
504: DAVecGetArray(da,check->last_step,(void**)&xa_last);
505: DAVecGetArray(da,x,(void**)&xa);
506: DAGetCorners(da,&xs,PETSC_NULL,PETSC_NULL,&xm,PETSC_NULL,PETSC_NULL);
508: /*
509: If we fail the user-defined check for validity of the candidate iterate,
510: then modify the iterate as we like. (Note that the particular modification
511: below is intended simply to demonstrate how to manipulate this data, not
512: as a meaningful or appropriate choice.)
513: */
514: for (i=xs; i<xs+xm; i++) {
515: rdiff = PetscAbsScalar((xa[i] - xa_last[i])/xa[i]);
516: if (rdiff > check->tolerance) {
517: tmp = xa[i];
518: xa[i] = (xa[i] + xa_last[i])/2.0;
519: *flg = PETSC_TRUE;
520: PetscPrintf(PETSC_COMM_WORLD," Altering entry %d: x=%g, x_last=%g, diff=%g, x_new=%gn",
521: i,PetscAbsScalar(tmp),PetscAbsScalar(xa_last[i]),rdiff,PetscAbsScalar(xa[i]));
522: }
523: }
524: DAVecRestoreArray(da,check->last_step,(void**)&xa_last);
525: DAVecRestoreArray(da,x,(void**)&xa);
526: }
527: VecCopy(x,check->last_step);
529: return(0);
530: }