Actual source code: ex5.c

  1: /*$Id: ex5.c,v 1.89 2001/03/23 23:23:55 balay Exp $*/

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

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

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

 26: int main(int argc,char **args)
 27: {
 28:   SLES       sles;             /* linear solver context */
 29:   Mat        C;                /* matrix */
 30:   Vec        x,u,b;          /* approx solution, RHS, exact solution */
 31:   double     norm;             /* norm of solution error */
 32:   Scalar     v,none = -1.0;
 33:   int        I,J,ldim,ierr,low,high,iglobal,Istart,Iend;
 34:   int        i,j,m = 3,n = 2,rank,size,its;
 35:   PetscTruth mat_nonsymmetric;

 37:   PetscInitialize(&argc,&args,(char *)0,help);
 38:   PetscOptionsGetInt(PETSC_NULL,"-m",&m,PETSC_NULL);
 39:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
 40:   MPI_Comm_size(PETSC_COMM_WORLD,&size);
 41:   n = 2*size;

 43:   /*
 44:      Set flag if we are doing a nonsymmetric problem; the default is symmetric.
 45:   */
 46:   PetscOptionsHasName(PETSC_NULL,"-mat_nonsym",&mat_nonsymmetric);

 48:   /*
 49:      Register two stages for separate profiling of the two linear solves.
 50:      Use the runtime option -log_summary for a printout of performance
 51:      statistics at the program's conlusion.
 52:   */
 53:   PetscLogStageRegister(0,"Original Solve");
 54:   PetscLogStageRegister(1,"Second Solve");

 56:   /* -------------- Stage 0: Solve Original System ---------------------- */
 57:   /* 
 58:      Indicate to PETSc profiling that we're beginning the first stage
 59:   */
 60:   PetscLogStagePush(0);

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

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

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

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

106:   /* 
107:      Assemble matrix, using the 2-step process:
108:        MatAssemblyBegin(), MatAssemblyEnd()
109:      Computations can be done while messages are in transition
110:      by placing code between these two statements.
111:   */
112:   MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
113:   MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);

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

126:   /* 
127:      Currently, all parallel PETSc vectors are partitioned by
128:      contiguous chunks across the processors.  Determine which
129:      range of entries are locally owned.
130:   */
131:   VecGetOwnershipRange(x,&low,&high);

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

147:   /* 
148:      Assemble vector, using the 2-step process:
149:        VecAssemblyBegin(), VecAssemblyEnd()
150:      Computations can be done while messages are in transition,
151:      by placing code between these two statements.
152:   */
153:   VecAssemblyBegin(u);
154:   VecAssemblyEnd(u);

156:   /* 
157:      Compute right-hand-side vector
158:   */
159:   MatMult(C,u,b);
160: 
161:   /* 
162:     Create linear solver context
163:   */
164:   SLESCreate(PETSC_COMM_WORLD,&sles);

166:   /* 
167:      Set operators. Here the matrix that defines the linear system
168:      also serves as the preconditioning matrix.
169:   */
170:   SLESSetOperators(sles,C,C,DIFFERENT_NONZERO_PATTERN);

172:   /* 
173:      Set runtime options (e.g., -ksp_type <type> -pc_type <type>)
174:   */

176:   SLESSetFromOptions(sles);

178:   /* 
179:      Solve linear system.  Here we explicitly call SLESSetUp() for more
180:      detailed performance monitoring of certain preconditioners, such
181:      as ICC and ILU.  This call is optional, as SLESSetUp() will
182:      automatically be called within SLESSolve() if it hasn't been
183:      called already.
184:   */
185:   SLESSetUp(sles,b,x);
186:   SLESSolve(sles,b,x,&its);
187: 
188:   /* 
189:      Check the error
190:   */
191:   VecAXPY(&none,u,x);
192:   VecNorm(x,NORM_2,&norm);
193:   PetscPrintf(PETSC_COMM_WORLD,"Norm of error %A, Iterations %dn",norm,its);

195:   /* -------------- Stage 1: Solve Second System ---------------------- */
196:   /* 
197:      Solve another linear system with the same method.  We reuse the SLES
198:      context, matrix and vector data structures, and hence save the
199:      overhead of creating new ones.

201:      Indicate to PETSc profiling that we're concluding the first
202:      stage with PetscLogStagePop(), and beginning the second stage with
203:      PetscLogStagePush().
204:   */
205:   PetscLogStagePop();
206:   PetscLogStagePush(1);

208:   /* 
209:      Initialize all matrix entries to zero.  MatZeroEntries() retains the
210:      nonzero structure of the matrix for sparse formats.
211:   */
212:   MatZeroEntries(C);

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

238:   /* 
239:      Compute another right-hand-side vector
240:   */
241:   MatMult(C,u,b);

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

266:   /* 
267:      Solve linear system
268:   */
269:   SLESSetUp(sles,b,x);
270:   SLESSolve(sles,b,x,&its);

272:   /* 
273:      Check the error
274:   */
275:   VecAXPY(&none,u,x);
276:   VecNorm(x,NORM_2,&norm);
277:   PetscPrintf(PETSC_COMM_WORLD,"Norm of error %A, Iterations %dn",norm,its);

279:   /* 
280:      Free work space.  All PETSc objects should be destroyed when they
281:      are no longer needed.
282:   */
283:   SLESDestroy(sles);
284:   VecDestroy(u);
285:   VecDestroy(x);
286:   VecDestroy(b);
287:   MatDestroy(C);

289:   /*
290:      Indicate to PETSc profiling that we're concluding the second stage 
291:   */
292:   PetscLogStagePop();

294:   PetscFinalize();
295:   return 0;
296: }