Actual source code: ex1.c
petsc-dev 2014-02-02
2: static char help[] = "Solves the nonlinear system, the Bratu (SFI - solid fuel ignition) problem in a 2D rectangular domain.\n\
3: This example also illustrates the use of matrix coloring. Runtime options include:\n\
4: -par <parameter>, where <parameter> indicates the problem's nonlinearity\n\
5: problem SFI: <parameter> = Bratu parameter (0 <= par <= 6.81)\n\
6: -mx <xg>, where <xg> = number of grid points in the x-direction\n\
7: -my <yg>, where <yg> = number of grid points in the y-direction\n\n";
9: /*T
10: Concepts: SNES^sequential Bratu example
11: Processors: 1
12: T*/
14: /* ------------------------------------------------------------------------
16: Solid Fuel Ignition (SFI) problem. This problem is modeled by
17: the partial differential equation
19: -Laplacian u - lambda*exp(u) = 0, 0 < x,y < 1,
21: with boundary conditions
23: u = 0 for x = 0, x = 1, y = 0, y = 1.
25: A finite difference approximation with the usual 5-point stencil
26: is used to discretize the boundary value problem to obtain a nonlinear
27: system of equations.
29: The parallel version of this code is snes/examples/tutorials/ex5.c
31: ------------------------------------------------------------------------- */
33: /*
34: Include "petscsnes.h" so that we can use SNES solvers. Note that
35: this file automatically includes:
36: petscsys.h - base PETSc routines petscvec.h - vectors
37: petscmat.h - matrices
38: petscis.h - index sets petscksp.h - Krylov subspace methods
39: petscviewer.h - viewers petscpc.h - preconditioners
40: petscksp.h - linear solvers
41: */
43: #include <petscsnes.h>
45: /*
46: User-defined application context - contains data needed by the
47: application-provided call-back routines, FormJacobian() and
48: FormFunction().
49: */
50: typedef struct {
51: PetscReal param; /* test problem parameter */
52: PetscInt mx; /* Discretization in x-direction */
53: PetscInt my; /* Discretization in y-direction */
54: } AppCtx;
56: /*
57: User-defined routines
58: */
59: extern PetscErrorCode FormJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*);
60: extern PetscErrorCode FormFunction(SNES,Vec,Vec,void*);
61: extern PetscErrorCode FormInitialGuess(AppCtx*,Vec);
65: int main(int argc,char **argv)
66: {
67: SNES snes; /* nonlinear solver context */
68: Vec x,r; /* solution, residual vectors */
69: Mat J; /* Jacobian matrix */
70: AppCtx user; /* user-defined application context */
72: PetscInt i,its,N,hist_its[50];
73: PetscMPIInt size;
74: PetscReal bratu_lambda_max = 6.81,bratu_lambda_min = 0.,history[50];
75: MatFDColoring fdcoloring;
76: PetscBool matrix_free = PETSC_FALSE,flg,fd_coloring = PETSC_FALSE;
78: PetscInitialize(&argc,&argv,(char*)0,help);
79: MPI_Comm_size(PETSC_COMM_WORLD,&size);
80: if (size != 1) SETERRQ(PETSC_COMM_SELF,1,"This is a uniprocessor example only!");
82: /*
83: Initialize problem parameters
84: */
85: user.mx = 4; user.my = 4; user.param = 6.0;
86: PetscOptionsGetInt(NULL,"-mx",&user.mx,NULL);
87: PetscOptionsGetInt(NULL,"-my",&user.my,NULL);
88: PetscOptionsGetReal(NULL,"-par",&user.param,NULL);
89: if (user.param >= bratu_lambda_max || user.param <= bratu_lambda_min) SETERRQ(PETSC_COMM_SELF,1,"Lambda is out of range");
90: N = user.mx*user.my;
92: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
93: Create nonlinear solver context
94: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
96: SNESCreate(PETSC_COMM_WORLD,&snes);
98: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
99: Create vector data structures; set function evaluation routine
100: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
102: VecCreate(PETSC_COMM_WORLD,&x);
103: VecSetSizes(x,PETSC_DECIDE,N);
104: VecSetFromOptions(x);
105: VecDuplicate(x,&r);
107: /*
108: Set function evaluation routine and vector. Whenever the nonlinear
109: solver needs to evaluate the nonlinear function, it will call this
110: routine.
111: - Note that the final routine argument is the user-defined
112: context that provides application-specific data for the
113: function evaluation routine.
114: */
115: SNESSetFunction(snes,r,FormFunction,(void*)&user);
117: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
118: Create matrix data structure; set Jacobian evaluation routine
119: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
121: /*
122: Create matrix. Here we only approximately preallocate storage space
123: for the Jacobian. See the users manual for a discussion of better
124: techniques for preallocating matrix memory.
125: */
126: PetscOptionsGetBool(NULL,"-snes_mf",&matrix_free,NULL);
127: if (!matrix_free) {
128: PetscBool matrix_free_operator = PETSC_FALSE;
129: PetscOptionsGetBool(NULL,"-snes_mf_operator",&matrix_free_operator,NULL);
130: if (matrix_free_operator) matrix_free = PETSC_FALSE;
131: }
132: if (!matrix_free) {
133: MatCreateSeqAIJ(PETSC_COMM_WORLD,N,N,5,NULL,&J);
134: }
136: /*
137: This option will cause the Jacobian to be computed via finite differences
138: efficiently using a coloring of the columns of the matrix.
139: */
140: PetscOptionsGetBool(NULL,"-snes_fd_coloring",&fd_coloring,NULL);
141: if (matrix_free && fd_coloring) SETERRQ(PETSC_COMM_SELF,1,"Use only one of -snes_mf, -snes_fd_coloring options!\nYou can do -snes_mf_operator -snes_fd_coloring");
143: if (fd_coloring) {
144: ISColoring iscoloring;
145: MatColoring mc;
146: MatStructure str;
148: /*
149: This initializes the nonzero structure of the Jacobian. This is artificial
150: because clearly if we had a routine to compute the Jacobian we won't need
151: to use finite differences.
152: */
153: FormJacobian(snes,x,&J,&J,&str,&user);
155: /*
156: Color the matrix, i.e. determine groups of columns that share no common
157: rows. These columns in the Jacobian can all be computed simulataneously.
158: */
159: MatColoringCreate(J,&mc);
160: MatColoringSetType(mc,MATCOLORINGSL);
161: MatColoringSetFromOptions(mc);
162: MatColoringApply(mc,&iscoloring);
163: MatColoringDestroy(&mc);
164: /*
165: Create the data structure that SNESComputeJacobianDefaultColor() uses
166: to compute the actual Jacobians via finite differences.
167: */
168: MatFDColoringCreate(J,iscoloring,&fdcoloring);
169: MatFDColoringSetFunction(fdcoloring,(PetscErrorCode (*)(void))FormFunction,&user);
170: MatFDColoringSetFromOptions(fdcoloring);
171: MatFDColoringSetUp(J,iscoloring,fdcoloring);
172: /*
173: Tell SNES to use the routine SNESComputeJacobianDefaultColor()
174: to compute Jacobians.
175: */
176: SNESSetJacobian(snes,J,J,SNESComputeJacobianDefaultColor,fdcoloring);
177: ISColoringDestroy(&iscoloring);
178: }
179: /*
180: Set Jacobian matrix data structure and default Jacobian evaluation
181: routine. Whenever the nonlinear solver needs to compute the
182: Jacobian matrix, it will call this routine.
183: - Note that the final routine argument is the user-defined
184: context that provides application-specific data for the
185: Jacobian evaluation routine.
186: - The user can override with:
187: -snes_fd : default finite differencing approximation of Jacobian
188: -snes_mf : matrix-free Newton-Krylov method with no preconditioning
189: (unless user explicitly sets preconditioner)
190: -snes_mf_operator : form preconditioning matrix as set by the user,
191: but use matrix-free approx for Jacobian-vector
192: products within Newton-Krylov method
193: */
194: else if (!matrix_free) {
195: SNESSetJacobian(snes,J,J,FormJacobian,(void*)&user);
196: }
198: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
199: Customize nonlinear solver; set runtime options
200: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
202: /*
203: Set runtime options (e.g., -snes_monitor -snes_rtol <rtol> -ksp_type <type>)
204: */
205: SNESSetFromOptions(snes);
207: /*
208: Set array that saves the function norms. This array is intended
209: when the user wants to save the convergence history for later use
210: rather than just to view the function norms via -snes_monitor.
211: */
212: SNESSetConvergenceHistory(snes,history,hist_its,50,PETSC_TRUE);
214: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
215: Evaluate initial guess; then solve nonlinear system
216: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
217: /*
218: Note: The user should initialize the vector, x, with the initial guess
219: for the nonlinear solver prior to calling SNESSolve(). In particular,
220: to employ an initial guess of zero, the user should explicitly set
221: this vector to zero by calling VecSet().
222: */
223: FormInitialGuess(&user,x);
224: SNESSolve(snes,NULL,x);
225: SNESGetIterationNumber(snes,&its);
226: PetscPrintf(PETSC_COMM_WORLD,"Number of SNES iterations = %D\n",its);
229: /*
230: Print the convergence history. This is intended just to demonstrate
231: use of the data attained via SNESSetConvergenceHistory().
232: */
233: PetscOptionsHasName(NULL,"-print_history",&flg);
234: if (flg) {
235: for (i=0; i<its+1; i++) {
236: PetscPrintf(PETSC_COMM_WORLD,"iteration %D: Linear iterations %D Function norm = %g\n",i,hist_its[i],(double)history[i]);
237: }
238: }
240: /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
241: Free work space. All PETSc objects should be destroyed when they
242: are no longer needed.
243: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
245: if (!matrix_free) {
246: MatDestroy(&J);
247: }
248: if (fd_coloring) {
249: MatFDColoringDestroy(&fdcoloring);
250: }
251: VecDestroy(&x);
252: VecDestroy(&r);
253: SNESDestroy(&snes);
254: PetscFinalize();
256: return 0;
257: }
258: /* ------------------------------------------------------------------- */
261: /*
262: FormInitialGuess - Forms initial approximation.
264: Input Parameters:
265: user - user-defined application context
266: X - vector
268: Output Parameter:
269: X - vector
270: */
271: PetscErrorCode FormInitialGuess(AppCtx *user,Vec X)
272: {
273: PetscInt i,j,row,mx,my;
275: PetscReal lambda,temp1,temp,hx,hy;
276: PetscScalar *x;
278: mx = user->mx;
279: my = user->my;
280: lambda = user->param;
282: hx = 1.0 / (PetscReal)(mx-1);
283: hy = 1.0 / (PetscReal)(my-1);
285: /*
286: Get a pointer to vector data.
287: - For default PETSc vectors, VecGetArray() returns a pointer to
288: the data array. Otherwise, the routine is implementation dependent.
289: - You MUST call VecRestoreArray() when you no longer need access to
290: the array.
291: */
292: VecGetArray(X,&x);
293: temp1 = lambda/(lambda + 1.0);
294: for (j=0; j<my; j++) {
295: temp = (PetscReal)(PetscMin(j,my-j-1))*hy;
296: for (i=0; i<mx; i++) {
297: row = i + j*mx;
298: if (i == 0 || j == 0 || i == mx-1 || j == my-1) {
299: x[row] = 0.0;
300: continue;
301: }
302: x[row] = temp1*PetscSqrtReal(PetscMin((PetscReal)(PetscMin(i,mx-i-1))*hx,temp));
303: }
304: }
306: /*
307: Restore vector
308: */
309: VecRestoreArray(X,&x);
310: return 0;
311: }
312: /* ------------------------------------------------------------------- */
315: /*
316: FormFunction - Evaluates nonlinear function, F(x).
318: Input Parameters:
319: . snes - the SNES context
320: . X - input vector
321: . ptr - optional user-defined context, as set by SNESSetFunction()
323: Output Parameter:
324: . F - function vector
325: */
326: PetscErrorCode FormFunction(SNES snes,Vec X,Vec F,void *ptr)
327: {
328: AppCtx *user = (AppCtx*)ptr;
329: PetscInt i,j,row,mx,my;
331: PetscReal two = 2.0,one = 1.0,lambda,hx,hy,hxdhy,hydhx;
332: PetscScalar ut,ub,ul,ur,u,uxx,uyy,sc,*x,*f;
334: mx = user->mx;
335: my = user->my;
336: lambda = user->param;
337: hx = one / (PetscReal)(mx-1);
338: hy = one / (PetscReal)(my-1);
339: sc = hx*hy;
340: hxdhy = hx/hy;
341: hydhx = hy/hx;
343: /*
344: Get pointers to vector data
345: */
346: VecGetArray(X,&x);
347: VecGetArray(F,&f);
349: /*
350: Compute function
351: */
352: for (j=0; j<my; j++) {
353: for (i=0; i<mx; i++) {
354: row = i + j*mx;
355: if (i == 0 || j == 0 || i == mx-1 || j == my-1) {
356: f[row] = x[row];
357: continue;
358: }
359: u = x[row];
360: ub = x[row - mx];
361: ul = x[row - 1];
362: ut = x[row + mx];
363: ur = x[row + 1];
364: uxx = (-ur + two*u - ul)*hydhx;
365: uyy = (-ut + two*u - ub)*hxdhy;
366: f[row] = uxx + uyy - sc*lambda*PetscExpScalar(u);
367: }
368: }
370: /*
371: Restore vectors
372: */
373: VecRestoreArray(X,&x);
374: VecRestoreArray(F,&f);
375: return 0;
376: }
377: /* ------------------------------------------------------------------- */
380: /*
381: FormJacobian - Evaluates Jacobian matrix.
383: Input Parameters:
384: . snes - the SNES context
385: . x - input vector
386: . ptr - optional user-defined context, as set by SNESSetJacobian()
388: Output Parameters:
389: . A - Jacobian matrix
390: . B - optionally different preconditioning matrix
391: . flag - flag indicating matrix structure
392: */
393: PetscErrorCode FormJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flag,void *ptr)
394: {
395: AppCtx *user = (AppCtx*)ptr; /* user-defined applicatin context */
396: Mat jac = *B; /* Jacobian matrix */
397: PetscInt i,j,row,mx,my,col[5];
399: PetscScalar two = 2.0,one = 1.0,lambda,v[5],sc,*x;
400: PetscReal hx,hy,hxdhy,hydhx;
402: mx = user->mx;
403: my = user->my;
404: lambda = user->param;
405: hx = 1.0 / (PetscReal)(mx-1);
406: hy = 1.0 / (PetscReal)(my-1);
407: sc = hx*hy;
408: hxdhy = hx/hy;
409: hydhx = hy/hx;
411: /*
412: Get pointer to vector data
413: */
414: VecGetArray(X,&x);
416: /*
417: Compute entries of the Jacobian
418: */
419: for (j=0; j<my; j++) {
420: for (i=0; i<mx; i++) {
421: row = i + j*mx;
422: if (i == 0 || j == 0 || i == mx-1 || j == my-1) {
423: MatSetValues(jac,1,&row,1,&row,&one,INSERT_VALUES);
424: continue;
425: }
426: v[0] = -hxdhy; col[0] = row - mx;
427: v[1] = -hydhx; col[1] = row - 1;
428: v[2] = two*(hydhx + hxdhy) - sc*lambda*PetscExpScalar(x[row]); col[2] = row;
429: v[3] = -hydhx; col[3] = row + 1;
430: v[4] = -hxdhy; col[4] = row + mx;
431: MatSetValues(jac,1,&row,5,col,v,INSERT_VALUES);
432: }
433: }
435: /*
436: Restore vector
437: */
438: VecRestoreArray(X,&x);
440: /*
441: Assemble matrix
442: */
443: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
444: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
446: if (jac != *J) {
447: MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);
448: MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);
449: }
451: /*
452: Set flag to indicate that the Jacobian matrix retains an identical
453: nonzero structure throughout all nonlinear iterations (although the
454: values of the entries change). Thus, we can save some work in setting
455: up the preconditioner (e.g., no need to redo symbolic factorization for
456: ILU/ICC preconditioners).
457: - If the nonzero structure of the matrix is different during
458: successive linear solves, then the flag DIFFERENT_NONZERO_PATTERN
459: must be used instead. If you are unsure whether the matrix
460: structure has changed or not, use the flag DIFFERENT_NONZERO_PATTERN.
461: - Caution: If you specify SAME_NONZERO_PATTERN, PETSc
462: believes your assertion and does not check the structure
463: of the matrix. If you erroneously claim that the structure
464: is the same when it actually is not, the new preconditioner
465: will not function correctly. Thus, use this optimization
466: feature with caution!
467: */
468: *flag = SAME_NONZERO_PATTERN;
469: return 0;
470: }