Actual source code: ex5.c

  1: /*$Id: ex5.c,v 1.142 2001/08/07 21:31:17 bsmith Exp $*/

  3: /* Program usage:  mpirun -np <procs> ex5 [-help] [all PETSc options] */

  5: static char help[] = "Bratu nonlinear PDE in 2d.n
  6: We solve the  Bratu (SFI - solid fuel ignition) problem in a 2D rectangularn
  7: domain, using distributed arrays (DAs) to partition the parallel grid.n
  8: The command line options include:n
  9:   -par <parameter>, where <parameter> indicates the problem's nonlinearityn
 10:      problem SFI:  <parameter> = Bratu parameter (0 <= par <= 6.81)nn";

 12: /*T
 13:    Concepts: SNES^parallel Bratu example
 14:    Concepts: DA^using distributed arrays;
 15:    Processors: n
 16: T*/

 18: /* ------------------------------------------------------------------------

 20:     Solid Fuel Ignition (SFI) problem.  This problem is modeled by
 21:     the partial differential equation
 22:   
 23:             -Laplacian u - lambda*exp(u) = 0,  0 < x,y < 1,
 24:   
 25:     with boundary conditions
 26:    
 27:              u = 0  for  x = 0, x = 1, y = 0, y = 1.
 28:   
 29:     A finite difference approximation with the usual 5-point stencil
 30:     is used to discretize the boundary value problem to obtain a nonlinear 
 31:     system of equations.


 34:   ------------------------------------------------------------------------- */

 36: /* 
 37:    Include "petscda.h" so that we can use distributed arrays (DAs).
 38:    Include "petscsnes.h" so that we can use SNES solvers.  Note that this
 39:    file automatically includes:
 40:      petsc.h       - base PETSc routines   petscvec.h - vectors
 41:      petscsys.h    - system routines       petscmat.h - matrices
 42:      petscis.h     - index sets            petscksp.h - Krylov subspace methods
 43:      petscviewer.h - viewers               petscpc.h  - preconditioners
 44:      petscsles.h   - linear solvers
 45: */
 46:  #include petscda.h
 47:  #include petscsnes.h

 49: /* 
 50:    User-defined application context - contains data needed by the 
 51:    application-provided call-back routines, FormJacobian() and
 52:    FormFunction().
 53: */
 54: typedef struct {
 55:    DA            da;             /* distributed array data structure */
 56:    PassiveReal param;          /* test problem parameter */
 57: } AppCtx;

 59: /* 
 60:    User-defined routines
 61: */
 62: extern int FormFunction(SNES,Vec,Vec,void*),FormInitialGuess(AppCtx*,Vec),FormFunctionMatlab(SNES,Vec,Vec,void*);
 63: extern int FormJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*);
 64: extern int FormFunctionLocal(DALocalInfo*,PetscScalar**,PetscScalar**,AppCtx*);
 65: extern int FormJacobianLocal(DALocalInfo*,PetscScalar**,Mat,AppCtx*);

 67: int main(int argc,char **argv)
 68: {
 69:   SNES                   snes;                 /* nonlinear solver */
 70:   Vec                    x,r;                  /* solution, residual vectors */
 71:   Mat                    A,J;                    /* Jacobian matrix */
 72:   AppCtx                 user;                 /* user-defined work context */
 73:   int                    its;                  /* iterations for convergence */
 74:   PetscTruth             local_function = PETSC_TRUE,global_function = PETSC_FALSE,matlab_function = PETSC_FALSE;
 75:   PetscTruth             fd_jacobian = PETSC_FALSE,global_jacobian=PETSC_FALSE,local_jacobian=PETSC_TRUE,adic_jacobian=PETSC_FALSE;
 76:   PetscTruth             adicmf_jacobian = PETSC_FALSE;
 77:   int                    ierr;
 78:   PetscReal              bratu_lambda_max = 6.81,bratu_lambda_min = 0.,fnorm;
 79:   MatFDColoring          matfdcoloring = 0;
 80:   ISColoring             iscoloring;


 83: 
 84:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 85:      Initialize program
 86:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 88:   PetscInitialize(&argc,&argv,(char *)0,help);

 90:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 91:      Initialize problem parameters
 92:   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 93:   user.param = 6.0;
 94:   PetscOptionsGetReal(PETSC_NULL,"-par",&user.param,PETSC_NULL);
 95:   if (user.param >= bratu_lambda_max || user.param <= bratu_lambda_min) {
 96:     SETERRQ(1,"Lambda is out of range");
 97:   }

 99:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
100:      Create nonlinear solver context
101:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
102:   SNESCreate(PETSC_COMM_WORLD,&snes);

104:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
105:      Create distributed array (DA) to manage parallel grid and vectors
106:   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
107:   DACreate2d(PETSC_COMM_WORLD,DA_NONPERIODIC,DA_STENCIL_STAR,-4,-4,PETSC_DECIDE,PETSC_DECIDE,
108:                     1,1,PETSC_NULL,PETSC_NULL,&user.da);

110:   /*  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
111:      Extract global vectors from DA; then duplicate for remaining
112:      vectors that are the same types
113:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
114:   DACreateGlobalVector(user.da,&x);
115:   VecDuplicate(x,&r);

117:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
118:      Set local function evaluation routine
119:   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
120:   DASetLocalFunction(user.da,(DALocalFunction1)FormFunctionLocal);
121:   DASetLocalJacobian(user.da,(DALocalFunction1)FormJacobianLocal);
122:   DASetLocalAdicFunction(user.da,ad_FormFunctionLocal);

124:   /* Decide which FormFunction to use */
125:   PetscOptionsGetLogical(PETSC_NULL,"-matlab_function",&matlab_function,0);
126:   PetscOptionsGetLogical(PETSC_NULL,"-global_function",&global_function,0);
127:   PetscOptionsGetLogical(PETSC_NULL,"-local_function",&local_function,0);

129:   if (global_function) {
130:     SNESSetFunction(snes,r,FormFunction,&user);
131: #if defined(PETSC_HAVE_MATLAB_ENGINE) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
132:   } else if (matlab_function) {
133:     SNESSetFunction(snes,r,FormFunctionMatlab,&user);
134: #endif
135:   } else if (local_function) {
136:     SNESSetFunction(snes,r,SNESDAFormFunction,&user);
137:   }

139:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
140:      Create matrix data structure; set Jacobian evaluation routine

142:      Set Jacobian matrix data structure and default Jacobian evaluation
143:      routine. User can override with:
144:      -snes_mf : matrix-free Newton-Krylov method with no preconditioning
145:                 (unless user explicitly sets preconditioner) 
146:      -snes_mf_operator : form preconditioning matrix as set by the user,
147:                          but use matrix-free approx for Jacobian-vector
148:                          products within Newton-Krylov method

150:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
151:   DAGetMatrix(user.da,MATMPIAIJ,&J);
152:   A    = J;

154:   PetscOptionsGetLogical(PETSC_NULL,"-fd_jacobian",&fd_jacobian,0);
155:   PetscOptionsGetLogical(PETSC_NULL,"-adic_jacobian",&adic_jacobian,0);
156:   PetscOptionsGetLogical(PETSC_NULL,"-global_jacobian",&global_jacobian,0);
157:   PetscOptionsGetLogical(PETSC_NULL,"-local_jacobian",&local_jacobian,0);

159:   PetscOptionsGetLogical(PETSC_NULL,"-adicmf_jacobian",&adicmf_jacobian,0);
160: #if defined(PETSC_HAVE_ADIC) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
161:   if (adicmf_jacobian) {
162:     DASetLocalAdicMFFunction(user.da,admf_FormFunctionLocal);
163:     MatRegisterDAAD();
164:     MatCreateDAAD(user.da,&A);
165:     MatDAADSetSNES(A,snes);
166:     MatDAADSetCtx(A,&user);
167:   }
168: #endif

170:   if (fd_jacobian) {
171:     DAGetColoring(user.da,IS_COLORING_LOCAL,&iscoloring);
172:     MatFDColoringCreate(J,iscoloring,&matfdcoloring);
173:     ISColoringDestroy(iscoloring);
174:     MatFDColoringSetFunction(matfdcoloring,(int (*)(void))FormFunction,&user);
175:     MatFDColoringSetFromOptions(matfdcoloring);
176:     SNESSetJacobian(snes,A,J,SNESDefaultComputeJacobianColor,matfdcoloring);
177: #if defined(PETSC_HAVE_ADIC) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
178:   } else if (adic_jacobian) {
179:     DAGetColoring(user.da,IS_COLORING_GHOSTED,&iscoloring);
180:     MatSetColoring(J,iscoloring);
181:     ISColoringDestroy(iscoloring);
182:     SNESSetJacobian(snes,A,J,SNESDAComputeJacobianWithAdic,&user);
183: #endif
184:   } else if (global_jacobian){
185:     SNESSetJacobian(snes,A,J,FormJacobian,&user);
186:   } else if (local_jacobian){
187:     SNESSetJacobian(snes,A,J,SNESDAComputeJacobian,&user);
188:   }

190:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
191:      Customize nonlinear solver; set runtime options
192:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
193:   SNESSetFromOptions(snes);

195:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
196:      Evaluate initial guess
197:      Note: The user should initialize the vector, x, with the initial guess
198:      for the nonlinear solver prior to calling SNESSolve().  In particular,
199:      to employ an initial guess of zero, the user should explicitly set
200:      this vector to zero by calling VecSet().
201:   */
202:   FormInitialGuess(&user,x);

204:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
205:      Solve nonlinear system
206:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
207:   SNESSolve(snes,x,&its);

209:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
210:      Explicitly check norm of the residual of the solution
211:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
212:   FormFunction(snes,x,r,(void *)&user);
213:   VecNorm(r,NORM_2,&fnorm);
214:   PetscPrintf(PETSC_COMM_WORLD,"Number of Newton iterations = %d fnorm %gn",its,fnorm);

216:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
217:      Free work space.  All PETSc objects should be destroyed when they
218:      are no longer needed.
219:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

221:   if (A != J) {
222:     MatDestroy(A);
223:   }
224:   MatDestroy(J);
225:   if (matfdcoloring) {
226:     MatFDColoringDestroy(matfdcoloring);
227:   }
228:   VecDestroy(x);
229:   VecDestroy(r);
230:   SNESDestroy(snes);
231:   DADestroy(user.da);
232:   PetscFinalize();

234:   return(0);
235: }
236: /* ------------------------------------------------------------------- */
237: /* 
238:    FormInitialGuess - Forms initial approximation.

240:    Input Parameters:
241:    user - user-defined application context
242:    X - vector

244:    Output Parameter:
245:    X - vector
246:  */
247: int FormInitialGuess(AppCtx *user,Vec X)
248: {
249:   int         i,j,Mx,My,ierr,xs,ys,xm,ym;
250:   PetscReal   lambda,temp1,temp,hx,hy;
251:   PetscScalar **x;

254:   DAGetInfo(user->da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
255:                    PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);

257:   lambda = user->param;
258:   hx     = 1.0/(PetscReal)(Mx-1);
259:   hy     = 1.0/(PetscReal)(My-1);
260:   temp1  = lambda/(lambda + 1.0);

262:   /*
263:      Get a pointer to vector data.
264:        - For default PETSc vectors, VecGetArray() returns a pointer to
265:          the data array.  Otherwise, the routine is implementation dependent.
266:        - You MUST call VecRestoreArray() when you no longer need access to
267:          the array.
268:   */
269:   DAVecGetArray(user->da,X,(void**)&x);

271:   /*
272:      Get local grid boundaries (for 2-dimensional DA):
273:        xs, ys   - starting grid indices (no ghost points)
274:        xm, ym   - widths of local grid (no ghost points)

276:   */
277:   DAGetCorners(user->da,&xs,&ys,PETSC_NULL,&xm,&ym,PETSC_NULL);

279:   /*
280:      Compute initial guess over the locally owned part of the grid
281:   */
282:   for (j=ys; j<ys+ym; j++) {
283:     temp = (PetscReal)(PetscMin(j,My-j-1))*hy;
284:     for (i=xs; i<xs+xm; i++) {

286:       if (i == 0 || j == 0 || i == Mx-1 || j == My-1) {
287:         /* boundary conditions are all zero Dirichlet */
288:         x[j][i] = 0.0;
289:       } else {
290:         x[j][i] = temp1*sqrt(PetscMin((PetscReal)(PetscMin(i,Mx-i-1))*hx,temp));
291:       }
292:     }
293:   }

295:   /*
296:      Restore vector
297:   */
298:   DAVecRestoreArray(user->da,X,(void**)&x);

300:   return(0);
301: }
302: /* ------------------------------------------------------------------- */
303: /* 
304:    FormFunction - Evaluates nonlinear function, F(x).

306:    Input Parameters:
307: .  snes - the SNES context
308: .  X - input vector
309: .  ptr - optional user-defined context, as set by SNESSetFunction()

311:    Output Parameter:
312: .  F - function vector
313:  */
314: int FormFunction(SNES snes,Vec X,Vec F,void *ptr)
315: {
316:   AppCtx       *user = (AppCtx*)ptr;
317:   int          ierr,i,j,Mx,My,xs,ys,xm,ym;
318:   PetscReal    two = 2.0,lambda,hx,hy,hxdhy,hydhx,sc;
319:   PetscScalar  u,uxx,uyy,**x,**f;
320:   Vec          localX;

323:   DAGetLocalVector(user->da,&localX);
324:   DAGetInfo(user->da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
325:                    PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);

327:   lambda = user->param;
328:   hx     = 1.0/(PetscReal)(Mx-1);
329:   hy     = 1.0/(PetscReal)(My-1);
330:   sc     = hx*hy*lambda;
331:   hxdhy  = hx/hy;
332:   hydhx  = hy/hx;

334:   /*
335:      Scatter ghost points to local vector,using the 2-step process
336:         DAGlobalToLocalBegin(),DAGlobalToLocalEnd().
337:      By placing code between these two statements, computations can be
338:      done while messages are in transition.
339:   */
340:   DAGlobalToLocalBegin(user->da,X,INSERT_VALUES,localX);
341:   DAGlobalToLocalEnd(user->da,X,INSERT_VALUES,localX);

343:   /*
344:      Get pointers to vector data
345:   */
346:   DAVecGetArray(user->da,localX,(void**)&x);
347:   DAVecGetArray(user->da,F,(void**)&f);

349:   /*
350:      Get local grid boundaries
351:   */
352:   DAGetCorners(user->da,&xs,&ys,PETSC_NULL,&xm,&ym,PETSC_NULL);

354:   /*
355:      Compute function over the locally owned part of the grid
356:   */
357:   for (j=ys; j<ys+ym; j++) {
358:     for (i=xs; i<xs+xm; i++) {
359:       if (i == 0 || j == 0 || i == Mx-1 || j == My-1) {
360:         f[j][i] = x[j][i];
361:       } else {
362:         u       = x[j][i];
363:         uxx     = (two*u - x[j][i-1] - x[j][i+1])*hydhx;
364:         uyy     = (two*u - x[j-1][i] - x[j+1][i])*hxdhy;
365:         f[j][i] = uxx + uyy - sc*PetscExpScalar(u);
366:       }
367:     }
368:   }

370:   /*
371:      Restore vectors
372:   */
373:   DAVecRestoreArray(user->da,localX,(void**)&x);
374:   DAVecRestoreArray(user->da,F,(void**)&f);
375:   DARestoreLocalVector(user->da,&localX);
376:   PetscLogFlops(11*ym*xm);
377:   return(0);
378: }
379: /* ------------------------------------------------------------------- */
380: /* 
381:    FormFunctionLocal - Evaluates nonlinear function, F(x).

383:        Process adiC: FormFunctionLocal

385:  */
386: int FormFunctionLocal(DALocalInfo *info,PetscScalar **x,PetscScalar **f,AppCtx *user)
387: {
388:   int         ierr,i,j;
389:   PetscReal   two = 2.0,lambda,hx,hy,hxdhy,hydhx,sc;
390:   PetscScalar u,uxx,uyy;


394:   lambda = user->param;
395:   hx     = 1.0/(PetscReal)(info->mx-1);
396:   hy     = 1.0/(PetscReal)(info->my-1);
397:   sc     = hx*hy*lambda;
398:   hxdhy  = hx/hy;
399:   hydhx  = hy/hx;
400:   /*
401:      Compute function over the locally owned part of the grid
402:   */
403:   for (j=info->ys; j<info->ys+info->ym; j++) {
404:     for (i=info->xs; i<info->xs+info->xm; i++) {
405:       if (i == 0 || j == 0 || i == info->mx-1 || j == info->my-1) {
406:         f[j][i] = x[j][i];
407:       } else {
408:         u       = x[j][i];
409:         uxx     = (two*u - x[j][i-1] - x[j][i+1])*hydhx;
410:         uyy     = (two*u - x[j-1][i] - x[j+1][i])*hxdhy;
411:         f[j][i] = uxx + uyy - sc*PetscExpScalar(u);
412:       }
413:     }
414:   }

416:   PetscLogFlops(11*info->ym*info->xm);
417:   return(0);
418: }
419: /* ------------------------------------------------------------------- */
420: /*
421:    FormJacobian - Evaluates Jacobian matrix.

423:    Input Parameters:
424: .  snes - the SNES context
425: .  x - input vector
426: .  ptr - optional user-defined context, as set by SNESSetJacobian()

428:    Output Parameters:
429: .  A - Jacobian matrix
430: .  B - optionally different preconditioning matrix
431: .  flag - flag indicating matrix structure

433: */
434: int FormJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
435: {
436:   AppCtx       *user = (AppCtx*)ptr;  /* user-defined application context */
437:   Mat          jac = *B;                /* Jacobian matrix */
438:   Vec          localX;
439:   int          ierr,i,j;
440:   MatStencil   col[5],row;
441:   int          xs,ys,xm,ym,Mx,My;
442:   PetscScalar  lambda,v[5],hx,hy,hxdhy,hydhx,sc,**x;

445:   DAGetLocalVector(user->da,&localX);
446:   DAGetInfo(user->da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
447:                    PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);

449:   lambda = user->param;
450:   hx     = 1.0/(PetscReal)(Mx-1);
451:   hy     = 1.0/(PetscReal)(My-1);
452:   sc     = hx*hy*lambda;
453:   hxdhy  = hx/hy;
454:   hydhx  = hy/hx;


457:   /*
458:      Scatter ghost points to local vector, using the 2-step process
459:         DAGlobalToLocalBegin(), DAGlobalToLocalEnd().
460:      By placing code between these two statements, computations can be
461:      done while messages are in transition.
462:   */
463:   DAGlobalToLocalBegin(user->da,X,INSERT_VALUES,localX);
464:   DAGlobalToLocalEnd(user->da,X,INSERT_VALUES,localX);

466:   /*
467:      Get pointer to vector data
468:   */
469:   DAVecGetArray(user->da,localX,(void**)&x);

471:   /*
472:      Get local grid boundaries
473:   */
474:   DAGetCorners(user->da,&xs,&ys,PETSC_NULL,&xm,&ym,PETSC_NULL);

476:   /* 
477:      Compute entries for the locally owned part of the Jacobian.
478:       - Currently, all PETSc parallel matrix formats are partitioned by
479:         contiguous chunks of rows across the processors. 
480:       - Each processor needs to insert only elements that it owns
481:         locally (but any non-local elements will be sent to the
482:         appropriate processor during matrix assembly). 
483:       - Here, we set all entries for a particular row at once.
484:       - We can set matrix entries either using either
485:         MatSetValuesLocal() or MatSetValues(), as discussed above.
486:   */
487:   for (j=ys; j<ys+ym; j++) {
488:     for (i=xs; i<xs+xm; i++) {
489:       row.j = j; row.i = i;
490:       /* boundary points */
491:       if (i == 0 || j == 0 || i == Mx-1 || j == My-1) {
492:         v[0] = 1.0;
493:         MatSetValuesStencil(jac,1,&row,1,&row,v,INSERT_VALUES);
494:       } else {
495:       /* interior grid points */
496:         v[0] = -hxdhy;                                           col[0].j = j - 1; col[0].i = i;
497:         v[1] = -hydhx;                                           col[1].j = j;     col[1].i = i-1;
498:         v[2] = 2.0*(hydhx + hxdhy) - sc*PetscExpScalar(x[j][i]); col[2].j = row.j; col[2].i = row.i;
499:         v[3] = -hydhx;                                           col[3].j = j;     col[3].i = i+1;
500: 
501:       v[4] = -hxdhy;                                           col[4].j = j + 1; col[4].i = i;
502:         MatSetValuesStencil(jac,1,&row,5,col,v,INSERT_VALUES);
503:       }
504:     }
505:   }
506:   DAVecRestoreArray(user->da,localX,(void**)&x);
507:   DARestoreLocalVector(user->da,&localX);

509:   /* 
510:      Assemble matrix, using the 2-step process:
511:        MatAssemblyBegin(), MatAssemblyEnd().
512:   */
513:   MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
514:   MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);

