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