Actual source code: ex5.c

  2: static char help[] = "Solves two linear systems in parallel with KSP.  The code\n\
  3: illustrates repeated solution of linear systems with the same preconditioner\n\
  4: method but different matrices (having the same nonzero structure).  The code\n\
  5: also uses multiple profiling stages.  Input arguments are\n\
  6:   -m <size> : problem size\n\
  7:   -mat_nonsym : use nonsymmetric matrix (default is symmetric)\n\n";

  9: /*T
 10:    Concepts: KSP^repeatedly solving linear systems;
 11:    Concepts: PetscLog^profiling multiple stages of code;
 12:    Processors: n
 13: T*/

 15: /* 
 16:   Include "petscksp.h" so that we can use KSP 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 petscksp.h

 27: int main(int argc,char **args)
 28: {
 29:   KSP            ksp;             /* linear solver context */
 30:   Mat            C;                /* matrix */
 31:   Vec            x,u,b;          /* approx solution, RHS, exact solution */
 32:   PetscReal      norm;             /* norm of solution error */
 33:   PetscScalar    v,none = -1.0;
 34:   PetscInt       I,J,ldim,low,high,iglobal,Istart,Iend;
 36:   PetscInt       i,j,m = 3,n = 2,its;
 37:   PetscMPIInt    size,rank;
 38:   PetscTruth     mat_nonsymmetric;
 39:   int            stages[2];

 41:   PetscInitialize(&argc,&args,(char *)0,help);
 42:   PetscOptionsGetInt(PETSC_NULL,"-m",&m,PETSC_NULL);
 43:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
 44:   MPI_Comm_size(PETSC_COMM_WORLD,&size);
 45:   n = 2*size;

 47:   /*
 48:      Set flag if we are doing a nonsymmetric problem; the default is symmetric.
 49:   */
 50:   PetscOptionsHasName(PETSC_NULL,"-mat_nonsym",&mat_nonsymmetric);

 52:   /*
 53:      Register two stages for separate profiling of the two linear solves.
 54:      Use the runtime option -log_summary for a printout of performance
 55:      statistics at the program's conlusion.
 56:   */
 57:   PetscLogStageRegister(&stages[0],"Original Solve");
 58:   PetscLogStageRegister(&stages[1],"Second Solve");

 60:   /* -------------- Stage 0: Solve Original System ---------------------- */
 61:   /* 
 62:      Indicate to PETSc profiling that we're beginning the first stage
 63:   */
 64:   PetscLogStagePush(stages[0]);

 66:   /* 
 67:      Create parallel matrix, specifying only its global dimensions.
 68:      When using MatCreate(), the matrix format can be specified at
 69:      runtime. Also, the parallel partitioning of the matrix is
 70:      determined by PETSc at runtime.
 71:   */
 72:   MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,m*n,m*n,&C);
 73:   MatSetFromOptions(C);

 75:   /* 
 76:      Currently, all PETSc parallel matrix formats are partitioned by
 77:      contiguous chunks of rows across the processors.  Determine which
 78:      rows of the matrix are locally owned. 
 79:   */
 80:   MatGetOwnershipRange(C,&Istart,&Iend);

 82:   /* 
 83:      Set matrix entries matrix in parallel.
 84:       - Each processor needs to insert only elements that it owns
 85:         locally (but any non-local elements will be sent to the
 86:         appropriate processor during matrix assembly). 
 87:       - Always specify global row and columns of matrix entries.
 88:   */
 89:   for (I=Istart; I<Iend; I++) {
 90:     v = -1.0; i = I/n; j = I - i*n;
 91:     if (i>0)   {J = I - n; MatSetValues(C,1,&I,1,&J,&v,ADD_VALUES);}
 92:     if (i<m-1) {J = I + n; MatSetValues(C,1,&I,1,&J,&v,ADD_VALUES);}
 93:     if (j>0)   {J = I - 1; MatSetValues(C,1,&I,1,&J,&v,ADD_VALUES);}
 94:     if (j<n-1) {J = I + 1; MatSetValues(C,1,&I,1,&J,&v,ADD_VALUES);}
 95:     v = 4.0; MatSetValues(C,1,&I,1,&I,&v,ADD_VALUES);
 96:   }

 98:   /*
 99:      Make the matrix nonsymmetric if desired
100:   */
101:   if (mat_nonsymmetric) {
102:     for (I=Istart; I<Iend; I++) {
103:       v = -1.5; i = I/n;
104:       if (i>1)   {J = I-n-1; MatSetValues(C,1,&I,1,&J,&v,ADD_VALUES);}
105:     }
106:   } else {
107:     MatSetOption(C,MAT_SYMMETRIC);
108:     MatSetOption(C,MAT_SYMMETRY_ETERNAL);
109:   }

