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: }