Actual source code: ex10.c

  2: static char help[] = "Reads a PETSc matrix and vector from a file and solves a linear system.\n\
  3: This version first preloads and solves a small system, then loads \n\
  4: another (larger) system and solves it as well.  This example illustrates\n\
  5: preloading of instructions with the smaller system so that more accurate\n\
  6: performance monitoring can be done with the larger one (that actually\n\
  7: is the system of interest).  See the 'Performance Hints' chapter of the\n\
  8: users manual for a discussion of preloading.  Input parameters include\n\
  9:   -f0 <input_file> : first file to load (small system)\n\
 10:   -f1 <input_file> : second file to load (larger system)\n\n\
 11:   -trans  : solve transpose system instead\n\n";
 12: /*
 13:   This code can be used to test PETSc interface to other packages.\n\
 14:   Examples of command line options:       \n\
 15:    ex10 -f0 <datafile> -ksp_type preonly  \n\
 16:         -help -ksp_view                  \n\
 17:         -num_numfac <num_numfac> -num_rhs <num_rhs> \n\
 18:         -ksp_type preonly -pc_type lu -pc_factor_mat_solver_package  spooles or superlu or superlu_dist or mumps \n\
 19:         -ksp_type preonly -pc_type cholesky -pc_factor_mat_solver_package spooles or dscpack or mumps \n\
 20:         -f0 <A> -fB <B> -pc_factor_mat_solver_package mumps -ksp_type preonly -pc_type cholesky -test_inertia -mat_sigma <sigma> \n\
 21:    mpiexec -n <np> ex10 -f0 <datafile> -ksp_type cg -pc_type asm -pc_asm_type basic -sub_pc_type icc -mat_type sbaij
 22:  \n\n";
 23: */
 24: /*T
 25:    Concepts: KSP^solving a linear system
 26:    Processors: n
 27: T*/

 29: /* 
 30:   Include "petscksp.h" so that we can use KSP solvers.  Note that this file
 31:   automatically includes:
 32:      petsc.h       - base PETSc routines   petscvec.h - vectors
 33:      petscsys.h    - system routines       petscmat.h - matrices
 34:      petscis.h     - index sets            petscksp.h - Krylov subspace methods
 35:      petscviewer.h - viewers               petscpc.h  - preconditioners
 36: */
 37:  #include petscksp.h

 41: int main(int argc,char **args)
 42: {
 43:   KSP            ksp;             /* linear solver context */
 44:   Mat            A,B;            /* matrix */
 45:   Vec            x,b,u;          /* approx solution, RHS, exact solution */
 46:   PetscViewer    fd;               /* viewer */
 47:   char           file[4][PETSC_MAX_PATH_LEN];     /* input file name */
 48:   PetscTruth     table,flg,flgB=PETSC_FALSE,trans=PETSC_FALSE,initialguess = PETSC_FALSE;
 49:   PetscTruth     outputSoln=PETSC_FALSE;
 51:   PetscInt       its,num_numfac,m,n,M;
 52:   PetscReal      norm;
 53:   PetscLogDouble tsetup,tsetup1,tsetup2,tsolve,tsolve1,tsolve2;
 54:   PetscTruth     preload=PETSC_TRUE,diagonalscale,isSymmetric,cknorm=PETSC_FALSE,Test_MatDuplicate=PETSC_FALSE;
 55:   PetscMPIInt    rank;
 56:   PetscScalar    sigma;

 58:   PetscInitialize(&argc,&args,(char *)0,help);
 59:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
 60:   PetscOptionsHasName(PETSC_NULL,"-table",&table);
 61:   PetscOptionsHasName(PETSC_NULL,"-trans",&trans);
 62:   PetscOptionsHasName(PETSC_NULL,"-initialguess",&initialguess);
 63:   PetscOptionsHasName(PETSC_NULL,"-output_solution",&outputSoln);

 65:   /* 
 66:      Determine files from which we read the two linear systems
 67:      (matrix and right-hand-side vector).
 68:   */
 69:   PetscOptionsGetString(PETSC_NULL,"-f",file[0],PETSC_MAX_PATH_LEN-1,&flg);
 70:   if (flg) {
 71:     PetscStrcpy(file[1],file[0]);
 72:     preload = PETSC_FALSE;
 73:   } else {
 74:     PetscOptionsGetString(PETSC_NULL,"-f0",file[0],PETSC_MAX_PATH_LEN-1,&flg);
 75:     if (!flg) SETERRQ(1,"Must indicate binary file with the -f0 or -f option");
 76:     PetscOptionsGetString(PETSC_NULL,"-f1",file[1],PETSC_MAX_PATH_LEN-1,&flg);
 77:     if (!flg) {preload = PETSC_FALSE;} /* don't bother with second system */
 78:   }

 80:   /* -----------------------------------------------------------
 81:                   Beginning of linear solver loop
 82:      ----------------------------------------------------------- */
 83:   /* 
 84:      Loop through the linear solve 2 times.  
 85:       - The intention here is to preload and solve a small system;
 86:         then load another (larger) system and solve it as well.
 87:         This process preloads the instructions with the smaller
 88:         system so that more accurate performance monitoring (via
 89:         -log_summary) can be done with the larger one (that actually
 90:         is the system of interest). 
 91:   */
 92:   PreLoadBegin(preload,"Load system");

 94:     /* - - - - - - - - - - - New Stage - - - - - - - - - - - - -
 95:                            Load system
 96:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 98:     /* 
 99:        Open binary file.  Note that we use FILE_MODE_READ to indicate
100:        reading from this file.
101:     */
102:     PetscViewerBinaryOpen(PETSC_COMM_WORLD,file[PreLoadIt],FILE_MODE_READ,&fd);
103: 
104:     /*
105:        Load the matrix and vector; then destroy the viewer.
106:     */
107:     MatLoad(fd,MATAIJ,&A);
108: 
109:     if (!preload){
110:       flg = PETSC_FALSE;
111:       PetscOptionsGetString(PETSC_NULL,"-rhs",file[2],PETSC_MAX_PATH_LEN-1,&flg);
112:       if (flg){ /* rhs is stored in a separate file */
113:         PetscViewerDestroy(fd);
114:         PetscViewerBinaryOpen(PETSC_COMM_WORLD,file[2],FILE_MODE_READ,&fd);
115:       }
116:     }
117:     if (rank){
118:         PetscExceptionTry1(VecLoad(fd,PETSC_NULL,&b),PETSC_ERR_FILE_UNEXPECTED);
119:     } else {
120:       PetscExceptionTry1(VecLoad(fd,PETSC_NULL,&b),PETSC_ERR_FILE_READ);
121:     }
122:     if (PetscExceptionCaught(ierr,PETSC_ERR_FILE_UNEXPECTED) || PetscExceptionCaught(ierr,PETSC_ERR_FILE_READ)) { /* if file contains no RHS, then use a vector of all ones */
123:       PetscInt    m;
124:       PetscScalar one = 1.0;
125:       PetscInfo(0,"Using vector of ones for RHS\n");
126:       MatGetLocalSize(A,&m,PETSC_NULL);
127:       VecCreate(PETSC_COMM_WORLD,&b);
128:       VecSetSizes(b,m,PETSC_DECIDE);
129:       VecSetFromOptions(b);
130:       VecSet(b,one);
131:     } else
132:     PetscViewerDestroy(fd);

134:     /* Test MatDuplicate() */
135:     if (Test_MatDuplicate){
136:       MatDuplicate(A,MAT_COPY_VALUES,&B);
137:       MatEqual(A,B,&flg);
138:       if (!flg){
139:         PetscPrintf(PETSC_COMM_WORLD,"  A != B \n");
140:       }
141:       MatDestroy(B);
142:     }

144:     /* Add a shift to A */
145:     PetscOptionsGetScalar(PETSC_NULL,"-mat_sigma",&sigma,&flg);
146:     if (flg) {
147:       PetscOptionsGetString(PETSC_NULL,"-fB",file[2],PETSC_MAX_PATH_LEN-1,&flgB);
148:       if (flgB){
149:         /* load B to get A = A + sigma*B */
150:         PetscViewerBinaryOpen(PETSC_COMM_WORLD,file[2],FILE_MODE_READ,&fd);
151:         MatLoad(fd,MATAIJ,&B);
152:         PetscViewerDestroy(fd);
153:         MatAXPY(A,sigma,B,DIFFERENT_NONZERO_PATTERN); /* A <- sigma*B + A */
154:       } else {
155:         MatShift(A,sigma);
156:       }
157:     }

159:     /* Make A singular for testing zero-pivot of ilu factorization        */
160:     /* Example: ./ex10 -f0 <datafile> -test_zeropivot -set_row_zero -pc_factor_shift_nonzero */
161:     PetscOptionsHasName(PETSC_NULL, "-test_zeropivot", &flg);
162:     if (flg) {
163:       PetscInt          row,ncols;
164:       const PetscInt    *cols;
165:       const PetscScalar *vals;
166:       PetscTruth        flg1=PETSC_FALSE;
167:       PetscScalar       *zeros;
168:       row = 0;
169:       MatGetRow(A,row,&ncols,&cols,&vals);
170:       PetscMalloc(sizeof(PetscScalar)*(ncols+1),&zeros);
171:       PetscMemzero(zeros,(ncols+1)*sizeof(PetscScalar));
172:       PetscOptionsHasName(PETSC_NULL, "-set_row_zero", &flg1);
173:       if (flg1){ /* set entire row as zero */
174:         MatSetValues(A,1,&row,ncols,cols,zeros,INSERT_VALUES);
175:       } else { /* only set (row,row) entry as zero */
176:         MatSetValues(A,1,&row,1,&row,zeros,INSERT_VALUES);
177:       }
178:       MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
179:       MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
180:     }

182:     /* Check whether A is symmetric */
183:     PetscOptionsHasName(PETSC_NULL, "-check_symmetry", &flg);
184:     if (flg) {
185:       Mat Atrans;
186:       MatTranspose(A, MAT_INITIAL_MATRIX,&Atrans);
187:       MatEqual(A, Atrans, &isSymmetric);
188:       if (isSymmetric) {
189:         MatSetOption(A,MAT_SYMMETRIC,PETSC_TRUE);
190:       } else {
191:         PetscPrintf(PETSC_COMM_WORLD,"Warning: A is non-symmetric \n");
192:       }
193:       MatDestroy(Atrans);
194:     }

196:     /* 
197:        If the loaded matrix is larger than the vector (due to being padded 
198:        to match the block size of the system), then create a new padded vector.
199:     */
200: 
201:     MatGetLocalSize(A,&m,&n);
202:     if (m != n) {
203:       SETERRQ2(PETSC_ERR_ARG_SIZ, "This example is not intended for rectangular matrices (%d, %d)", m, n);
204:     }
205:     MatGetSize(A,&M,PETSC_NULL);
206:     VecGetSize(b,&m);
207:     if (M != m) { /* Create a new vector b by padding the old one */
208:       PetscInt    j,mvec,start,end,indx;
209:       Vec         tmp;
210:       PetscScalar *bold;

212:       VecCreate(PETSC_COMM_WORLD,&tmp);
213:       VecSetSizes(tmp,n,PETSC_DECIDE);
214:       VecSetFromOptions(tmp);
215:       VecGetOwnershipRange(b,&start,&end);
216:       VecGetLocalSize(b,&mvec);
217:       VecGetArray(b,&bold);
218:       for (j=0; j<mvec; j++) {
219:         indx = start+j;
220:         VecSetValues(tmp,1,&indx,bold+j,INSERT_VALUES);
221:       }
222:       VecRestoreArray(b,&bold);
223:       VecDestroy(b);
224:       VecAssemblyBegin(tmp);
225:       VecAssemblyEnd(tmp);
226:       b = tmp;
227:     }
228:     VecDuplicate(b,&x);
229:     VecDuplicate(b,&u);
230:     VecSet(x,0.0);


233:     /* Check scaling in A */
234:     PetscOptionsHasName(PETSC_NULL, "-check_scaling", &flg);
235:     if (flg) {
236:       Vec         max, min;
237:       PetscInt    idx;
238:       PetscReal   val;

240:       VecDuplicate(x, &max);
241:       VecDuplicate(x, &min);
242:       MatGetRowMaxAbs(A, max, PETSC_NULL);
243:       MatGetRowMinAbs(A, min, PETSC_NULL);
244:       {
245:         PetscViewer viewer;

247:         PetscViewerASCIIOpen(PETSC_COMM_WORLD, "max.data", &viewer);
248:         VecView(max, viewer);
249:         PetscViewerDestroy(viewer);
250:         PetscViewerASCIIOpen(PETSC_COMM_WORLD, "min.data", &viewer);
251:         VecView(min, viewer);
252:         PetscViewerDestroy(viewer);
253:       }
254:       VecView(max, PETSC_VIEWER_DRAW_WORLD);
255:       VecMax(max, &idx, &val);
256:       PetscPrintf(PETSC_COMM_WORLD, "Largest max row element %G at row %d\n", val, idx);
257:       VecView(min, PETSC_VIEWER_DRAW_WORLD);
258:       VecMin(min, &idx, &val);
259:       PetscPrintf(PETSC_COMM_WORLD, "Smallest min row element %G at row %d\n", val, idx);
260:       VecMin(max, &idx, &val);
261:       PetscPrintf(PETSC_COMM_WORLD, "Smallest max row element %G at row %d\n", val, idx);
262:       VecPointwiseDivide(max, max, min);
263:       VecMax(max, &idx, &val);
264:       PetscPrintf(PETSC_COMM_WORLD, "Largest row ratio %G at row %d\n", val, idx);
265:       VecView(max, PETSC_VIEWER_DRAW_WORLD);
266:       VecDestroy(max);
267:       VecDestroy(min);
268:     }

270:     /* - - - - - - - - - - - New Stage - - - - - - - - - - - - -
271:                       Setup solve for system
272:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
273:     /*
274:        Conclude profiling last stage; begin profiling next stage.
275:     */
276:     PreLoadStage("KSPSetUp");

278:     /*
279:        We also explicitly time this stage via PetscGetTime()
280:     */
281:     PetscGetTime(&tsetup1);

283:     /*
284:        Create linear solver; set operators; set runtime options.
285:     */
286:     KSPCreate(PETSC_COMM_WORLD,&ksp);
287:     KSPSetInitialGuessNonzero(ksp,initialguess);
288:     num_numfac = 1;
289:     PetscOptionsGetInt(PETSC_NULL,"-num_numfac",&num_numfac,PETSC_NULL);
290:     while ( num_numfac-- ){
291: 

293:       KSPSetOperators(ksp,A,A,SAME_NONZERO_PATTERN);
294:       KSPSetFromOptions(ksp);

296:       /* 
297:        Here we explicitly call KSPSetUp() and KSPSetUpOnBlocks() to
298:        enable more precise profiling of setting up the preconditioner.
299:        These calls are optional, since both will be called within
300:        KSPSolve() if they haven't been called already.
301:       */
302:       KSPSetUp(ksp);
303:       KSPSetUpOnBlocks(ksp);
304:       PetscGetTime(&tsetup2);
305:       tsetup = tsetup2 - tsetup1;

307:       /*
308:       Test MatGetInertia()
309:       Usage:
310:       ex10 -f0 <mat_binaryfile> -ksp_type preonly -pc_type cholesky -mat_type seqsbaij -test_inertia -mat_sigma <sigma>
311:       */
312:       PetscOptionsHasName(PETSC_NULL,"-test_inertia",&flg);
313:       if (flg){
314:         PC        pc;
315:         PetscInt  nneg, nzero, npos;
316:         Mat       F;
317: 
318:         KSPGetPC(ksp,&pc);
319:         PCFactorGetMatrix(pc,&F);
320:         MatGetInertia(F,&nneg,&nzero,&npos);
321:         PetscPrintf(PETSC_COMM_SELF," MatInertia: nneg: %D, nzero: %D, npos: %D\n",nneg,nzero,npos);
322:       }

324:       /*
325:        Tests "diagonal-scaling of preconditioned residual norm" as used 
326:        by many ODE integrator codes including SUNDIALS. Note this is different
327:        than diagonally scaling the matrix before computing the preconditioner
328:       */
329:       PetscOptionsHasName(PETSC_NULL,"-diagonal_scale",&diagonalscale);
330:       if (diagonalscale) {
331:         PC       pc;
332:         PetscInt j,start,end,n;
333:         Vec      scale;
334: 
335:         KSPGetPC(ksp,&pc);
336:         VecGetSize(x,&n);
337:         VecDuplicate(x,&scale);
338:         VecGetOwnershipRange(scale,&start,&end);
339:         for (j=start; j<end; j++) {
340:           VecSetValue(scale,j,((PetscReal)(j+1))/((PetscReal)n),INSERT_VALUES);
341:         }
342:         VecAssemblyBegin(scale);
343:         VecAssemblyEnd(scale);
344:         PCDiagonalScaleSet(pc,scale);
345:         VecDestroy(scale);
346:       }

348:       /* - - - - - - - - - - - New Stage - - - - - - - - - - - - -
349:                            Solve system
350:         - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

352:       /*
353:        Begin profiling next stage
354:       */
355:       PreLoadStage("KSPSolve");

357:       /*
358:        Solve linear system; we also explicitly time this stage.
359:       */
360:       PetscGetTime(&tsolve1);
361:       if (trans) {
362:         KSPSolveTranspose(ksp,b,x);
363:         KSPGetIterationNumber(ksp,&its);
364:       } else {
365:         PetscInt  num_rhs=1;
366:         PetscOptionsGetInt(PETSC_NULL,"-num_rhs",&num_rhs,PETSC_NULL);
367:         PetscOptionsHasName(PETSC_NULL,"-cknorm",&cknorm);
368:         while ( num_rhs-- ) {
369:           KSPSolve(ksp,b,x);
370:           VecAssemblyBegin(x);
371:           VecAssemblyEnd(x);
372:         }
373:         KSPGetIterationNumber(ksp,&its);
374:         if (cknorm){   /* Check error for each rhs */
375:           if (trans) {
376:             MatMultTranspose(A,x,u);
377:           } else {
378:             MatMult(A,x,u);
379:           }
380:           VecAXPY(u,-1.0,b);
381:           VecNorm(u,NORM_2,&norm);
382:           PetscPrintf(PETSC_COMM_WORLD,"  Number of iterations = %3D\n",its);
383:           PetscPrintf(PETSC_COMM_WORLD,"  Residual norm %A\n",norm);
384:         }
385:       } /* while ( num_rhs-- ) */
386:       PetscGetTime(&tsolve2);
387:       tsolve = tsolve2 - tsolve1;

389:       /* 
390:        Conclude profiling this stage
391:       */
392:       PreLoadStage("Cleanup");

394:       /* - - - - - - - - - - - New Stage - - - - - - - - - - - - -
395:             Check error, print output, free data structures.
396:        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

398:       /* 
399:          Check error
400:       */
401:       if (trans) {
402:         MatMultTranspose(A,x,u);
403:       } else {
404:         MatMult(A,x,u);
405:       }
406:       VecAXPY(u,-1.0,b);
407:       VecNorm(u,NORM_2,&norm);

409:       /*
410:        Write output (optinally using table for solver details).
411:         - PetscPrintf() handles output for multiprocessor jobs 
412:           by printing from only one processor in the communicator.
413:         - KSPView() prints information about the linear solver.
414:       */
415:       if (table) {
416:         char        *matrixname,kspinfo[120];
417:         PetscViewer viewer;

419:         /*
420:          Open a string viewer; then write info to it.
421:         */
422:         PetscViewerStringOpen(PETSC_COMM_WORLD,kspinfo,120,&viewer);
423:         KSPView(ksp,viewer);
424:         PetscStrrchr(file[PreLoadIt],'/',&matrixname);
425:         PetscPrintf(PETSC_COMM_WORLD,"%-8.8s %3D %2.0e %2.1e %2.1e %2.1e %s \n",
426:                 matrixname,its,norm,tsetup+tsolve,tsetup,tsolve,kspinfo);

428:         /*
429:           Destroy the viewer
430:         */
431:         PetscViewerDestroy(viewer);
432:       } else {
433:         PetscPrintf(PETSC_COMM_WORLD,"Number of iterations = %3D\n",its);
434:         PetscPrintf(PETSC_COMM_WORLD,"Residual norm %A\n",norm);
435:       }
436:       PetscOptionsGetString(PETSC_NULL,"-solution",file[3],PETSC_MAX_PATH_LEN-1,&flg);
437:       if (flg) {
438:         PetscViewer viewer;
439:         Vec         xstar;
440:         PetscReal   norm;

442:         PetscViewerBinaryOpen(PETSC_COMM_WORLD,file[3],FILE_MODE_READ,&viewer);
443:         VecLoad(viewer, VECMPI, &xstar);
444:         VecAXPY(xstar, -1.0, x);
445:         VecNorm(xstar, NORM_2, &norm);
446:         PetscPrintf(PETSC_COMM_WORLD, "Error norm %A\n", norm);
447:         VecDestroy(xstar);
448:         PetscViewerDestroy(viewer);
449:       }
450:       if (outputSoln) {
451:         PetscViewer viewer;

453:         PetscViewerBinaryOpen(PETSC_COMM_WORLD,"solution.petsc",FILE_MODE_WRITE,&viewer);
454:         VecView(x, viewer);
455:         PetscViewerDestroy(viewer);
456:       }

458:       PetscOptionsHasName(PETSC_NULL, "-ksp_reason", &flg);
459:       if (flg){
460:         KSPConvergedReason reason;
461:         KSPGetConvergedReason(ksp,&reason);
462:         PetscPrintf(PETSC_COMM_WORLD,"KSPConvergedReason: %D\n", reason);
463:       }
464: 
465:     } /* while ( num_numfac-- ) */

467:     /* 
468:        Free work space.  All PETSc objects should be destroyed when they
469:        are no longer needed.
470:     */
471:     MatDestroy(A); VecDestroy(b);
472:     VecDestroy(u); VecDestroy(x);
473:     KSPDestroy(ksp);
474:     if (flgB) { MatDestroy(B); }
475:   PreLoadEnd();
476:   /* -----------------------------------------------------------
477:                       End of linear solver loop
478:      ----------------------------------------------------------- */

480:   PetscFinalize();
481:   return 0;
482: }