516:   /*
517:      Normally since the matrix has already been assembled above; this
518:      would do nothing. But in the matrix free mode -snes_mf_operator
519:      this tells the "matrix-free" matrix that a new linear system solve
520:      is about to be done.
521:   */

523:   MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
524:   MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);

526:   /*
527:      Set flag to indicate that the Jacobian matrix retains an identical
528:      nonzero structure throughout all nonlinear iterations (although the
529:      values of the entries change). Thus, we can save some work in setting
530:      up the preconditioner (e.g., no need to redo symbolic factorization for
531:      ILU/ICC preconditioners).
532:       - If the nonzero structure of the matrix is different during
533:         successive linear solves, then the flag DIFFERENT_NONZERO_PATTERN
534:         must be used instead.  If you are unsure whether the matrix
535:         structure has changed or not, use the flag DIFFERENT_NONZERO_PATTERN.
536:       - Caution:  If you specify SAME_NONZERO_PATTERN, PETSc
537:         believes your assertion and does not check the structure
538:         of the matrix.  If you erroneously claim that the structure
539:         is the same when it actually is not, the new preconditioner
540:         will not function correctly.  Thus, use this optimization
541:         feature with caution!
542:   */
543:   *flag = SAME_NONZERO_PATTERN;


546:   /*
547:      Tell the matrix we will never add a new nonzero location to the
548:      matrix. If we do, it will generate an error.
549:   */
550:   MatSetOption(jac,MAT_NEW_NONZERO_LOCATION_ERR);
551:   return(0);
552: }

