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