Actual source code: eptorsion2.c

petsc-dev 2014-02-02
Report Typos and Errors
  1: /* Program usage: mpirun -np <proc> eptorsion2 [-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 uniprocessor version of this code is eptorsion1.c; the Fortran
 16:   version of this code is eptorsion2f.F.

 18:   This application solves the problem without calculating hessians
 19: ---------------------------------------------------------------------- */

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

 33: #include <petsctao.h>
 34: #include <petscdmda.h>

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

 45: /*T
 46:    Concepts: TAO^Solving an unconstrained minimization problem
 47:    Routines: TaoCreate(); TaoSetType();
 48:    Routines: TaoSetInitialVector();
 49:    Routines: TaoSetObjectiveAndGradientRoutine();
 50:    Routines: TaoSetHessianRoutine(); TaoSetFromOptions();
 51:    Routines: TaoSolve();
 52:    Routines: TaoGetTerminationReason(); TaoDestroy();
 53:    Processors: n
 54: T*/

 56: /*
 57:    User-defined application context - contains data needed by the
 58:    application-provided call-back routines, FormFunction() and
 59:    FormGradient().
 60: */
 61: typedef struct {
 62:   /* parameters */
 63:    PetscInt           mx, my;         /* global discretization in x- and y-directions */
 64:    PetscReal        param;          /* nonlinearity parameter */

 66:   /* work space */
 67:    Vec           localX;         /* local vectors */
 68:    DM            dm;             /* distributed array data structure */
 69: } AppCtx;


 72: PetscErrorCode FormInitialGuess(AppCtx*, Vec);
 73: PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal*,Vec,void*);
 74: PetscErrorCode FormHessian(Tao,Vec,Mat*,Mat*,MatStructure*,void*);


 79: int main(int argc, char **argv)
 80: {
 82:     Vec x;
 83:     Mat H;
 84:     PetscInt Nx, Ny;
 85:     Tao tao;
 86:     TaoTerminationReason reason;
 87:     PetscBool flg;
 88:     KSP ksp; PC pc;
 89:     AppCtx user;

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

 94:     /* Specify default dimension of the problem */
 95:     user.param = 5.0; user.mx = 10; user.my = 10;
 96:     Nx = Ny = PETSC_DECIDE;

 98:     /* Check for any command line arguments that override defaults */
 99:     PetscOptionsGetReal(NULL,"-par",&user.param,&flg);
100:     PetscOptionsGetInt(NULL,"-my",&user.my,&flg);
101:     PetscOptionsGetInt(NULL,"-mx",&user.mx,&flg);

103:     PetscPrintf(PETSC_COMM_WORLD,"\n---- Elastic-Plastic Torsion Problem -----\n");
104:     PetscPrintf(PETSC_COMM_WORLD,"mx: %D     my: %D   \n\n",user.mx,user.my);

106:     /* Set up distributed array */
107:     DMDACreate2d(PETSC_COMM_WORLD,DMDA_BOUNDARY_NONE,DMDA_BOUNDARY_NONE,DMDA_STENCIL_STAR,user.mx,user.my,Nx,Ny,1,1,NULL,NULL,
108:                         &user.dm);

110:     /* Create vectors */
111:     DMCreateGlobalVector(user.dm,&x);

113:     DMCreateLocalVector(user.dm,&user.localX);

115:     /* Create Hessian */
116:     DMCreateMatrix(user.dm,&H);
117:     MatSetOption(H,MAT_SYMMETRIC,PETSC_TRUE);

119:     /* The TAO code begins here */

121:     /* Create TAO solver and set desired solution method */
122:     TaoCreate(PETSC_COMM_WORLD,&tao);
123:     TaoSetType(tao,"tao_cg");

125:     /* Set initial solution guess */
126:     FormInitialGuess(&user,x);
127:     TaoSetInitialVector(tao,x);

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

132:     TaoSetHessianRoutine(tao,H,H,FormHessian,(void*)&user);


135:     /* Check for any TAO command line options */
136:     TaoSetFromOptions(tao);

138:     TaoGetKSP(tao,&ksp);
139:     if (ksp) {
140:       KSPGetPC(ksp,&pc);
141:       PCSetType(pc,PCNONE);
142:     }

144:     /* SOLVE THE APPLICATION */
145:     TaoSolve(tao);

147:     /* Get information on termination */
148:     TaoGetTerminationReason(tao,&reason);
149:     if (reason <= 0){
150:         ierr=PetscPrintf(MPI_COMM_WORLD, "Try another method! \n");
151:     }

153:     /* Free TAO data structures */
154:     TaoDestroy(&tao);

156:     /* Free PETSc data structures */
157:     VecDestroy(&x);
158:     MatDestroy(&H);

160:     VecDestroy(&user.localX);
161:     DMDestroy(&user.dm);

163:     PetscFinalize();
164:     return 0;
165: }


