Actual source code: ex10.c

petsc-3.3-p7 2013-05-11
  1: /* 
  2:   Program usage:  mpiexec -n <procs> usg [-help] [all PETSc options] 
  3: */

  5: #if !defined(PETSC_USE_COMPLEX)

  7: static char help[] = "An Unstructured Grid Example.\n\
  8: This example demonstrates how to solve a nonlinear system in parallel\n\
  9: with SNES for an unstructured mesh. The mesh and partitioning information\n\
 10: is read in an application defined ordering,which is later transformed\n\
 11: into another convenient ordering (called the local ordering). The local\n\
 12: ordering, apart from being efficient on cpu cycles and memory, allows\n\
 13: the use of the SPMD model of parallel programming. After partitioning\n\
 14: is done, scatters are created between local (sequential)and global\n\
 15: (distributed) vectors. Finally, we set up the nonlinear solver context\n\
 16: in the usual way as a structured grid  (see\n\
 17: petsc/src/snes/examples/tutorials/ex5.c).\n\
 18: This example also illustrates the use of parallel matrix coloring.\n\
 19: The command line options include:\n\
 20:   -vert <Nv>, where Nv is the global number of nodes\n\
 21:   -elem <Ne>, where Ne is the global number of elements\n\
 22:   -nl_par <lambda>, where lambda is the multiplier for the non linear term (u*u) term\n\
 23:   -lin_par <alpha>, where alpha is the multiplier for the linear term (u)\n\
 24:   -fd_jacobian_coloring -mat_coloring_type lf\n";

 26: /*T
 27:    Concepts: SNES^unstructured grid
 28:    Concepts: AO^application to PETSc ordering or vice versa;
 29:    Concepts: VecScatter^using vector scatter operations;
 30:    Processors: n
 31: T*/

 33: /* ------------------------------------------------------------------------

 35:    PDE Solved : L(u) + lambda*u*u + alpha*u = 0 where L(u) is the Laplacian.

 37:    The Laplacian is approximated in the following way: each edge is given a weight
 38:    of one meaning that the diagonal term will have the weight equal to the degree
 39:    of a node. The off diagonal terms will get a weight of -1. 

 41:    -----------------------------------------------------------------------*/

 43: /*
 44:    Include petscao.h so that we can use AO (Application Ordering) object's services.
 45:    Include "petscsnes.h" so that we can use SNES solvers.  Note that this
 46:    file automatically includes:
 47:      petscsys.h       - base PETSc routines   petscvec.h - vectors
 48:      petscmat.h - matrices
 49:      petscis.h     - index sets            petscksp.h - Krylov subspace methods
 50:      petscviewer.h - viewers               petscpc.h  - preconditioners
 51:      petscksp.h   - linear solvers
 52: */
 53: #include <petscao.h>
 54: #include <petscsnes.h>


 57: #define MAX_ELEM      500  /* Maximum number of elements */
 58: #define MAX_VERT      100  /* Maximum number of vertices */
 59: #define MAX_VERT_ELEM   3  /* Vertices per element       */

 61: /*
 62:   Application-defined context for problem specific data 
 63: */
 64: typedef struct {
 65:       PetscInt    Nvglobal,Nvlocal;            /* global and local number of vertices */
 66:       PetscInt    Neglobal,Nelocal;            /* global and local number of vertices */
 67:       PetscInt           AdjM[MAX_VERT][50];           /* adjacency list of a vertex */
 68:       PetscInt           itot[MAX_VERT];               /* total number of neighbors for a vertex */
 69:       PetscInt           icv[MAX_ELEM][MAX_VERT_ELEM]; /* vertices belonging to an element */
 70:       PetscInt          v2p[MAX_VERT];                /* processor number for a vertex */
 71:       PetscInt    *locInd,*gloInd;             /* local and global orderings for a node */
 72:       Vec           localX,localF;               /* local solution (u) and f(u) vectors */
 73:       PetscReal          non_lin_param;                /* nonlinear parameter for the PDE */
 74:       PetscReal          lin_param;                    /* linear parameter for the PDE */
 75:       VecScatter  scatter;                      /* scatter context for the local and 
 76:                                                     distributed vectors */
 77: } AppCtx;

 79: /*
 80:   User-defined routines
 81: */
 82: PetscErrorCode  FormJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*),
 83:                 FormFunction(SNES,Vec,Vec,void*),
 84:                 FormInitialGuess(AppCtx*,Vec);

 88: int main(int argc,char **argv)
 89: {
 90:   SNES                   snes;                 /* SNES context */
 91:   const SNESType         type = SNESLS;        /* default nonlinear solution method */
 92:   Vec                    x,r;                  /* solution, residual vectors */
 93:   Mat                    Jac;                  /* Jacobian matrix */
 94:   AppCtx                 user;                 /* user-defined application context */
 95:   AO                     ao;                   /* Application Ordering object */
 96:   IS                     isglobal,islocal;     /* global and local index sets */
 97:   PetscMPIInt            rank,size;            /* rank of a process, number of processors */
 98:   PetscInt               rstart;               /* starting index of PETSc ordering for a processor */
 99:   PetscInt               nfails;               /* number of unsuccessful Newton steps */
100:   PetscInt               bs = 1;               /* block size for multicomponent systems */
101:   PetscInt               nvertices;            /* number of local plus ghost nodes of a processor */
102:   PetscInt               *pordering;           /* PETSc ordering */
103:   PetscInt               *vertices;            /* list of all vertices (incl. ghost ones) 
104:                                                 on a processor */
105:   PetscInt               *verticesmask;
106:   PetscInt               *tmp;
107:   PetscInt               i,j,jstart,inode,nb,nbrs,Nvneighborstotal = 0;
108:   PetscErrorCode         ierr;
109:   PetscInt               its,N;
110:   PetscScalar            *xx;
111:   char                   str[256],form[256],part_name[256];
112:   FILE                   *fptr,*fptr1;
113:   ISLocalToGlobalMapping isl2g;
114:   int                    dtmp;
115: #if defined (UNUSED_VARIABLES)
116:   PetscDraw              draw;                 /* drawing context */
117:   PetscScalar            *ff,*gg;
118:   PetscReal              tiny = 1.0e-10,zero = 0.0,one = 1.0,big = 1.0e+10;
119:   PetscInt               *tmp1,*tmp2;
120: #endif
121:   MatFDColoring          matfdcoloring = 0;
122:   PetscBool              fd_jacobian_coloring = PETSC_FALSE;

124:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
125:      Initialize program
126:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

128:   PetscInitialize(&argc,&argv,"options.inf",help);
129:   MPI_Comm_rank(MPI_COMM_WORLD,&rank);
130:   MPI_Comm_size(MPI_COMM_WORLD,&size);

132:   /* The current input file options.inf is for 2 proc run only */
133:   if (size != 2) SETERRQ(PETSC_COMM_SELF,1,"This Example currently runs on 2 procs only.");

135:   /*
136:      Initialize problem parameters
137:   */
138:   user.Nvglobal = 16;      /*Global # of vertices  */
139:   user.Neglobal = 18;      /*Global # of elements  */
140:   PetscOptionsGetInt(PETSC_NULL,"-vert",&user.Nvglobal,PETSC_NULL);
141:   PetscOptionsGetInt(PETSC_NULL,"-elem",&user.Neglobal,PETSC_NULL);
142:   user.non_lin_param = 0.06;
143:   PetscOptionsGetReal(PETSC_NULL,"-nl_par",&user.non_lin_param,PETSC_NULL);
144:   user.lin_param = -1.0;
145:   PetscOptionsGetReal(PETSC_NULL,"-lin_par",&user.lin_param,PETSC_NULL);
146:   user.Nvlocal = 0;
147:   user.Nelocal = 0;

149:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
150:       Read the mesh and partitioning information  
151:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
152: 
153:   /*
154:      Read the mesh and partitioning information from 'adj.in'.
155:      The file format is as follows.
156:      For each line the first entry is the processor rank where the 
157:      current node belongs. The second entry is the number of 
158:      neighbors of a node. The rest of the line is the adjacency
159:      list of a node. Currently this file is set up to work on two 
160:      processors.

162:      This is not a very good example of reading input. In the future, 
163:      we will put an example that shows the style that should be 
164:      used in a real application, where partitioning will be done 
165:      dynamically by calling partitioning routines (at present, we have 
166:      a  ready interface to ParMeTiS). 
167:    */
168:   fptr = fopen("adj.in","r");
169:   if (!fptr) SETERRQ(PETSC_COMM_SELF,0,"Could not open adj.in");
170: 
171:   /*
172:      Each processor writes to the file output.<rank> where rank is the
173:      processor's rank.
174:   */
175:   sprintf(part_name,"output.%d",rank);
176:   fptr1 = fopen(part_name,"w");
177:   if (!fptr1) SETERRQ(PETSC_COMM_SELF,0,"Could no open output file");
178:   PetscMalloc(user.Nvglobal*sizeof(PetscInt),&user.gloInd);
179:   PetscFPrintf(PETSC_COMM_SELF,fptr1,"Rank is %D\n",rank);
180:   for (inode = 0; inode < user.Nvglobal; inode++) {
181:     if (!fgets(str,256,fptr)) SETERRQ(PETSC_COMM_SELF,1,"fgets read failed");
182:     sscanf(str,"%d",&dtmp);user.v2p[inode] = dtmp;
183:     if (user.v2p[inode] == rank) {
184:        PetscFPrintf(PETSC_COMM_SELF,fptr1,"Node %D belongs to processor %D\n",inode,user.v2p[inode]);
185:        user.gloInd[user.Nvlocal] = inode;
186:        sscanf(str,"%*d %d",&dtmp);nbrs = dtmp;
187:        PetscFPrintf(PETSC_COMM_SELF,fptr1,"Number of neighbors for the vertex %D is %D\n",inode,nbrs);
188:        user.itot[user.Nvlocal] = nbrs;
189:        Nvneighborstotal += nbrs;
190:        for (i = 0; i < user.itot[user.Nvlocal]; i++){
191:          form[0]='\0';
192:          for (j=0; j < i+2; j++){
193:            PetscStrcat(form,"%*d ");
194:          }
195:            PetscStrcat(form,"%d");
196:            sscanf(str,form,&dtmp); user.AdjM[user.Nvlocal][i] = dtmp;
197:            PetscFPrintf(PETSC_COMM_SELF,fptr1,"%D ",user.AdjM[user.Nvlocal][i]);
198:         }
199:         PetscFPrintf(PETSC_COMM_SELF,fptr1,"\n");
200:         user.Nvlocal++;
201:      }
202:    }
203:   PetscFPrintf(PETSC_COMM_SELF,fptr1,"Total # of Local Vertices is %D \n",user.Nvlocal);

205:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
206:      Create different orderings
207:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

209:   /*
210:     Create the local ordering list for vertices. First a list using the PETSc global 
211:     ordering is created. Then we use the AO object to get the PETSc-to-application and 
212:     application-to-PETSc mappings. Each vertex also gets a local index (stored in the 
213:     locInd array). 
214:   */
215:   MPI_Scan(&user.Nvlocal,&rstart,1,MPIU_INT,MPI_SUM,PETSC_COMM_WORLD);
216:   rstart -= user.Nvlocal;
217:   PetscMalloc(user.Nvlocal*sizeof(PetscInt),&pordering);

219:   for (i=0; i < user.Nvlocal; i++) {
220:     pordering[i] = rstart + i;
221:   }

223:   /* 
224:     Create the AO object 
225:   */
226:   AOCreateBasic(MPI_COMM_WORLD,user.Nvlocal,user.gloInd,pordering,&ao);
227:   PetscFree(pordering);
228: 
229:   /* 
230:     Keep the global indices for later use 
231:   */
232:   PetscMalloc(user.Nvlocal*sizeof(PetscInt),&user.locInd);
233:   PetscMalloc(Nvneighborstotal*sizeof(PetscInt),&tmp);
234: 
235:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
236:     Demonstrate the use of AO functionality 
237:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

239:   PetscFPrintf(PETSC_COMM_SELF,fptr1,"Before AOApplicationToPetsc, local indices are : \n");
240:   for (i=0; i < user.Nvlocal; i++) {
241:    PetscFPrintf(PETSC_COMM_SELF,fptr1," %D ",user.gloInd[i]);
242:    user.locInd[i] = user.gloInd[i];
243:   }
244:   PetscFPrintf(PETSC_COMM_SELF,fptr1,"\n");
245:   jstart = 0;
246:   for (i=0; i < user.Nvlocal; i++) {
247:    PetscFPrintf(PETSC_COMM_SELF,fptr1,"Neghbors of local vertex %D are : ",user.gloInd[i]);
248:    for (j=0; j < user.itot[i]; j++) {
249:     PetscFPrintf(PETSC_COMM_SELF,fptr1,"%D ",user.AdjM[i][j]);
250:     tmp[j + jstart] = user.AdjM[i][j];
251:    }
252:    jstart += user.itot[i];
253:    PetscFPrintf(PETSC_COMM_SELF,fptr1,"\n");
254:   }

256:   /* 
257:     Now map the vlocal and neighbor lists to the PETSc ordering 
258:   */
259:   AOApplicationToPetsc(ao,user.Nvlocal,user.locInd);
260:   AOApplicationToPetsc(ao,Nvneighborstotal,tmp);
261:   AODestroy(&ao);

263:   PetscFPrintf(PETSC_COMM_SELF,fptr1,"After AOApplicationToPetsc, local indices are : \n");
264:   for (i=0; i < user.Nvlocal; i++) {
265:    PetscFPrintf(PETSC_COMM_SELF,fptr1," %D ",user.locInd[i]);
266:   }
267:   PetscFPrintf(PETSC_COMM_SELF,fptr1,"\n");

269:   jstart = 0;
270:   for (i=0; i < user.Nvlocal; i++) {
271:    PetscFPrintf(PETSC_COMM_SELF,fptr1,"Neghbors of local vertex %D are : ",user.locInd[i]);
272:    for (j=0; j < user.itot[i]; j++) {
273:     user.AdjM[i][j] = tmp[j+jstart];
274:     PetscFPrintf(PETSC_COMM_SELF,fptr1,"%D ",user.AdjM[i][j]);
275:    }
276:    jstart += user.itot[i];
277:    PetscFPrintf(PETSC_COMM_SELF,fptr1,"\n");
278:   }

280:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
281:      Extract the ghost vertex information for each processor
282:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
283:   /*
284:    Next, we need to generate a list of vertices required for this processor
285:    and a local numbering scheme for all vertices required on this processor.
286:       vertices - integer array of all vertices needed on this processor in PETSc 
287:                  global numbering; this list consists of first the "locally owned" 
288:                  vertices followed by the ghost vertices.
289:       verticesmask - integer array that for each global vertex lists its local 
290:                      vertex number (in vertices) + 1. If the global vertex is not
291:                      represented on this processor, then the corresponding
292:                      entry in verticesmask is zero
293:  
294:       Note: vertices and verticesmask are both Nvglobal in length; this may
295:     sound terribly non-scalable, but in fact is not so bad for a reasonable
296:     number of processors. Importantly, it allows us to use NO SEARCHING
297:     in setting up the data structures.
298:   */
299:   PetscMalloc(user.Nvglobal*sizeof(PetscInt),&vertices);
300:   PetscMalloc(user.Nvglobal*sizeof(PetscInt),&verticesmask);
301:   PetscMemzero(verticesmask,user.Nvglobal*sizeof(PetscInt));
302:   nvertices = 0;
303: 
304:   /* 
305:     First load "owned vertices" into list 
306:   */
307:   for (i=0; i < user.Nvlocal; i++) {
308:     vertices[nvertices++]   = user.locInd[i];
309:     verticesmask[user.locInd[i]] = nvertices;
310:   }
311: 
312:   /* 
313:     Now load ghost vertices into list 
314:   */
315:   for (i=0; i < user.Nvlocal; i++) {
316:     for (j=0; j < user.itot[i]; j++) {
317:       nb = user.AdjM[i][j];
318:       if (!verticesmask[nb]) {
319:         vertices[nvertices++] = nb;
320:         verticesmask[nb]      = nvertices;
321:       }
322:     }
323:   }

325:   PetscFPrintf(PETSC_COMM_SELF,fptr1,"\n");
326:   PetscFPrintf(PETSC_COMM_SELF,fptr1,"The array vertices is :\n");
327:   for (i=0; i < nvertices; i++) {
328:    PetscFPrintf(PETSC_COMM_SELF,fptr1,"%D ",vertices[i]);
329:    }
330:   PetscFPrintf(PETSC_COMM_SELF,fptr1,"\n");
331: 
332:   /*
333:      Map the vertices listed in the neighbors to the local numbering from
334:     the global ordering that they contained initially.
335:   */
336:   PetscFPrintf(PETSC_COMM_SELF,fptr1,"\n");
337:   PetscFPrintf(PETSC_COMM_SELF,fptr1,"After mapping neighbors in the local contiguous ordering\n");
338:   for (i=0; i<user.Nvlocal; i++) {
339:     PetscFPrintf(PETSC_COMM_SELF,fptr1,"Neghbors of local vertex %D are :\n",i);
340:     for (j = 0; j < user.itot[i]; j++) {
341:       nb = user.AdjM[i][j];
342:       user.AdjM[i][j] = verticesmask[nb] - 1;
343:       PetscFPrintf(PETSC_COMM_SELF,fptr1,"%D ",user.AdjM[i][j]);
344:     }
345:    PetscFPrintf(PETSC_COMM_SELF,fptr1,"\n");
346:   }

348:   N = user.Nvglobal;
349: 
350:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
351:      Create vector and matrix data structures
352:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

354:   /* 
355:     Create vector data structures 
356:   */
357:   VecCreate(MPI_COMM_WORLD,&x);
358:   VecSetSizes(x,user.Nvlocal,N);
359:   VecSetFromOptions(x);
360:   VecDuplicate(x,&r);
361:   VecCreateSeq(MPI_COMM_SELF,bs*nvertices,&user.localX);
362:   VecDuplicate(user.localX,&user.localF);

364:   /*
365:     Create the scatter between the global representation and the 
366:     local representation
367:   */
368:   ISCreateStride(MPI_COMM_SELF,bs*nvertices,0,1,&islocal);
369:   ISCreateBlock(MPI_COMM_SELF,bs,nvertices,vertices,PETSC_COPY_VALUES,&isglobal);
370:   VecScatterCreate(x,isglobal,user.localX,islocal,&user.scatter);
371:   ISDestroy(&isglobal);
372:   ISDestroy(&islocal);

374:   /* 
375:      Create matrix data structure; Just to keep the example simple, we have not done any 
376:      preallocation of memory for the matrix. In real application code with big matrices,
377:      preallocation should always be done to expedite the matrix creation. 
378:   */
379:   MatCreate(MPI_COMM_WORLD,&Jac);
380:   MatSetSizes(Jac,PETSC_DECIDE,PETSC_DECIDE,N,N);
381:   MatSetFromOptions(Jac);
382:   MatSetUp(Jac);

384:   /* 
385:     The following routine allows us to set the matrix values in local ordering 
386:   */
387:   ISLocalToGlobalMappingCreate(MPI_COMM_SELF,bs*nvertices,vertices,PETSC_COPY_VALUES,&isl2g);
388:   MatSetLocalToGlobalMapping(Jac,isl2g,isl2g);

390:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
391:      Create nonlinear solver context
392:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

394:   SNESCreate(MPI_COMM_WORLD,&snes);
395:   SNESSetType(snes,type);

397:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
398:     Set routines for function and Jacobian evaluation
399:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
400:   SNESSetFunction(snes,r,FormFunction,(void*)&user);

402:    PetscOptionsGetBool(PETSC_NULL,"-fd_jacobian_coloring",&fd_jacobian_coloring,0);
403:    if (!fd_jacobian_coloring){
404:      SNESSetJacobian(snes,Jac,Jac,FormJacobian,(void*)&user);
405:    } else { /* Use matfdcoloring */
406:      ISColoring    iscoloring;
407:      MatStructure  flag;
408:      /* Get the data structure of Jac */
409:      FormJacobian(snes,x,&Jac,&Jac,&flag,&user);
410:      /* Create coloring context */
411:      MatGetColoring(Jac,MATCOLORINGSL,&iscoloring);
412:      MatFDColoringCreate(Jac,iscoloring,&matfdcoloring);
413:      MatFDColoringSetFunction(matfdcoloring,(PetscErrorCode (*)(void))FormFunction,&user);
414:      MatFDColoringSetFromOptions(matfdcoloring);
415:      /* MatFDColoringView(matfdcoloring,PETSC_VIEWER_STDOUT_WORLD); */
416:      SNESSetJacobian(snes,Jac,Jac,SNESDefaultComputeJacobianColor,matfdcoloring);
417:      ISColoringDestroy(&iscoloring);
418:    }

420:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
421:      Customize nonlinear solver; set runtime options
422:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

424:   SNESSetFromOptions(snes);

426:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
427:      Evaluate initial guess; then solve nonlinear system
428:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

430:   /*
431:      Note: The user should initialize the vector, x, with the initial guess
432:      for the nonlinear solver prior to calling SNESSolve().  In particular,
433:      to employ an initial guess of zero, the user should explicitly set
434:      this vector to zero by calling VecSet().
435:   */
436:   FormInitialGuess(&user,x);

438:    /* 
439:      Print the initial guess 
440:    */
441:   VecGetArray(x,&xx);
442:   for (inode = 0; inode < user.Nvlocal; inode++){
443:     PetscFPrintf(PETSC_COMM_SELF,fptr1,"Initial Solution at node %D is %f \n",inode,xx[inode]);
444:   }
445:   VecRestoreArray(x,&xx);

447:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
448:      Now solve the nonlinear system
449:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

451:   SNESSolve(snes,PETSC_NULL,x);
452:   SNESGetIterationNumber(snes,&its);
453:   SNESGetNonlinearStepFailures(snes,&nfails);
454: 
455:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
456:     Print the output : solution vector and other information
457:      Each processor writes to the file output.<rank> where rank is the
458:      processor's rank.
459:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

461:   VecGetArray(x,&xx);
462:   for (inode = 0; inode < user.Nvlocal; inode++)
463:    PetscFPrintf(PETSC_COMM_SELF,fptr1,"Solution at node %D is %f \n",inode,xx[inode]);
464:   VecRestoreArray(x,&xx);
465:   fclose(fptr1);
466:   PetscPrintf(MPI_COMM_WORLD,"number of SNES iterations = %D, ",its);
467:   PetscPrintf(MPI_COMM_WORLD,"number of unsuccessful steps = %D\n",nfails);

469:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
470:      Free work space.  All PETSc objects should be destroyed when they
471:      are no longer needed.
472:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
473:   PetscFree(user.gloInd);
474:   PetscFree(user.locInd);
475:   PetscFree(vertices);
476:   PetscFree(verticesmask);
477:   PetscFree(tmp);
478:   VecScatterDestroy(&user.scatter);
479:   ISLocalToGlobalMappingDestroy(&isl2g);
480:   VecDestroy(&x);
481:   VecDestroy(&r);
482:   VecDestroy(&user.localX);
483:   VecDestroy(&user.localF);
484:   MatDestroy(&Jac);  SNESDestroy(&snes);
485:   /*PetscDrawDestroy(draw);*/
486:   if (fd_jacobian_coloring){
487:     MatFDColoringDestroy(&matfdcoloring);
488:   }
489:   PetscFinalize();

491:   return 0;
492: }
495: /* --------------------  Form initial approximation ----------------- */

