Actual source code: eptorsion1.c

petsc-dev 2014-02-02
Report Typos and Errors
  1: /* Program usage: mpirun -np 1 eptorsion1 [-help] [all TAO options] */

  3: /* ----------------------------------------------------------------------

  5:   Elastic-plastic torsion problem.

  7:   The elastic plastic torsion problem arises from the determination
  8:   of the stress field on an infinitely long cylindrical bar, which is
  9:   equivalent to the solution of the following problem:

 11:   min{ .5 * integral(||gradient(v(x))||^2 dx) - C * integral(v(x) dx)}

 13:   where C is the torsion angle per unit length.

 15:   The multiprocessor version of this code is eptorsion2.c.

 17: ---------------------------------------------------------------------- */

 19: /*
 20:   Include "petsctao.h" so that we can use TAO solvers.  Note that this
 21:   file automatically includes files for lower-level support, such as those
 22:   provided by the PETSc library:
 23:      petsc.h       - base PETSc routines   petscvec.h - vectors
 24:      petscsys.h    - sysem routines        petscmat.h - matrices
 25:      petscis.h     - index sets            petscksp.h - Krylov subspace methods
 26:      petscviewer.h - viewers               petscpc.h  - preconditioners
 27: */

 29: #include <petsctao.h>


 32: static  char help[]=
 33: "Demonstrates use of the TAO package to solve \n\
 34: unconstrained minimization problems on a single processor.  This example \n\
 35: is based on the Elastic-Plastic Torsion (dept) problem from the MINPACK-2 \n\
 36: test suite.\n\
 37: The command line options are:\n\
 38:   -mx <xg>, where <xg> = number of grid points in the 1st coordinate direction\n\
 39:   -my <yg>, where <yg> = number of grid points in the 2nd coordinate direction\n\
 40:   -par <param>, where <param> = angle of twist per unit length\n\n";

 42: /*T
 43:    Concepts: TAO^Solving an unconstrained minimization problem
 44:    Routines: TaoCreate(); TaoSetType();
 45:    Routines: TaoSetInitialVector();
 46:    Routines: TaoSetObjectiveAndGradientRoutine();
 47:    Routines: TaoSetHessianRoutine(); TaoSetFromOptions();
 48:    Routines: TaoGetKSP(); TaoSolve();
 49:    Routines: TaoGetTerminationReason(); TaoDestroy();
 50:    Processors: 1
 51: T*/

 53: /*
 54:    User-defined application context - contains data needed by the
 55:    application-provided call-back routines, FormFunction(),
 56:    FormGradient(), and FormHessian().
 57: */

 59: typedef struct {
 60:    PetscReal  param;      /* nonlinearity parameter */
 61:    PetscInt   mx, my;     /* discretization in x- and y-directions */
 62:    PetscInt   ndim;       /* problem dimension */
 63:    Vec        s, y, xvec; /* work space for computing Hessian */
 64:    PetscReal  hx, hy;     /* mesh spacing in x- and y-directions */
 65: } AppCtx;

 67: /* -------- User-defined Routines --------- */

 69: PetscErrorCode FormInitialGuess(AppCtx*,Vec);
 70: PetscErrorCode FormFunction(Tao,Vec,PetscReal*,void*);
 71: PetscErrorCode FormGradient(Tao,Vec,Vec,void*);
 72: PetscErrorCode FormHessian(Tao,Vec,Mat*,Mat*, MatStructure *,void*);
 73: PetscErrorCode HessianProductMat(Mat,Vec,Vec);
 74: PetscErrorCode HessianProduct(void*,Vec,Vec);
 75: PetscErrorCode MatrixFreeHessian(Tao,Vec,Mat*,Mat*,MatStructure*,void*);
 76: PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal *,Vec,void *);

 80: PetscErrorCode main(int argc,char **argv)
 81: {
 82:   PetscErrorCode       ierr;                /* used to check for functions returning nonzeros */
 83:   PetscInt             mx=10;               /* discretization in x-direction */
 84:   PetscInt             my=10;               /* discretization in y-direction */
 85:   Vec                  x;                   /* solution, gradient vectors */
 86:   PetscBool            flg;                 /* A return value when checking for use options */
 87:   Tao                  tao;                 /* Tao solver context */
 88:   Mat                  H;                   /* Hessian matrix */
 89:   TaoTerminationReason reason;
 90:   KSP                  ksp;                 /* PETSc Krylov subspace solver */
 91:   AppCtx               user;                /* application context */
 92:   PetscMPIInt          size;                /* number of processes */
 93:   PetscReal            one=1.0;

 95:   /* Initialize TAO,PETSc */
 96:   PetscInitialize(&argc,&argv,(char *)0,help);

 98:   MPI_Comm_size(MPI_COMM_WORLD,&size);
 99:   if (size >1) SETERRQ(PETSC_COMM_SELF,1,"Incorrect number of processors");

101:   /* Specify default parameters for the problem, check for command-line overrides */
102:   user.param = 5.0;
103:   PetscOptionsGetInt(NULL,"-my",&my,&flg);
104:   PetscOptionsGetInt(NULL,"-mx",&mx,&flg);
105:   PetscOptionsGetReal(NULL,"-par",&user.param,&flg);

107:   PetscPrintf(PETSC_COMM_SELF,"\n---- Elastic-Plastic Torsion Problem -----\n");
108:   PetscPrintf(PETSC_COMM_SELF,"mx: %D     my: %D   \n\n",mx,my);
109:   user.ndim = mx * my; user.mx = mx; user.my = my;
110:   user.hx = one/(mx+1); user.hy = one/(my+1);

112:   /* Allocate vectors */
113:   VecCreateSeq(PETSC_COMM_SELF,user.ndim,&user.y);
114:   VecDuplicate(user.y,&user.s);
115:   VecDuplicate(user.y,&x);

117:   /* Create TAO solver and set desired solution method */
118:   TaoCreate(PETSC_COMM_SELF,&tao);
119:   TaoSetType(tao,"tao_lmvm");

121:   /* Set solution vector with an initial guess */
122:   FormInitialGuess(&user,x);
123:   TaoSetInitialVector(tao,x);

125:   /* Set routine for function and gradient evaluation */
126:   TaoSetObjectiveAndGradientRoutine(tao,FormFunctionGradient,(void *)&user);

128:   /* From command line options, determine if using matrix-free hessian */
129:   PetscOptionsHasName(NULL,"-my_tao_mf",&flg);
130:   if (flg) {
131:     MatCreateShell(PETSC_COMM_SELF,user.ndim,user.ndim,user.ndim,user.ndim,(void*)&user,&H);
132:     MatShellSetOperation(H,MATOP_MULT,(void(*)(void))HessianProductMat);
133:     MatSetOption(H,MAT_SYMMETRIC,PETSC_TRUE);

135:     TaoSetHessianRoutine(tao,H,H,MatrixFreeHessian,(void *)&user);

137:     /* Set null preconditioner.  Alternatively, set user-provided
138:        preconditioner or explicitly form preconditioning matrix */
139:     PetscOptionsSetValue("-pc_type","none");
140:   } else {
141:     MatCreateSeqAIJ(PETSC_COMM_SELF,user.ndim,user.ndim,5,NULL,&H);
142:     MatSetOption(H,MAT_SYMMETRIC,PETSC_TRUE);
143:     TaoSetHessianRoutine(tao,H,H,FormHessian,(void *)&user);
144:   }

146:   PetscOptionsSetValue("-ksp_type","cg");

148:   /* Check for any TAO command line options */
149:   TaoSetFromOptions(tao);

151:   /* SOLVE THE APPLICATION */
152:   TaoSolve(tao);
153:   TaoGetKSP(tao,&ksp);
154:   if (ksp) {
155:     KSPView(ksp,PETSC_VIEWER_STDOUT_SELF);
156:   }

158:   /*
159:      To View TAO solver information use
160:       TaoView(tao);
161:   */

163:   /* Get information on termination */
164:   TaoGetTerminationReason(tao,&reason);
165:   if (reason <= 0){
166:     PetscPrintf(PETSC_COMM_WORLD,"Try a different TAO method, adjust some parameters, or check the function evaluation routines\n");
167:   }

169:   TaoDestroy(&tao);
170:   VecDestroy(&user.s);
171:   VecDestroy(&user.y);
172:   VecDestroy(&x);
173:   MatDestroy(&H);

175:   PetscFinalize();
176:   return 0;
177: }