168: /* ------------------------------------------------------------------- */
171: /*
172:     FormInitialGuess - Computes an initial approximation to the solution.

174:     Input Parameters:
175: .   user - user-defined application context
176: .   X    - vector

178:     Output Parameters:
179:     X    - vector
180: */
181: PetscErrorCode FormInitialGuess(AppCtx *user,Vec X)
182: {
183:   PetscErrorCode    ierr;
184:   PetscInt   i, j, k, mx = user->mx, my = user->my;
185:   PetscInt   xs, ys, xm, ym, gxm, gym, gxs, gys, xe, ye;
186:   PetscReal hx = 1.0/(mx+1), hy = 1.0/(my+1), temp, val;

189:   /* Get local mesh boundaries */
190:   DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL);
191:   DMDAGetGhostCorners(user->dm,&gxs,&gys,NULL,&gxm,&gym,NULL);

193:   /* Compute initial guess over locally owned part of mesh */
194:   xe = xs+xm;
195:   ye = ys+ym;
196:   for (j=ys; j<ye; j++) {  /*  for (j=0; j<my; j++) */
197:     temp = PetscMin(j+1,my-j)*hy;
198:     for (i=xs; i<xe; i++) {  /*  for (i=0; i<mx; i++) */
199:       k   = (j-gys)*gxm + i-gxs;
200:       val = PetscMin((PetscMin(i+1,mx-i))*hx,temp);
201:       VecSetValuesLocal(X,1,&k,&val,ADD_VALUES);
202:     }
203:   }
204:   VecAssemblyBegin(X);
205:   VecAssemblyEnd(X);
206:   return(0);
207: }


210: /* ------------------------------------------------------------------ */
213: /*
214:    FormFunctionGradient - Evaluates the function and corresponding gradient.

216:    Input Parameters:
217:    tao - the Tao context
218:    X   - the input vector
219:    ptr - optional user-defined context, as set by TaoSetObjectiveAndGradientRoutine()

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

227:   AppCtx *user = (AppCtx *)ptr;
228:   PetscErrorCode    ierr;
229:   PetscInt i,j,k,ind;
230:   PetscInt xe,ye,xsm,ysm,xep,yep;
231:   PetscInt xs, ys, xm, ym, gxm, gym, gxs, gys;
232:   PetscInt mx = user->mx, my = user->my;
233:   PetscReal three = 3.0, zero = 0.0, *x, floc, cdiv3 = user->param/three;
234:   PetscReal p5 = 0.5, area, val, flin, fquad;
235:   PetscReal v,vb,vl,vr,vt,dvdx,dvdy;
236:   PetscReal hx = 1.0/(user->mx + 1);
237:   PetscReal hy = 1.0/(user->my + 1);
238:   Vec    localX = user->localX;


242:   /* Initialize */
243:   flin = fquad = zero;

245:   VecSet(G, zero);
246:   /*
247:      Scatter ghost points to local vector,using the 2-step process
248:         DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
249:      By placing code between these two statements, computations can be
250:      done while messages are in transition.
251:   */
252:   DMGlobalToLocalBegin(user->dm,X,INSERT_VALUES,localX);
253:   DMGlobalToLocalEnd(user->dm,X,INSERT_VALUES,localX);

255:   /* Get pointer to vector data */
256:   VecGetArray(localX,&x);

258:   /* Get local mesh boundaries */
259:   DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL);
260:   DMDAGetGhostCorners(user->dm,&gxs,&gys,NULL,&gxm,&gym,NULL);

262:   /* Set local loop dimensions */
263:   xe = xs+xm;
264:   ye = ys+ym;
265:   if (xs == 0)  xsm = xs-1;
266:   else          xsm = xs;
267:   if (ys == 0)  ysm = ys-1;
268:   else          ysm = ys;
269:   if (xe == mx) xep = xe+1;
270:   else          xep = xe;
271:   if (ye == my) yep = ye+1;
272:   else          yep = ye;

274:   /* Compute local gradient contributions over the lower triangular elements */
275:   for (j=ysm; j<ye; j++) {  /*  for (j=-1; j<my; j++) */
276:     for (i=xsm; i<xe; i++) {  /*   for (i=-1; i<mx; i++) */
277:       k = (j-gys)*gxm + i-gxs;
278:       v = zero;
279:       vr = zero;
280:       vt = zero;
281:       if (i >= 0 && j >= 0) v = x[k];
282:       if (i < mx-1 && j > -1) vr = x[k+1];
283:       if (i > -1 && j < my-1) vt = x[k+gxm];
284:       dvdx = (vr-v)/hx;
285:       dvdy = (vt-v)/hy;
286:       if (i != -1 && j != -1) {
287:         ind = k; val = - dvdx/hx - dvdy/hy - cdiv3;
288:         VecSetValuesLocal(G,1,&k,&val,ADD_VALUES);
289:       }
290:       if (i != mx-1 && j != -1) {
291:         ind = k+1; val =  dvdx/hx - cdiv3;
292:         VecSetValuesLocal(G,1,&ind,&val,ADD_VALUES);
293:       }
294:       if (i != -1 && j != my-1) {
295:         ind = k+gxm; val = dvdy/hy - cdiv3;
296:         VecSetValuesLocal(G,1,&ind,&val,ADD_VALUES);
297:       }
298:       fquad += dvdx*dvdx + dvdy*dvdy;
299:       flin -= cdiv3 * (v + vr + vt);
300:     }
301:   }

