Actual source code: ex9.c
1: static char help[] = "The solution of 2 different linear systems with different linear solvers.\n\
2: Also, this example illustrates the repeated\n\
3: solution of linear systems, while reusing matrix, vector, and solver data\n\
4: structures throughout the process. Note the various stages of event logging.\n\n";
6: /*
7: Include "petscksp.h" so that we can use KSP solvers. Note that this file
8: automatically includes:
9: petscsys.h - base PETSc routines petscvec.h - vectors
10: petscmat.h - matrices
11: petscis.h - index sets petscksp.h - Krylov subspace methods
12: petscviewer.h - viewers petscpc.h - preconditioners
13: */
14: #include <petscksp.h>
16: /*
17: Declare user-defined routines
18: */
19: extern PetscErrorCode CheckError(Vec, Vec, Vec, PetscInt, PetscReal, PetscLogEvent);
20: extern PetscErrorCode MyKSPMonitor(KSP, PetscInt, PetscReal, void *);
22: int main(int argc, char **args)
23: {
24: Vec x1, b1, x2, b2; /* solution and RHS vectors for systems #1 and #2 */
25: Vec u; /* exact solution vector */
26: Mat C1, C2; /* matrices for systems #1 and #2 */
27: KSP ksp1, ksp2; /* KSP contexts for systems #1 and #2 */
28: PetscInt ntimes = 3; /* number of times to solve the linear systems */
29: PetscLogEvent CHECK_ERROR; /* event number for error checking */
30: PetscInt ldim, low, high, iglobal, Istart, Iend, Istart2, Iend2;
31: PetscInt Ii, J, i, j, m = 3, n = 2, its, t;
32: PetscBool flg = PETSC_FALSE, unsym = PETSC_TRUE;
33: PetscScalar v;
34: PetscMPIInt rank, size;
35: PetscLogStage stages[3];
37: PetscFunctionBeginUser;
38: PetscCall(PetscInitialize(&argc, &args, NULL, help));
39: PetscCall(PetscOptionsGetInt(NULL, NULL, "-m", &m, NULL));
40: PetscCall(PetscOptionsGetInt(NULL, NULL, "-t", &ntimes, NULL));
41: PetscCall(PetscOptionsGetBool(NULL, NULL, "-unsym", &unsym, NULL));
42: PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
43: PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
44: n = 2 * size;
46: /*
47: Register various stages for profiling
48: */
49: PetscCall(PetscLogStageRegister("Prelim setup", &stages[0]));
50: PetscCall(PetscLogStageRegister("Linear System 1", &stages[1]));
51: PetscCall(PetscLogStageRegister("Linear System 2", &stages[2]));
53: /*
54: Register a user-defined event for profiling (error checking).
55: */
56: CHECK_ERROR = 0;
57: PetscCall(PetscLogEventRegister("Check Error", KSP_CLASSID, &CHECK_ERROR));
59: /* - - - - - - - - - - - - Stage 0: - - - - - - - - - - - - - -
60: Preliminary Setup
61: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
63: PetscCall(PetscLogStagePush(stages[0]));
65: /*
66: Create data structures for first linear system.
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: - Create parallel vectors.
72: - When using VecSetSizes(), we specify only the vector's global
73: dimension; the parallel partitioning is determined at runtime.
74: - Note: We form 1 vector from scratch and then duplicate as needed.
75: */
76: PetscCall(MatCreate(PETSC_COMM_WORLD, &C1));
77: PetscCall(MatSetSizes(C1, PETSC_DECIDE, PETSC_DECIDE, m * n, m * n));
78: PetscCall(MatSetFromOptions(C1));
79: PetscCall(MatSetUp(C1));
80: PetscCall(MatGetOwnershipRange(C1, &Istart, &Iend));
81: PetscCall(VecCreate(PETSC_COMM_WORLD, &u));
82: PetscCall(VecSetSizes(u, PETSC_DECIDE, m * n));
83: PetscCall(VecSetFromOptions(u));
84: PetscCall(VecDuplicate(u, &b1));
85: PetscCall(VecDuplicate(u, &x1));
87: /*
88: Create first linear solver context.
89: Set runtime options (e.g., -pc_type <type>).
90: Note that the first linear system uses the default option
91: names, while the second linear system uses a different
92: options prefix.
93: */
94: PetscCall(KSPCreate(PETSC_COMM_WORLD, &ksp1));
95: PetscCall(KSPSetFromOptions(ksp1));
97: /*
98: Set user-defined monitoring routine for first linear system.
99: */
100: PetscCall(PetscOptionsGetBool(NULL, NULL, "-my_ksp_monitor", &flg, NULL));
101: if (flg) PetscCall(KSPMonitorSet(ksp1, MyKSPMonitor, NULL, 0));
103: /*
104: Create data structures for second linear system.
105: */
106: PetscCall(MatCreate(PETSC_COMM_WORLD, &C2));
107: PetscCall(MatSetSizes(C2, PETSC_DECIDE, PETSC_DECIDE, m * n, m * n));
108: PetscCall(MatSetFromOptions(C2));
109: PetscCall(MatSetUp(C2));
110: PetscCall(MatGetOwnershipRange(C2, &Istart2, &Iend2));
111: PetscCall(VecDuplicate(u, &b2));
112: PetscCall(VecDuplicate(u, &x2));
114: /*
115: Create second linear solver context
116: */
117: PetscCall(KSPCreate(PETSC_COMM_WORLD, &ksp2));
119: /*
120: Set different options prefix for second linear system.
121: Set runtime options (e.g., -s2_pc_type <type>)
122: */
123: PetscCall(KSPAppendOptionsPrefix(ksp2, "s2_"));
124: PetscCall(KSPSetFromOptions(ksp2));
126: /*
127: Assemble exact solution vector in parallel. Note that each
128: processor needs to set only its local part of the vector.
129: */
130: PetscCall(VecGetLocalSize(u, &ldim));
131: PetscCall(VecGetOwnershipRange(u, &low, &high));
132: for (i = 0; i < ldim; i++) {
133: iglobal = i + low;
134: v = (PetscScalar)(i + 100 * rank);
135: PetscCall(VecSetValues(u, 1, &iglobal, &v, ADD_VALUES));
136: }
137: PetscCall(VecAssemblyBegin(u));
138: PetscCall(VecAssemblyEnd(u));
140: /*
141: Log the number of flops for computing vector entries
142: */
143: PetscCall(PetscLogFlops(2.0 * ldim));
145: /*
146: End current profiling stage
147: */
148: PetscCall(PetscLogStagePop());
150: /* --------------------------------------------------------------
151: Linear solver loop:
152: Solve 2 different linear systems several times in succession
153: -------------------------------------------------------------- */
155: for (t = 0; t < ntimes; t++) {
156: /* - - - - - - - - - - - - Stage 1: - - - - - - - - - - - - - -
157: Assemble and solve first linear system
158: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
160: /*
161: Begin profiling stage #1
162: */
163: PetscCall(PetscLogStagePush(stages[1]));
165: /*
166: Initialize all matrix entries to zero. MatZeroEntries() retains
167: the nonzero structure of the matrix for sparse formats.
168: */
169: if (t > 0) PetscCall(MatZeroEntries(C1));
171: /*
172: Set matrix entries in parallel. Also, log the number of flops
173: for computing matrix entries.
174: - Each processor needs to insert only elements that it owns
175: locally (but any non-local elements will be sent to the
176: appropriate processor during matrix assembly).
177: - Always specify global row and columns of matrix entries.
178: */
179: for (Ii = Istart; Ii < Iend; Ii++) {
180: v = -1.0;
181: i = Ii / n;
182: j = Ii - i * n;
183: if (i > 0) {
184: J = Ii - n;
185: PetscCall(MatSetValues(C1, 1, &Ii, 1, &J, &v, ADD_VALUES));
186: }
187: if (i < m - 1) {
188: J = Ii + n;
189: PetscCall(MatSetValues(C1, 1, &Ii, 1, &J, &v, ADD_VALUES));
190: }
191: if (j > 0) {
192: J = Ii - 1;
193: PetscCall(MatSetValues(C1, 1, &Ii, 1, &J, &v, ADD_VALUES));
194: }
195: if (j < n - 1) {
196: J = Ii + 1;
197: PetscCall(MatSetValues(C1, 1, &Ii, 1, &J, &v, ADD_VALUES));
198: }
199: v = 4.0;
200: PetscCall(MatSetValues(C1, 1, &Ii, 1, &Ii, &v, ADD_VALUES));
201: }
202: if (unsym) {
203: for (Ii = Istart; Ii < Iend; Ii++) { /* Make matrix nonsymmetric */
204: v = -1.0 * (t + 0.5);
205: i = Ii / n;
206: if (i > 0) {
207: J = Ii - n;
208: PetscCall(MatSetValues(C1, 1, &Ii, 1, &J, &v, ADD_VALUES));
209: }
210: }
211: PetscCall(PetscLogFlops(2.0 * (Iend - Istart)));
212: }
214: /*
215: Assemble matrix, using the 2-step process:
216: MatAssemblyBegin(), MatAssemblyEnd()
217: Computations can be done while messages are in transition
218: by placing code between these two statements.
219: */
220: PetscCall(MatAssemblyBegin(C1, MAT_FINAL_ASSEMBLY));
221: PetscCall(MatAssemblyEnd(C1, MAT_FINAL_ASSEMBLY));
223: /*
224: Indicate same nonzero structure of successive linear system matrices
225: */
226: PetscCall(MatSetOption(C1, MAT_NEW_NONZERO_LOCATIONS, PETSC_TRUE));
228: /*
229: Compute right-hand-side vector
230: */
231: PetscCall(MatMult(C1, u, b1));
233: /*
234: Set operators. Here the matrix that defines the linear system
235: also serves as the preconditioning matrix.
236: */
237: PetscCall(KSPSetOperators(ksp1, C1, C1));
239: /*
240: Use the previous solution of linear system #1 as the initial
241: guess for the next solve of linear system #1. The user MUST
242: call KSPSetInitialGuessNonzero() in indicate use of an initial
243: guess vector; otherwise, an initial guess of zero is used.
244: */
245: if (t > 0) PetscCall(KSPSetInitialGuessNonzero(ksp1, PETSC_TRUE));
247: /*
248: Solve the first linear system. Here we explicitly call
249: KSPSetUp() for more detailed performance monitoring of
250: certain preconditioners, such as ICC and ILU. This call
251: is optional, ase KSPSetUp() will automatically be called
252: within KSPSolve() if it hasn't been called already.
253: */
254: PetscCall(KSPSetUp(ksp1));
255: PetscCall(KSPSolve(ksp1, b1, x1));
256: PetscCall(KSPGetIterationNumber(ksp1, &its));
258: /*
259: Check error of solution to first linear system
260: */
261: PetscCall(CheckError(u, x1, b1, its, 1.e-4, 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: PetscCall(PetscLogStagePop());
271: PetscCall(PetscLogStagePush(stages[2]));
273: /*
274: Initialize all matrix entries to zero
275: */
276: if (t > 0) PetscCall(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;
292: Ii = j + n * i;
293: if (i > 0) {
294: J = Ii - n;
295: PetscCall(MatSetValues(C2, 1, &Ii, 1, &J, &v, ADD_VALUES));
296: }
297: if (i < m - 1) {
298: J = Ii + n;
299: PetscCall(MatSetValues(C2, 1, &Ii, 1, &J, &v, ADD_VALUES));
300: }
301: if (j > 0) {
302: J = Ii - 1;
303: PetscCall(MatSetValues(C2, 1, &Ii, 1, &J, &v, ADD_VALUES));
304: }
305: if (j < n - 1) {
306: J = Ii + 1;
307: PetscCall(MatSetValues(C2, 1, &Ii, 1, &J, &v, ADD_VALUES));
308: }
309: v = 6.0 + t * 0.5;
310: PetscCall(MatSetValues(C2, 1, &Ii, 1, &Ii, &v, ADD_VALUES));
311: }
312: }
313: if (unsym) {
314: for (Ii = Istart2; Ii < Iend2; Ii++) { /* Make matrix nonsymmetric */
315: v = -1.0 * (t + 0.5);
316: i = Ii / n;
317: if (i > 0) {
318: J = Ii - n;
319: PetscCall(MatSetValues(C2, 1, &Ii, 1, &J, &v, ADD_VALUES));
320: }
321: }
322: }
323: PetscCall(MatAssemblyBegin(C2, MAT_FINAL_ASSEMBLY));
324: PetscCall(MatAssemblyEnd(C2, MAT_FINAL_ASSEMBLY));
325: PetscCall(PetscLogFlops(2.0 * (Iend - Istart)));
327: /*
328: Indicate same nonzero structure of successive linear system matrices
329: */
330: PetscCall(MatSetOption(C2, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE));
332: /*
333: Compute right-hand-side vector
334: */
335: PetscCall(MatMult(C2, u, b2));
337: /*
338: Set operators. Here the matrix that defines the linear system
339: also serves as the preconditioning matrix. Indicate same nonzero
340: structure of successive preconditioner matrices by setting flag
341: SAME_NONZERO_PATTERN.
342: */
343: PetscCall(KSPSetOperators(ksp2, C2, C2));
345: /*
346: Solve the second linear system
347: */
348: PetscCall(KSPSetUp(ksp2));
349: PetscCall(KSPSolve(ksp2, b2, x2));
350: PetscCall(KSPGetIterationNumber(ksp2, &its));
352: /*
353: Check error of solution to second linear system
354: */
355: PetscCall(CheckError(u, x2, b2, its, 1.e-4, CHECK_ERROR));
357: /*
358: Conclude profiling stage #2
359: */
360: PetscCall(PetscLogStagePop());
361: }
362: /* --------------------------------------------------------------
363: End of linear solver loop
364: -------------------------------------------------------------- */
366: /*
367: Free work space. All PETSc objects should be destroyed when they
368: are no longer needed.
369: */
370: PetscCall(KSPDestroy(&ksp1));
371: PetscCall(KSPDestroy(&ksp2));
372: PetscCall(VecDestroy(&x1));
373: PetscCall(VecDestroy(&x2));
374: PetscCall(VecDestroy(&b1));
375: PetscCall(VecDestroy(&b2));
376: PetscCall(MatDestroy(&C1));
377: PetscCall(MatDestroy(&C2));
378: PetscCall(VecDestroy(&u));
380: PetscCall(PetscFinalize());
381: return 0;
382: }
383: /* ------------------------------------------------------------- */
384: /*
385: CheckError - Checks the error of the solution.
387: Input Parameters:
388: u - exact solution
389: x - approximate solution
390: b - work vector
391: its - number of iterations for convergence
392: tol - tolerance
393: CHECK_ERROR - the event number for error checking
394: (for use with profiling)
396: Notes:
397: In order to profile this section of code separately from the
398: rest of the program, we register it as an "event" with
399: PetscLogEventRegister() in the main program. Then, we indicate
400: the start and end of this event by respectively calling
401: PetscLogEventBegin(CHECK_ERROR,u,x,b,0);
402: PetscLogEventEnd(CHECK_ERROR,u,x,b,0);
403: Here, we specify the objects most closely associated with
404: the event (the vectors u,x,b). Such information is optional;
405: we could instead just use 0 instead for all objects.
406: */
407: PetscErrorCode CheckError(Vec u, Vec x, Vec b, PetscInt its, PetscReal tol, PetscLogEvent CHECK_ERROR)
408: {
409: PetscScalar none = -1.0;
410: PetscReal norm;
412: PetscFunctionBeginUser;
413: PetscCall(PetscLogEventBegin(CHECK_ERROR, u, x, b, 0));
415: /*
416: Compute error of the solution, using b as a work vector.
417: */
418: PetscCall(VecCopy(x, b));
419: PetscCall(VecAXPY(b, none, u));
420: PetscCall(VecNorm(b, NORM_2, &norm));
421: if (norm > tol) PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Norm of error %g, Iterations %" PetscInt_FMT "\n", (double)norm, its));
422: PetscCall(PetscLogEventEnd(CHECK_ERROR, u, x, b, 0));
423: PetscFunctionReturn(PETSC_SUCCESS);
424: }
425: /* ------------------------------------------------------------- */
426: /*
427: MyKSPMonitor - This is a user-defined routine for monitoring
428: the KSP iterative solvers.
430: Input Parameters:
431: ksp - iterative context
432: n - iteration number
433: rnorm - 2-norm (preconditioned) residual value (may be estimated)
434: dummy - optional user-defined monitor context (unused here)
435: */
436: PetscErrorCode MyKSPMonitor(KSP ksp, PetscInt n, PetscReal rnorm, void *dummy)
437: {
438: Vec x;
440: PetscFunctionBeginUser;
441: /*
442: Build the solution vector
443: */
444: PetscCall(KSPBuildSolution(ksp, NULL, &x));
446: /*
447: Write the solution vector and residual norm to stdout.
448: - PetscPrintf() handles output for multiprocessor jobs
449: by printing from only one processor in the communicator.
450: - The parallel viewer PETSC_VIEWER_STDOUT_WORLD handles
451: data from multiple processors so that the output
452: is not jumbled.
453: */
454: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "iteration %" PetscInt_FMT " solution vector:\n", n));
455: PetscCall(VecView(x, PETSC_VIEWER_STDOUT_WORLD));
456: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "iteration %" PetscInt_FMT " KSP Residual norm %14.12e\n", n, (double)rnorm));
457: PetscFunctionReturn(PETSC_SUCCESS);
458: }
460: /*TEST
462: test:
463: args: -t 2 -pc_type jacobi -ksp_monitor_short -ksp_type gmres -ksp_gmres_cgs_refinement_type refine_always -s2_ksp_type bcgs -s2_pc_type jacobi -s2_ksp_monitor_short
465: test:
466: requires: hpddm
467: suffix: hpddm
468: args: -t 2 -pc_type jacobi -ksp_monitor_short -ksp_type {{gmres hpddm}} -s2_ksp_type {{gmres hpddm}} -s2_pc_type jacobi -s2_ksp_monitor_short
470: test:
471: requires: hpddm
472: suffix: hpddm_2
473: args: -t 2 -pc_type jacobi -ksp_monitor_short -ksp_type gmres -s2_ksp_type hpddm -s2_ksp_hpddm_type gcrodr -s2_ksp_hpddm_recycle 10 -s2_pc_type jacobi -s2_ksp_monitor_short
475: testset:
476: requires: hpddm
477: output_file: output/ex9_hpddm_cg.out
478: args: -unsym 0 -t 2 -pc_type jacobi -ksp_monitor_short -s2_pc_type jacobi -s2_ksp_monitor_short -ksp_rtol 1.e-2 -s2_ksp_rtol 1.e-2
479: test:
480: suffix: hpddm_cg_p_p
481: args: -ksp_type cg -s2_ksp_type cg
482: test:
483: suffix: hpddm_cg_p_h
484: args: -ksp_type cg -s2_ksp_type hpddm -s2_ksp_hpddm_type {{cg bcg bfbcg}shared output}
485: test:
486: suffix: hpddm_cg_h_h
487: args: -ksp_type hpddm -ksp_hpddm_type cg -s2_ksp_type hpddm -s2_ksp_hpddm_type {{cg bcg bfbcg}shared output}
489: TEST*/