497: /* 
498:    FormInitialGuess - Forms initial approximation.

500:    Input Parameters:
501:    user - user-defined application context
502:    X - vector

504:    Output Parameter:
505:    X - vector
506:  */
507: PetscErrorCode FormInitialGuess(AppCtx *user,Vec X)
508: {
509:   PetscInt    i,Nvlocal,ierr;
510:   PetscInt    *gloInd;
511:   PetscScalar *x;
512: #if defined (UNUSED_VARIABLES)
513:   PetscReal  temp1,temp,hx,hy,hxdhy,hydhx,sc;
514:   PetscInt   Neglobal,Nvglobal,j,row;
515:   PetscReal  alpha,lambda;

517:   Nvglobal = user->Nvglobal;
518:   Neglobal = user->Neglobal;
519:   lambda   = user->non_lin_param;
520:   alpha    = user->lin_param;
521: #endif

523:   Nvlocal  = user->Nvlocal;
524:   gloInd   = user->gloInd;

526:   /*
527:      Get a pointer to vector data.
528:        - For default PETSc vectors, VecGetArray() returns a pointer to
529:          the data array.  Otherwise, the routine is implementation dependent.
530:        - You MUST call VecRestoreArray() when you no longer need access to
531:          the array.
532:   */
533:   VecGetArray(X,&x);

535:   /*
536:      Compute initial guess over the locally owned part of the grid
537:   */
538:   for (i=0; i < Nvlocal; i++) {
539:     x[i] = (PetscReal)gloInd[i];
540:   }

542:   /*
543:      Restore vector
544:   */
545:   VecRestoreArray(X,&x);
546:   return 0;
547: }
550: /* --------------------  Evaluate Function F(x) --------------------- */
551: /* 
552:    FormFunction - Evaluates nonlinear function, F(x).

554:    Input Parameters:
555: .  snes - the SNES context
556: .  X - input vector
557: .  ptr - optional user-defined context, as set by SNESSetFunction()

559:    Output Parameter:
560: .  F - function vector
561:  */
562: PetscErrorCode FormFunction(SNES snes,Vec X,Vec F,void *ptr)
563: {
564:   AppCtx         *user = (AppCtx*)ptr;
566:   PetscInt       i,j,Nvlocal;
567:   PetscReal      alpha,lambda;
568:   PetscScalar    *x,*f;
569:   VecScatter     scatter;
570:   Vec            localX = user->localX;
571: #if defined (UNUSED_VARIABLES)
572:   PetscScalar    ut,ub,ul,ur,u,*g,sc,uyy,uxx;
573:   PetscReal      hx,hy,hxdhy,hydhx;
574:   PetscReal      two = 2.0,one = 1.0;
575:   PetscInt       Nvglobal,Neglobal,row;
576:   PetscInt       *gloInd;

578:   Nvglobal = user->Nvglobal;
579:   Neglobal = user->Neglobal;
580:   gloInd   = user->gloInd;
581: #endif

583:   Nvlocal  = user->Nvlocal;
584:   lambda   = user->non_lin_param;
585:   alpha    = user->lin_param;
586:   scatter  = user->scatter;

588:   /* 
589:      PDE : L(u) + lambda*u*u +alpha*u = 0 where L(u) is the approximate Laplacian as
590:      described in the beginning of this code 
591:                                                                                    
592:      First scatter the distributed vector X into local vector localX (that includes
593:      values for ghost nodes. If we wish,we can put some other work between 
594:      VecScatterBegin() and VecScatterEnd() to overlap the communication with
595:      computation.
596:  */
597:   VecScatterBegin(scatter,X,localX,INSERT_VALUES,SCATTER_FORWARD);
598:   VecScatterEnd(scatter,X,localX,INSERT_VALUES,SCATTER_FORWARD);

600:   /*
601:      Get pointers to vector data
602:   */
603:   VecGetArray(localX,&x);
604:   VecGetArray(F,&f);

606:   /* 
607:     Now compute the f(x). As mentioned earlier, the computed Laplacian is just an 
608:     approximate one chosen for illustrative purpose only. Another point to notice 
609:     is that this is a local (completly parallel) calculation. In practical application 
610:     codes, function calculation time is a dominat portion of the overall execution time.
611:   */
612:   for (i=0; i < Nvlocal; i++) {
613:     f[i] = (user->itot[i] - alpha)*x[i] - lambda*x[i]*x[i];
614:     for (j = 0; j < user->itot[i]; j++) {
615:       f[i] -= x[user->AdjM[i][j]];
616:     }
617:   }

619:   /*
620:      Restore vectors
621:   */
622:   VecRestoreArray(localX,&x);
623:   VecRestoreArray(F,&f);
624:   /*VecView(F,PETSC_VIEWER_STDOUT_WORLD);*/

626:   return 0;
627: }