111:   /* 
112:      Assemble matrix, using the 2-step process:
113:        MatAssemblyBegin(), MatAssemblyEnd()
114:      Computations can be done while messages are in transition
115:      by placing code between these two statements.
116:   */
117:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
118:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);

120:   /* 
121:      Create parallel vectors.
122:       - When using VecSetSizes(), we specify only the vector's global
123:         dimension; the parallel partitioning is determined at runtime. 
124:       - Note: We form 1 vector from scratch and then duplicate as needed.
125:   */
126:   VecCreate(PETSC_COMM_WORLD,&u);
127:   VecSetSizes(u,PETSC_DECIDE,m*n);
128:   VecSetFromOptions(u);
129:   VecDuplicate(u,&b);
130:   VecDuplicate(b,&x);

132:   /* 
133:      Currently, all parallel PETSc vectors are partitioned by
134:      contiguous chunks across the processors.  Determine which
135:      range of entries are locally owned.
136:   */
137:   VecGetOwnershipRange(x,&low,&high);

139:   /*
140:     Set elements within the exact solution vector in parallel.
141:      - Each processor needs to insert only elements that it owns
142:        locally (but any non-local entries will be sent to the
143:        appropriate processor during vector assembly).
144:      - Always specify global locations of vector entries.
145:   */
146:   VecGetLocalSize(x,&ldim);
147:   for (i=0; i<ldim; i++) {
148:     iglobal = i + low;
149:     v = (PetscScalar)(i + 100*rank);
150:     VecSetValues(u,1,&iglobal,&v,INSERT_VALUES);
151:   }

153:   /* 
154:      Assemble vector, using the 2-step process:
155:        VecAssemblyBegin(), VecAssemblyEnd()
156:      Computations can be done while messages are in transition,
157:      by placing code between these two statements.
158:   */
159:   VecAssemblyBegin(u);
160:   VecAssemblyEnd(u);

162:   /* 
163:      Compute right-hand-side vector
164:   */
165:   MatMult(C,u,b);
166: 
167:   /* 
168:     Create linear solver context
169:   */
170:   KSPCreate(PETSC_COMM_WORLD,&ksp);

172:   /* 
173:      Set operators. Here the matrix that defines the linear system
174:      also serves as the preconditioning matrix.
175:   */
176:   KSPSetOperators(ksp,C,C,DIFFERENT_NONZERO_PATTERN);

178:   /* 
179:      Set runtime options (e.g., -ksp_type <type> -pc_type <type>)
180:   */

182:   KSPSetFromOptions(ksp);

184:   /* 
185:      Solve linear system.  Here we explicitly call KSPSetUp() for more
186:      detailed performance monitoring of certain preconditioners, such
187:      as ICC and ILU.  This call is optional, as KSPSetUp() will
188:      automatically be called within KSPSolve() if it hasn't been
189:      called already.
190:   */
191:   KSPSetUp(ksp);
192:   KSPSolve(ksp,b,x);
193: 
194:   /* 
195:      Check the error
196:   */
197:   VecAXPY(&none,u,x);
198:   VecNorm(x,NORM_2,&norm);
199:   KSPGetIterationNumber(ksp,&its);
200:   PetscPrintf(PETSC_COMM_WORLD,"Norm of error %A, Iterations %D\n",norm,its);

