xref: /petsc/src/tao/unconstrained/tutorials/eptorsion1.c (revision c4762a1b19cd2af06abeed90e8f9d34fb975dd94)
1*c4762a1bSJed Brown /* Program usage: mpiexec -n 1 eptorsion1 [-help] [all TAO options] */
2*c4762a1bSJed Brown 
3*c4762a1bSJed Brown /* ----------------------------------------------------------------------
4*c4762a1bSJed Brown 
5*c4762a1bSJed Brown   Elastic-plastic torsion problem.
6*c4762a1bSJed Brown 
7*c4762a1bSJed Brown   The elastic plastic torsion problem arises from the determination
8*c4762a1bSJed Brown   of the stress field on an infinitely long cylindrical bar, which is
9*c4762a1bSJed Brown   equivalent to the solution of the following problem:
10*c4762a1bSJed Brown 
11*c4762a1bSJed Brown   min{ .5 * integral(||gradient(v(x))||^2 dx) - C * integral(v(x) dx)}
12*c4762a1bSJed Brown 
13*c4762a1bSJed Brown   where C is the torsion angle per unit length.
14*c4762a1bSJed Brown 
15*c4762a1bSJed Brown   The multiprocessor version of this code is eptorsion2.c.
16*c4762a1bSJed Brown 
17*c4762a1bSJed Brown ---------------------------------------------------------------------- */
18*c4762a1bSJed Brown 
19*c4762a1bSJed Brown /*
20*c4762a1bSJed Brown   Include "petsctao.h" so that we can use TAO solvers.  Note that this
21*c4762a1bSJed Brown   file automatically includes files for lower-level support, such as those
22*c4762a1bSJed Brown   provided by the PETSc library:
23*c4762a1bSJed Brown      petsc.h       - base PETSc routines   petscvec.h - vectors
24*c4762a1bSJed Brown      petscsys.h    - sysem routines        petscmat.h - matrices
25*c4762a1bSJed Brown      petscis.h     - index sets            petscksp.h - Krylov subspace methods
26*c4762a1bSJed Brown      petscviewer.h - viewers               petscpc.h  - preconditioners
27*c4762a1bSJed Brown */
28*c4762a1bSJed Brown 
29*c4762a1bSJed Brown #include <petsctao.h>
30*c4762a1bSJed Brown 
31*c4762a1bSJed Brown 
32*c4762a1bSJed Brown static  char help[]=
33*c4762a1bSJed Brown "Demonstrates use of the TAO package to solve \n\
34*c4762a1bSJed Brown unconstrained minimization problems on a single processor.  This example \n\
35*c4762a1bSJed Brown is based on the Elastic-Plastic Torsion (dept) problem from the MINPACK-2 \n\
36*c4762a1bSJed Brown test suite.\n\
37*c4762a1bSJed Brown The command line options are:\n\
38*c4762a1bSJed Brown   -mx <xg>, where <xg> = number of grid points in the 1st coordinate direction\n\
39*c4762a1bSJed Brown   -my <yg>, where <yg> = number of grid points in the 2nd coordinate direction\n\
40*c4762a1bSJed Brown   -par <param>, where <param> = angle of twist per unit length\n\n";
41*c4762a1bSJed Brown 
42*c4762a1bSJed Brown /*T
43*c4762a1bSJed Brown    Concepts: TAO^Solving an unconstrained minimization problem
44*c4762a1bSJed Brown    Routines: TaoCreate(); TaoSetType();
45*c4762a1bSJed Brown    Routines: TaoSetInitialVector();
46*c4762a1bSJed Brown    Routines: TaoSetObjectiveAndGradientRoutine();
47*c4762a1bSJed Brown    Routines: TaoSetHessianRoutine(); TaoSetFromOptions();
48*c4762a1bSJed Brown    Routines: TaoGetKSP(); TaoSolve();
49*c4762a1bSJed Brown    Routines: TaoDestroy();
50*c4762a1bSJed Brown    Processors: 1
51*c4762a1bSJed Brown T*/
52*c4762a1bSJed Brown 
53*c4762a1bSJed Brown /*
54*c4762a1bSJed Brown    User-defined application context - contains data needed by the
55*c4762a1bSJed Brown    application-provided call-back routines, FormFunction(),
56*c4762a1bSJed Brown    FormGradient(), and FormHessian().
57*c4762a1bSJed Brown */
58*c4762a1bSJed Brown 
59*c4762a1bSJed Brown typedef struct {
60*c4762a1bSJed Brown    PetscReal  param;      /* nonlinearity parameter */
61*c4762a1bSJed Brown    PetscInt   mx, my;     /* discretization in x- and y-directions */
62*c4762a1bSJed Brown    PetscInt   ndim;       /* problem dimension */
63*c4762a1bSJed Brown    Vec        s, y, xvec; /* work space for computing Hessian */
64*c4762a1bSJed Brown    PetscReal  hx, hy;     /* mesh spacing in x- and y-directions */
65*c4762a1bSJed Brown } AppCtx;
66*c4762a1bSJed Brown 
67*c4762a1bSJed Brown /* -------- User-defined Routines --------- */
68*c4762a1bSJed Brown 
69*c4762a1bSJed Brown PetscErrorCode FormInitialGuess(AppCtx*,Vec);
70*c4762a1bSJed Brown PetscErrorCode FormFunction(Tao,Vec,PetscReal*,void*);
71*c4762a1bSJed Brown PetscErrorCode FormGradient(Tao,Vec,Vec,void*);
72*c4762a1bSJed Brown PetscErrorCode FormHessian(Tao,Vec,Mat,Mat, void*);
73*c4762a1bSJed Brown PetscErrorCode HessianProductMat(Mat,Vec,Vec);
74*c4762a1bSJed Brown PetscErrorCode HessianProduct(void*,Vec,Vec);
75*c4762a1bSJed Brown PetscErrorCode MatrixFreeHessian(Tao,Vec,Mat,Mat,void*);
76*c4762a1bSJed Brown PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal *,Vec,void *);
77*c4762a1bSJed Brown 
78*c4762a1bSJed Brown PetscErrorCode main(int argc,char **argv)
79*c4762a1bSJed Brown {
80*c4762a1bSJed Brown   PetscErrorCode     ierr;                /* used to check for functions returning nonzeros */
81*c4762a1bSJed Brown   PetscInt           mx=10;               /* discretization in x-direction */
82*c4762a1bSJed Brown   PetscInt           my=10;               /* discretization in y-direction */
83*c4762a1bSJed Brown   Vec                x;                   /* solution, gradient vectors */
84*c4762a1bSJed Brown   PetscBool          flg;                 /* A return value when checking for use options */
85*c4762a1bSJed Brown   Tao                tao;                 /* Tao solver context */
86*c4762a1bSJed Brown   Mat                H;                   /* Hessian matrix */
87*c4762a1bSJed Brown   AppCtx             user;                /* application context */
88*c4762a1bSJed Brown   PetscMPIInt        size;                /* number of processes */
89*c4762a1bSJed Brown   PetscReal          one=1.0;
90*c4762a1bSJed Brown 
91*c4762a1bSJed Brown   PetscBool          test_lmvm = PETSC_FALSE;
92*c4762a1bSJed Brown   KSP                ksp;
93*c4762a1bSJed Brown   PC                 pc;
94*c4762a1bSJed Brown   Mat                M;
95*c4762a1bSJed Brown   Vec                in, out, out2;
96*c4762a1bSJed Brown   PetscReal          mult_solve_dist;
97*c4762a1bSJed Brown 
98*c4762a1bSJed Brown   /* Initialize TAO,PETSc */
99*c4762a1bSJed Brown   ierr = PetscInitialize(&argc,&argv,(char *)0,help);if (ierr) return ierr;
100*c4762a1bSJed Brown   ierr = MPI_Comm_size(MPI_COMM_WORLD,&size);CHKERRQ(ierr);
101*c4762a1bSJed Brown   if (size >1) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"Incorrect number of processors");
102*c4762a1bSJed Brown 
103*c4762a1bSJed Brown   /* Specify default parameters for the problem, check for command-line overrides */
104*c4762a1bSJed Brown   user.param = 5.0;
105*c4762a1bSJed Brown   ierr = PetscOptionsGetInt(NULL,NULL,"-my",&my,&flg);CHKERRQ(ierr);
106*c4762a1bSJed Brown   ierr = PetscOptionsGetInt(NULL,NULL,"-mx",&mx,&flg);CHKERRQ(ierr);
107*c4762a1bSJed Brown   ierr = PetscOptionsGetReal(NULL,NULL,"-par",&user.param,&flg);CHKERRQ(ierr);
108*c4762a1bSJed Brown   ierr = PetscOptionsGetBool(NULL,NULL,"-test_lmvm",&test_lmvm,&flg);CHKERRQ(ierr);
109*c4762a1bSJed Brown 
110*c4762a1bSJed Brown   ierr = PetscPrintf(PETSC_COMM_SELF,"\n---- Elastic-Plastic Torsion Problem -----\n");CHKERRQ(ierr);
111*c4762a1bSJed Brown   ierr = PetscPrintf(PETSC_COMM_SELF,"mx: %D     my: %D   \n\n",mx,my); CHKERRQ(ierr);
112*c4762a1bSJed Brown   user.ndim = mx * my; user.mx = mx; user.my = my;
113*c4762a1bSJed Brown   user.hx = one/(mx+1); user.hy = one/(my+1);
114*c4762a1bSJed Brown 
115*c4762a1bSJed Brown   /* Allocate vectors */
116*c4762a1bSJed Brown   ierr = VecCreateSeq(PETSC_COMM_SELF,user.ndim,&user.y);CHKERRQ(ierr);
117*c4762a1bSJed Brown   ierr = VecDuplicate(user.y,&user.s);CHKERRQ(ierr);
118*c4762a1bSJed Brown   ierr = VecDuplicate(user.y,&x);CHKERRQ(ierr);
119*c4762a1bSJed Brown 
120*c4762a1bSJed Brown   /* Create TAO solver and set desired solution method */
121*c4762a1bSJed Brown   ierr = TaoCreate(PETSC_COMM_SELF,&tao);CHKERRQ(ierr);
122*c4762a1bSJed Brown   ierr = TaoSetType(tao,TAOLMVM);CHKERRQ(ierr);
123*c4762a1bSJed Brown 
124*c4762a1bSJed Brown   /* Set solution vector with an initial guess */
125*c4762a1bSJed Brown   ierr = FormInitialGuess(&user,x);CHKERRQ(ierr);
126*c4762a1bSJed Brown   ierr = TaoSetInitialVector(tao,x);CHKERRQ(ierr);
127*c4762a1bSJed Brown 
128*c4762a1bSJed Brown   /* Set routine for function and gradient evaluation */
129*c4762a1bSJed Brown   ierr = TaoSetObjectiveAndGradientRoutine(tao,FormFunctionGradient,(void *)&user);CHKERRQ(ierr);
130*c4762a1bSJed Brown 
131*c4762a1bSJed Brown   /* From command line options, determine if using matrix-free hessian */
132*c4762a1bSJed Brown   ierr = PetscOptionsHasName(NULL,NULL,"-my_tao_mf",&flg);CHKERRQ(ierr);
133*c4762a1bSJed Brown   if (flg) {
134*c4762a1bSJed Brown     ierr = MatCreateShell(PETSC_COMM_SELF,user.ndim,user.ndim,user.ndim,user.ndim,(void*)&user,&H);CHKERRQ(ierr);
135*c4762a1bSJed Brown     ierr = MatShellSetOperation(H,MATOP_MULT,(void(*)(void))HessianProductMat);CHKERRQ(ierr);
136*c4762a1bSJed Brown     ierr = MatSetOption(H,MAT_SYMMETRIC,PETSC_TRUE);CHKERRQ(ierr);
137*c4762a1bSJed Brown 
138*c4762a1bSJed Brown     ierr = TaoSetHessianRoutine(tao,H,H,MatrixFreeHessian,(void *)&user);CHKERRQ(ierr);
139*c4762a1bSJed Brown   } else {
140*c4762a1bSJed Brown     ierr = MatCreateSeqAIJ(PETSC_COMM_SELF,user.ndim,user.ndim,5,NULL,&H);CHKERRQ(ierr);
141*c4762a1bSJed Brown     ierr = MatSetOption(H,MAT_SYMMETRIC,PETSC_TRUE);CHKERRQ(ierr);
142*c4762a1bSJed Brown     ierr = TaoSetHessianRoutine(tao,H,H,FormHessian,(void *)&user);CHKERRQ(ierr);
143*c4762a1bSJed Brown   }
144*c4762a1bSJed Brown 
145*c4762a1bSJed Brown   /* Test the LMVM matrix */
146*c4762a1bSJed Brown   if (test_lmvm) {
147*c4762a1bSJed Brown     ierr = PetscOptionsSetValue(NULL, "-tao_type", "bntr");CHKERRQ(ierr);
148*c4762a1bSJed Brown     ierr = PetscOptionsSetValue(NULL, "-tao_bnk_pc_type", "lmvm");CHKERRQ(ierr);
149*c4762a1bSJed Brown   }
150*c4762a1bSJed Brown 
151*c4762a1bSJed Brown   /* Check for any TAO command line options */
152*c4762a1bSJed Brown   ierr = TaoSetFromOptions(tao);CHKERRQ(ierr);
153*c4762a1bSJed Brown 
154*c4762a1bSJed Brown   /* SOLVE THE APPLICATION */
155*c4762a1bSJed Brown   ierr = TaoSolve(tao); CHKERRQ(ierr);
156*c4762a1bSJed Brown 
157*c4762a1bSJed Brown   /* Test the LMVM matrix */
158*c4762a1bSJed Brown   if (test_lmvm) {
159*c4762a1bSJed Brown     ierr = TaoGetKSP(tao, &ksp);CHKERRQ(ierr);
160*c4762a1bSJed Brown     ierr = KSPGetPC(ksp, &pc);CHKERRQ(ierr);
161*c4762a1bSJed Brown     ierr = PCLMVMGetMatLMVM(pc, &M);CHKERRQ(ierr);
162*c4762a1bSJed Brown     ierr = VecDuplicate(x, &in);CHKERRQ(ierr);
163*c4762a1bSJed Brown     ierr = VecDuplicate(x, &out);CHKERRQ(ierr);
164*c4762a1bSJed Brown     ierr = VecDuplicate(x, &out2);CHKERRQ(ierr);
165*c4762a1bSJed Brown     ierr = VecSet(in, 5.0);CHKERRQ(ierr);
166*c4762a1bSJed Brown     ierr = MatMult(M, in, out);CHKERRQ(ierr);
167*c4762a1bSJed Brown     ierr = MatSolve(M, out, out2);CHKERRQ(ierr);
168*c4762a1bSJed Brown     ierr = VecAXPY(out2, -1.0, in);CHKERRQ(ierr);
169*c4762a1bSJed Brown     ierr = VecNorm(out2, NORM_2, &mult_solve_dist);CHKERRQ(ierr);
170*c4762a1bSJed Brown     ierr = PetscPrintf(PetscObjectComm((PetscObject)tao), "error between MatMult and MatSolve: %e\n", mult_solve_dist);CHKERRQ(ierr);
171*c4762a1bSJed Brown     ierr = VecDestroy(&in);CHKERRQ(ierr);
172*c4762a1bSJed Brown     ierr = VecDestroy(&out);CHKERRQ(ierr);
173*c4762a1bSJed Brown     ierr = VecDestroy(&out2);CHKERRQ(ierr);
174*c4762a1bSJed Brown   }
175*c4762a1bSJed Brown 
176*c4762a1bSJed Brown   ierr = TaoDestroy(&tao);CHKERRQ(ierr);
177*c4762a1bSJed Brown   ierr = VecDestroy(&user.s);CHKERRQ(ierr);
178*c4762a1bSJed Brown   ierr = VecDestroy(&user.y);CHKERRQ(ierr);
179*c4762a1bSJed Brown   ierr = VecDestroy(&x);CHKERRQ(ierr);
180*c4762a1bSJed Brown   ierr = MatDestroy(&H);CHKERRQ(ierr);
181*c4762a1bSJed Brown 
182*c4762a1bSJed Brown   ierr = PetscFinalize();
183*c4762a1bSJed Brown   return ierr;
184*c4762a1bSJed Brown }
185*c4762a1bSJed Brown 
186*c4762a1bSJed Brown /* ------------------------------------------------------------------- */
187*c4762a1bSJed Brown /*
188*c4762a1bSJed Brown     FormInitialGuess - Computes an initial approximation to the solution.
189*c4762a1bSJed Brown 
190*c4762a1bSJed Brown     Input Parameters:
191*c4762a1bSJed Brown .   user - user-defined application context
192*c4762a1bSJed Brown .   X    - vector
193*c4762a1bSJed Brown 
194*c4762a1bSJed Brown     Output Parameters:
195*c4762a1bSJed Brown .   X    - vector
196*c4762a1bSJed Brown */
197*c4762a1bSJed Brown PetscErrorCode FormInitialGuess(AppCtx *user,Vec X)
198*c4762a1bSJed Brown {
199*c4762a1bSJed Brown   PetscReal      hx = user->hx, hy = user->hy, temp;
200*c4762a1bSJed Brown   PetscReal      val;
201*c4762a1bSJed Brown   PetscErrorCode ierr;
202*c4762a1bSJed Brown   PetscInt       i, j, k, nx = user->mx, ny = user->my;
203*c4762a1bSJed Brown 
204*c4762a1bSJed Brown   /* Compute initial guess */
205*c4762a1bSJed Brown   PetscFunctionBeginUser;
206*c4762a1bSJed Brown   for (j=0; j<ny; j++) {
207*c4762a1bSJed Brown     temp = PetscMin(j+1,ny-j)*hy;
208*c4762a1bSJed Brown     for (i=0; i<nx; i++) {
209*c4762a1bSJed Brown       k   = nx*j + i;
210*c4762a1bSJed Brown       val = PetscMin((PetscMin(i+1,nx-i))*hx,temp);
211*c4762a1bSJed Brown       ierr = VecSetValues(X,1,&k,&val,ADD_VALUES);CHKERRQ(ierr);
212*c4762a1bSJed Brown     }
213*c4762a1bSJed Brown   }
214*c4762a1bSJed Brown   ierr = VecAssemblyBegin(X);CHKERRQ(ierr);
215*c4762a1bSJed Brown   ierr = VecAssemblyEnd(X);CHKERRQ(ierr);
216*c4762a1bSJed Brown   PetscFunctionReturn(0);
217*c4762a1bSJed Brown }
218*c4762a1bSJed Brown 
219*c4762a1bSJed Brown /* ------------------------------------------------------------------- */
220*c4762a1bSJed Brown /*
221*c4762a1bSJed Brown    FormFunctionGradient - Evaluates the function and corresponding gradient.
222*c4762a1bSJed Brown 
223*c4762a1bSJed Brown    Input Parameters:
224*c4762a1bSJed Brown    tao - the Tao context
225*c4762a1bSJed Brown    X   - the input vector
226*c4762a1bSJed Brown    ptr - optional user-defined context, as set by TaoSetFunction()
227*c4762a1bSJed Brown 
228*c4762a1bSJed Brown    Output Parameters:
229*c4762a1bSJed Brown    f   - the newly evaluated function
230*c4762a1bSJed Brown    G   - the newly evaluated gradient
231*c4762a1bSJed Brown */
232*c4762a1bSJed Brown PetscErrorCode FormFunctionGradient(Tao tao,Vec X,PetscReal *f,Vec G,void *ptr)
233*c4762a1bSJed Brown {
234*c4762a1bSJed Brown   PetscErrorCode ierr;
235*c4762a1bSJed Brown 
236*c4762a1bSJed Brown   PetscFunctionBeginUser;
237*c4762a1bSJed Brown   ierr = FormFunction(tao,X,f,ptr);CHKERRQ(ierr);
238*c4762a1bSJed Brown   ierr = FormGradient(tao,X,G,ptr);CHKERRQ(ierr);
239*c4762a1bSJed Brown   PetscFunctionReturn(0);
240*c4762a1bSJed Brown }
241*c4762a1bSJed Brown 
242*c4762a1bSJed Brown /* ------------------------------------------------------------------- */
243*c4762a1bSJed Brown /*
244*c4762a1bSJed Brown    FormFunction - Evaluates the function, f(X).
245*c4762a1bSJed Brown 
246*c4762a1bSJed Brown    Input Parameters:
247*c4762a1bSJed Brown .  tao - the Tao context
248*c4762a1bSJed Brown .  X   - the input vector
249*c4762a1bSJed Brown .  ptr - optional user-defined context, as set by TaoSetFunction()
250*c4762a1bSJed Brown 
251*c4762a1bSJed Brown    Output Parameters:
252*c4762a1bSJed Brown .  f    - the newly evaluated function
253*c4762a1bSJed Brown */
254*c4762a1bSJed Brown PetscErrorCode FormFunction(Tao tao,Vec X,PetscReal *f,void *ptr)
255*c4762a1bSJed Brown {
256*c4762a1bSJed Brown   AppCtx            *user = (AppCtx *) ptr;
257*c4762a1bSJed Brown   PetscReal         hx = user->hx, hy = user->hy, area, three = 3.0, p5 = 0.5;
258*c4762a1bSJed Brown   PetscReal         zero = 0.0, vb, vl, vr, vt, dvdx, dvdy, flin = 0.0, fquad = 0.0;
259*c4762a1bSJed Brown   PetscReal         v, cdiv3 = user->param/three;
260*c4762a1bSJed Brown   const PetscScalar *x;
261*c4762a1bSJed Brown   PetscErrorCode    ierr;
262*c4762a1bSJed Brown   PetscInt          nx = user->mx, ny = user->my, i, j, k;
263*c4762a1bSJed Brown 
264*c4762a1bSJed Brown   PetscFunctionBeginUser;
265*c4762a1bSJed Brown   /* Get pointer to vector data */
266*c4762a1bSJed Brown   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
267*c4762a1bSJed Brown 
268*c4762a1bSJed Brown   /* Compute function contributions over the lower triangular elements */
269*c4762a1bSJed Brown   for (j=-1; j<ny; j++) {
270*c4762a1bSJed Brown     for (i=-1; i<nx; i++) {
271*c4762a1bSJed Brown       k = nx*j + i;
272*c4762a1bSJed Brown       v = zero;
273*c4762a1bSJed Brown       vr = zero;
274*c4762a1bSJed Brown       vt = zero;
275*c4762a1bSJed Brown       if (i >= 0 && j >= 0) v = x[k];
276*c4762a1bSJed Brown       if (i < nx-1 && j > -1) vr = x[k+1];
277*c4762a1bSJed Brown       if (i > -1 && j < ny-1) vt = x[k+nx];
278*c4762a1bSJed Brown       dvdx = (vr-v)/hx;
279*c4762a1bSJed Brown       dvdy = (vt-v)/hy;
280*c4762a1bSJed Brown       fquad += dvdx*dvdx + dvdy*dvdy;
281*c4762a1bSJed Brown       flin -= cdiv3*(v+vr+vt);
282*c4762a1bSJed Brown     }
283*c4762a1bSJed Brown   }
284*c4762a1bSJed Brown 
285*c4762a1bSJed Brown   /* Compute function contributions over the upper triangular elements */
286*c4762a1bSJed Brown   for (j=0; j<=ny; j++) {
287*c4762a1bSJed Brown     for (i=0; i<=nx; i++) {
288*c4762a1bSJed Brown       k = nx*j + i;
289*c4762a1bSJed Brown       vb = zero;
290*c4762a1bSJed Brown       vl = zero;
291*c4762a1bSJed Brown       v = zero;
292*c4762a1bSJed Brown       if (i < nx && j > 0) vb = x[k-nx];
293*c4762a1bSJed Brown       if (i > 0 && j < ny) vl = x[k-1];
294*c4762a1bSJed Brown       if (i < nx && j < ny) v = x[k];
295*c4762a1bSJed Brown       dvdx = (v-vl)/hx;
296*c4762a1bSJed Brown       dvdy = (v-vb)/hy;
297*c4762a1bSJed Brown       fquad = fquad + dvdx*dvdx + dvdy*dvdy;
298*c4762a1bSJed Brown       flin = flin - cdiv3*(vb+vl+v);
299*c4762a1bSJed Brown     }
300*c4762a1bSJed Brown   }
301*c4762a1bSJed Brown 
302*c4762a1bSJed Brown   /* Restore vector */
303*c4762a1bSJed Brown   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
304*c4762a1bSJed Brown 
305*c4762a1bSJed Brown   /* Scale the function */
306*c4762a1bSJed Brown   area = p5*hx*hy;
307*c4762a1bSJed Brown   *f = area*(p5*fquad+flin);
308*c4762a1bSJed Brown 
309*c4762a1bSJed Brown   ierr = PetscLogFlops(nx*ny*24);CHKERRQ(ierr);
310*c4762a1bSJed Brown   PetscFunctionReturn(0);
311*c4762a1bSJed Brown }
312*c4762a1bSJed Brown 
313*c4762a1bSJed Brown /* ------------------------------------------------------------------- */
314*c4762a1bSJed Brown /*
315*c4762a1bSJed Brown     FormGradient - Evaluates the gradient, G(X).
316*c4762a1bSJed Brown 
317*c4762a1bSJed Brown     Input Parameters:
318*c4762a1bSJed Brown .   tao  - the Tao context
319*c4762a1bSJed Brown .   X    - input vector
320*c4762a1bSJed Brown .   ptr  - optional user-defined context
321*c4762a1bSJed Brown 
322*c4762a1bSJed Brown     Output Parameters:
323*c4762a1bSJed Brown .   G - vector containing the newly evaluated gradient
324*c4762a1bSJed Brown */
325*c4762a1bSJed Brown PetscErrorCode FormGradient(Tao tao,Vec X,Vec G,void *ptr)
326*c4762a1bSJed Brown {
327*c4762a1bSJed Brown   AppCtx            *user = (AppCtx *) ptr;
328*c4762a1bSJed Brown   PetscReal         zero=0.0, p5=0.5, three = 3.0, area, val;
329*c4762a1bSJed Brown   PetscErrorCode    ierr;
330*c4762a1bSJed Brown   PetscInt          nx = user->mx, ny = user->my, ind, i, j, k;
331*c4762a1bSJed Brown   PetscReal         hx = user->hx, hy = user->hy;
332*c4762a1bSJed Brown   PetscReal         vb, vl, vr, vt, dvdx, dvdy;
333*c4762a1bSJed Brown   PetscReal         v, cdiv3 = user->param/three;
334*c4762a1bSJed Brown   const PetscScalar *x;
335*c4762a1bSJed Brown 
336*c4762a1bSJed Brown   PetscFunctionBeginUser;
337*c4762a1bSJed Brown   /* Initialize gradient to zero */
338*c4762a1bSJed Brown   ierr = VecSet(G, zero);CHKERRQ(ierr);
339*c4762a1bSJed Brown 
340*c4762a1bSJed Brown   /* Get pointer to vector data */
341*c4762a1bSJed Brown   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
342*c4762a1bSJed Brown 
343*c4762a1bSJed Brown   /* Compute gradient contributions over the lower triangular elements */
344*c4762a1bSJed Brown   for (j=-1; j<ny; j++) {
345*c4762a1bSJed Brown     for (i=-1; i<nx; i++) {
346*c4762a1bSJed Brown       k  = nx*j + i;
347*c4762a1bSJed Brown       v  = zero;
348*c4762a1bSJed Brown       vr = zero;
349*c4762a1bSJed Brown       vt = zero;
350*c4762a1bSJed Brown       if (i >= 0 && j >= 0)    v = x[k];
351*c4762a1bSJed Brown       if (i < nx-1 && j > -1) vr = x[k+1];
352*c4762a1bSJed Brown       if (i > -1 && j < ny-1) vt = x[k+nx];
353*c4762a1bSJed Brown       dvdx = (vr-v)/hx;
354*c4762a1bSJed Brown       dvdy = (vt-v)/hy;
355*c4762a1bSJed Brown       if (i != -1 && j != -1) {
356*c4762a1bSJed Brown         ind = k; val = - dvdx/hx - dvdy/hy - cdiv3;
357*c4762a1bSJed Brown         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
358*c4762a1bSJed Brown       }
359*c4762a1bSJed Brown       if (i != nx-1 && j != -1) {
360*c4762a1bSJed Brown         ind = k+1; val =  dvdx/hx - cdiv3;
361*c4762a1bSJed Brown         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
362*c4762a1bSJed Brown       }
363*c4762a1bSJed Brown       if (i != -1 && j != ny-1) {
364*c4762a1bSJed Brown         ind = k+nx; val = dvdy/hy - cdiv3;
365*c4762a1bSJed Brown         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
366*c4762a1bSJed Brown       }
367*c4762a1bSJed Brown     }
368*c4762a1bSJed Brown   }
369*c4762a1bSJed Brown 
370*c4762a1bSJed Brown   /* Compute gradient contributions over the upper triangular elements */
371*c4762a1bSJed Brown   for (j=0; j<=ny; j++) {
372*c4762a1bSJed Brown     for (i=0; i<=nx; i++) {
373*c4762a1bSJed Brown       k = nx*j + i;
374*c4762a1bSJed Brown       vb = zero;
375*c4762a1bSJed Brown       vl = zero;
376*c4762a1bSJed Brown       v  = zero;
377*c4762a1bSJed Brown       if (i < nx && j > 0) vb = x[k-nx];
378*c4762a1bSJed Brown       if (i > 0 && j < ny) vl = x[k-1];
379*c4762a1bSJed Brown       if (i < nx && j < ny) v = x[k];
380*c4762a1bSJed Brown       dvdx = (v-vl)/hx;
381*c4762a1bSJed Brown       dvdy = (v-vb)/hy;
382*c4762a1bSJed Brown       if (i != nx && j != 0) {
383*c4762a1bSJed Brown         ind = k-nx; val = - dvdy/hy - cdiv3;
384*c4762a1bSJed Brown         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
385*c4762a1bSJed Brown       }
386*c4762a1bSJed Brown       if (i != 0 && j != ny) {
387*c4762a1bSJed Brown         ind = k-1; val =  - dvdx/hx - cdiv3;
388*c4762a1bSJed Brown         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
389*c4762a1bSJed Brown       }
390*c4762a1bSJed Brown       if (i != nx && j != ny) {
391*c4762a1bSJed Brown         ind = k; val =  dvdx/hx + dvdy/hy - cdiv3;
392*c4762a1bSJed Brown         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
393*c4762a1bSJed Brown       }
394*c4762a1bSJed Brown     }
395*c4762a1bSJed Brown   }
396*c4762a1bSJed Brown   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
397*c4762a1bSJed Brown 
398*c4762a1bSJed Brown   /* Assemble gradient vector */
399*c4762a1bSJed Brown   ierr = VecAssemblyBegin(G);CHKERRQ(ierr);
400*c4762a1bSJed Brown   ierr = VecAssemblyEnd(G);CHKERRQ(ierr);
401*c4762a1bSJed Brown 
402*c4762a1bSJed Brown   /* Scale the gradient */
403*c4762a1bSJed Brown   area = p5*hx*hy;
404*c4762a1bSJed Brown   ierr = VecScale(G, area);CHKERRQ(ierr);
405*c4762a1bSJed Brown   ierr = PetscLogFlops(nx*ny*24);CHKERRQ(ierr);
406*c4762a1bSJed Brown   PetscFunctionReturn(0);
407*c4762a1bSJed Brown }
408*c4762a1bSJed Brown 
409*c4762a1bSJed Brown /* ------------------------------------------------------------------- */
410*c4762a1bSJed Brown /*
411*c4762a1bSJed Brown    FormHessian - Forms the Hessian matrix.
412*c4762a1bSJed Brown 
413*c4762a1bSJed Brown    Input Parameters:
414*c4762a1bSJed Brown .  tao - the Tao context
415*c4762a1bSJed Brown .  X    - the input vector
416*c4762a1bSJed Brown .  ptr  - optional user-defined context, as set by TaoSetHessian()
417*c4762a1bSJed Brown 
418*c4762a1bSJed Brown    Output Parameters:
419*c4762a1bSJed Brown .  H     - Hessian matrix
420*c4762a1bSJed Brown .  PrecH - optionally different preconditioning Hessian
421*c4762a1bSJed Brown .  flag  - flag indicating matrix structure
422*c4762a1bSJed Brown 
423*c4762a1bSJed Brown    Notes:
424*c4762a1bSJed Brown    This routine is intended simply as an example of the interface
425*c4762a1bSJed Brown    to a Hessian evaluation routine.  Since this example compute the
426*c4762a1bSJed Brown    Hessian a column at a time, it is not particularly efficient and
427*c4762a1bSJed Brown    is not recommended.
428*c4762a1bSJed Brown */
429*c4762a1bSJed Brown PetscErrorCode FormHessian(Tao tao,Vec X,Mat H,Mat Hpre, void *ptr)
430*c4762a1bSJed Brown {
431*c4762a1bSJed Brown   AppCtx         *user = (AppCtx *) ptr;
432*c4762a1bSJed Brown   PetscErrorCode ierr;
433*c4762a1bSJed Brown   PetscInt       i,j, ndim = user->ndim;
434*c4762a1bSJed Brown   PetscReal      *y, zero = 0.0, one = 1.0;
435*c4762a1bSJed Brown   PetscBool      assembled;
436*c4762a1bSJed Brown 
437*c4762a1bSJed Brown   PetscFunctionBeginUser;
438*c4762a1bSJed Brown   user->xvec = X;
439*c4762a1bSJed Brown 
440*c4762a1bSJed Brown   /* Initialize Hessian entries and work vector to zero */
441*c4762a1bSJed Brown   ierr = MatAssembled(H,&assembled);CHKERRQ(ierr);
442*c4762a1bSJed Brown   if (assembled){ierr = MatZeroEntries(H); CHKERRQ(ierr);}
443*c4762a1bSJed Brown 
444*c4762a1bSJed Brown   ierr = VecSet(user->s, zero);CHKERRQ(ierr);
445*c4762a1bSJed Brown 
446*c4762a1bSJed Brown   /* Loop over matrix columns to compute entries of the Hessian */
447*c4762a1bSJed Brown   for (j=0; j<ndim; j++) {
448*c4762a1bSJed Brown     ierr = VecSetValues(user->s,1,&j,&one,INSERT_VALUES);CHKERRQ(ierr);
449*c4762a1bSJed Brown     ierr = VecAssemblyBegin(user->s);CHKERRQ(ierr);
450*c4762a1bSJed Brown     ierr = VecAssemblyEnd(user->s);CHKERRQ(ierr);
451*c4762a1bSJed Brown 
452*c4762a1bSJed Brown     ierr = HessianProduct(ptr,user->s,user->y);CHKERRQ(ierr);
453*c4762a1bSJed Brown 
454*c4762a1bSJed Brown     ierr = VecSetValues(user->s,1,&j,&zero,INSERT_VALUES);CHKERRQ(ierr);
455*c4762a1bSJed Brown     ierr = VecAssemblyBegin(user->s);CHKERRQ(ierr);
456*c4762a1bSJed Brown     ierr = VecAssemblyEnd(user->s);CHKERRQ(ierr);
457*c4762a1bSJed Brown 
458*c4762a1bSJed Brown     ierr = VecGetArray(user->y,&y);CHKERRQ(ierr);
459*c4762a1bSJed Brown     for (i=0; i<ndim; i++) {
460*c4762a1bSJed Brown       if (y[i] != zero) {
461*c4762a1bSJed Brown         ierr = MatSetValues(H,1,&i,1,&j,&y[i],ADD_VALUES);CHKERRQ(ierr);
462*c4762a1bSJed Brown       }
463*c4762a1bSJed Brown     }
464*c4762a1bSJed Brown     ierr = VecRestoreArray(user->y,&y);CHKERRQ(ierr);
465*c4762a1bSJed Brown   }
466*c4762a1bSJed Brown   ierr = MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
467*c4762a1bSJed Brown   ierr = MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
468*c4762a1bSJed Brown   PetscFunctionReturn(0);
469*c4762a1bSJed Brown }
470*c4762a1bSJed Brown 
471*c4762a1bSJed Brown /* ------------------------------------------------------------------- */
472*c4762a1bSJed Brown /*
473*c4762a1bSJed Brown    MatrixFreeHessian - Sets a pointer for use in computing Hessian-vector
474*c4762a1bSJed Brown    products.
475*c4762a1bSJed Brown 
476*c4762a1bSJed Brown    Input Parameters:
477*c4762a1bSJed Brown .  tao - the Tao context
478*c4762a1bSJed Brown .  X    - the input vector
479*c4762a1bSJed Brown .  ptr  - optional user-defined context, as set by TaoSetHessian()
480*c4762a1bSJed Brown 
481*c4762a1bSJed Brown    Output Parameters:
482*c4762a1bSJed Brown .  H     - Hessian matrix
483*c4762a1bSJed Brown .  PrecH - optionally different preconditioning Hessian
484*c4762a1bSJed Brown .  flag  - flag indicating matrix structure
485*c4762a1bSJed Brown */
486*c4762a1bSJed Brown PetscErrorCode MatrixFreeHessian(Tao tao,Vec X,Mat H,Mat PrecH, void *ptr)
487*c4762a1bSJed Brown {
488*c4762a1bSJed Brown   AppCtx     *user = (AppCtx *) ptr;
489*c4762a1bSJed Brown 
490*c4762a1bSJed Brown   /* Sets location of vector for use in computing matrix-vector products  of the form H(X)*y  */
491*c4762a1bSJed Brown   user->xvec = X;
492*c4762a1bSJed Brown   PetscFunctionReturn(0);
493*c4762a1bSJed Brown }
494*c4762a1bSJed Brown 
495*c4762a1bSJed Brown /* ------------------------------------------------------------------- */
496*c4762a1bSJed Brown /*
497*c4762a1bSJed Brown    HessianProductMat - Computes the matrix-vector product
498*c4762a1bSJed Brown    y = mat*svec.
499*c4762a1bSJed Brown 
500*c4762a1bSJed Brown    Input Parameters:
501*c4762a1bSJed Brown .  mat  - input matrix
502*c4762a1bSJed Brown .  svec - input vector
503*c4762a1bSJed Brown 
504*c4762a1bSJed Brown    Output Parameters:
505*c4762a1bSJed Brown .  y    - solution vector
506*c4762a1bSJed Brown */
507*c4762a1bSJed Brown PetscErrorCode HessianProductMat(Mat mat,Vec svec,Vec y)
508*c4762a1bSJed Brown {
509*c4762a1bSJed Brown   void           *ptr;
510*c4762a1bSJed Brown   PetscErrorCode ierr;
511*c4762a1bSJed Brown 
512*c4762a1bSJed Brown   PetscFunctionBeginUser;
513*c4762a1bSJed Brown   ierr = MatShellGetContext(mat,&ptr);CHKERRQ(ierr);
514*c4762a1bSJed Brown   ierr = HessianProduct(ptr,svec,y);CHKERRQ(ierr);
515*c4762a1bSJed Brown   PetscFunctionReturn(0);
516*c4762a1bSJed Brown }
517*c4762a1bSJed Brown 
518*c4762a1bSJed Brown /* ------------------------------------------------------------------- */
519*c4762a1bSJed Brown /*
520*c4762a1bSJed Brown    Hessian Product - Computes the matrix-vector product:
521*c4762a1bSJed Brown    y = f''(x)*svec.
522*c4762a1bSJed Brown 
523*c4762a1bSJed Brown    Input Parameters
524*c4762a1bSJed Brown .  ptr  - pointer to the user-defined context
525*c4762a1bSJed Brown .  svec - input vector
526*c4762a1bSJed Brown 
527*c4762a1bSJed Brown    Output Parameters:
528*c4762a1bSJed Brown .  y    - product vector
529*c4762a1bSJed Brown */
530*c4762a1bSJed Brown PetscErrorCode HessianProduct(void *ptr,Vec svec,Vec y)
531*c4762a1bSJed Brown {
532*c4762a1bSJed Brown   AppCtx            *user = (AppCtx *)ptr;
533*c4762a1bSJed Brown   PetscReal         p5 = 0.5, zero = 0.0, one = 1.0, hx, hy, val, area;
534*c4762a1bSJed Brown   const PetscScalar *x, *s;
535*c4762a1bSJed Brown   PetscReal         v, vb, vl, vr, vt, hxhx, hyhy;
536*c4762a1bSJed Brown   PetscErrorCode    ierr;
537*c4762a1bSJed Brown   PetscInt          nx, ny, i, j, k, ind;
538*c4762a1bSJed Brown 
539*c4762a1bSJed Brown   PetscFunctionBeginUser;
540*c4762a1bSJed Brown   nx   = user->mx;
541*c4762a1bSJed Brown   ny   = user->my;
542*c4762a1bSJed Brown   hx   = user->hx;
543*c4762a1bSJed Brown   hy   = user->hy;
544*c4762a1bSJed Brown   hxhx = one/(hx*hx);
545*c4762a1bSJed Brown   hyhy = one/(hy*hy);
546*c4762a1bSJed Brown 
547*c4762a1bSJed Brown   /* Get pointers to vector data */
548*c4762a1bSJed Brown   ierr = VecGetArrayRead(user->xvec,&x);CHKERRQ(ierr);
549*c4762a1bSJed Brown   ierr = VecGetArrayRead(svec,&s);CHKERRQ(ierr);
550*c4762a1bSJed Brown 
551*c4762a1bSJed Brown   /* Initialize product vector to zero */
552*c4762a1bSJed Brown   ierr = VecSet(y, zero);CHKERRQ(ierr);
553*c4762a1bSJed Brown 
554*c4762a1bSJed Brown   /* Compute f''(x)*s over the lower triangular elements */
555*c4762a1bSJed Brown   for (j=-1; j<ny; j++) {
556*c4762a1bSJed Brown     for (i=-1; i<nx; i++) {
557*c4762a1bSJed Brown        k = nx*j + i;
558*c4762a1bSJed Brown        v = zero;
559*c4762a1bSJed Brown        vr = zero;
560*c4762a1bSJed Brown        vt = zero;
561*c4762a1bSJed Brown        if (i != -1 && j != -1) v = s[k];
562*c4762a1bSJed Brown        if (i != nx-1 && j != -1) {
563*c4762a1bSJed Brown          vr = s[k+1];
564*c4762a1bSJed Brown          ind = k+1; val = hxhx*(vr-v);
565*c4762a1bSJed Brown          ierr = VecSetValues(y,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
566*c4762a1bSJed Brown        }
567*c4762a1bSJed Brown        if (i != -1 && j != ny-1) {
568*c4762a1bSJed Brown          vt = s[k+nx];
569*c4762a1bSJed Brown          ind = k+nx; val = hyhy*(vt-v);
570*c4762a1bSJed Brown          ierr = VecSetValues(y,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
571*c4762a1bSJed Brown        }
572*c4762a1bSJed Brown        if (i != -1 && j != -1) {
573*c4762a1bSJed Brown          ind = k; val = hxhx*(v-vr) + hyhy*(v-vt);
574*c4762a1bSJed Brown          ierr = VecSetValues(y,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
575*c4762a1bSJed Brown        }
576*c4762a1bSJed Brown      }
577*c4762a1bSJed Brown    }
578*c4762a1bSJed Brown 
579*c4762a1bSJed Brown   /* Compute f''(x)*s over the upper triangular elements */
580*c4762a1bSJed Brown   for (j=0; j<=ny; j++) {
581*c4762a1bSJed Brown     for (i=0; i<=nx; i++) {
582*c4762a1bSJed Brown        k = nx*j + i;
583*c4762a1bSJed Brown        v = zero;
584*c4762a1bSJed Brown        vl = zero;
585*c4762a1bSJed Brown        vb = zero;
586*c4762a1bSJed Brown        if (i != nx && j != ny) v = s[k];
587*c4762a1bSJed Brown        if (i != nx && j != 0) {
588*c4762a1bSJed Brown          vb = s[k-nx];
589*c4762a1bSJed Brown          ind = k-nx; val = hyhy*(vb-v);
590*c4762a1bSJed Brown          ierr = VecSetValues(y,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
591*c4762a1bSJed Brown        }
592*c4762a1bSJed Brown        if (i != 0 && j != ny) {
593*c4762a1bSJed Brown          vl = s[k-1];
594*c4762a1bSJed Brown          ind = k-1; val = hxhx*(vl-v);
595*c4762a1bSJed Brown          ierr = VecSetValues(y,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
596*c4762a1bSJed Brown        }
597*c4762a1bSJed Brown        if (i != nx && j != ny) {
598*c4762a1bSJed Brown          ind = k; val = hxhx*(v-vl) + hyhy*(v-vb);
599*c4762a1bSJed Brown          ierr = VecSetValues(y,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
600*c4762a1bSJed Brown        }
601*c4762a1bSJed Brown     }
602*c4762a1bSJed Brown   }
603*c4762a1bSJed Brown   /* Restore vector data */
604*c4762a1bSJed Brown   ierr = VecRestoreArrayRead(svec,&s);CHKERRQ(ierr);
605*c4762a1bSJed Brown   ierr = VecRestoreArrayRead(user->xvec,&x);CHKERRQ(ierr);
606*c4762a1bSJed Brown 
607*c4762a1bSJed Brown   /* Assemble vector */
608*c4762a1bSJed Brown   ierr = VecAssemblyBegin(y);CHKERRQ(ierr);
609*c4762a1bSJed Brown   ierr = VecAssemblyEnd(y);CHKERRQ(ierr);
610*c4762a1bSJed Brown 
611*c4762a1bSJed Brown   /* Scale resulting vector by area */
612*c4762a1bSJed Brown   area = p5*hx*hy;
613*c4762a1bSJed Brown   ierr = VecScale(y, area);CHKERRQ(ierr);
614*c4762a1bSJed Brown   ierr = PetscLogFlops(nx*ny*18);CHKERRQ(ierr);
615*c4762a1bSJed Brown   PetscFunctionReturn(0);
616*c4762a1bSJed Brown }
617*c4762a1bSJed Brown 
618*c4762a1bSJed Brown 
619*c4762a1bSJed Brown /*TEST
620*c4762a1bSJed Brown 
621*c4762a1bSJed Brown    build:
622*c4762a1bSJed Brown       requires: !complex
623*c4762a1bSJed Brown 
624*c4762a1bSJed Brown    test:
625*c4762a1bSJed Brown       suffix: 1
626*c4762a1bSJed Brown       args: -tao_smonitor -tao_type ntl -tao_gatol 1.e-4
627*c4762a1bSJed Brown 
628*c4762a1bSJed Brown    test:
629*c4762a1bSJed Brown       suffix: 2
630*c4762a1bSJed Brown       args: -tao_smonitor -tao_type ntr -tao_gatol 1.e-4
631*c4762a1bSJed Brown 
632*c4762a1bSJed Brown    test:
633*c4762a1bSJed Brown       suffix: 3
634*c4762a1bSJed Brown       args: -tao_smonitor -tao_type bntr -tao_gatol 1.e-4 -my_tao_mf -tao_test_hessian
635*c4762a1bSJed Brown 
636*c4762a1bSJed Brown    test:
637*c4762a1bSJed Brown      suffix: 4
638*c4762a1bSJed Brown      args: -tao_smonitor -tao_gatol 1e-3 -tao_type bqnls
639*c4762a1bSJed Brown 
640*c4762a1bSJed Brown    test:
641*c4762a1bSJed Brown      suffix: 5
642*c4762a1bSJed Brown      args: -tao_smonitor -tao_gatol 1e-3 -tao_type blmvm
643*c4762a1bSJed Brown 
644*c4762a1bSJed Brown    test:
645*c4762a1bSJed Brown      suffix: 6
646*c4762a1bSJed Brown      args: -tao_smonitor -tao_gatol 1e-3 -tao_type bqnktr -tao_bqnk_mat_type lmvmsr1
647*c4762a1bSJed Brown 
648*c4762a1bSJed Brown TEST*/
649