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