202:   /* -------------- Stage 1: Solve Second System ---------------------- */
203:   /* 
204:      Solve another linear system with the same method.  We reuse the KSP
205:      context, matrix and vector data structures, and hence save the
206:      overhead of creating new ones.

208:      Indicate to PETSc profiling that we're concluding the first
209:      stage with PetscLogStagePop(), and beginning the second stage with
210:      PetscLogStagePush().
211:   */
212:   PetscLogStagePop();
213:   PetscLogStagePush(stages[1]);

215:   /* 
216:      Initialize all matrix entries to zero.  MatZeroEntries() retains the
217:      nonzero structure of the matrix for sparse formats.
218:   */
219:   MatZeroEntries(C);

221:   /* 
222:      Assemble matrix again.  Note that we retain the same matrix data
223:      structure and the same nonzero pattern; we just change the values
224:      of the matrix entries.
225:   */
226:   for (i=0; i<m; i++) {
227:     for (j=2*rank; j<2*rank+2; j++) {
228:       v = -1.0;  I = j + n*i;
229:       if (i>0)   {J = I - n; MatSetValues(C,1,&I,1,&J,&v,ADD_VALUES);}
230:       if (i<m-1) {J = I + n; MatSetValues(C,1,&I,1,&J,&v,ADD_VALUES);}
231:       if (j>0)   {J = I - 1; MatSetValues(C,1,&I,1,&J,&v,ADD_VALUES);}
232:       if (j<n-1) {J = I + 1; MatSetValues(C,1,&I,1,&J,&v,ADD_VALUES);}
233:       v = 6.0; MatSetValues(C,1,&I,1,&I,&v,ADD_VALUES);
234:     }
235:   }
236:   if (mat_nonsymmetric) {
237:     for (I=Istart; I<Iend; I++) {
238:       v = -1.5; i = I/n;
239:       if (i>1)   {J = I-n-1; MatSetValues(C,1,&I,1,&J,&v,ADD_VALUES);}
240:     }
241:   }
242:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
243:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);

245:   /* 
246:      Compute another right-hand-side vector
247:   */
248:   MatMult(C,u,b);

250:   /* 
251:      Set operators. Here the matrix that defines the linear system
252:      also serves as the preconditioning matrix.
253:       - The flag SAME_NONZERO_PATTERN indicates that the
254:         preconditioning matrix has identical nonzero structure
255:         as during the last linear solve (although the values of
256:         the entries have changed). Thus, we can save some
257:         work in setting up the preconditioner (e.g., no need to
258:         redo symbolic factorization for ILU/ICC preconditioners).
259:       - If the nonzero structure of the matrix is different during
260:         the second linear solve, then the flag DIFFERENT_NONZERO_PATTERN
261:         must be used instead.  If you are unsure whether the
262:         matrix structure has changed or not, use the flag
263:         DIFFERENT_NONZERO_PATTERN.
264:       - Caution:  If you specify SAME_NONZERO_PATTERN, PETSc
265:         believes your assertion and does not check the structure
266:         of the matrix.  If you erroneously claim that the structure
267:         is the same when it actually is not, the new preconditioner
268:         will not function correctly.  Thus, use this optimization
269:         feature with caution!
270:   */
271:   KSPSetOperators(ksp,C,C,SAME_NONZERO_PATTERN);

273:   /* 
274:      Solve linear system
275:   */
276:   KSPSetUp(ksp);
277:   KSPSolve(ksp,b,x);

279:   /* 
280:      Check the error
281:   */
282:   VecAXPY(&none,u,x);
283:   VecNorm(x,NORM_2,&norm);
284:   KSPGetIterationNumber(ksp,&its);
285:   PetscPrintf(PETSC_COMM_WORLD,"Norm of error %A, Iterations %D\n",norm,its);

287:   /* 
288:      Free work space.  All PETSc objects should be destroyed when they
289:      are no longer needed.
290:   */
291:   KSPDestroy(ksp);
292:   VecDestroy(u);
293:   VecDestroy(x);
294:   VecDestroy(b);
295:   MatDestroy(C);

297:   /*
298:      Indicate to PETSc profiling that we're concluding the second stage 
299:   */
300:   PetscLogStagePop();

302:   PetscFinalize();
303:   return 0;
304: }