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: }