Actual source code: ex9.c

  1: /*$Id: ex9.c,v 1.49 2001/04/10 19:36:40 bsmith Exp $*/

  3: static char help[] = "The solution of 2 different linear systems with different linear solvers.n
  4: Also, this example illustrates the repeatedn
  5: solution of linear systems, while reusing matrix, vector, and solver datan
  6: structures throughout the process.  Note the various stages of event logging.nn";

  8: /*T
  9:    Concepts: SLES^repeatedly solving linear systems;
 10:    Concepts: PetscLog^profiling multiple stages of code;
 11:    Concepts: PetscLog^user-defined event profiling;
 12:    Processors: n
 13: T*/

 15: /* 
 16:   Include "petscsles.h" so that we can use SLES solvers.  Note that this file
 17:   automatically includes:
 18:      petsc.h       - base PETSc routines   petscvec.h - vectors
 19:      petscsys.h    - system routines       petscmat.h - matrices
 20:      petscis.h     - index sets            petscksp.h - Krylov subspace methods
 21:      petscviewer.h - viewers               petscpc.h  - preconditioners
 22: */
 23:  #include petscsles.h

 25: /* 
 26:    Declare user-defined routines
 27: */
 28: extern int CheckError(Vec,Vec,Vec,int,int);
 29: extern int MyKSPMonitor(KSP,int,double,void*);

 31: int main(int argc,char **args)
 32: {
 33:   Vec        x1,b1,x2,b2; /* solution and RHS vectors for systems #1 and #2 */
 34:   Vec        u;              /* exact solution vector */
 35:   Mat        C1,C2;         /* matrices for systems #1 and #2 */
 36:   SLES       sles1,sles2;   /* SLES contexts for systems #1 and #2 */
 37:   KSP        ksp1;           /* KSP context for system #1 */
 38:   int        ntimes = 3;     /* number of times to solve the linear systems */
 39:   int        CHECK_ERROR;    /* event number for error checking */
 40:   int        ldim,ierr,low,high,iglobal,Istart,Iend,Istart2,Iend2;
 41:   int        I,J,i,j,m = 3,n = 2,rank,size,its,t;
 42:   PetscTruth flg;
 43:   Scalar     v;

 45:   PetscInitialize(&argc,&args,(char *)0,help);
 46:   PetscOptionsGetInt(PETSC_NULL,"-m",&m,PETSC_NULL);
 47:   PetscOptionsGetInt(PETSC_NULL,"-t",&ntimes,PETSC_NULL);
 48:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
 49:   MPI_Comm_size(PETSC_COMM_WORLD,&size);
 50:   n = 2*size;

 52:   /* 
 53:      Register various stages for profiling
 54:   */
 55:   PetscLogStageRegister(0,"Prelim setup");
 56:   PetscLogStageRegister(1,"Linear System 1");
 57:   PetscLogStageRegister(2,"Linear System 2");

 59:   /* 
 60:      Register a user-defined event for profiling (error checking).
 61:   */
 62:   CHECK_ERROR = 0;
 63:   PetscLogEventRegister(&CHECK_ERROR,"Check Error","Red:");

 65:   /* - - - - - - - - - - - - Stage 0: - - - - - - - - - - - - - -
 66:                         Preliminary Setup
 67:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 69:   PetscLogStagePush(0);

 71:   /* 
 72:      Create data structures for first linear system.
 73:       - Create parallel matrix, specifying only its global dimensions.
 74:         When using MatCreate(), the matrix format can be specified at
 75:         runtime. Also, the parallel partitioning of the matrix is
 76:         determined by PETSc at runtime.
 77:       - Create parallel vectors.
 78:         - When using VecCreate(), we specify only the vector's global
 79:           dimension; the parallel partitioning is determined at runtime. 
 80:         - Note: We form 1 vector from scratch and then duplicate as needed.
 81:   */
 82:   MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,m*n,m*n,&C1);
 83:   MatSetFromOptions(C1);
 84:   MatGetOwnershipRange(C1,&Istart,&Iend);
 85:   VecCreate(PETSC_COMM_WORLD,PETSC_DECIDE,m*n,&u);
 86:   VecSetFromOptions(u);
 87:   VecDuplicate(u,&b1);
 88:   VecDuplicate(u,&x1);

 90:   /*
 91:      Create first linear solver context.
 92:      Set runtime options (e.g., -pc_type <type>).
 93:      Note that the first linear system uses the default option
 94:      names, while the second linear systme uses a different
 95:      options prefix.
 96:   */
 97:   SLESCreate(PETSC_COMM_WORLD,&sles1);
 98:   SLESSetFromOptions(sles1);