554: /*
555:    FormJacobianLocal - Evaluates Jacobian matrix.


558: */
559: int FormJacobianLocal(DALocalInfo *info,PetscScalar **x,Mat jac,AppCtx *user)
560: {
561:   int          ierr,i,j;
562:   MatStencil   col[5],row;
563:   PetscScalar  lambda,v[5],hx,hy,hxdhy,hydhx,sc;

566:   lambda = user->param;
567:   hx     = 1.0/(PetscReal)(info->mx-1);
568:   hy     = 1.0/(PetscReal)(info->my-1);
569:   sc     = hx*hy*lambda;
570:   hxdhy  = hx/hy;
571:   hydhx  = hy/hx;


574:   /* 
575:      Compute entries for the locally owned part of the Jacobian.
576:       - Currently, all PETSc parallel matrix formats are partitioned by
577:         contiguous chunks of rows across the processors. 
578:       - Each processor needs to insert only elements that it owns
579:         locally (but any non-local elements will be sent to the
580:         appropriate processor during matrix assembly). 
581:       - Here, we set all entries for a particular row at once.
582:       - We can set matrix entries either using either
583:         MatSetValuesLocal() or MatSetValues(), as discussed above.
584:   */
585:   for (j=info->ys; j<info->ys+info->ym; j++) {
586:     for (i=info->xs; i<info->xs+info->xm; i++) {
587:       row.j = j; row.i = i;
588:       /* boundary points */
589:       if (i == 0 || j == 0 || i == info->mx-1 || j == info->my-1) {
590:         v[0] = 1.0;
591:         MatSetValuesStencil(jac,1,&row,1,&row,v,INSERT_VALUES);
592:       } else {
593:       /* interior grid points */
594:         v[0] = -hxdhy;                                           col[0].j = j - 1; col[0].i = i;
595:         v[1] = -hydhx;                                           col[1].j = j;     col[1].i = i-1;
596:         v[2] = 2.0*(hydhx + hxdhy) - sc*PetscExpScalar(x[j][i]); col[2].j = row.j; col[2].i = row.i;
597:         v[3] = -hydhx;                                           col[3].j = j;     col[3].i = i+1;
598:         v[4] = -hxdhy;                                           col[4].j = j + 1; col[4].i = i;
599:         MatSetValuesStencil(jac,1,&row,5,col,v,INSERT_VALUES);
600:       }
601:     }
602:   }

604:   /* 
605:      Assemble matrix, using the 2-step process:
606:        MatAssemblyBegin(), MatAssemblyEnd().
607:   */
608:   MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
609:   MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
610:   /*
611:      Tell the matrix we will never add a new nonzero location to the
612:      matrix. If we do, it will generate an error.
613:   */
614:   MatSetOption(jac,MAT_NEW_NONZERO_LOCATION_ERR);
615:   return(0);
616: }