303:   /* Compute local gradient contributions over the upper triangular elements */
304:   for (j=ys; j<yep; j++) { /*  for (j=0; j<=my; j++) */
305:     for (i=xs; i<xep; i++) {  /*   for (i=0; i<=mx; i++) */
306:       k = (j-gys)*gxm + i-gxs;
307:       vb = zero;
308:       vl = zero;
309:       v  = zero;
310:       if (i < mx && j > 0) vb = x[k-gxm];
311:       if (i > 0 && j < my) vl = x[k-1];
312:       if (i < mx && j < my) v = x[k];
313:       dvdx = (v-vl)/hx;
314:       dvdy = (v-vb)/hy;
315:       if (i != mx && j != 0) {
316:         ind = k-gxm; val = - dvdy/hy - cdiv3;
317:         VecSetValuesLocal(G,1,&ind,&val,ADD_VALUES);
318:       }
319:       if (i != 0 && j != my) {
320:         ind = k-1; val =  - dvdx/hx - cdiv3;
321:         VecSetValuesLocal(G,1,&ind,&val,ADD_VALUES);
322:       }
323:       if (i != mx && j != my) {
324:         ind = k; val =  dvdx/hx + dvdy/hy - cdiv3;
325:         VecSetValuesLocal(G,1,&ind,&val,ADD_VALUES);
326:       }
327:       fquad += dvdx*dvdx + dvdy*dvdy;
328:       flin -= cdiv3 * (vb + vl + v);
329:     }
330:   }


333:   /* Restore vector */
334:   VecRestoreArray(localX,&x);

336:   /* Assemble gradient vector */
337:   VecAssemblyBegin(G);
338:   VecAssemblyEnd(G);

340:   /* Scale the gradient */
341:   area = p5*hx*hy;
342:   floc = area * (p5 * fquad + flin);
343:   VecScale(G, area);

345:   /* Sum function contributions from all processes */
346:   (PetscErrorCode)MPI_Allreduce((void*)&floc,(void*)f,1,MPIU_REAL,MPIU_SUM,MPI_COMM_WORLD);

348:   ierr=PetscLogFlops((ye-ysm)*(xe-xsm)*20+(xep-xs)*(yep-ys)*16);

350:   return(0);
351: }



357: PetscErrorCode FormHessian(Tao tao, Vec X, Mat *H, Mat *Hpre, MatStructure *flag, void*ctx){

359:   AppCtx *user= (AppCtx*) ctx;
361:   PetscInt i,j,k;
362:   PetscInt col[5],row;
363:   PetscInt xs,xm,gxs,gxm,ys,ym,gys,gym;
364:   PetscReal v[5];
365:   PetscReal hx=1.0/(user->mx+1), hy=1.0/(user->my+1), hxhx=1.0/(hx*hx), hyhy=1.0/(hy*hy), area=0.5*hx*hy;
366:   Mat A=*H;

368:   /* Compute the quadratic term in the objective function */

370:   /*
371:      Get local grid boundaries
372:   */

375:   DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL);
376:   DMDAGetGhostCorners(user->dm,&gxs,&gys,NULL,&gxm,&gym,NULL);

378:   for (j=ys; j<ys+ym; j++){

380:     for (i=xs; i< xs+xm; i++){

382:       row=(j-gys)*gxm + (i-gxs);

384:       k=0;
385:       if (j>gys){
386:         v[k]=-2*hyhy; col[k]=row - gxm; k++;
387:       }

389:       if (i>gxs){
390:         v[k]= -2*hxhx; col[k]=row - 1; k++;
391:       }

393:       v[k]= 4.0*(hxhx+hyhy); col[k]=row; k++;

395:       if (i+1 < gxs+gxm){
396:         v[k]= -2.0*hxhx; col[k]=row+1; k++;
397:       }

399:       if (j+1 <gys+gym){
400:         v[k]= -2*hyhy; col[k] = row+gxm; k++;
401:       }

403:       MatSetValuesLocal(A,1,&row,k,col,v,INSERT_VALUES);

405:     }
406:   }
407:   /*
408:      Assemble matrix, using the 2-step process:
409:      MatAssemblyBegin(), MatAssemblyEnd().
410:      By placing code between these two statements, computations can be
411:      done while messages are in transition.
412:   */
413:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
414:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
415:   /*
416:     Tell the matrix we will never add a new nonzero location to the
417:     matrix. If we do it will generate an error.
418:   */
419:   MatScale(A,area);
420:   MatSetOption(A,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE);
421:   MatSetOption(A,MAT_SYMMETRIC,PETSC_TRUE);

423:   PetscLogFlops(9*xm*ym+49*xm);

425:   return(0);
426: }