179: /* ------------------------------------------------------------------- */
182: /*
183:     FormInitialGuess - Computes an initial approximation to the solution.

185:     Input Parameters:
186: .   user - user-defined application context
187: .   X    - vector

189:     Output Parameters:
190: .   X    - vector
191: */
192: PetscErrorCode FormInitialGuess(AppCtx *user,Vec X)
193: {
194:   PetscReal      hx = user->hx, hy = user->hy, temp;
195:   PetscReal      val;
197:   PetscInt       i, j, k, nx = user->mx, ny = user->my;

199:   /* Compute initial guess */
200:   for (j=0; j<ny; j++) {
201:     temp = PetscMin(j+1,ny-j)*hy;
202:     for (i=0; i<nx; i++) {
203:       k   = nx*j + i;
204:       val = PetscMin((PetscMin(i+1,nx-i))*hx,temp);
205:       VecSetValues(X,1,&k,&val,ADD_VALUES);
206:     }
207:   }
208:   VecAssemblyBegin(X);
209:   VecAssemblyEnd(X);
210:   return 0;
211: }

213: /* ------------------------------------------------------------------- */
216: /*
217:    FormFunctionGradient - Evaluates the function and corresponding gradient.

219:    Input Parameters:
220:    tao - the Tao context
221:    X   - the input vector
222:    ptr - optional user-defined context, as set by TaoSetFunction()

224:    Output Parameters:
225:    f   - the newly evaluated function
226:    G   - the newly evaluated gradient
227: */
228: PetscErrorCode FormFunctionGradient(Tao tao,Vec X,PetscReal *f,Vec G,void *ptr)
229: {

232:   FormFunction(tao,X,f,ptr);
233:   FormGradient(tao,X,G,ptr);
234:   return 0;
235: }