618: /*
619:       Variant of FormFunction() that computes the function in Matlab
620: */
621: #if defined(PETSC_HAVE_MATLAB_ENGINE) && !defined(PETSC_USE_COMPLEX) && !defined(PETSC_USE_SINGLE)
622: int FormFunctionMatlab(SNES snes,Vec X,Vec F,void *ptr)
623: {
624:   AppCtx    *user = (AppCtx*)ptr;
625:   int       ierr,Mx,My;
626:   PetscReal lambda,hx,hy;
627:   Vec       localX,localF;
628:   MPI_Comm  comm;

631:   DAGetLocalVector(user->da,&localX);
632:   DAGetLocalVector(user->da,&localF);
633:   PetscObjectSetName((PetscObject)localX,"localX");
634:   PetscObjectSetName((PetscObject)localF,"localF");
635:   DAGetInfo(user->da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
636:                    PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);

638:   lambda = user->param;
639:   hx     = 1.0/(PetscReal)(Mx-1);
640:   hy     = 1.0/(PetscReal)(My-1);

642:   PetscObjectGetComm((PetscObject)snes,&comm);
643:   /*
644:      Scatter ghost points to local vector,using the 2-step process
645:         DAGlobalToLocalBegin(),DAGlobalToLocalEnd().
646:      By placing code between these two statements, computations can be
647:      done while messages are in transition.
648:   */
649:   DAGlobalToLocalBegin(user->da,X,INSERT_VALUES,localX);
650:   DAGlobalToLocalEnd(user->da,X,INSERT_VALUES,localX);
651:   PetscMatlabEnginePut(PETSC_MATLAB_ENGINE_(comm),(PetscObject)localX);
652:   PetscMatlabEngineEvaluate(PETSC_MATLAB_ENGINE_(comm),"localF=ex5m(localX,%18.16e,%18.16e,%18.16e)",hx,hy,lambda);
653:   PetscMatlabEngineGet(PETSC_MATLAB_ENGINE_(comm),(PetscObject)localF);

655:   /*
656:      Insert values into global vector
657:   */
658:   DALocalToGlobal(user->da,localF,INSERT_VALUES,F);
659:   DARestoreLocalVector(user->da,&localX);
660:   DARestoreLocalVector(user->da,&localF);
661:   return(0);
662: }
663: #endif