Actual source code: ex9.c
1: /*$Id: ex9.c,v 1.53 2001/08/07 21:30:54 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,PetscReal,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: int stages[3];
43: PetscTruth flg;
44: PetscScalar v;
46: PetscInitialize(&argc,&args,(char *)0,help);
47: PetscOptionsGetInt(PETSC_NULL,"-m",&m,PETSC_NULL);
48: PetscOptionsGetInt(PETSC_NULL,"-t",&ntimes,PETSC_NULL);
49: MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
50: MPI_Comm_size(PETSC_COMM_WORLD,&size);
51: n = 2*size;
53: /*
54: Register various stages for profiling
55: */
56: PetscLogStageRegister(&stages[0],"Prelim setup");
57: PetscLogStageRegister(&stages[1],"Linear System 1");
58: PetscLogStageRegister(&stages[2],"Linear System 2");
60: /*
61: Register a user-defined event for profiling (error checking).
62: */
63: CHECK_ERROR = 0;
64: PetscLogEventRegister(&CHECK_ERROR,"Check Error",SLES_COOKIE);
66: /* - - - - - - - - - - - - Stage 0: - - - - - - - - - - - - - -
67: Preliminary Setup
68: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
70: PetscLogStagePush(stages[0]);
72: /*
73: Create data structures for first linear system.
74: - Create parallel matrix, specifying only its global dimensions.
75: When using MatCreate(), the matrix format can be specified at
76: runtime. Also, the parallel partitioning of the matrix is
77: determined by PETSc at runtime.
78: - Create parallel vectors.
79: - When using VecSetSizes(), we specify only the vector's global
80: dimension; the parallel partitioning is determined at runtime.
81: - Note: We form 1 vector from scratch and then duplicate as needed.
82: */
83: MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,m*n,m*n,&C1);
84: MatSetFromOptions(C1);
85: MatGetOwnershipRange(C1,&Istart,&Iend);
86: VecCreate(PETSC_COMM_WORLD,&u);
87: VecSetSizes(u,PETSC_DECIDE,m*n);
88: VecSetFromOptions(u);
89: VecDuplicate(u,&b1);
90: VecDuplicate(u,&x1);
92: /*
93: Create first linear solver context.
94: Set runtime options (e.g., -pc_type <type>).
95: Note that the first linear system uses the default option
96: names, while the second linear systme uses a different
97: options prefix.
98: */
99: SLESCreate(PETSC_COMM_WORLD,&sles1);
100: SLESSetFromOptions(sles1);
102: /*
103: Set user-defined monitoring routine for first linear system.
104: */
105: SLESGetKSP(sles1,&ksp1);
106: PetscOptionsHasName(PETSC_NULL,"-my_ksp_monitor",&flg);
107: if (flg) {KSPSetMonitor(ksp1,MyKSPMonitor,PETSC_NULL,0);}
109: /*
110: Create data structures for second linear system.
111: */
112: MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,m*n,m*n,&C2);
113: MatSetFromOptions(C2);
114: MatGetOwnershipRange(C2,&Istart2,&Iend2);
115: VecDuplicate(u,&b2);
116: VecDuplicate(u,&x2);
118: /*
119: Create second linear solver context
120: */
121: SLESCreate(PETSC_COMM_WORLD,&sles2);
123: /*
124: Set different options prefix for second linear system.
125: Set runtime options (e.g., -s2_pc_type <type>)
126: */
127: SLESAppendOptionsPrefix(sles2,"s2_");
128: SLESSetFromOptions(sles2);
130: /*
131: Assemble exact solution vector in parallel. Note that each
132: processor needs to set only its local part of the vector.
133: */
134: VecGetLocalSize(u,&ldim);
135: VecGetOwnershipRange(u,&low,&high);
136: for (i=0; i<ldim; i++) {
137: iglobal = i + low;
138: v = (PetscScalar)(i + 100*rank);
139: VecSetValues(u,1,&iglobal,&v,ADD_VALUES);
140: }
141: VecAssemblyBegin(u);
142: VecAssemblyEnd(u);
144: /*
145: Log the number of flops for computing vector entries
146: */
147: PetscLogFlops(2*ldim);
149: /*
150: End curent profiling stage
151: */
152: PetscLogStagePop();
154: /* --------------------------------------------------------------
155: Linear solver loop:
156: Solve 2 different linear systems several times in succession
157: -------------------------------------------------------------- */
159: for (t=0; t<ntimes; t++) {
161: /* - - - - - - - - - - - - Stage 1: - - - - - - - - - - - - - -
162: Assemble and solve first linear system
163: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
165: /*
166: Begin profiling stage #1
167: */
168: PetscLogStagePush(stages[1]);
170: /*
171: Initialize all matrix entries to zero. MatZeroEntries() retains
172: the nonzero structure of the matrix for sparse formats.
173: */
174: MatZeroEntries(C1);
176: /*
177: Set matrix entries in parallel. Also, log the number of flops
178: for computing matrix entries.
179: - Each processor needs to insert only elements that it owns
180: locally (but any non-local elements will be sent to the
181: appropriate processor during matrix assembly).
182: - Always specify global row and columns of matrix entries.
183: */
184: for (I=Istart; I<Iend; I++) {
185: v = -1.0; i = I/n; j = I - i*n;
186: if (i>0) {J = I - n; MatSetValues(C1,1,&I,1,&J,&v,ADD_VALUES);}
187: if (i<m-1) {J = I + n; MatSetValues(C1,1,&I,1,&J,&v,ADD_VALUES);}
188: if (j>0) {J = I - 1; MatSetValues(C1,1,&I,1,&J,&v,ADD_VALUES);}
189: if (j<n-1) {J = I + 1; MatSetValues(C1,1,&I,1,&J,&v,ADD_VALUES);}
190: v = 4.0; MatSetValues(C1,1,&I,1,&I,&v,ADD_VALUES);
191: }
192: for (I=Istart; I<Iend; I++) { /* Make matrix nonsymmetric */
193: v = -1.0*(t+0.5); i = I/n;
194: if (i>0) {J = I - n; MatSetValues(C1,1,&I,1,&J,&v,ADD_VALUES);}
195: }
196: PetscLogFlops(2*(Istart-Iend));
198: /*
199: Assemble matrix, using the 2-step process:
200: MatAssemblyBegin(), MatAssemblyEnd()
201: Computations can be done while messages are in transition
202: by placing code between these two statements.
203: */
204: MatAssemblyBegin(C1,MAT_FINAL_ASSEMBLY);
205: MatAssemblyEnd(C1,MAT_FINAL_ASSEMBLY);
207: /*
208: Indicate same nonzero structure of successive linear system matrices
209: */
210: MatSetOption(C1,MAT_NO_NEW_NONZERO_LOCATIONS);
212: /*
213: Compute right-hand-side vector
214: */
215: MatMult(C1,u,b1);
217: /*
218: Set operators. Here the matrix that defines the linear system
219: also serves as the preconditioning matrix.
220: - The flag SAME_NONZERO_PATTERN indicates that the
221: preconditioning matrix has identical nonzero structure
222: as during the last linear solve (although the values of
223: the entries have changed). Thus, we can save some
224: work in setting up the preconditioner (e.g., no need to
225: redo symbolic factorization for ILU/ICC preconditioners).
226: - If the nonzero structure of the matrix is different during
227: the second linear solve, then the flag DIFFERENT_NONZERO_PATTERN
228: must be used instead. If you are unsure whether the
229: matrix structure has changed or not, use the flag
230: DIFFERENT_NONZERO_PATTERN.
231: - Caution: If you specify SAME_NONZERO_PATTERN, PETSc
232: believes your assertion and does not check the structure
233: of the matrix. If you erroneously claim that the structure
234: is the same when it actually is not, the new preconditioner
235: will not function correctly. Thus, use this optimization
236: feature with caution!
237: */
238: SLESSetOperators(sles1,C1,C1,SAME_NONZERO_PATTERN);
240: /*
241: Use the previous solution of linear system #1 as the initial
242: guess for the next solve of linear system #1. The user MUST
243: call KSPSetInitialGuessNonzero() in indicate use of an initial
244: guess vector; otherwise, an initial guess of zero is used.
245: */
246: if (t>0) {
247: KSPSetInitialGuessNonzero(ksp1,PETSC_TRUE);
248: }
250: /*
251: Solve the first linear system. Here we explicitly call
252: SLESSetUp() for more detailed performance monitoring of
253: certain preconditioners, such as ICC and ILU. This call
254: is optional, ase SLESSetUp() will automatically be called
255: within SLESSolve() if it hasn't been called already.
256: */
257: SLESSetUp(sles1,b1,x1);
258: SLESSolve(sles1,b1,x1,&its);
260: /*
261: Check error of solution to first linear system
262: */
263: CheckError(u,x1,b1,its,CHECK_ERROR);
265: /* - - - - - - - - - - - - Stage 2: - - - - - - - - - - - - - -
266: Assemble and solve second linear system
267: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
269: /*
270: Conclude profiling stage #1; begin profiling stage #2
271: */
272: PetscLogStagePop();
273: PetscLogStagePush(stages[2]);
275: /*
276: Initialize all matrix entries to zero
277: */
278: MatZeroEntries(C2);
280: /*
281: Assemble matrix in parallel. Also, log the number of flops
282: for computing matrix entries.
283: - To illustrate the features of parallel matrix assembly, we
284: intentionally set the values differently from the way in
285: which the matrix is distributed across the processors. Each
286: entry that is not owned locally will be sent to the appropriate
287: processor during MatAssemblyBegin() and MatAssemblyEnd().
288: - For best efficiency the user should strive to set as many
289: entries locally as possible.
290: */
291: for (i=0; i<m; i++) {
292: for (j=2*rank; j<2*rank+2; j++) {
293: v = -1.0; I = j + n*i;
294: if (i>0) {J = I - n; MatSetValues(C2,1,&I,1,&J,&v,ADD_VALUES);}
295: if (i<m-1) {J = I + n; MatSetValues(C2,1,&I,1,&J,&v,ADD_VALUES);}
296: if (j>0) {J = I - 1; MatSetValues(C2,1,&I,1,&J,&v,ADD_VALUES);}
297: if (j<n-1) {J = I + 1; MatSetValues(C2,1,&I,1,&J,&v,ADD_VALUES);}
298: v = 6.0 + t*0.5; MatSetValues(C2,1,&I,1,&I,&v,ADD_VALUES);
299: }
300: }
301: for (I=Istart2; I<Iend2; I++) { /* Make matrix nonsymmetric */
302: v = -1.0*(t+0.5); i = I/n;
303: if (i>0) {J = I - n; MatSetValues(C2,1,&I,1,&J,&v,ADD_VALUES);}
304: }
305: MatAssemblyBegin(C2,MAT_FINAL_ASSEMBLY);
306: MatAssemblyEnd(C2,MAT_FINAL_ASSEMBLY);
307: PetscLogFlops(2*(Istart-Iend));
309: /*
310: Indicate same nonzero structure of successive linear system matrices
311: */
312: MatSetOption(C2,MAT_NO_NEW_NONZERO_LOCATIONS);
314: /*
315: Compute right-hand-side vector
316: */
317: MatMult(C2,u,b2);
319: /*
320: Set operators. Here the matrix that defines the linear system
321: also serves as the preconditioning matrix. Indicate same nonzero
322: structure of successive preconditioner matrices by setting flag
323: SAME_NONZERO_PATTERN.
324: */
325: SLESSetOperators(sles2,C2,C2,SAME_NONZERO_PATTERN);
327: /*
328: Solve the second linear system
329: */
330: SLESSetUp(sles2,b2,x2);
331: SLESSolve(sles2,b2,x2,&its);
333: /*
334: Check error of solution to second linear system
335: */
336: CheckError(u,x2,b2,its,CHECK_ERROR);
338: /*
339: Conclude profiling stage #2
340: */
341: PetscLogStagePop();
342: }
343: /* --------------------------------------------------------------
344: End of linear solver loop
345: -------------------------------------------------------------- */
347: /*
348: Free work space. All PETSc objects should be destroyed when they
349: are no longer needed.
350: */
351: SLESDestroy(sles1); SLESDestroy(sles2);
352: VecDestroy(x1); VecDestroy(x2);
353: VecDestroy(b1); VecDestroy(b2);
354: MatDestroy(C1); MatDestroy(C2);
355: VecDestroy(u);
357: PetscFinalize();
358: return 0;
359: }
360: /* ------------------------------------------------------------- */
361: /*
362: CheckError - Checks the error of the solution.
364: Input Parameters:
365: u - exact solution
366: x - approximate solution
367: b - work vector
368: its - number of iterations for convergence
369: CHECK_ERROR - the event number for error checking
370: (for use with profiling)
372: Notes:
373: In order to profile this section of code separately from the
374: rest of the program, we register it as an "event" with
375: PetscLogEventRegister() in the main program. Then, we indicate
376: the start and end of this event by respectively calling
377: PetscLogEventBegin(CHECK_ERROR,u,x,b,0);
378: PetscLogEventEnd(CHECK_ERROR,u,x,b,0);
379: Here, we specify the objects most closely associated with
380: the event (the vectors u,x,b). Such information is optional;
381: we could instead just use 0 instead for all objects.
382: */
383: int CheckError(Vec u,Vec x,Vec b,int its,int CHECK_ERROR)
384: {
385: PetscScalar none = -1.0;
386: PetscReal norm;
387: int ierr;
389: PetscLogEventBegin(CHECK_ERROR,u,x,b,0);
391: /*
392: Compute error of the solution, using b as a work vector.
393: */
394: VecCopy(x,b);
395: VecAXPY(&none,u,b);
396: VecNorm(b,NORM_2,&norm);
397: PetscPrintf(PETSC_COMM_WORLD,"Norm of error %A, Iterations %dn",norm,its);
398: PetscLogEventEnd(CHECK_ERROR,u,x,b,0);
399: return 0;
400: }
401: /* ------------------------------------------------------------- */
402: /*
403: MyKSPMonitor - This is a user-defined routine for monitoring
404: the SLES iterative solvers.
406: Input Parameters:
407: ksp - iterative context
408: n - iteration number
409: rnorm - 2-norm (preconditioned) residual value (may be estimated)
410: dummy - optional user-defined monitor context (unused here)
411: */
412: int MyKSPMonitor(KSP ksp,int n,PetscReal rnorm,void *dummy)
413: {
414: Vec x;
415: int ierr;
417: /*
418: Build the solution vector
419: */
420: KSPBuildSolution(ksp,PETSC_NULL,&x);
422: /*
423: Write the solution vector and residual norm to stdout.
424: - PetscPrintf() handles output for multiprocessor jobs
425: by printing from only one processor in the communicator.
426: - The parallel viewer PETSC_VIEWER_STDOUT_WORLD handles
427: data from multiple processors so that the output
428: is not jumbled.
429: */
430: PetscPrintf(PETSC_COMM_WORLD,"iteration %d solution vector:n",n);
431: VecView(x,PETSC_VIEWER_STDOUT_WORLD);
432: PetscPrintf(PETSC_COMM_WORLD,"iteration %d KSP Residual norm %14.12e n",n,rnorm);
433: return 0;
434: }