631: /* --------------------  Evaluate Jacobian F'(x) -------------------- */
632: /*
633:    FormJacobian - Evaluates Jacobian matrix.

635:    Input Parameters:
636: .  snes - the SNES context
637: .  X - input vector
638: .  ptr - optional user-defined context, as set by SNESSetJacobian()

640:    Output Parameters:
641: .  A - Jacobian matrix
642: .  B - optionally different preconditioning matrix
643: .  flag - flag indicating matrix structure

645: */
646: PetscErrorCode FormJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
647: {
648:   AppCtx *user = (AppCtx*)ptr;
649:   Mat     jac = *B;
650:   PetscInt     i,j,Nvlocal,col[50],ierr;
651:   PetscScalar  alpha,lambda,value[50];
652:   Vec          localX = user->localX;
653:   VecScatter scatter;
654:   PetscScalar  *x;
655: #if defined (UNUSED_VARIABLES)
656:   PetscScalar  two = 2.0,one = 1.0;
657:   PetscInt     row,Nvglobal,Neglobal;
658:   PetscInt     *gloInd;

660:   Nvglobal = user->Nvglobal;
661:   Neglobal = user->Neglobal;
662:   gloInd   = user->gloInd;
663: #endif
664: 
665:   /*printf("Entering into FormJacobian \n");*/
666:   Nvlocal  = user->Nvlocal;
667:   lambda   = user->non_lin_param;
668:   alpha    =  user->lin_param;
669:   scatter  = user->scatter;

671:   /* 
672:      PDE : L(u) + lambda*u*u +alpha*u = 0 where L(u) is the approximate Laplacian as
673:      described in the beginning of this code 
674:                                                                                    
675:      First scatter the distributed vector X into local vector localX (that includes
676:      values for ghost nodes. If we wish, we can put some other work between 
677:      VecScatterBegin() and VecScatterEnd() to overlap the communication with
678:      computation.
679:   */
680:   VecScatterBegin(scatter,X,localX,INSERT_VALUES,SCATTER_FORWARD);
681:   VecScatterEnd(scatter,X,localX,INSERT_VALUES,SCATTER_FORWARD);
682: 
683:   /*
684:      Get pointer to vector data
685:   */
686:   VecGetArray(localX,&x);

688:   for (i=0; i < Nvlocal; i++) {
689:     col[0] = i;
690:     value[0] = user->itot[i] - 2.0*lambda*x[i] - alpha;
691:     for (j = 0; j < user->itot[i]; j++) {
692:       col[j+1] = user->AdjM[i][j];
693:       value[j+1] = -1.0;
694:     }

696:   /* 
697:     Set the matrix values in the local ordering. Note that in order to use this
698:     feature we must call the routine MatSetLocalToGlobalMapping() after the 
699:     matrix has been created. 
700:   */
701:     MatSetValuesLocal(jac,1,&i,1+user->itot[i],col,value,INSERT_VALUES);
702:   }

704:   /* 
705:      Assemble matrix, using the 2-step process:
706:        MatAssemblyBegin(), MatAssemblyEnd(). 
707:      Between these two calls, the pointer to vector data has been restored to
708:      demonstrate the use of overlapping communicationn with computation.
709:   */
710:   MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
711:   VecRestoreArray(localX,&x);
712:   MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);