237: /* ------------------------------------------------------------------- */
240: /*
241:    FormFunction - Evaluates the function, f(X).

243:    Input Parameters:
244: .  tao - the Tao context
245: .  X   - the input vector
246: .  ptr - optional user-defined context, as set by TaoSetFunction()

248:    Output Parameters:
249: .  f    - the newly evaluated function
250: */
251: PetscErrorCode FormFunction(Tao tao,Vec X,PetscReal *f,void *ptr)
252: {
253:   AppCtx         *user = (AppCtx *) ptr;
254:   PetscReal      hx = user->hx, hy = user->hy, area, three = 3.0, p5 = 0.5;
255:   PetscReal      zero = 0.0, vb, vl, vr, vt, dvdx, dvdy, flin = 0.0, fquad = 0.0;
256:   PetscReal      v, cdiv3 = user->param/three;
257:   PetscReal      *x;
259:   PetscInt       nx = user->mx, ny = user->my, i, j, k;

261:   /* Get pointer to vector data */
262:   VecGetArray(X,&x);

264:   /* Compute function contributions over the lower triangular elements */
265:   for (j=-1; j<ny; j++) {
266:     for (i=-1; i<nx; i++) {
267:       k = nx*j + i;
268:       v = zero;
269:       vr = zero;
270:       vt = zero;
271:       if (i >= 0 && j >= 0) v = x[k];
272:       if (i < nx-1 && j > -1) vr = x[k+1];
273:       if (i > -1 && j < ny-1) vt = x[k+nx];
274:       dvdx = (vr-v)/hx;
275:       dvdy = (vt-v)/hy;
276:       fquad += dvdx*dvdx + dvdy*dvdy;
277:       flin -= cdiv3*(v+vr+vt);
278:     }
279:   }

281:   /* Compute function contributions over the upper triangular elements */
282:   for (j=0; j<=ny; j++) {
283:     for (i=0; i<=nx; i++) {
284:       k = nx*j + i;
285:       vb = zero;
286:       vl = zero;
287:       v = zero;
288:       if (i < nx && j > 0) vb = x[k-nx];
289:       if (i > 0 && j < ny) vl = x[k-1];
290:       if (i < nx && j < ny) v = x[k];
291:       dvdx = (v-vl)/hx;
292:       dvdy = (v-vb)/hy;
293:       fquad = fquad + dvdx*dvdx + dvdy*dvdy;
294:       flin = flin - cdiv3*(vb+vl+v);
295:     }
296:   }

298:   /* Restore vector */
299:   VecRestoreArray(X,&x);

301:   /* Scale the function */
302:   area = p5*hx*hy;
303:   *f = area*(p5*fquad+flin);

305:   PetscLogFlops(nx*ny*24);
306:   return 0;
307: }