100:   /* 
101:      Set user-defined monitoring routine for first linear system.
102:   */
103:   SLESGetKSP(sles1,&ksp1);
104:   PetscOptionsHasName(PETSC_NULL,"-my_ksp_monitor",&flg);
105:   if (flg) {KSPSetMonitor(ksp1,MyKSPMonitor,PETSC_NULL,0);}

107:   /*
108:      Create data structures for second linear system.
109:   */
110:   MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,m*n,m*n,&C2);
111:   MatSetFromOptions(C2);
112:   MatGetOwnershipRange(C2,&Istart2,&Iend2);
113:   VecDuplicate(u,&b2);
114:   VecDuplicate(u,&x2);

116:   /*
117:      Create second linear solver context
118:   */
119:   SLESCreate(PETSC_COMM_WORLD,&sles2);

121:   /* 
122:      Set different options prefix for second linear system.
123:      Set runtime options (e.g., -s2_pc_type <type>)
124:   */
125:   SLESAppendOptionsPrefix(sles2,"s2_");
126:   SLESSetFromOptions(sles2);

128:   /* 
129:      Assemble exact solution vector in parallel.  Note that each
130:      processor needs to set only its local part of the vector.
131:   */
132:   VecGetLocalSize(u,&ldim);
133:   VecGetOwnershipRange(u,&low,&high);
134:   for (i=0; i<ldim; i++) {
135:     iglobal = i + low;
136:     v = (Scalar)(i + 100*rank);
137:     VecSetValues(u,1,&iglobal,&v,ADD_VALUES);
138:   }
139:   VecAssemblyBegin(u);
140:   VecAssemblyEnd(u);

142:   /* 
143:      Log the number of flops for computing vector entries
144:   */
145:   PetscLogFlops(2*ldim);

147:   /*
148:      End curent profiling stage
149:   */
150:   PetscLogStagePop();

152:   /* -------------------------------------------------------------- 
153:                         Linear solver loop:
154:       Solve 2 different linear systems several times in succession 
155:      -------------------------------------------------------------- */