714:   /*
715:      Set flag to indicate that the Jacobian matrix retains an identical
716:      nonzero structure throughout all nonlinear iterations (although the
717:      values of the entries change). Thus, we can save some work in setting
718:      up the preconditioner (e.g., no need to redo symbolic factorization for
719:      ILU/ICC preconditioners).
720:       - If the nonzero structure of the matrix is different during
721:         successive linear solves, then the flag DIFFERENT_NONZERO_PATTERN
722:         must be used instead.  If you are unsure whether the matrix
723:         structure has changed or not, use the flag DIFFERENT_NONZERO_PATTERN.
724:       - Caution:  If you specify SAME_NONZERO_PATTERN, PETSc
725:         believes your assertion and does not check the structure
726:         of the matrix.  If you erroneously claim that the structure
727:         is the same when it actually is not, the new preconditioner
728:         will not function correctly.  Thus, use this optimization
729:         feature with caution!
730:   */
731:   *flag = SAME_NONZERO_PATTERN;

733:   /*
734:      Tell the matrix we will never add a new nonzero location to the
735:      matrix. If we do, it will generate an error.
736:   */
737:   MatSetOption(jac,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
738:   /* MatView(jac,PETSC_VIEWER_STDOUT_SELF); */
739:   return 0;
740: }
741: #else
742: #include <stdio.h>
743: int main(int argc,char **args)
744: {
745:   fprintf(stdout,"This example does not work for complex numbers.\n");
746:   return 0;
747: }
748: #endif