309: /* ------------------------------------------------------------------- */
312: /*
313:     FormGradient - Evaluates the gradient, G(X).

315:     Input Parameters:
316: .   tao  - the Tao context
317: .   X    - input vector
318: .   ptr  - optional user-defined context

320:     Output Parameters:
321: .   G - vector containing the newly evaluated gradient
322: */
323: PetscErrorCode FormGradient(Tao tao,Vec X,Vec G,void *ptr)
324: {
325:   AppCtx         *user = (AppCtx *) ptr;
326:   PetscReal      zero=0.0, p5=0.5, three = 3.0, area, val, *x;
328:   PetscInt       nx = user->mx, ny = user->my, ind, i, j, k;
329:   PetscReal      hx = user->hx, hy = user->hy;
330:   PetscReal      vb, vl, vr, vt, dvdx, dvdy;
331:   PetscReal      v, cdiv3 = user->param/three;

333:   /* Initialize gradient to zero */
334:   VecSet(G, zero);

336:   /* Get pointer to vector data */
337:   VecGetArray(X,&x);

339:   /* Compute gradient contributions over the lower triangular elements */
340:   for (j=-1; j<ny; j++) {
341:     for (i=-1; i<nx; i++) {
342:       k  = nx*j + i;
343:       v  = zero;
344:       vr = zero;
345:       vt = zero;
346:       if (i >= 0 && j >= 0)    v = x[k];
347:       if (i < nx-1 && j > -1) vr = x[k+1];
348:       if (i > -1 && j < ny-1) vt = x[k+nx];
349:       dvdx = (vr-v)/hx;
350:       dvdy = (vt-v)/hy;
351:       if (i != -1 && j != -1) {
352:         ind = k; val = - dvdx/hx - dvdy/hy - cdiv3;
353:         VecSetValues(G,1,&ind,&val,ADD_VALUES);
354:       }
355:       if (i != nx-1 && j != -1) {
356:         ind = k+1; val =  dvdx/hx - cdiv3;
357:         VecSetValues(G,1,&ind,&val,ADD_VALUES);
358:       }
359:       if (i != -1 && j != ny-1) {
360:         ind = k+nx; val = dvdy/hy - cdiv3;
361:         VecSetValues(G,1,&ind,&val,ADD_VALUES);
362:       }
363:     }
364:   }

366:   /* Compute gradient contributions over the upper triangular elements */
367:   for (j=0; j<=ny; j++) {
368:     for (i=0; i<=nx; i++) {
369:       k = nx*j + i;
370:       vb = zero;
371:       vl = zero;
372:       v  = zero;
373:       if (i < nx && j > 0) vb = x[k-nx];
374:       if (i > 0 && j < ny) vl = x[k-1];
375:       if (i < nx && j < ny) v = x[k];
376:       dvdx = (v-vl)/hx;
377:       dvdy = (v-vb)/hy;
378:       if (i != nx && j != 0) {
379:         ind = k-nx; val = - dvdy/hy - cdiv3;
380:         VecSetValues(G,1,&ind,&val,ADD_VALUES);
381:       }
382:       if (i != 0 && j != ny) {
383:         ind = k-1; val =  - dvdx/hx - cdiv3;
384:         VecSetValues(G,1,&ind,&val,ADD_VALUES);
385:       }
386:       if (i != nx && j != ny) {
387:         ind = k; val =  dvdx/hx + dvdy/hy - cdiv3;
388:         VecSetValues(G,1,&ind,&val,ADD_VALUES);
389:       }
390:     }
391:   }
392:   VecRestoreArray(X,&x);

394:   /* Assemble gradient vector */
395:   VecAssemblyBegin(G);
396:   VecAssemblyEnd(G);

398:   /* Scale the gradient */
399:   area = p5*hx*hy;
400:   VecScale(G, area);
401:   PetscLogFlops(nx*ny*24);
402:   return 0;
403: }

