Actual source code: ex2.c

  1: /*$Id: ex2.c,v 1.81 2001/03/23 23:24:25 balay Exp $*/

  3: static char help[] = "Newton method to solve u'' + u^{2} = f, sequentially.n
  4: This example employs a user-defined monitoring routine.nn";

  6: /*T
  7:    Concepts: SNES^basic uniprocessor example
  8:    Concepts: SNES^setting a user-defined monitoring routine
  9:    Processors: 1
 10: T*/

 12: /* 
 13:    Include "petscdraw.h" so that we can use PETSc drawing routines.
 14:    Include "petscsnes.h" so that we can use SNES solvers.  Note that this
 15:    file automatically includes:
 16:      petsc.h       - base PETSc routines   petscvec.h - vectors
 17:      petscsys.h    - system routines       petscmat.h - matrices
 18:      petscis.h     - index sets            petscksp.h - Krylov subspace methods
 19:      petscviewer.h - viewers               petscpc.h  - preconditioners
 20:      petscsles.h   - linear solvers
 21: */

 23: #include "petscsnes.h"

 25: /* 
 26:    User-defined routines
 27: */
 28: extern int FormJacobian(SNES,Vec,Mat*,Mat*,MatStructure*,void*);
 29: extern int FormFunction(SNES,Vec,Vec,void*);
 30: extern int FormInitialGuess(Vec);
 31: extern int Monitor(SNES,int,double,void *);

 33: /*
 34:    User-defined context for monitoring
 35: */
 36: typedef struct {
 37:    PetscViewer viewer;
 38: } MonitorCtx;

 40: int main(int argc,char **argv)
 41: {
 42:   SNES       snes;                   /* SNES context */
 43:   Vec        x,r,F,U;             /* vectors */
 44:   Mat        J;                      /* Jacobian matrix */
 45:   MonitorCtx monP;                   /* monitoring context */
 46:   int        ierr,its,n = 5,i,maxit,maxf,size;
 47:   Scalar     h,xp,v,none = -1.0;
 48:   double     atol,rtol,stol,norm;

 50:   PetscInitialize(&argc,&argv,(char *)0,help);
 51:   MPI_Comm_size(PETSC_COMM_WORLD,&size);
 52:   if (size != 1) SETERRQ(1,"This is a uniprocessor example only!");
 53:   PetscOptionsGetInt(PETSC_NULL,"-n",&n,PETSC_NULL);
 54:   h = 1.0/(n-1);

 56:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 57:      Create nonlinear solver context
 58:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 60:   SNESCreate(PETSC_COMM_WORLD,SNES_NONLINEAR_EQUATIONS,&snes);

 62:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 63:      Create vector data structures; set function evaluation routine
 64:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 65:   /*
 66:      Note that we form 1 vector from scratch and then duplicate as needed.
 67:   */
 68:   VecCreate(PETSC_COMM_WORLD,PETSC_DECIDE,n,&x);
 69:   VecSetFromOptions(x);
 70:   VecDuplicate(x,&r);
 71:   VecDuplicate(x,&F);
 72:   VecDuplicate(x,&U);

 74:   /* 
 75:      Set function evaluation routine and vector
 76:   */
 77:   SNESSetFunction(snes,r,FormFunction,(void*)F);


 80:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 81:      Create matrix data structure; set Jacobian evaluation routine
 82:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 84:   MatCreate(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,n,n,&J);
 85:   MatSetFromOptions(J);

 87:   /* 
 88:      Set Jacobian matrix data structure and default Jacobian evaluation
 89:      routine. User can override with:
 90:      -snes_fd : default finite differencing approximation of Jacobian
 91:      -snes_mf : matrix-free Newton-Krylov method with no preconditioning
 92:                 (unless user explicitly sets preconditioner) 
 93:      -snes_mf_operator : form preconditioning matrix as set by the user,
 94:                          but use matrix-free approx for Jacobian-vector
 95:                          products within Newton-Krylov method
 96:   */

 98:   SNESSetJacobian(snes,J,J,FormJacobian,PETSC_NULL);

100:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
101:      Customize nonlinear solver; set runtime options
102:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

104:   /* 
105:      Set an optional user-defined monitoring routine
106:   */
107:   PetscViewerDrawOpen(PETSC_COMM_WORLD,0,0,0,0,400,400,&monP.viewer);
108:   SNESSetMonitor(snes,Monitor,&monP,0);

110:   /*
111:      Set names for some vectors to facilitate monitoring (optional)
112:   */
113:   PetscObjectSetName((PetscObject)x,"Approximate Solution");
114:   PetscObjectSetName((PetscObject)U,"Exact Solution");

116:   /* 
117:      Set SNES/SLES/KSP/PC runtime options, e.g.,
118:          -snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc>
119:   */
120:   SNESSetFromOptions(snes);

122:   /* 
123:      Print parameters used for convergence testing (optional) ... just
124:      to demonstrate this routine; this information is also printed with
125:      the option -snes_view
126:   */
127:   SNESGetTolerances(snes,&atol,&rtol,&stol,&maxit,&maxf);
128:   PetscPrintf(PETSC_COMM_WORLD,"atol=%g, rtol=%g, stol=%g, maxit=%d, maxf=%dn",atol,rtol,stol,maxit,maxf);

130:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
131:      Initialize application:
132:      Store right-hand-side of PDE and exact solution
133:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

135:   xp = 0.0;
136:   for (i=0; i<n; i++) {
137:     v = 6.0*xp + PetscPowScalar(xp+1.e-12,6.0); /* +1.e-12 is to prevent 0^6 */
138:     VecSetValues(F,1,&i,&v,INSERT_VALUES);
139:     v= xp*xp*xp;
140:     VecSetValues(U,1,&i,&v,INSERT_VALUES);
141:     xp += h;
142:   }

144:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
145:      Evaluate initial guess; then solve nonlinear system
146:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
147:   /*
148:      Note: The user should initialize the vector, x, with the initial guess
149:      for the nonlinear solver prior to calling SNESSolve().  In particular,
150:      to employ an initial guess of zero, the user should explicitly set
151:      this vector to zero by calling VecSet().
152:   */
153:   FormInitialGuess(x);
154:   SNESSolve(snes,x,&its);
155:   PetscPrintf(PETSC_COMM_WORLD,"number of Newton iterations = %dnn",its);

157:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
158:      Check solution and clean up
159:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

161:   /* 
162:      Check the error
163:   */
164:   VecAXPY(&none,U,x);
165:   ierr  = VecNorm(x,NORM_2,&norm);
166:   PetscPrintf(PETSC_COMM_WORLD,"Norm of error %A, Iterations %dn",norm,its);


169:   /*
170:      Free work space.  All PETSc objects should be destroyed when they
171:      are no longer needed.
172:   */
173:   VecDestroy(x);  VecDestroy(r);
174:   VecDestroy(U);  VecDestroy(F);
175:   MatDestroy(J);  SNESDestroy(snes);
176:   PetscViewerDestroy(monP.viewer);
177:   PetscFinalize();

179:   return 0;
180: }
181: /* ------------------------------------------------------------------- */
182: /*
183:    FormInitialGuess - Computes initial guess.

185:    Input/Output Parameter:
186: .  x - the solution vector
187: */
188: int FormInitialGuess(Vec x)
189: {
190:    int    ierr;
191:    Scalar pfive = .50;
192:    VecSet(&pfive,x);
193:    return 0;
194: }
195: /* ------------------------------------------------------------------- */
196: /* 
197:    FormFunction - Evaluates nonlinear function, F(x).

199:    Input Parameters:
200: .  snes - the SNES context
201: .  x - input vector
202: .  ctx - optional user-defined context, as set by SNESSetFunction()

204:    Output Parameter:
205: .  f - function vector

207:    Note:
208:    The user-defined context can contain any application-specific data
209:    needed for the function evaluation (such as various parameters, work
210:    vectors, and grid information).  In this program the context is just
211:    a vector containing the right-hand-side of the discretized PDE.
212:  */