157:   for (t=0; t<ntimes; t++) {

159:     /* - - - - - - - - - - - - Stage 1: - - - - - - - - - - - - - -
160:                  Assemble and solve first linear system            
161:        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

163:     /*
164:        Begin profiling stage #1
165:     */
166:     PetscLogStagePush(1);

168:     /* 
169:        Initialize all matrix entries to zero.  MatZeroEntries() retains
170:        the nonzero structure of the matrix for sparse formats.
171:     */
172:     MatZeroEntries(C1);

174:     /* 
175:        Set matrix entries in parallel.  Also, log the number of flops
176:        for computing matrix entries.
177:         - Each processor needs to insert only elements that it owns
178:           locally (but any non-local elements will be sent to the
179:           appropriate processor during matrix assembly). 
180:         - Always specify global row and columns of matrix entries.
181:     */
182:     for (I=Istart; I<Iend; I++) {
183:       v = -1.0; i = I/n; j = I - i*n;
184:       if (i>0)   {J = I - n; MatSetValues(C1,1,&I,1,&J,&v,ADD_VALUES);}
185:       if (i<m-1) {J = I + n; MatSetValues(C1,1,&I,1,&J,&v,ADD_VALUES);}
186:       if (j>0)   {J = I - 1; MatSetValues(C1,1,&I,1,&J,&v,ADD_VALUES);}
187:       if (j<n-1) {J = I + 1; MatSetValues(C1,1,&I,1,&J,&v,ADD_VALUES);}
188:       v = 4.0; MatSetValues(C1,1,&I,1,&I,&v,ADD_VALUES);
189:     }
190:     for (I=Istart; I<Iend; I++) { /* Make matrix nonsymmetric */
191:       v = -1.0*(t+0.5); i = I/n;
192:       if (i>0)   {J = I - n; MatSetValues(C1,1,&I,1,&J,&v,ADD_VALUES);}
193:     }
194:     PetscLogFlops(2*(Istart-Iend));

196:     /* 
197:        Assemble matrix, using the 2-step process:
198:          MatAssemblyBegin(), MatAssemblyEnd()
199:        Computations can be done while messages are in transition
200:        by placing code between these two statements.
201:     */
202:     MatAssemblyBegin(C1,MAT_FINAL_ASSEMBLY);
203:     MatAssemblyEnd(C1,MAT_FINAL_ASSEMBLY);

205:     /* 
206:        Indicate same nonzero structure of successive linear system matrices
207:     */
208:     MatSetOption(C1,MAT_NO_NEW_NONZERO_LOCATIONS);

210:     /* 
211:        Compute right-hand-side vector
212:     */
213:     MatMult(C1,u,b1);

215:     /* 
216:        Set operators. Here the matrix that defines the linear system
217:        also serves as the preconditioning matrix.
218:         - The flag SAME_NONZERO_PATTERN indicates that the
219:           preconditioning matrix has identical nonzero structure
220:           as during the last linear solve (although the values of
221:           the entries have changed). Thus, we can save some
222:           work in setting up the preconditioner (e.g., no need to
223:           redo symbolic factorization for ILU/ICC preconditioners).
224:         - If the nonzero structure of the matrix is different during
225:           the second linear solve, then the flag DIFFERENT_NONZERO_PATTERN
226:           must be used instead.  If you are unsure whether the
227:           matrix structure has changed or not, use the flag
228:           DIFFERENT_NONZERO_PATTERN.
229:         - Caution:  If you specify SAME_NONZERO_PATTERN, PETSc
230:           believes your assertion and does not check the structure
231:           of the matrix.  If you erroneously claim that the structure
232:           is the same when it actually is not, the new preconditioner
233:           will not function correctly.  Thus, use this optimization
234:           feature with caution!
235:     */
236:     SLESSetOperators(sles1,C1,C1,SAME_NONZERO_PATTERN);

238:     /* 
239:        Use the previous solution of linear system #1 as the initial
240:        guess for the next solve of linear system #1.  The user MUST
241:        call KSPSetInitialGuessNonzero() in indicate use of an initial
242:        guess vector; otherwise, an initial guess of zero is used.
243:     */
244:     if (t>0) {
245:       KSPSetInitialGuessNonzero(ksp1);
246:     }

248:     /* 
249:        Solve the first linear system.  Here we explicitly call
250:        SLESSetUp() for more detailed performance monitoring of
251:        certain preconditioners, such as ICC and ILU.  This call
252:        is optional, ase SLESSetUp() will automatically be called
253:        within SLESSolve() if it hasn't been called already.
254:     */
255:     SLESSetUp(sles1,b1,x1);
256:     SLESSolve(sles1,b1,x1,&its);

258:     /*
259:        Check error of solution to first linear system
260:     */
261:     CheckError(u,x1,b1,its,CHECK_ERROR);

263:     /* - - - - - - - - - - - - Stage 2: - - - - - - - - - - - - - -
264:                  Assemble and solve second linear system            
265:        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

267:     /*
268:        Conclude profiling stage #1; begin profiling stage #2
269:     */
270:     PetscLogStagePop();
271:     PetscLogStagePush(2);

273:     /*
274:        Initialize all matrix entries to zero
275:     */
276:     MatZeroEntries(C2);

278:    /* 
279:       Assemble matrix in parallel. Also, log the number of flops
280:       for computing matrix entries.
281:        - To illustrate the features of parallel matrix assembly, we
282:          intentionally set the values differently from the way in
283:          which the matrix is distributed across the processors.  Each
284:          entry that is not owned locally will be sent to the appropriate
285:          processor during MatAssemblyBegin() and MatAssemblyEnd().
286:        - For best efficiency the user should strive to set as many
287:          entries locally as possible.
288:     */
289:     for (i=0; i<m; i++) {
290:       for (j=2*rank; j<2*rank+2; j++) {
291:         v = -1.0;  I = j + n*i;
292:         if (i>0)   {J = I - n; MatSetValues(C2,1,&I,1,&J,&v,ADD_VALUES);}
293:         if (i<m-1) {J = I + n; MatSetValues(C2,1,&I,1,&J,&v,ADD_VALUES);}
294:         if (j>0)   {J = I - 1; MatSetValues(C2,1,&I,1,&J,&v,ADD_VALUES);}
295:         if (j<n-1) {J = I + 1; MatSetValues(C2,1,&I,1,&J,&v,ADD_VALUES);}
296:         v = 6.0 + t*0.5; MatSetValues(C2,1,&I,1,&I,&v,ADD_VALUES);
297:       }
298:     }
299:     for (I=Istart2; I<Iend2; I++) { /* Make matrix nonsymmetric */
300:       v = -1.0*(t+0.5); i = I/n;
301:       if (i>0)   {J = I - n; MatSetValues(C2,1,&I,1,&J,&v,ADD_VALUES);}
302:     }
303:     MatAssemblyBegin(C2,MAT_FINAL_ASSEMBLY);
304:     MatAssemblyEnd(C2,MAT_FINAL_ASSEMBLY);
305:     PetscLogFlops(2*(Istart-Iend));

307:     /* 
308:        Indicate same nonzero structure of successive linear system matrices
309:     */
310:     MatSetOption(C2,MAT_NO_NEW_NONZERO_LOCATIONS);

312:     /*
313:        Compute right-hand-side vector 
314:     */
315:     MatMult(C2,u,b2);

317:     /*
318:        Set operators. Here the matrix that defines the linear system
319:        also serves as the preconditioning matrix.  Indicate same nonzero
320:        structure of successive preconditioner matrices by setting flag
321:        SAME_NONZERO_PATTERN.
322:     */
323:     SLESSetOperators(sles2,C2,C2,SAME_NONZERO_PATTERN);

325:     /* 
326:        Solve the second linear system
327:     */
328:     SLESSetUp(sles2,b2,x2);
329:     SLESSolve(sles2,b2,x2,&its);

331:     /*
332:        Check error of solution to first linear system
333:     */
334:     CheckError(u,x2,b2,its,CHECK_ERROR);

336:     /* 
337:        Conclude profiling stage #2
338:     */
339:     PetscLogStagePop();
340:   }
341:   /* -------------------------------------------------------------- 
342:                        End of linear solver loop
343:      -------------------------------------------------------------- */

