Actual source code: eptorsion1.c
petsc-dev 2014-02-02
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: }