405: /* ------------------------------------------------------------------- */
408: /*
409:    FormHessian - Forms the Hessian matrix.

411:    Input Parameters:
412: .  tao - the Tao context
413: .  X    - the input vector
414: .  ptr  - optional user-defined context, as set by TaoSetHessian()

416:    Output Parameters:
417: .  H     - Hessian matrix
418: .  PrecH - optionally different preconditioning Hessian
419: .  flag  - flag indicating matrix structure

421:    Notes:
422:    This routine is intended simply as an example of the interface
423:    to a Hessian evaluation routine.  Since this example compute the
424:    Hessian a column at a time, it is not particularly efficient and
425:    is not recommended.
426: */
427: PetscErrorCode FormHessian(Tao tao,Vec X,Mat *HH,Mat *Hpre, MatStructure *flg, void *ptr)
428: {
429:   AppCtx         *user = (AppCtx *) ptr;
431:   PetscInt       i,j, ndim = user->ndim;
432:   PetscReal      *y, zero = 0.0, one = 1.0;
433:   Mat            H=*HH;
434:   PetscBool      assembled;

436:   *Hpre = H;
437:   user->xvec = X;

439:   /* Initialize Hessian entries and work vector to zero */
440:   MatAssembled(H,&assembled);
441:   if (assembled){MatZeroEntries(H); }

443:   VecSet(user->s, zero);

445:   /* Loop over matrix columns to compute entries of the Hessian */
446:   for (j=0; j<ndim; j++) {
447:     VecSetValues(user->s,1,&j,&one,INSERT_VALUES);
448:     VecAssemblyBegin(user->s);
449:     VecAssemblyEnd(user->s);

451:     HessianProduct(ptr,user->s,user->y);

453:     VecSetValues(user->s,1,&j,&zero,INSERT_VALUES);
454:     VecAssemblyBegin(user->s);
455:     VecAssemblyEnd(user->s);

457:     VecGetArray(user->y,&y);
458:     for (i=0; i<ndim; i++) {
459:       if (y[i] != zero) {
460:         MatSetValues(H,1,&i,1,&j,&y[i],ADD_VALUES);
461:       }
462:     }
463:     VecRestoreArray(user->y,&y);
464:   }

466:   *flg=SAME_NONZERO_PATTERN;
467:   MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY);
468:   MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY);
469:   return 0;
470: }

472: /* ------------------------------------------------------------------- */
475: /*
476:    MatrixFreeHessian - Sets a pointer for use in computing Hessian-vector
477:    products.

479:    Input Parameters:
480: .  tao - the Tao context
481: .  X    - the input vector
482: .  ptr  - optional user-defined context, as set by TaoSetHessian()

484:    Output Parameters:
485: .  H     - Hessian matrix
486: .  PrecH - optionally different preconditioning Hessian
487: .  flag  - flag indicating matrix structure
488: */
489: PetscErrorCode MatrixFreeHessian(Tao tao,Vec X,Mat *H,Mat *PrecH, MatStructure *flag,void *ptr)
490: {
491:   AppCtx     *user = (AppCtx *) ptr;

493:   /* Sets location of vector for use in computing matrix-vector products  of the form H(X)*y  */
494:   user->xvec = X;
495:   return 0;
496: }