214: int FormFunction(SNES snes,Vec x,Vec f,void *ctx)
215: {
216:    Vec    g = (Vec)ctx;
217:    Scalar *xx,*ff,*gg,d;
218:    int    i,ierr,n;

220:   /*
221:      Get pointers to vector data.
222:        - For default PETSc vectors, VecGetArray() returns a pointer to
223:          the data array.  Otherwise, the routine is implementation dependent.
224:        - You MUST call VecRestoreArray() when you no longer need access to
225:          the array.
226:   */
227:    VecGetArray(x,&xx);
228:    VecGetArray(f,&ff);
229:    VecGetArray(g,&gg);

231:   /*
232:      Compute function
233:   */
234:    VecGetSize(x,&n);
235:    d = (double)(n - 1); d = d*d;
236:    ff[0]   = xx[0];
237:    for (i=1; i<n-1; i++) {
238:      ff[i] = d*(xx[i-1] - 2.0*xx[i] + xx[i+1]) + xx[i]*xx[i] - gg[i];
239:    }
240:    ff[n-1] = xx[n-1] - 1.0;

242:   /*
243:      Restore vectors
244:   */
245:   VecRestoreArray(x,&xx);
246:   VecRestoreArray(f,&ff);
247:   VecRestoreArray(g,&gg);
248:   return 0;
249: }
250: /* ------------------------------------------------------------------- */
251: /*
252:    FormJacobian - Evaluates Jacobian matrix.

254:    Input Parameters:
255: .  snes - the SNES context
256: .  x - input vector
257: .  dummy - optional user-defined context (not used here)

259:    Output Parameters:
260: .  jac - Jacobian matrix
261: .  B - optionally different preconditioning matrix
262: .  flag - flag indicating matrix structure
263: */