345:   /* 
346:      Free work space.  All PETSc objects should be destroyed when they
347:      are no longer needed.
348:   */
349:   SLESDestroy(sles1); SLESDestroy(sles2);
350:   VecDestroy(x1);     VecDestroy(x2);
351:   VecDestroy(b1);     VecDestroy(b2);
352:   MatDestroy(C1);     MatDestroy(C2);
353:   VecDestroy(u);

355:   PetscFinalize();
356:   return 0;
357: }
358: /* ------------------------------------------------------------- */
359: /*
360:     CheckError - Checks the error of the solution.

362:     Input Parameters:
363:     u - exact solution
364:     x - approximate solution
365:     b - work vector
366:     its - number of iterations for convergence
367:     CHECK_ERROR - the event number for error checking
368:                   (for use with profiling)

370:     Notes:
371:     In order to profile this section of code separately from the
372:     rest of the program, we register it as an "event" with
373:     PetscLogEventRegister() in the main program.  Then, we indicate
374:     the start and end of this event by respectively calling
375:         PetscLogEventBegin(CHECK_ERROR,u,x,b,0);
376:         PetscLogEventEnd(CHECK_ERROR,u,x,b,0);
377:     Here, we specify the objects most closely associated with
378:     the event (the vectors u,x,b).  Such information is optional;
379:     we could instead just use 0 instead for all objects.
380: */
381: int CheckError(Vec u,Vec x,Vec b,int its,int CHECK_ERROR)
382: {
383:   Scalar none = -1.0;
384:   double norm;
385:   int    ierr;

387:   PetscLogEventBegin(CHECK_ERROR,u,x,b,0);

389:   /*
390:      Compute error of the solution, using b as a work vector.
391:   */
392:   VecCopy(x,b);
393:   VecAXPY(&none,u,b);
394:   VecNorm(b,NORM_2,&norm);
395:   PetscPrintf(PETSC_COMM_WORLD,"Norm of error %A, Iterations %dn",norm,its);
396:   PetscLogEventEnd(CHECK_ERROR,u,x,b,0);
397:   return 0;
398: }
399: /* ------------------------------------------------------------- */
400: /*
401:    MyKSPMonitor - This is a user-defined routine for monitoring
402:    the SLES iterative solvers.

404:    Input Parameters:
405:      ksp   - iterative context
406:      n     - iteration number
407:      rnorm - 2-norm (preconditioned) residual value (may be estimated)
408:      dummy - optional user-defined monitor context (unused here)
409: */
410: int MyKSPMonitor(KSP ksp,int n,double rnorm,void *dummy)
411: {
412:   Vec      x;
413:   int      ierr;

415:   /* 
416:      Build the solution vector
417:   */
418:   KSPBuildSolution(ksp,PETSC_NULL,&x);

420:   /*
421:      Write the solution vector and residual norm to stdout.
422:       - PetscPrintf() handles output for multiprocessor jobs 
423:         by printing from only one processor in the communicator.
424:       - The parallel viewer PETSC_VIEWER_STDOUT_WORLD handles
425:         data from multiple processors so that the output
426:         is not jumbled.
427:   */
428:   PetscPrintf(PETSC_COMM_WORLD,"iteration %d solution vector:n",n);
429:   VecView(x,PETSC_VIEWER_STDOUT_WORLD);
430:   PetscPrintf(PETSC_COMM_WORLD,"iteration %d KSP Residual norm %14.12e n",n,rnorm);
431:   return 0;
432: }