Actual source code: ex7.c
1: /*$Id: ex7.c,v 1.59 2001/08/07 21:31:12 bsmith Exp $*/
3: static char help[] = "Solves u`` + u^{2} = f with Newton-like methods. Usingn
4: matrix-free techniques with user-provided explicit preconditioner matrix.nn";
6: #include petscsnes.h
8: extern int FormJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*);
9: extern int FormFunction(SNES,Vec,Vec,void*);
10: extern int FormInitialGuess(SNES,Vec);
11: extern int Monitor(SNES,int,PetscReal,void *);
13: typedef struct {
14: PetscViewer viewer;
15: } MonitorCtx;
17: typedef struct {
18: Mat precond;
19: PetscTruth variant;
20: } AppCtx;
22: int main(int argc,char **argv)
23: {
24: SNES snes; /* SNES context */
25: SNESType type = SNESLS; /* default nonlinear solution method */
26: Vec x,r,F,U,work; /* vectors */
27: Mat J,B; /* Jacobian matrix-free, explicit preconditioner */
28: MonitorCtx monP; /* monitoring context */
29: AppCtx user; /* user-defined work context */
30: PetscScalar h,xp = 0.0,v;
31: int ierr,its,n = 5,i;
33: PetscInitialize(&argc,&argv,(char *)0,help);
34: PetscOptionsGetInt(PETSC_NULL,"-n",&n,PETSC_NULL);
35: PetscOptionsHasName(PETSC_NULL,"-variant",&user.variant);
36: h = 1.0/(n-1);
38: /* Set up data structures */
39: PetscViewerDrawOpen(PETSC_COMM_SELF,0,0,0,0,400,400,&monP.viewer);
40: VecCreateSeq(PETSC_COMM_SELF,n,&x);
41: PetscObjectSetName((PetscObject)x,"Approximate Solution");
42: VecDuplicate(x,&r);
43: VecDuplicate(x,&F);
44: VecDuplicate(x,&U);
45: PetscObjectSetName((PetscObject)U,"Exact Solution");
47: /* create explict matrix preconditioner */
48: MatCreateSeqAIJ(PETSC_COMM_SELF,n,n,3,PETSC_NULL,&B);
49: user.precond = B;
51: /* Store right-hand-side of PDE and exact solution */
52: for (i=0; i<n; i++) {
53: v = 6.0*xp + PetscPowScalar(xp+1.e-12,6.0); /* +1.e-12 is to prevent 0^6 */
54: VecSetValues(F,1,&i,&v,INSERT_VALUES);
55: v= xp*xp*xp;
56: VecSetValues(U,1,&i,&v,INSERT_VALUES);
57: xp += h;
58: }
60: /* Create nonlinear solver */
61: SNESCreate(PETSC_COMM_WORLD,&snes);
62: SNESSetType(snes,type);
64: if (user.variant) {
65: MatCreateMF(x,&J);
66: VecDuplicate(x,&work);
67: MatSNESMFSetFunction(J,work,FormFunction,F);
68: } else {
69: /* create matrix free matrix for Jacobian */
70: MatCreateSNESMF(snes,x,&J);
71: }
73: /* Set various routines and options */
74: SNESSetFunction(snes,r,FormFunction,F);
75: SNESSetJacobian(snes,J,B,FormJacobian,&user);
76: SNESSetMonitor(snes,Monitor,&monP,0);
77: SNESSetFromOptions(snes);
79: /* Solve nonlinear system */
80: FormInitialGuess(snes,x);
81: SNESSolve(snes,x,&its);
82: PetscPrintf(PETSC_COMM_SELF,"number of Newton iterations = %dnn",its);
84: /* Free data structures */
85: if (user.variant) {
86: VecDestroy(work);
87: }
88: VecDestroy(x); VecDestroy(r);
89: VecDestroy(U); VecDestroy(F);
90: MatDestroy(J); MatDestroy(B);
91: SNESDestroy(snes);
92: PetscViewerDestroy(monP.viewer);
93: PetscFinalize();
95: return 0;
96: }
97: /* -------------------- Evaluate Function F(x) --------------------- */
99: int FormFunction(SNES snes,Vec x,Vec f,void *dummy)
100: {
101: PetscScalar *xx,*ff,*FF,d;
102: int i,ierr,n;
104: VecGetArray(x,&xx);
105: VecGetArray(f,&ff);
106: VecGetArray((Vec) dummy,&FF);
107: VecGetSize(x,&n);
108: d = (PetscReal)(n - 1); d = d*d;
109: ff[0] = xx[0];
110: for (i=1; i<n-1; i++) {
111: ff[i] = d*(xx[i-1] - 2.0*xx[i] + xx[i+1]) + xx[i]*xx[i] - FF[i];
112: }
113: ff[n-1] = xx[n-1] - 1.0;
114: VecRestoreArray(x,&xx);
115: VecRestoreArray(f,&ff);
116: VecRestoreArray((Vec)dummy,&FF);
117: return 0;
118: }
119: /* -------------------- Form initial approximation ----------------- */
121: int FormInitialGuess(SNES snes,Vec x)
122: {
123: int ierr;
124: PetscScalar pfive = .50;
125: VecSet(&pfive,x);
126: return 0;
127: }
128: /* -------------------- Evaluate Jacobian F'(x) -------------------- */
129: /* Evaluates a matrix that is used to precondition the matrix-free
130: jacobian. In this case, the explict preconditioner matrix is
131: also EXACTLY the Jacobian. In general, it would be some lower
132: order, simplified apprioximation */
134: int FormJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure*flag,void *dummy)
135: {
136: PetscScalar *xx,A[3],d;
137: int i,n,j[3],ierr,iter;
138: AppCtx *user = (AppCtx*) dummy;
140: SNESGetIterationNumber(snes,&iter);
142: if (iter%2 ==0) { /* Compute new preconditioner matrix */
143: printf("iter=%d, computing new preconditioning matrixn",iter+1);
144: *B = user->precond;
145: VecGetArray(x,&xx);
146: VecGetSize(x,&n);
147: d = (PetscReal)(n - 1); d = d*d;
149: i = 0; A[0] = 1.0;
150: MatSetValues(*B,1,&i,1,&i,&A[0],INSERT_VALUES);
151: for (i=1; i<n-1; i++) {
152: j[0] = i - 1; j[1] = i; j[2] = i + 1;
153: A[0] = d; A[1] = -2.0*d + 2.0*xx[i]; A[2] = d;
154: MatSetValues(*B,1,&i,3,j,A,INSERT_VALUES);
155: }
156: i = n-1; A[0] = 1.0;
157: MatSetValues(*B,1,&i,1,&i,&A[0],INSERT_VALUES);
158: MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);
159: MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);
160: VecRestoreArray(x,&xx);
161: *flag = SAME_NONZERO_PATTERN;
162: } else { /* reuse preconditioner from last iteration */
163: printf("iter=%d, using old preconditioning matrixn",iter+1);
164: *flag = SAME_PRECONDITIONER;
165: }
166: if (user->variant) {
167: MatSNESMFSetBase(*jac,x);
168: }
169: MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
170: MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);
171: return 0;
172: }
173: /* -------------------- User-defined monitor ----------------------- */
175: int Monitor(SNES snes,int its,PetscReal fnorm,void *dummy)
176: {
177: int ierr;
178: MonitorCtx *monP = (MonitorCtx*) dummy;
179: Vec x;
180: MPI_Comm comm;
182: PetscObjectGetComm((PetscObject)snes,&comm);
183: PetscFPrintf(comm,stdout,"iter = %d, SNES Function norm %g n",its,fnorm);
184: SNESGetSolution(snes,&x);
185: VecView(x,monP->viewer);
186: return 0;
187: }