xref: /petsc/src/tao/unconstrained/tutorials/eptorsion1.c (revision 2f613bf53f46f9356e00a2ca2bd69453be72fc31)
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    - system 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 static  char help[]=
32 "Demonstrates use of the TAO package to solve \n\
33 unconstrained minimization problems on a single processor.  This example \n\
34 is based on the Elastic-Plastic Torsion (dept) problem from the MINPACK-2 \n\
35 test suite.\n\
36 The command line options are:\n\
37   -mx <xg>, where <xg> = number of grid points in the 1st coordinate direction\n\
38   -my <yg>, where <yg> = number of grid points in the 2nd coordinate direction\n\
39   -par <param>, where <param> = angle of twist per unit length\n\n";
40 
41 /*T
42    Concepts: TAO^Solving an unconstrained minimization problem
43    Routines: TaoCreate(); TaoSetType();
44    Routines: TaoSetInitialVector();
45    Routines: TaoSetObjectiveAndGradientRoutine();
46    Routines: TaoSetHessianRoutine(); TaoSetFromOptions();
47    Routines: TaoGetKSP(); TaoSolve();
48    Routines: TaoDestroy();
49    Processors: 1
50 T*/
51 
52 /*
53    User-defined application context - contains data needed by the
54    application-provided call-back routines, FormFunction(),
55    FormGradient(), and FormHessian().
56 */
57 
58 typedef struct {
59    PetscReal  param;      /* nonlinearity parameter */
60    PetscInt   mx, my;     /* discretization in x- and y-directions */
61    PetscInt   ndim;       /* problem dimension */
62    Vec        s, y, xvec; /* work space for computing Hessian */
63    PetscReal  hx, hy;     /* mesh spacing in x- and y-directions */
64 } AppCtx;
65 
66 /* -------- User-defined Routines --------- */
67 
68 PetscErrorCode FormInitialGuess(AppCtx*,Vec);
69 PetscErrorCode FormFunction(Tao,Vec,PetscReal*,void*);
70 PetscErrorCode FormGradient(Tao,Vec,Vec,void*);
71 PetscErrorCode FormHessian(Tao,Vec,Mat,Mat, void*);
72 PetscErrorCode HessianProductMat(Mat,Vec,Vec);
73 PetscErrorCode HessianProduct(void*,Vec,Vec);
74 PetscErrorCode MatrixFreeHessian(Tao,Vec,Mat,Mat,void*);
75 PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal *,Vec,void *);
76 
77 PetscErrorCode main(int argc,char **argv)
78 {
79   PetscErrorCode     ierr;                /* used to check for functions returning nonzeros */
80   PetscInt           mx=10;               /* discretization in x-direction */
81   PetscInt           my=10;               /* discretization in y-direction */
82   Vec                x;                   /* solution, gradient vectors */
83   PetscBool          flg;                 /* A return value when checking for use options */
84   Tao                tao;                 /* Tao solver context */
85   Mat                H;                   /* Hessian matrix */
86   AppCtx             user;                /* application context */
87   PetscMPIInt        size;                /* number of processes */
88   PetscReal          one=1.0;
89 
90   PetscBool          test_lmvm = PETSC_FALSE;
91   KSP                ksp;
92   PC                 pc;
93   Mat                M;
94   Vec                in, out, out2;
95   PetscReal          mult_solve_dist;
96 
97   /* Initialize TAO,PETSc */
98   ierr = PetscInitialize(&argc,&argv,(char *)0,help);if (ierr) return ierr;
99   ierr = MPI_Comm_size(MPI_COMM_WORLD,&size);CHKERRMPI(ierr);
100   if (size >1) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"Incorrect number of processors");
101 
102   /* Specify default parameters for the problem, check for command-line overrides */
103   user.param = 5.0;
104   ierr = PetscOptionsGetInt(NULL,NULL,"-my",&my,&flg);CHKERRQ(ierr);
105   ierr = PetscOptionsGetInt(NULL,NULL,"-mx",&mx,&flg);CHKERRQ(ierr);
106   ierr = PetscOptionsGetReal(NULL,NULL,"-par",&user.param,&flg);CHKERRQ(ierr);
107   ierr = PetscOptionsGetBool(NULL,NULL,"-test_lmvm",&test_lmvm,&flg);CHKERRQ(ierr);
108 
109   ierr = PetscPrintf(PETSC_COMM_SELF,"\n---- Elastic-Plastic Torsion Problem -----\n");CHKERRQ(ierr);
110   ierr = PetscPrintf(PETSC_COMM_SELF,"mx: %D     my: %D   \n\n",mx,my);CHKERRQ(ierr);
111   user.ndim = mx * my; user.mx = mx; user.my = my;
112   user.hx = one/(mx+1); user.hy = one/(my+1);
113 
114   /* Allocate vectors */
115   ierr = VecCreateSeq(PETSC_COMM_SELF,user.ndim,&user.y);CHKERRQ(ierr);
116   ierr = VecDuplicate(user.y,&user.s);CHKERRQ(ierr);
117   ierr = VecDuplicate(user.y,&x);CHKERRQ(ierr);
118 
119   /* Create TAO solver and set desired solution method */
120   ierr = TaoCreate(PETSC_COMM_SELF,&tao);CHKERRQ(ierr);
121   ierr = TaoSetType(tao,TAOLMVM);CHKERRQ(ierr);
122 
123   /* Set solution vector with an initial guess */
124   ierr = FormInitialGuess(&user,x);CHKERRQ(ierr);
125   ierr = TaoSetInitialVector(tao,x);CHKERRQ(ierr);
126 
127   /* Set routine for function and gradient evaluation */
128   ierr = TaoSetObjectiveAndGradientRoutine(tao,FormFunctionGradient,(void *)&user);CHKERRQ(ierr);
129 
130   /* From command line options, determine if using matrix-free hessian */
131   ierr = PetscOptionsHasName(NULL,NULL,"-my_tao_mf",&flg);CHKERRQ(ierr);
132   if (flg) {
133     ierr = MatCreateShell(PETSC_COMM_SELF,user.ndim,user.ndim,user.ndim,user.ndim,(void*)&user,&H);CHKERRQ(ierr);
134     ierr = MatShellSetOperation(H,MATOP_MULT,(void(*)(void))HessianProductMat);CHKERRQ(ierr);
135     ierr = MatSetOption(H,MAT_SYMMETRIC,PETSC_TRUE);CHKERRQ(ierr);
136 
137     ierr = TaoSetHessianRoutine(tao,H,H,MatrixFreeHessian,(void *)&user);CHKERRQ(ierr);
138   } else {
139     ierr = MatCreateSeqAIJ(PETSC_COMM_SELF,user.ndim,user.ndim,5,NULL,&H);CHKERRQ(ierr);
140     ierr = MatSetOption(H,MAT_SYMMETRIC,PETSC_TRUE);CHKERRQ(ierr);
141     ierr = TaoSetHessianRoutine(tao,H,H,FormHessian,(void *)&user);CHKERRQ(ierr);
142   }
143 
144   /* Test the LMVM matrix */
145   if (test_lmvm) {
146     ierr = PetscOptionsSetValue(NULL, "-tao_type", "bntr");CHKERRQ(ierr);
147     ierr = PetscOptionsSetValue(NULL, "-tao_bnk_pc_type", "lmvm");CHKERRQ(ierr);
148   }
149 
150   /* Check for any TAO command line options */
151   ierr = TaoSetFromOptions(tao);CHKERRQ(ierr);
152 
153   /* SOLVE THE APPLICATION */
154   ierr = TaoSolve(tao);CHKERRQ(ierr);
155 
156   /* Test the LMVM matrix */
157   if (test_lmvm) {
158     ierr = TaoGetKSP(tao, &ksp);CHKERRQ(ierr);
159     ierr = KSPGetPC(ksp, &pc);CHKERRQ(ierr);
160     ierr = PCLMVMGetMatLMVM(pc, &M);CHKERRQ(ierr);
161     ierr = VecDuplicate(x, &in);CHKERRQ(ierr);
162     ierr = VecDuplicate(x, &out);CHKERRQ(ierr);
163     ierr = VecDuplicate(x, &out2);CHKERRQ(ierr);
164     ierr = VecSet(in, 5.0);CHKERRQ(ierr);
165     ierr = MatMult(M, in, out);CHKERRQ(ierr);
166     ierr = MatSolve(M, out, out2);CHKERRQ(ierr);
167     ierr = VecAXPY(out2, -1.0, in);CHKERRQ(ierr);
168     ierr = VecNorm(out2, NORM_2, &mult_solve_dist);CHKERRQ(ierr);
169     ierr = PetscPrintf(PetscObjectComm((PetscObject)tao), "error between MatMult and MatSolve: %e\n", mult_solve_dist);CHKERRQ(ierr);
170     ierr = VecDestroy(&in);CHKERRQ(ierr);
171     ierr = VecDestroy(&out);CHKERRQ(ierr);
172     ierr = VecDestroy(&out2);CHKERRQ(ierr);
173   }
174 
175   ierr = TaoDestroy(&tao);CHKERRQ(ierr);
176   ierr = VecDestroy(&user.s);CHKERRQ(ierr);
177   ierr = VecDestroy(&user.y);CHKERRQ(ierr);
178   ierr = VecDestroy(&x);CHKERRQ(ierr);
179   ierr = MatDestroy(&H);CHKERRQ(ierr);
180 
181   ierr = PetscFinalize();
182   return ierr;
183 }
184 
185 /* ------------------------------------------------------------------- */
186 /*
187     FormInitialGuess - Computes an initial approximation to the solution.
188 
189     Input Parameters:
190 .   user - user-defined application context
191 .   X    - vector
192 
193     Output Parameters:
194 .   X    - vector
195 */
196 PetscErrorCode FormInitialGuess(AppCtx *user,Vec X)
197 {
198   PetscReal      hx = user->hx, hy = user->hy, temp;
199   PetscReal      val;
200   PetscErrorCode ierr;
201   PetscInt       i, j, k, nx = user->mx, ny = user->my;
202 
203   /* Compute initial guess */
204   PetscFunctionBeginUser;
205   for (j=0; j<ny; j++) {
206     temp = PetscMin(j+1,ny-j)*hy;
207     for (i=0; i<nx; i++) {
208       k   = nx*j + i;
209       val = PetscMin((PetscMin(i+1,nx-i))*hx,temp);
210       ierr = VecSetValues(X,1,&k,&val,ADD_VALUES);CHKERRQ(ierr);
211     }
212   }
213   ierr = VecAssemblyBegin(X);CHKERRQ(ierr);
214   ierr = VecAssemblyEnd(X);CHKERRQ(ierr);
215   PetscFunctionReturn(0);
216 }
217 
218 /* ------------------------------------------------------------------- */
219 /*
220    FormFunctionGradient - Evaluates the function and corresponding gradient.
221 
222    Input Parameters:
223    tao - the Tao context
224    X   - the input vector
225    ptr - optional user-defined context, as set by TaoSetFunction()
226 
227    Output Parameters:
228    f   - the newly evaluated function
229    G   - the newly evaluated gradient
230 */
231 PetscErrorCode FormFunctionGradient(Tao tao,Vec X,PetscReal *f,Vec G,void *ptr)
232 {
233   PetscErrorCode ierr;
234 
235   PetscFunctionBeginUser;
236   ierr = FormFunction(tao,X,f,ptr);CHKERRQ(ierr);
237   ierr = FormGradient(tao,X,G,ptr);CHKERRQ(ierr);
238   PetscFunctionReturn(0);
239 }
240 
241 /* ------------------------------------------------------------------- */
242 /*
243    FormFunction - Evaluates the function, f(X).
244 
245    Input Parameters:
246 .  tao - the Tao context
247 .  X   - the input vector
248 .  ptr - optional user-defined context, as set by TaoSetFunction()
249 
250    Output Parameters:
251 .  f    - the newly evaluated function
252 */
253 PetscErrorCode FormFunction(Tao tao,Vec X,PetscReal *f,void *ptr)
254 {
255   AppCtx            *user = (AppCtx *) ptr;
256   PetscReal         hx = user->hx, hy = user->hy, area, three = 3.0, p5 = 0.5;
257   PetscReal         zero = 0.0, vb, vl, vr, vt, dvdx, dvdy, flin = 0.0, fquad = 0.0;
258   PetscReal         v, cdiv3 = user->param/three;
259   const PetscScalar *x;
260   PetscErrorCode    ierr;
261   PetscInt          nx = user->mx, ny = user->my, i, j, k;
262 
263   PetscFunctionBeginUser;
264   /* Get pointer to vector data */
265   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
266 
267   /* Compute function contributions over the lower triangular elements */
268   for (j=-1; j<ny; j++) {
269     for (i=-1; i<nx; i++) {
270       k = nx*j + i;
271       v = zero;
272       vr = zero;
273       vt = zero;
274       if (i >= 0 && j >= 0) v = x[k];
275       if (i < nx-1 && j > -1) vr = x[k+1];
276       if (i > -1 && j < ny-1) vt = x[k+nx];
277       dvdx = (vr-v)/hx;
278       dvdy = (vt-v)/hy;
279       fquad += dvdx*dvdx + dvdy*dvdy;
280       flin -= cdiv3*(v+vr+vt);
281     }
282   }
283 
284   /* Compute function contributions over the upper triangular elements */
285   for (j=0; j<=ny; j++) {
286     for (i=0; i<=nx; i++) {
287       k = nx*j + i;
288       vb = zero;
289       vl = zero;
290       v = zero;
291       if (i < nx && j > 0) vb = x[k-nx];
292       if (i > 0 && j < ny) vl = x[k-1];
293       if (i < nx && j < ny) v = x[k];
294       dvdx = (v-vl)/hx;
295       dvdy = (v-vb)/hy;
296       fquad = fquad + dvdx*dvdx + dvdy*dvdy;
297       flin = flin - cdiv3*(vb+vl+v);
298     }
299   }
300 
301   /* Restore vector */
302   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
303 
304   /* Scale the function */
305   area = p5*hx*hy;
306   *f = area*(p5*fquad+flin);
307 
308   ierr = PetscLogFlops(24.0*nx*ny);CHKERRQ(ierr);
309   PetscFunctionReturn(0);
310 }
311 
312 /* ------------------------------------------------------------------- */
313 /*
314     FormGradient - Evaluates the gradient, G(X).
315 
316     Input Parameters:
317 .   tao  - the Tao context
318 .   X    - input vector
319 .   ptr  - optional user-defined context
320 
321     Output Parameters:
322 .   G - vector containing the newly evaluated gradient
323 */
324 PetscErrorCode FormGradient(Tao tao,Vec X,Vec G,void *ptr)
325 {
326   AppCtx            *user = (AppCtx *) ptr;
327   PetscReal         zero=0.0, p5=0.5, three = 3.0, area, val;
328   PetscErrorCode    ierr;
329   PetscInt          nx = user->mx, ny = user->my, ind, i, j, k;
330   PetscReal         hx = user->hx, hy = user->hy;
331   PetscReal         vb, vl, vr, vt, dvdx, dvdy;
332   PetscReal         v, cdiv3 = user->param/three;
333   const PetscScalar *x;
334 
335   PetscFunctionBeginUser;
336   /* Initialize gradient to zero */
337   ierr = VecSet(G, zero);CHKERRQ(ierr);
338 
339   /* Get pointer to vector data */
340   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
341 
342   /* Compute gradient contributions over the lower triangular elements */
343   for (j=-1; j<ny; j++) {
344     for (i=-1; i<nx; i++) {
345       k  = nx*j + i;
346       v  = zero;
347       vr = zero;
348       vt = zero;
349       if (i >= 0 && j >= 0)    v = x[k];
350       if (i < nx-1 && j > -1) vr = x[k+1];
351       if (i > -1 && j < ny-1) vt = x[k+nx];
352       dvdx = (vr-v)/hx;
353       dvdy = (vt-v)/hy;
354       if (i != -1 && j != -1) {
355         ind = k; val = - dvdx/hx - dvdy/hy - cdiv3;
356         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
357       }
358       if (i != nx-1 && j != -1) {
359         ind = k+1; val =  dvdx/hx - cdiv3;
360         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
361       }
362       if (i != -1 && j != ny-1) {
363         ind = k+nx; val = dvdy/hy - cdiv3;
364         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
365       }
366     }
367   }
368 
369   /* Compute gradient contributions over the upper triangular elements */
370   for (j=0; j<=ny; j++) {
371     for (i=0; i<=nx; i++) {
372       k = nx*j + i;
373       vb = zero;
374       vl = zero;
375       v  = zero;
376       if (i < nx && j > 0) vb = x[k-nx];
377       if (i > 0 && j < ny) vl = x[k-1];
378       if (i < nx && j < ny) v = x[k];
379       dvdx = (v-vl)/hx;
380       dvdy = (v-vb)/hy;
381       if (i != nx && j != 0) {
382         ind = k-nx; val = - dvdy/hy - cdiv3;
383         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
384       }
385       if (i != 0 && j != ny) {
386         ind = k-1; val =  - dvdx/hx - cdiv3;
387         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
388       }
389       if (i != nx && j != ny) {
390         ind = k; val =  dvdx/hx + dvdy/hy - cdiv3;
391         ierr = VecSetValues(G,1,&ind,&val,ADD_VALUES);CHKERRQ(ierr);
392       }
393     }
394   }
395   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
396 
397   /* Assemble gradient vector */
398   ierr = VecAssemblyBegin(G);CHKERRQ(ierr);
399   ierr = VecAssemblyEnd(G);CHKERRQ(ierr);
400 
401   /* Scale the gradient */
402   area = p5*hx*hy;
403   ierr = VecScale(G, area);CHKERRQ(ierr);
404   ierr = PetscLogFlops(24.0*nx*ny);CHKERRQ(ierr);
405   PetscFunctionReturn(0);
406 }
407 
408 /* ------------------------------------------------------------------- */
409 /*
410    FormHessian - Forms the Hessian matrix.
411 
412    Input Parameters:
413 .  tao - the Tao context
414 .  X    - the input vector
415 .  ptr  - optional user-defined context, as set by TaoSetHessian()
416 
417    Output Parameters:
418 .  H     - Hessian matrix
419 .  PrecH - optionally different preconditioning Hessian
420 .  flag  - flag indicating matrix structure
421 
422    Notes:
423    This routine is intended simply as an example of the interface
424    to a Hessian evaluation routine.  Since this example compute the
425    Hessian a column at a time, it is not particularly efficient and
426    is not recommended.
427 */
428 PetscErrorCode FormHessian(Tao tao,Vec X,Mat H,Mat Hpre, void *ptr)
429 {
430   AppCtx         *user = (AppCtx *) ptr;
431   PetscErrorCode ierr;
432   PetscInt       i,j, ndim = user->ndim;
433   PetscReal      *y, zero = 0.0, one = 1.0;
434   PetscBool      assembled;
435 
436   PetscFunctionBeginUser;
437   user->xvec = X;
438 
439   /* Initialize Hessian entries and work vector to zero */
440   ierr = MatAssembled(H,&assembled);CHKERRQ(ierr);
441   if (assembled){ierr = MatZeroEntries(H);CHKERRQ(ierr);}
442 
443   ierr = VecSet(user->s, zero);CHKERRQ(ierr);
444 
445   /* Loop over matrix columns to compute entries of the Hessian */
446   for (j=0; j<ndim; j++) {
447     ierr = VecSetValues(user->s,1,&j,&one,INSERT_VALUES);CHKERRQ(ierr);
448     ierr = VecAssemblyBegin(user->s);CHKERRQ(ierr);
449     ierr = VecAssemblyEnd(user->s);CHKERRQ(ierr);
450 
451     ierr = HessianProduct(ptr,user->s,user->y);CHKERRQ(ierr);
452 
453     ierr = VecSetValues(user->s,1,&j,&zero,INSERT_VALUES);CHKERRQ(ierr);
454     ierr = VecAssemblyBegin(user->s);CHKERRQ(ierr);
455     ierr = VecAssemblyEnd(user->s);CHKERRQ(ierr);
456 
457     ierr = VecGetArray(user->y,&y);CHKERRQ(ierr);
458     for (i=0; i<ndim; i++) {
459       if (y[i] != zero) {
460         ierr = MatSetValues(H,1,&i,1,&j,&y[i],ADD_VALUES);CHKERRQ(ierr);
461       }
462     }
463     ierr = VecRestoreArray(user->y,&y);CHKERRQ(ierr);
464   }
465   ierr = MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
466   ierr = MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
467   PetscFunctionReturn(0);
468 }
469 
470 /* ------------------------------------------------------------------- */
471 /*
472    MatrixFreeHessian - Sets a pointer for use in computing Hessian-vector
473    products.
474 
475    Input Parameters:
476 .  tao - the Tao context
477 .  X    - the input vector
478 .  ptr  - optional user-defined context, as set by TaoSetHessian()
479 
480    Output Parameters:
481 .  H     - Hessian matrix
482 .  PrecH - optionally different preconditioning Hessian
483 .  flag  - flag indicating matrix structure
484 */
485 PetscErrorCode MatrixFreeHessian(Tao tao,Vec X,Mat H,Mat PrecH, void *ptr)
486 {
487   AppCtx *user = (AppCtx *) ptr;
488 
489   /* Sets location of vector for use in computing matrix-vector products  of the form H(X)*y  */
490   PetscFunctionBeginUser;
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 /*TEST
619 
620    build:
621       requires: !complex
622 
623    test:
624       suffix: 1
625       args: -tao_smonitor -tao_type ntl -tao_gatol 1.e-4
626 
627    test:
628       suffix: 2
629       args: -tao_smonitor -tao_type ntr -tao_gatol 1.e-4
630 
631    test:
632       suffix: 3
633       args: -tao_smonitor -tao_type bntr -tao_gatol 1.e-4 -my_tao_mf -tao_test_hessian
634 
635    test:
636      suffix: 4
637      args: -tao_smonitor -tao_gatol 1e-3 -tao_type bqnls
638 
639    test:
640      suffix: 5
641      args: -tao_smonitor -tao_gatol 1e-3 -tao_type blmvm
642 
643    test:
644      suffix: 6
645      args: -tao_smonitor -tao_gatol 1e-3 -tao_type bqnktr -tao_bqnk_mat_type lmvmsr1
646 
647 TEST*/
648