498: /* ------------------------------------------------------------------- */
501: /*
502:    HessianProductMat - Computes the matrix-vector product
503:    y = mat*svec.

505:    Input Parameters:
506: .  mat  - input matrix
507: .  svec - input vector

509:    Output Parameters:
510: .  y    - solution vector
511: */
512: PetscErrorCode HessianProductMat(Mat mat,Vec svec,Vec y)
513: {
514:   void           *ptr;

517:   MatShellGetContext(mat,&ptr);
518:   HessianProduct(ptr,svec,y);
519:   return 0;
520: }

522: /* ------------------------------------------------------------------- */
525: /*
526:    Hessian Product - Computes the matrix-vector product:
527:    y = f''(x)*svec.

529:    Input Parameters
530: .  ptr  - pointer to the user-defined context
531: .  svec - input vector

533:    Output Parameters:
534: .  y    - product vector
535: */
536: PetscErrorCode HessianProduct(void *ptr,Vec svec,Vec y)
537: {
538:   AppCtx         *user = (AppCtx *)ptr;
539:   PetscReal      p5 = 0.5, zero = 0.0, one = 1.0, hx, hy, val, area, *x, *s;
540:   PetscReal      v, vb, vl, vr, vt, hxhx, hyhy;
542:   PetscInt       nx, ny, i, j, k, ind;

544:   nx   = user->mx;
545:   ny   = user->my;
546:   hx   = user->hx;
547:   hy   = user->hy;
548:   hxhx = one/(hx*hx);
549:   hyhy = one/(hy*hy);

551:   /* Get pointers to vector data */
552:   VecGetArray(user->xvec,&x);
553:   VecGetArray(svec,&s);

555:   /* Initialize product vector to zero */
556:   VecSet(y, zero);

558:   /* Compute f''(x)*s over the lower triangular elements */
559:   for (j=-1; j<ny; j++) {
560:     for (i=-1; i<nx; i++) {
561:        k = nx*j + i;
562:        v = zero;
563:        vr = zero;
564:        vt = zero;
565:        if (i != -1 && j != -1) v = s[k];
566:        if (i != nx-1 && j != -1) {
567:          vr = s[k+1];
568:          ind = k+1; val = hxhx*(vr-v);
569:          VecSetValues(y,1,&ind,&val,ADD_VALUES);
570:        }
571:        if (i != -1 && j != ny-1) {
572:          vt = s[k+nx];
573:          ind = k+nx; val = hyhy*(vt-v);
574:          VecSetValues(y,1,&ind,&val,ADD_VALUES);
575:        }
576:        if (i != -1 && j != -1) {
577:          ind = k; val = hxhx*(v-vr) + hyhy*(v-vt);
578:          VecSetValues(y,1,&ind,&val,ADD_VALUES);
579:        }
580:      }
581:    }

583:   /* Compute f''(x)*s over the upper triangular elements */
584:   for (j=0; j<=ny; j++) {
585:     for (i=0; i<=nx; i++) {
586:        k = nx*j + i;
587:        v = zero;
588:        vl = zero;
589:        vb = zero;
590:        if (i != nx && j != ny) v = s[k];
591:        if (i != nx && j != 0) {
592:          vb = s[k-nx];
593:          ind = k-nx; val = hyhy*(vb-v);
594:          VecSetValues(y,1,&ind,&val,ADD_VALUES);
595:        }
596:        if (i != 0 && j != ny) {
597:          vl = s[k-1];
598:          ind = k-1; val = hxhx*(vl-v);
599:          VecSetValues(y,1,&ind,&val,ADD_VALUES);
600:        }
601:        if (i != nx && j != ny) {
602:          ind = k; val = hxhx*(v-vl) + hyhy*(v-vb);
603:          VecSetValues(y,1,&ind,&val,ADD_VALUES);
604:        }
605:     }
606:   }
607:   /* Restore vector data */
608:   VecRestoreArray(svec,&s);
609:   VecRestoreArray(user->xvec,&x);

611:   /* Assemble vector */
612:   VecAssemblyBegin(y);
613:   VecAssemblyEnd(y);

615:   /* Scale resulting vector by area */
616:   area = p5*hx*hy;
617:   VecScale(y, area);
618:   PetscLogFlops(nx*ny*18);
619:   return 0;
620: }