265: int FormJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure*flag,void *dummy)
266: {
267:   Scalar *xx,A[3],d;
268:   int    i,n,j[3],ierr;

270:   /*
271:      Get pointer to vector data
272:   */
273:   VecGetArray(x,&xx);

275:   /*
276:      Compute Jacobian entries and insert into matrix.
277:       - Note that in this case we set all elements for a particular
278:         row at once.
279:   */
280:   VecGetSize(x,&n);
281:   d = (double)(n - 1); d = d*d;

283:   /*
284:      Interior grid points
285:   */
286:   for (i=1; i<n-1; i++) {
287:     j[0] = i - 1; j[1] = i; j[2] = i + 1;
288:     A[0] = A[2] = d; A[1] = -2.0*d + 2.0*xx[i];
289:     MatSetValues(*jac,1,&i,3,j,A,INSERT_VALUES);
290:   }

292:   /*
293:      Boundary points
294:   */
295:   i = 0;   A[0] = 1.0;
296:   MatSetValues(*jac,1,&i,1,&i,A,INSERT_VALUES);
297:   i = n-1; A[0] = 1.0;
298:   MatSetValues(*jac,1,&i,1,&i,A,INSERT_VALUES);

300:   /*
301:      Restore vector
302:   */
303:   VecRestoreArray(x,&xx);

305:   /*
306:      Assemble matrix
307:   */
308:   MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);
309:   MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);

311:   return 0;
312: }
313: /* ------------------------------------------------------------------- */
314: /*
315:    Monitor - User-defined monitoring routine that views the
316:    current iterate with an x-window plot.

318:    Input Parameters:
319:    snes - the SNES context
320:    its - iteration number
321:    norm - 2-norm function value (may be estimated)
322:    ctx - optional user-defined context for private data for the 
323:          monitor routine, as set by SNESSetMonitor()

325:    Note:
326:    See the manpage for PetscViewerDrawOpen() for useful runtime options,
327:    such as -nox to deactivate all x-window output.
328:  */
329: int Monitor(SNES snes,int its,double fnorm,void *ctx)
330: {
331:   int        ierr;
332:   MonitorCtx *monP = (MonitorCtx*) ctx;
333:   Vec        x;

335:   PetscPrintf(PETSC_COMM_WORLD,"iter = %d, SNES Function norm %gn",its,fnorm);
336:   SNESGetSolution(snes,&x);
337:   VecView(x,monP->viewer);
338:   return 0;
339: }