Actual source code: ex6.c
1: static char help[] = "Newton method to solve u'' + u^{2} = f, sequentially.\n\
2: This example employs a user-defined reasonview routine.\n\n";
4: #include <petscsnes.h>
6: /*
7: User-defined routines
8: */
9: PETSC_EXTERN PetscErrorCode FormJacobian(SNES, Vec, Mat, Mat, void *);
10: PETSC_EXTERN PetscErrorCode FormFunction(SNES, Vec, Vec, void *);
11: PETSC_EXTERN PetscErrorCode FormInitialGuess(Vec);
12: PETSC_EXTERN PetscErrorCode MySNESConvergedReasonView(SNES, void *);
13: PETSC_EXTERN PetscErrorCode MyKSPConvergedReasonView(KSP, void *);
15: /*
16: User-defined context for monitoring
17: */
18: typedef struct {
19: PetscViewer viewer;
20: } ReasonViewCtx;
22: int main(int argc, char **argv)
23: {
24: SNES snes; /* SNES context */
25: KSP ksp; /* KSP context */
26: Vec x, r, F, U; /* vectors */
27: Mat J; /* Jacobian matrix */
28: ReasonViewCtx monP; /* monitoring context */
29: PetscInt its, n = 5, i;
30: PetscMPIInt size;
31: PetscScalar h, xp, v;
32: MPI_Comm comm;
34: PetscFunctionBeginUser;
35: PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));
36: PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
37: PetscCheck(size == 1, PETSC_COMM_SELF, PETSC_ERR_WRONG_MPI_SIZE, "This is a uniprocessor example only!");
38: PetscCall(PetscOptionsGetInt(NULL, NULL, "-n", &n, NULL));
39: h = 1.0 / (n - 1);
40: comm = PETSC_COMM_WORLD;
41: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
42: Create nonlinear solver context
43: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
45: PetscCall(SNESCreate(comm, &snes));
47: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
48: Create vector data structures; set function evaluation routine
49: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
50: /*
51: Note that we form 1 vector from scratch and then duplicate as needed.
52: */
53: PetscCall(VecCreate(comm, &x));
54: PetscCall(VecSetSizes(x, PETSC_DECIDE, n));
55: PetscCall(VecSetFromOptions(x));
56: PetscCall(VecDuplicate(x, &r));
57: PetscCall(VecDuplicate(x, &F));
58: PetscCall(VecDuplicate(x, &U));
60: /*
61: Set function evaluation routine and vector
62: */
63: PetscCall(SNESSetFunction(snes, r, FormFunction, (void *)F));
65: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
66: Create matrix data structure; set Jacobian evaluation routine
67: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
69: PetscCall(MatCreate(comm, &J));
70: PetscCall(MatSetSizes(J, PETSC_DECIDE, PETSC_DECIDE, n, n));
71: PetscCall(MatSetFromOptions(J));
72: PetscCall(MatSeqAIJSetPreallocation(J, 3, NULL));
74: /*
75: Set Jacobian matrix data structure and default Jacobian evaluation
76: routine. User can override with:
77: -snes_fd : default finite differencing approximation of Jacobian
78: -snes_mf : matrix-free Newton-Krylov method with no preconditioning
79: (unless user explicitly sets preconditioner)
80: -snes_mf_operator : form preconditioning matrix as set by the user,
81: but use matrix-free approx for Jacobian-vector
82: products within Newton-Krylov method
83: */
85: PetscCall(SNESSetJacobian(snes, J, J, FormJacobian, NULL));
87: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
88: Customize nonlinear solver; set runtime options
89: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
91: /*
92: Set an optional user-defined reasonview routine
93: */
94: PetscCall(PetscViewerASCIIGetStdout(comm, &monP.viewer));
95: /* Just make sure we can not repeat adding the same function
96: * PETSc will be able to ignore the repeated function
97: */
98: for (i = 0; i < 4; i++) PetscCall(SNESConvergedReasonViewSet(snes, MySNESConvergedReasonView, &monP, 0));
99: PetscCall(SNESGetKSP(snes, &ksp));
100: /* Just make sure we can not repeat adding the same function
101: * PETSc will be able to ignore the repeated function
102: */
103: for (i = 0; i < 4; i++) PetscCall(KSPConvergedReasonViewSet(ksp, MyKSPConvergedReasonView, &monP, 0));
104: /*
105: Set SNES/KSP/KSP/PC runtime options, e.g.,
106: -snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc>
107: */
108: PetscCall(SNESSetFromOptions(snes));
110: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
111: Initialize application:
112: Store right-hand-side of PDE and exact solution
113: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
115: xp = 0.0;
116: for (i = 0; i < n; i++) {
117: v = 6.0 * xp + PetscPowScalar(xp + 1.e-12, 6.0); /* +1.e-12 is to prevent 0^6 */
118: PetscCall(VecSetValues(F, 1, &i, &v, INSERT_VALUES));
119: v = xp * xp * xp;
120: PetscCall(VecSetValues(U, 1, &i, &v, INSERT_VALUES));
121: xp += h;
122: }
124: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
125: Evaluate initial guess; then solve nonlinear system
126: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
127: /*
128: Note: The user should initialize the vector, x, with the initial guess
129: for the nonlinear solver prior to calling SNESSolve(). In particular,
130: to employ an initial guess of zero, the user should explicitly set
131: this vector to zero by calling VecSet().
132: */
133: PetscCall(FormInitialGuess(x));
134: PetscCall(SNESSolve(snes, NULL, x));
135: PetscCall(SNESGetIterationNumber(snes, &its));
137: /*
138: Free work space. All PETSc objects should be destroyed when they
139: are no longer needed.
140: */
141: PetscCall(VecDestroy(&x));
142: PetscCall(VecDestroy(&r));
143: PetscCall(VecDestroy(&U));
144: PetscCall(VecDestroy(&F));
145: PetscCall(MatDestroy(&J));
146: PetscCall(SNESDestroy(&snes));
147: PetscCall(PetscFinalize());
148: return 0;
149: }
151: /*
152: FormInitialGuess - Computes initial guess.
154: Input/Output Parameter:
155: . x - the solution vector
156: */
157: PetscErrorCode FormInitialGuess(Vec x)
158: {
159: PetscScalar pfive = .50;
161: PetscFunctionBeginUser;
162: PetscCall(VecSet(x, pfive));
163: PetscFunctionReturn(PETSC_SUCCESS);
164: }
166: /*
167: FormFunction - Evaluates nonlinear function, F(x).
169: Input Parameters:
170: . snes - the SNES context
171: . x - input vector
172: . ctx - optional user-defined context, as set by SNESSetFunction()
174: Output Parameter:
175: . f - function vector
177: Note:
178: The user-defined context can contain any application-specific data
179: needed for the function evaluation (such as various parameters, work
180: vectors, and grid information). In this program the context is just
181: a vector containing the right-hand-side of the discretized PDE.
182: */
184: PetscErrorCode FormFunction(SNES snes, Vec x, Vec f, void *ctx)
185: {
186: Vec g = (Vec)ctx;
187: const PetscScalar *xx, *gg;
188: PetscScalar *ff, d;
189: PetscInt i, n;
191: PetscFunctionBeginUser;
192: /*
193: Get pointers to vector data.
194: - For default PETSc vectors, VecGetArray() returns a pointer to
195: the data array. Otherwise, the routine is implementation dependent.
196: - You MUST call VecRestoreArray() when you no longer need access to
197: the array.
198: */
199: PetscCall(VecGetArrayRead(x, &xx));
200: PetscCall(VecGetArray(f, &ff));
201: PetscCall(VecGetArrayRead(g, &gg));
203: /*
204: Compute function
205: */
206: PetscCall(VecGetSize(x, &n));
207: d = (PetscReal)(n - 1);
208: d = d * d;
209: ff[0] = xx[0];
210: for (i = 1; i < n - 1; i++) ff[i] = d * (xx[i - 1] - 2.0 * xx[i] + xx[i + 1]) + xx[i] * xx[i] - gg[i];
211: ff[n - 1] = xx[n - 1] - 1.0;
213: /*
214: Restore vectors
215: */
216: PetscCall(VecRestoreArrayRead(x, &xx));
217: PetscCall(VecRestoreArray(f, &ff));
218: PetscCall(VecRestoreArrayRead(g, &gg));
219: PetscFunctionReturn(PETSC_SUCCESS);
220: }
221: /* ------------------------------------------------------------------- */
222: /*
223: FormJacobian - Evaluates Jacobian matrix.
225: Input Parameters:
226: . snes - the SNES context
227: . x - input vector
228: . dummy - optional user-defined context (not used here)
230: Output Parameters:
231: . jac - Jacobian matrix
232: . B - optionally different preconditioning matrix
234: */
236: PetscErrorCode FormJacobian(SNES snes, Vec x, Mat jac, Mat B, void *dummy)
237: {
238: const PetscScalar *xx;
239: PetscScalar A[3], d;
240: PetscInt i, n, j[3];
242: PetscFunctionBeginUser;
243: /*
244: Get pointer to vector data
245: */
246: PetscCall(VecGetArrayRead(x, &xx));
248: /*
249: Compute Jacobian entries and insert into matrix.
250: - Note that in this case we set all elements for a particular
251: row at once.
252: */
253: PetscCall(VecGetSize(x, &n));
254: d = (PetscReal)(n - 1);
255: d = d * d;
257: /*
258: Interior grid points
259: */
260: for (i = 1; i < n - 1; i++) {
261: j[0] = i - 1;
262: j[1] = i;
263: j[2] = i + 1;
264: A[0] = A[2] = d;
265: A[1] = -2.0 * d + 2.0 * xx[i];
266: PetscCall(MatSetValues(B, 1, &i, 3, j, A, INSERT_VALUES));
267: }
269: /*
270: Boundary points
271: */
272: i = 0;
273: A[0] = 1.0;
275: PetscCall(MatSetValues(B, 1, &i, 1, &i, A, INSERT_VALUES));
277: i = n - 1;
278: A[0] = 1.0;
280: PetscCall(MatSetValues(B, 1, &i, 1, &i, A, INSERT_VALUES));
282: /*
283: Restore vector
284: */
285: PetscCall(VecRestoreArrayRead(x, &xx));
287: /*
288: Assemble matrix
289: */
290: PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
291: PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
292: if (jac != B) {
293: PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY));
294: PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY));
295: }
296: PetscFunctionReturn(PETSC_SUCCESS);
297: }
299: PetscErrorCode MySNESConvergedReasonView(SNES snes, void *ctx)
300: {
301: ReasonViewCtx *monP = (ReasonViewCtx *)ctx;
302: PetscViewer viewer = monP->viewer;
303: SNESConvergedReason reason;
304: const char *strreason;
306: PetscFunctionBeginUser;
307: PetscCall(SNESGetConvergedReason(snes, &reason));
308: PetscCall(SNESGetConvergedReasonString(snes, &strreason));
309: PetscCall(PetscViewerASCIIPrintf(viewer, "Customized SNES converged reason view\n"));
310: PetscCall(PetscViewerASCIIAddTab(viewer, 1));
311: if (reason > 0) {
312: PetscCall(PetscViewerASCIIPrintf(viewer, "Converged due to %s\n", strreason));
313: } else if (reason <= 0) {
314: PetscCall(PetscViewerASCIIPrintf(viewer, "Did not converge due to %s\n", strreason));
315: }
316: PetscCall(PetscViewerASCIISubtractTab(viewer, 1));
317: PetscFunctionReturn(PETSC_SUCCESS);
318: }
320: PetscErrorCode MyKSPConvergedReasonView(KSP ksp, void *ctx)
321: {
322: ReasonViewCtx *monP = (ReasonViewCtx *)ctx;
323: PetscViewer viewer = monP->viewer;
324: KSPConvergedReason reason;
325: const char *reasonstr;
327: PetscFunctionBeginUser;
328: PetscCall(KSPGetConvergedReason(ksp, &reason));
329: PetscCall(KSPGetConvergedReasonString(ksp, &reasonstr));
330: PetscCall(PetscViewerASCIIAddTab(viewer, 2));
331: PetscCall(PetscViewerASCIIPrintf(viewer, "Customized KSP converged reason view\n"));
332: PetscCall(PetscViewerASCIIAddTab(viewer, 1));
333: if (reason > 0) {
334: PetscCall(PetscViewerASCIIPrintf(viewer, "Converged due to %s\n", reasonstr));
335: } else if (reason <= 0) {
336: PetscCall(PetscViewerASCIIPrintf(viewer, "Did not converge due to %s\n", reasonstr));
337: }
338: PetscCall(PetscViewerASCIISubtractTab(viewer, 3));
339: PetscFunctionReturn(PETSC_SUCCESS);
340: }
342: /*TEST
344: test:
345: suffix: 1
346: nsize: 1
347: filter: sed -e "s/CONVERGED_ATOL/CONVERGED_RTOL/g"
349: test:
350: suffix: 2
351: nsize: 1
352: args: -ksp_converged_reason_view_cancel
353: filter: sed -e "s/CONVERGED_ATOL/CONVERGED_RTOL/g"
355: test:
356: suffix: 3
357: nsize: 1
358: args: -ksp_converged_reason_view_cancel -ksp_converged_reason
359: filter: sed -e "s/CONVERGED_ATOL/CONVERGED_RTOL/g"
361: test:
362: suffix: 4
363: nsize: 1
364: args: -snes_converged_reason_view_cancel
365: filter: sed -e "s/CONVERGED_ATOL/CONVERGED_RTOL/g"
367: test:
368: suffix: 5
369: nsize: 1
370: args: -snes_converged_reason_view_cancel -snes_converged_reason
371: filter: sed -e "s/CONVERGED_ATOL/CONVERGED_RTOL/g"
373: TEST*/