xref: /petsc/src/tao/unconstrained/tutorials/minsurf2.c (revision 9f1eecfabe6bcba715771669d07a4cd08bad4712)
1c4762a1bSJed Brown /* Program usage: mpiexec -n <proc> minsurf2 [-help] [all TAO options] */
2c4762a1bSJed Brown 
3c4762a1bSJed Brown /*
4c4762a1bSJed Brown   Include "petsctao.h" so we can use TAO solvers.
5c4762a1bSJed Brown   petscdmda.h for distributed array
6c4762a1bSJed Brown */
7c4762a1bSJed Brown #include <petsctao.h>
8c4762a1bSJed Brown #include <petscdmda.h>
9c4762a1bSJed Brown 
109371c9d4SSatish Balay static char help[] = "This example demonstrates use of the TAO package to \n\
11c4762a1bSJed Brown solve an unconstrained minimization problem. This example is based on a \n\
12c4762a1bSJed Brown problem from the MINPACK-2 test suite. Given a rectangular 2-D domain and \n\
13c4762a1bSJed Brown boundary values along the edges of the domain, the objective is to find the\n\
14c4762a1bSJed Brown surface with the minimal area that satisfies the boundary conditions.\n\
15c4762a1bSJed Brown The command line options are:\n\
16*9f1eecfaSStefano Zampini   -da_grid_x <xg>, where <xg> = number of grid points in the 1st coordinate direction\n\
17*9f1eecfaSStefano Zampini   -da_grid_y <yg>, where <yg> = number of grid points in the 2nd coordinate direction\n\
18c4762a1bSJed Brown   -start <st>, where <st> =0 for zero vector, <st> >0 for random start, and <st> <0 \n\
19c4762a1bSJed Brown                for an average of the boundary conditions\n\n";
20c4762a1bSJed Brown 
21c4762a1bSJed Brown /*
22c4762a1bSJed Brown    User-defined application context - contains data needed by the
234936d809SStefano Zampini    application-provided call-back routines, FormFunction(),
244936d809SStefano Zampini    FormFunctionGradient(), and FormHessian().
25c4762a1bSJed Brown */
26c4762a1bSJed Brown typedef struct {
27c4762a1bSJed Brown   PetscInt   mx, my;                      /* discretization in x, y directions */
28c4762a1bSJed Brown   PetscReal *bottom, *top, *left, *right; /* boundary values */
29c4762a1bSJed Brown   DM         dm;                          /* distributed array data structure */
30c4762a1bSJed Brown   Mat        H;                           /* Hessian */
31c4762a1bSJed Brown } AppCtx;
32c4762a1bSJed Brown 
33c4762a1bSJed Brown /* -------- User-defined Routines --------- */
34c4762a1bSJed Brown 
35c4762a1bSJed Brown static PetscErrorCode MSA_BoundaryConditions(AppCtx *);
36c4762a1bSJed Brown static PetscErrorCode MSA_InitialPoint(AppCtx *, Vec);
374936d809SStefano Zampini static PetscErrorCode QuadraticH(AppCtx *, Vec, Mat);
384936d809SStefano Zampini static PetscErrorCode FormFunction(Tao, Vec, PetscReal *, void *);
394936d809SStefano Zampini static PetscErrorCode FormFunctionGradient(Tao, Vec, PetscReal *, Vec, void *);
404936d809SStefano Zampini static PetscErrorCode FormGradient(Tao, Vec, Vec, void *);
414936d809SStefano Zampini static PetscErrorCode FormHessian(Tao, Vec, Mat, Mat, void *);
424936d809SStefano Zampini static PetscErrorCode My_Monitor(Tao, void *);
43c4762a1bSJed Brown 
44d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
45d71ae5a4SJacob Faibussowitsch {
46c4762a1bSJed Brown   Vec           x;                     /* solution, gradient vectors */
47*9f1eecfaSStefano Zampini   PetscBool     viewmat;               /* flags */
48c4762a1bSJed Brown   PetscBool     fddefault, fdcoloring; /* flags */
49c4762a1bSJed Brown   Tao           tao;                   /* TAO solver context */
50c4762a1bSJed Brown   AppCtx        user;                  /* user-defined work context */
51c4762a1bSJed Brown   ISColoring    iscoloring;
52c4762a1bSJed Brown   MatFDColoring matfdcoloring;
53c4762a1bSJed Brown 
54c4762a1bSJed Brown   /* Initialize TAO */
55327415f7SBarry Smith   PetscFunctionBeginUser;
569566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));
57c4762a1bSJed Brown 
58c4762a1bSJed Brown   /* Create distributed array (DM) to manage parallel grid and vectors  */
59*9f1eecfaSStefano Zampini   PetscCall(DMDACreate2d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_BOX, 10, 10, PETSC_DECIDE, PETSC_DECIDE, 1, 1, NULL, NULL, &user.dm));
609566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(user.dm));
619566063dSJacob Faibussowitsch   PetscCall(DMSetUp(user.dm));
624936d809SStefano Zampini   PetscCall(DMDASetUniformCoordinates(user.dm, -0.5, 0.5, -0.5, 0.5, PETSC_DECIDE, PETSC_DECIDE));
63*9f1eecfaSStefano Zampini   PetscCall(DMDAGetInfo(user.dm, PETSC_IGNORE, &user.mx, &user.my, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE));
64*9f1eecfaSStefano Zampini 
65*9f1eecfaSStefano Zampini   PetscCall(PetscPrintf(MPI_COMM_WORLD, "\n---- Minimum Surface Area Problem -----\n"));
66*9f1eecfaSStefano Zampini   PetscCall(PetscPrintf(MPI_COMM_WORLD, "mx: %" PetscInt_FMT "     my: %" PetscInt_FMT "   \n\n", user.mx, user.my));
67c4762a1bSJed Brown 
68c4762a1bSJed Brown   /* Create TAO solver and set desired solution method.*/
699566063dSJacob Faibussowitsch   PetscCall(TaoCreate(PETSC_COMM_WORLD, &tao));
709566063dSJacob Faibussowitsch   PetscCall(TaoSetType(tao, TAOCG));
71c4762a1bSJed Brown 
72c4762a1bSJed Brown   /*
73c4762a1bSJed Brown      Extract global vector from DA for the vector of variables --  PETSC routine
74c4762a1bSJed Brown      Compute the initial solution                              --  application specific, see below
75c4762a1bSJed Brown      Set this vector for use by TAO                            --  TAO routine
76c4762a1bSJed Brown   */
779566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(user.dm, &x));
789566063dSJacob Faibussowitsch   PetscCall(MSA_BoundaryConditions(&user));
799566063dSJacob Faibussowitsch   PetscCall(MSA_InitialPoint(&user, x));
809566063dSJacob Faibussowitsch   PetscCall(TaoSetSolution(tao, x));
81c4762a1bSJed Brown 
82c4762a1bSJed Brown   /*
83c4762a1bSJed Brown      Initialize the Application context for use in function evaluations  --  application specific, see below.
84c4762a1bSJed Brown      Set routines for function and gradient evaluation
85c4762a1bSJed Brown   */
864936d809SStefano Zampini   PetscCall(TaoSetObjective(tao, FormFunction, (void *)&user));
879566063dSJacob Faibussowitsch   PetscCall(TaoSetObjectiveAndGradient(tao, NULL, FormFunctionGradient, (void *)&user));
88c4762a1bSJed Brown 
89c4762a1bSJed Brown   /*
90c4762a1bSJed Brown      Given the command line arguments, calculate the hessian with either the user-
91c4762a1bSJed Brown      provided function FormHessian, or the default finite-difference driven Hessian
92c4762a1bSJed Brown      functions
93c4762a1bSJed Brown   */
949566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, NULL, "-tao_fddefault", &fddefault));
959566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, NULL, "-tao_fdcoloring", &fdcoloring));
96c4762a1bSJed Brown 
97c4762a1bSJed Brown   /*
98c4762a1bSJed Brown      Create a matrix data structure to store the Hessian and set
99d5b43468SJose E. Roman      the Hessian evaluation routine.
100d5b43468SJose E. Roman      Set the matrix structure to be used for Hessian evaluations
101c4762a1bSJed Brown   */
1029566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(user.dm, &user.H));
1039566063dSJacob Faibussowitsch   PetscCall(MatSetOption(user.H, MAT_SYMMETRIC, PETSC_TRUE));
104c4762a1bSJed Brown 
105c4762a1bSJed Brown   if (fdcoloring) {
1069566063dSJacob Faibussowitsch     PetscCall(DMCreateColoring(user.dm, IS_COLORING_GLOBAL, &iscoloring));
1079566063dSJacob Faibussowitsch     PetscCall(MatFDColoringCreate(user.H, iscoloring, &matfdcoloring));
1089566063dSJacob Faibussowitsch     PetscCall(ISColoringDestroy(&iscoloring));
1099566063dSJacob Faibussowitsch     PetscCall(MatFDColoringSetFunction(matfdcoloring, (PetscErrorCode(*)(void))FormGradient, (void *)&user));
1109566063dSJacob Faibussowitsch     PetscCall(MatFDColoringSetFromOptions(matfdcoloring));
1119566063dSJacob Faibussowitsch     PetscCall(TaoSetHessian(tao, user.H, user.H, TaoDefaultComputeHessianColor, (void *)matfdcoloring));
112c4762a1bSJed Brown   } else if (fddefault) {
1139566063dSJacob Faibussowitsch     PetscCall(TaoSetHessian(tao, user.H, user.H, TaoDefaultComputeHessian, (void *)NULL));
114c4762a1bSJed Brown   } else {
1159566063dSJacob Faibussowitsch     PetscCall(TaoSetHessian(tao, user.H, user.H, FormHessian, (void *)&user));
116c4762a1bSJed Brown   }
117c4762a1bSJed Brown 
118c4762a1bSJed Brown   /*
119c4762a1bSJed Brown      If my_monitor option is in command line, then use the user-provided
120c4762a1bSJed Brown      monitoring function
121c4762a1bSJed Brown   */
1229566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, NULL, "-my_monitor", &viewmat));
1231baa6e33SBarry Smith   if (viewmat) PetscCall(TaoSetMonitor(tao, My_Monitor, NULL, NULL));
124c4762a1bSJed Brown 
125c4762a1bSJed Brown   /* Check for any tao command line options */
1269566063dSJacob Faibussowitsch   PetscCall(TaoSetFromOptions(tao));
127c4762a1bSJed Brown 
128c4762a1bSJed Brown   /* SOLVE THE APPLICATION */
1299566063dSJacob Faibussowitsch   PetscCall(TaoSolve(tao));
130c4762a1bSJed Brown 
1319566063dSJacob Faibussowitsch   PetscCall(TaoView(tao, PETSC_VIEWER_STDOUT_WORLD));
132c4762a1bSJed Brown 
133c4762a1bSJed Brown   /* Free TAO data structures */
1349566063dSJacob Faibussowitsch   PetscCall(TaoDestroy(&tao));
135c4762a1bSJed Brown 
136c4762a1bSJed Brown   /* Free PETSc data structures */
1379566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&x));
1389566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user.H));
13948a46eb9SPierre Jolivet   if (fdcoloring) PetscCall(MatFDColoringDestroy(&matfdcoloring));
1409566063dSJacob Faibussowitsch   PetscCall(PetscFree(user.bottom));
1419566063dSJacob Faibussowitsch   PetscCall(PetscFree(user.top));
1429566063dSJacob Faibussowitsch   PetscCall(PetscFree(user.left));
1439566063dSJacob Faibussowitsch   PetscCall(PetscFree(user.right));
1449566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&user.dm));
1459566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
146b122ec5aSJacob Faibussowitsch   return 0;
147c4762a1bSJed Brown }
148c4762a1bSJed Brown 
1494936d809SStefano Zampini /* -------------------------------------------------------------------- */
1504936d809SStefano Zampini /*
1514936d809SStefano Zampini     FormFunction - Evaluates the objective function.
1524936d809SStefano Zampini 
1534936d809SStefano Zampini     Input Parameters:
1544936d809SStefano Zampini .   tao     - the Tao context
1554936d809SStefano Zampini .   X       - input vector
1564936d809SStefano Zampini .   userCtx - optional user-defined context, as set by TaoSetObjective()
1574936d809SStefano Zampini 
1584936d809SStefano Zampini     Output Parameters:
1594936d809SStefano Zampini .   fcn     - the newly evaluated function
1604936d809SStefano Zampini */
1614936d809SStefano Zampini PetscErrorCode FormFunction(Tao tao, Vec X, PetscReal *fcn, void *userCtx)
162d71ae5a4SJacob Faibussowitsch {
1634936d809SStefano Zampini   AppCtx     *user = (AppCtx *)userCtx;
1644936d809SStefano Zampini   PetscInt    i, j;
1654936d809SStefano Zampini   PetscInt    mx = user->mx, my = user->my;
1664936d809SStefano Zampini   PetscInt    xs, xm, gxs, gxm, ys, ym, gys, gym;
1674936d809SStefano Zampini   PetscReal   ft = 0.0;
1684936d809SStefano Zampini   PetscReal   hx = 1.0 / (mx + 1), hy = 1.0 / (my + 1), area = 0.5 * hx * hy;
1694936d809SStefano Zampini   PetscReal   rhx = mx + 1, rhy = my + 1;
1704936d809SStefano Zampini   PetscReal   f2, f4, d1, d2, d3, d4, xc, xl, xr, xt, xb;
1714936d809SStefano Zampini   PetscReal **x;
1724936d809SStefano Zampini   Vec         localX;
173c4762a1bSJed Brown 
174c4762a1bSJed Brown   PetscFunctionBegin;
1754936d809SStefano Zampini   /* Get local mesh boundaries */
1764936d809SStefano Zampini   PetscCall(DMGetLocalVector(user->dm, &localX));
1774936d809SStefano Zampini   PetscCall(DMDAGetCorners(user->dm, &xs, &ys, NULL, &xm, &ym, NULL));
1784936d809SStefano Zampini   PetscCall(DMDAGetGhostCorners(user->dm, &gxs, &gys, NULL, &gxm, &gym, NULL));
1794936d809SStefano Zampini 
1804936d809SStefano Zampini   /* Scatter ghost points to local vector */
1814936d809SStefano Zampini   PetscCall(DMGlobalToLocalBegin(user->dm, X, INSERT_VALUES, localX));
1824936d809SStefano Zampini   PetscCall(DMGlobalToLocalEnd(user->dm, X, INSERT_VALUES, localX));
1834936d809SStefano Zampini 
1844936d809SStefano Zampini   /* Get pointers to vector data */
1854936d809SStefano Zampini   PetscCall(DMDAVecGetArray(user->dm, localX, (void **)&x));
1864936d809SStefano Zampini 
1874936d809SStefano Zampini   /* Compute function and gradient over the locally owned part of the mesh */
1884936d809SStefano Zampini   for (j = ys; j < ys + ym; j++) {
1894936d809SStefano Zampini     for (i = xs; i < xs + xm; i++) {
1904936d809SStefano Zampini       xc = x[j][i];
1914936d809SStefano Zampini 
1924936d809SStefano Zampini       if (i == 0) { /* left side */
1934936d809SStefano Zampini         xl = user->left[j - ys + 1];
1944936d809SStefano Zampini       } else {
1954936d809SStefano Zampini         xl = x[j][i - 1];
1964936d809SStefano Zampini       }
1974936d809SStefano Zampini 
1984936d809SStefano Zampini       if (j == 0) { /* bottom side */
1994936d809SStefano Zampini         xb = user->bottom[i - xs + 1];
2004936d809SStefano Zampini       } else {
2014936d809SStefano Zampini         xb = x[j - 1][i];
2024936d809SStefano Zampini       }
2034936d809SStefano Zampini 
2044936d809SStefano Zampini       if (i + 1 == gxs + gxm) { /* right side */
2054936d809SStefano Zampini         xr = user->right[j - ys + 1];
2064936d809SStefano Zampini       } else {
2074936d809SStefano Zampini         xr = x[j][i + 1];
2084936d809SStefano Zampini       }
2094936d809SStefano Zampini 
2104936d809SStefano Zampini       if (j + 1 == gys + gym) { /* top side */
2114936d809SStefano Zampini         xt = user->top[i - xs + 1];
2124936d809SStefano Zampini       } else {
2134936d809SStefano Zampini         xt = x[j + 1][i];
2144936d809SStefano Zampini       }
2154936d809SStefano Zampini 
2164936d809SStefano Zampini       d1 = (xc - xl);
2174936d809SStefano Zampini       d2 = (xc - xr);
2184936d809SStefano Zampini       d3 = (xc - xt);
2194936d809SStefano Zampini       d4 = (xc - xb);
2204936d809SStefano Zampini 
2214936d809SStefano Zampini       d1 *= rhx;
2224936d809SStefano Zampini       d2 *= rhx;
2234936d809SStefano Zampini       d3 *= rhy;
2244936d809SStefano Zampini       d4 *= rhy;
2254936d809SStefano Zampini 
2264936d809SStefano Zampini       f2 = PetscSqrtReal(1.0 + d1 * d1 + d4 * d4);
2274936d809SStefano Zampini       f4 = PetscSqrtReal(1.0 + d3 * d3 + d2 * d2);
2284936d809SStefano Zampini 
2294936d809SStefano Zampini       ft = ft + (f2 + f4);
2304936d809SStefano Zampini     }
2314936d809SStefano Zampini   }
2324936d809SStefano Zampini 
2334936d809SStefano Zampini   /* Compute triangular areas along the border of the domain. */
2344936d809SStefano Zampini   if (xs == 0) { /* left side */
2354936d809SStefano Zampini     for (j = ys; j < ys + ym; j++) {
2364936d809SStefano Zampini       d3 = (user->left[j - ys + 1] - user->left[j - ys + 2]) * rhy;
2374936d809SStefano Zampini       d2 = (user->left[j - ys + 1] - x[j][0]) * rhx;
2384936d809SStefano Zampini       ft = ft + PetscSqrtReal(1.0 + d3 * d3 + d2 * d2);
2394936d809SStefano Zampini     }
2404936d809SStefano Zampini   }
2414936d809SStefano Zampini   if (ys == 0) { /* bottom side */
2424936d809SStefano Zampini     for (i = xs; i < xs + xm; i++) {
2434936d809SStefano Zampini       d2 = (user->bottom[i + 1 - xs] - user->bottom[i - xs + 2]) * rhx;
2444936d809SStefano Zampini       d3 = (user->bottom[i - xs + 1] - x[0][i]) * rhy;
2454936d809SStefano Zampini       ft = ft + PetscSqrtReal(1.0 + d3 * d3 + d2 * d2);
2464936d809SStefano Zampini     }
2474936d809SStefano Zampini   }
2484936d809SStefano Zampini   if (xs + xm == mx) { /* right side */
2494936d809SStefano Zampini     for (j = ys; j < ys + ym; j++) {
2504936d809SStefano Zampini       d1 = (x[j][mx - 1] - user->right[j - ys + 1]) * rhx;
2514936d809SStefano Zampini       d4 = (user->right[j - ys] - user->right[j - ys + 1]) * rhy;
2524936d809SStefano Zampini       ft = ft + PetscSqrtReal(1.0 + d1 * d1 + d4 * d4);
2534936d809SStefano Zampini     }
2544936d809SStefano Zampini   }
2554936d809SStefano Zampini   if (ys + ym == my) { /* top side */
2564936d809SStefano Zampini     for (i = xs; i < xs + xm; i++) {
2574936d809SStefano Zampini       d1 = (x[my - 1][i] - user->top[i - xs + 1]) * rhy;
2584936d809SStefano Zampini       d4 = (user->top[i - xs + 1] - user->top[i - xs]) * rhx;
2594936d809SStefano Zampini       ft = ft + PetscSqrtReal(1.0 + d1 * d1 + d4 * d4);
2604936d809SStefano Zampini     }
2614936d809SStefano Zampini   }
2624936d809SStefano Zampini   if (ys == 0 && xs == 0) {
2634936d809SStefano Zampini     d1 = (user->left[0] - user->left[1]) / hy;
2644936d809SStefano Zampini     d2 = (user->bottom[0] - user->bottom[1]) * rhx;
2654936d809SStefano Zampini     ft += PetscSqrtReal(1.0 + d1 * d1 + d2 * d2);
2664936d809SStefano Zampini   }
2674936d809SStefano Zampini   if (ys + ym == my && xs + xm == mx) {
2684936d809SStefano Zampini     d1 = (user->right[ym + 1] - user->right[ym]) * rhy;
2694936d809SStefano Zampini     d2 = (user->top[xm + 1] - user->top[xm]) * rhx;
2704936d809SStefano Zampini     ft += PetscSqrtReal(1.0 + d1 * d1 + d2 * d2);
2714936d809SStefano Zampini   }
2724936d809SStefano Zampini 
2734936d809SStefano Zampini   ft = ft * area;
2744936d809SStefano Zampini   PetscCall(MPIU_Allreduce(&ft, fcn, 1, MPIU_REAL, MPIU_SUM, MPI_COMM_WORLD));
2754936d809SStefano Zampini 
2764936d809SStefano Zampini   /* Restore vectors */
2774936d809SStefano Zampini   PetscCall(DMDAVecRestoreArray(user->dm, localX, (void **)&x));
2784936d809SStefano Zampini   PetscCall(DMRestoreLocalVector(user->dm, &localX));
2793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
280c4762a1bSJed Brown }
281c4762a1bSJed Brown 
282c4762a1bSJed Brown /* -------------------------------------------------------------------- */
2834936d809SStefano Zampini /*
2844936d809SStefano Zampini     FormFunctionGradient - Evaluates the function and corresponding gradient.
285c4762a1bSJed Brown 
286c4762a1bSJed Brown     Input Parameters:
287c4762a1bSJed Brown .   tao     - the Tao context
2884936d809SStefano Zampini .   X      - input vector
289a82e8c82SStefano Zampini .   userCtx - optional user-defined context, as set by TaoSetObjectiveAndGradient()
290c4762a1bSJed Brown 
291c4762a1bSJed Brown     Output Parameters:
292c4762a1bSJed Brown .   fcn     - the newly evaluated function
2934936d809SStefano Zampini .   G       - vector containing the newly evaluated gradient
294c4762a1bSJed Brown */
295d71ae5a4SJacob Faibussowitsch PetscErrorCode FormFunctionGradient(Tao tao, Vec X, PetscReal *fcn, Vec G, void *userCtx)
296d71ae5a4SJacob Faibussowitsch {
297c4762a1bSJed Brown   AppCtx     *user = (AppCtx *)userCtx;
298c4762a1bSJed Brown   PetscInt    i, j;
299c4762a1bSJed Brown   PetscInt    mx = user->mx, my = user->my;
300c4762a1bSJed Brown   PetscInt    xs, xm, gxs, gxm, ys, ym, gys, gym;
301c4762a1bSJed Brown   PetscReal   ft = 0.0;
302c4762a1bSJed Brown   PetscReal   hx = 1.0 / (mx + 1), hy = 1.0 / (my + 1), hydhx = hy / hx, hxdhy = hx / hy, area = 0.5 * hx * hy;
303c4762a1bSJed Brown   PetscReal   rhx = mx + 1, rhy = my + 1;
304c4762a1bSJed Brown   PetscReal   f1, f2, f3, f4, f5, f6, d1, d2, d3, d4, d5, d6, d7, d8, xc, xl, xr, xt, xb, xlt, xrb;
305c4762a1bSJed Brown   PetscReal   df1dxc, df2dxc, df3dxc, df4dxc, df5dxc, df6dxc;
306c4762a1bSJed Brown   PetscReal **g, **x;
307c4762a1bSJed Brown   Vec         localX;
308c4762a1bSJed Brown 
309c4762a1bSJed Brown   PetscFunctionBegin;
310c4762a1bSJed Brown   /* Get local mesh boundaries */
3119566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(user->dm, &localX));
3129566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(user->dm, &xs, &ys, NULL, &xm, &ym, NULL));
3139566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(user->dm, &gxs, &gys, NULL, &gxm, &gym, NULL));
314c4762a1bSJed Brown 
315c4762a1bSJed Brown   /* Scatter ghost points to local vector */
3169566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(user->dm, X, INSERT_VALUES, localX));
3179566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(user->dm, X, INSERT_VALUES, localX));
318c4762a1bSJed Brown 
319c4762a1bSJed Brown   /* Get pointers to vector data */
3209566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(user->dm, localX, (void **)&x));
3219566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(user->dm, G, (void **)&g));
322c4762a1bSJed Brown 
323c4762a1bSJed Brown   /* Compute function and gradient over the locally owned part of the mesh */
324c4762a1bSJed Brown   for (j = ys; j < ys + ym; j++) {
325c4762a1bSJed Brown     for (i = xs; i < xs + xm; i++) {
326c4762a1bSJed Brown       xc  = x[j][i];
327c4762a1bSJed Brown       xlt = xrb = xl = xr = xb = xt = xc;
328c4762a1bSJed Brown 
329c4762a1bSJed Brown       if (i == 0) { /* left side */
330c4762a1bSJed Brown         xl  = user->left[j - ys + 1];
331c4762a1bSJed Brown         xlt = user->left[j - ys + 2];
332c4762a1bSJed Brown       } else {
333c4762a1bSJed Brown         xl = x[j][i - 1];
334c4762a1bSJed Brown       }
335c4762a1bSJed Brown 
336c4762a1bSJed Brown       if (j == 0) { /* bottom side */
337c4762a1bSJed Brown         xb  = user->bottom[i - xs + 1];
338c4762a1bSJed Brown         xrb = user->bottom[i - xs + 2];
339c4762a1bSJed Brown       } else {
340c4762a1bSJed Brown         xb = x[j - 1][i];
341c4762a1bSJed Brown       }
342c4762a1bSJed Brown 
343c4762a1bSJed Brown       if (i + 1 == gxs + gxm) { /* right side */
344c4762a1bSJed Brown         xr  = user->right[j - ys + 1];
345c4762a1bSJed Brown         xrb = user->right[j - ys];
346c4762a1bSJed Brown       } else {
347c4762a1bSJed Brown         xr = x[j][i + 1];
348c4762a1bSJed Brown       }
349c4762a1bSJed Brown 
350c4762a1bSJed Brown       if (j + 1 == gys + gym) { /* top side */
351c4762a1bSJed Brown         xt  = user->top[i - xs + 1];
352c4762a1bSJed Brown         xlt = user->top[i - xs];
353c4762a1bSJed Brown       } else {
354c4762a1bSJed Brown         xt = x[j + 1][i];
355c4762a1bSJed Brown       }
356c4762a1bSJed Brown 
357ad540459SPierre Jolivet       if (i > gxs && j + 1 < gys + gym) xlt = x[j + 1][i - 1];
358ad540459SPierre Jolivet       if (j > gys && i + 1 < gxs + gxm) xrb = x[j - 1][i + 1];
359c4762a1bSJed Brown 
360c4762a1bSJed Brown       d1 = (xc - xl);
361c4762a1bSJed Brown       d2 = (xc - xr);
362c4762a1bSJed Brown       d3 = (xc - xt);
363c4762a1bSJed Brown       d4 = (xc - xb);
364c4762a1bSJed Brown       d5 = (xr - xrb);
365c4762a1bSJed Brown       d6 = (xrb - xb);
366c4762a1bSJed Brown       d7 = (xlt - xl);
367c4762a1bSJed Brown       d8 = (xt - xlt);
368c4762a1bSJed Brown 
369c4762a1bSJed Brown       df1dxc = d1 * hydhx;
370c4762a1bSJed Brown       df2dxc = (d1 * hydhx + d4 * hxdhy);
371c4762a1bSJed Brown       df3dxc = d3 * hxdhy;
372c4762a1bSJed Brown       df4dxc = (d2 * hydhx + d3 * hxdhy);
373c4762a1bSJed Brown       df5dxc = d2 * hydhx;
374c4762a1bSJed Brown       df6dxc = d4 * hxdhy;
375c4762a1bSJed Brown 
376c4762a1bSJed Brown       d1 *= rhx;
377c4762a1bSJed Brown       d2 *= rhx;
378c4762a1bSJed Brown       d3 *= rhy;
379c4762a1bSJed Brown       d4 *= rhy;
380c4762a1bSJed Brown       d5 *= rhy;
381c4762a1bSJed Brown       d6 *= rhx;
382c4762a1bSJed Brown       d7 *= rhy;
383c4762a1bSJed Brown       d8 *= rhx;
384c4762a1bSJed Brown 
385c4762a1bSJed Brown       f1 = PetscSqrtReal(1.0 + d1 * d1 + d7 * d7);
386c4762a1bSJed Brown       f2 = PetscSqrtReal(1.0 + d1 * d1 + d4 * d4);
387c4762a1bSJed Brown       f3 = PetscSqrtReal(1.0 + d3 * d3 + d8 * d8);
388c4762a1bSJed Brown       f4 = PetscSqrtReal(1.0 + d3 * d3 + d2 * d2);
389c4762a1bSJed Brown       f5 = PetscSqrtReal(1.0 + d2 * d2 + d5 * d5);
390c4762a1bSJed Brown       f6 = PetscSqrtReal(1.0 + d4 * d4 + d6 * d6);
391c4762a1bSJed Brown 
392c4762a1bSJed Brown       ft = ft + (f2 + f4);
393c4762a1bSJed Brown 
394c4762a1bSJed Brown       df1dxc /= f1;
395c4762a1bSJed Brown       df2dxc /= f2;
396c4762a1bSJed Brown       df3dxc /= f3;
397c4762a1bSJed Brown       df4dxc /= f4;
398c4762a1bSJed Brown       df5dxc /= f5;
399c4762a1bSJed Brown       df6dxc /= f6;
400c4762a1bSJed Brown 
401c4762a1bSJed Brown       g[j][i] = (df1dxc + df2dxc + df3dxc + df4dxc + df5dxc + df6dxc) * 0.5;
402c4762a1bSJed Brown     }
403c4762a1bSJed Brown   }
404c4762a1bSJed Brown 
405c4762a1bSJed Brown   /* Compute triangular areas along the border of the domain. */
406c4762a1bSJed Brown   if (xs == 0) { /* left side */
407c4762a1bSJed Brown     for (j = ys; j < ys + ym; j++) {
408c4762a1bSJed Brown       d3 = (user->left[j - ys + 1] - user->left[j - ys + 2]) * rhy;
409c4762a1bSJed Brown       d2 = (user->left[j - ys + 1] - x[j][0]) * rhx;
410c4762a1bSJed Brown       ft = ft + PetscSqrtReal(1.0 + d3 * d3 + d2 * d2);
411c4762a1bSJed Brown     }
412c4762a1bSJed Brown   }
413c4762a1bSJed Brown   if (ys == 0) { /* bottom side */
414c4762a1bSJed Brown     for (i = xs; i < xs + xm; i++) {
415c4762a1bSJed Brown       d2 = (user->bottom[i + 1 - xs] - user->bottom[i - xs + 2]) * rhx;
416c4762a1bSJed Brown       d3 = (user->bottom[i - xs + 1] - x[0][i]) * rhy;
417c4762a1bSJed Brown       ft = ft + PetscSqrtReal(1.0 + d3 * d3 + d2 * d2);
418c4762a1bSJed Brown     }
419c4762a1bSJed Brown   }
420c4762a1bSJed Brown 
421c4762a1bSJed Brown   if (xs + xm == mx) { /* right side */
422c4762a1bSJed Brown     for (j = ys; j < ys + ym; j++) {
423c4762a1bSJed Brown       d1 = (x[j][mx - 1] - user->right[j - ys + 1]) * rhx;
424c4762a1bSJed Brown       d4 = (user->right[j - ys] - user->right[j - ys + 1]) * rhy;
425c4762a1bSJed Brown       ft = ft + PetscSqrtReal(1.0 + d1 * d1 + d4 * d4);
426c4762a1bSJed Brown     }
427c4762a1bSJed Brown   }
428c4762a1bSJed Brown   if (ys + ym == my) { /* top side */
429c4762a1bSJed Brown     for (i = xs; i < xs + xm; i++) {
430c4762a1bSJed Brown       d1 = (x[my - 1][i] - user->top[i - xs + 1]) * rhy;
431c4762a1bSJed Brown       d4 = (user->top[i - xs + 1] - user->top[i - xs]) * rhx;
432c4762a1bSJed Brown       ft = ft + PetscSqrtReal(1.0 + d1 * d1 + d4 * d4);
433c4762a1bSJed Brown     }
434c4762a1bSJed Brown   }
435c4762a1bSJed Brown 
436c4762a1bSJed Brown   if (ys == 0 && xs == 0) {
437c4762a1bSJed Brown     d1 = (user->left[0] - user->left[1]) / hy;
438c4762a1bSJed Brown     d2 = (user->bottom[0] - user->bottom[1]) * rhx;
439c4762a1bSJed Brown     ft += PetscSqrtReal(1.0 + d1 * d1 + d2 * d2);
440c4762a1bSJed Brown   }
441c4762a1bSJed Brown   if (ys + ym == my && xs + xm == mx) {
442c4762a1bSJed Brown     d1 = (user->right[ym + 1] - user->right[ym]) * rhy;
443c4762a1bSJed Brown     d2 = (user->top[xm + 1] - user->top[xm]) * rhx;
444c4762a1bSJed Brown     ft += PetscSqrtReal(1.0 + d1 * d1 + d2 * d2);
445c4762a1bSJed Brown   }
446c4762a1bSJed Brown 
447c4762a1bSJed Brown   ft = ft * area;
448712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&ft, fcn, 1, MPIU_REAL, MPIU_SUM, MPI_COMM_WORLD));
449c4762a1bSJed Brown 
450c4762a1bSJed Brown   /* Restore vectors */
4519566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(user->dm, localX, (void **)&x));
4529566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(user->dm, G, (void **)&g));
4539566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(user->dm, &localX));
4549566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(67.0 * xm * ym));
4553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
456c4762a1bSJed Brown }
457c4762a1bSJed Brown 
4584936d809SStefano Zampini PetscErrorCode FormGradient(Tao tao, Vec X, Vec G, void *userCtx)
4594936d809SStefano Zampini {
4604936d809SStefano Zampini   PetscReal fcn;
4614936d809SStefano Zampini 
4624936d809SStefano Zampini   PetscFunctionBegin;
4634936d809SStefano Zampini   PetscCall(FormFunctionGradient(tao, X, &fcn, G, userCtx));
4644936d809SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
4654936d809SStefano Zampini }
4664936d809SStefano Zampini 
467c4762a1bSJed Brown /* ------------------------------------------------------------------- */
468c4762a1bSJed Brown /*
469c4762a1bSJed Brown    FormHessian - Evaluates Hessian matrix.
470c4762a1bSJed Brown 
471c4762a1bSJed Brown    Input Parameters:
472c4762a1bSJed Brown .  tao  - the Tao context
473c4762a1bSJed Brown .  x    - input vector
474a82e8c82SStefano Zampini .  ptr  - optional user-defined context, as set by TaoSetHessian()
475c4762a1bSJed Brown 
476c4762a1bSJed Brown    Output Parameters:
477c4762a1bSJed Brown .  H    - Hessian matrix
478c4762a1bSJed Brown .  Hpre - optionally different preconditioning matrix
479c4762a1bSJed Brown .  flg  - flag indicating matrix structure
480c4762a1bSJed Brown 
481c4762a1bSJed Brown */
482d71ae5a4SJacob Faibussowitsch PetscErrorCode FormHessian(Tao tao, Vec X, Mat H, Mat Hpre, void *ptr)
483d71ae5a4SJacob Faibussowitsch {
484c4762a1bSJed Brown   AppCtx *user = (AppCtx *)ptr;
485c4762a1bSJed Brown 
486c4762a1bSJed Brown   PetscFunctionBegin;
487c4762a1bSJed Brown   /* Evaluate the Hessian entries*/
4889566063dSJacob Faibussowitsch   PetscCall(QuadraticH(user, X, H));
4893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
490c4762a1bSJed Brown }
491c4762a1bSJed Brown 
492c4762a1bSJed Brown /* ------------------------------------------------------------------- */
493c4762a1bSJed Brown /*
494c4762a1bSJed Brown    QuadraticH - Evaluates Hessian matrix.
495c4762a1bSJed Brown 
496c4762a1bSJed Brown    Input Parameters:
497c4762a1bSJed Brown .  user - user-defined context, as set by TaoSetHessian()
498c4762a1bSJed Brown .  X    - input vector
499c4762a1bSJed Brown 
500c4762a1bSJed Brown    Output Parameter:
501c4762a1bSJed Brown .  H    - Hessian matrix
502c4762a1bSJed Brown */
503d71ae5a4SJacob Faibussowitsch PetscErrorCode QuadraticH(AppCtx *user, Vec X, Mat Hessian)
504d71ae5a4SJacob Faibussowitsch {
505c4762a1bSJed Brown   PetscInt    i, j, k;
506c4762a1bSJed Brown   PetscInt    mx = user->mx, my = user->my;
507c4762a1bSJed Brown   PetscInt    xs, xm, gxs, gxm, ys, ym, gys, gym;
508c4762a1bSJed Brown   PetscReal   hx = 1.0 / (mx + 1), hy = 1.0 / (my + 1), hydhx = hy / hx, hxdhy = hx / hy;
509c4762a1bSJed Brown   PetscReal   f1, f2, f3, f4, f5, f6, d1, d2, d3, d4, d5, d6, d7, d8, xc, xl, xr, xt, xb, xlt, xrb;
510c4762a1bSJed Brown   PetscReal   hl, hr, ht, hb, hc, htl, hbr;
511c4762a1bSJed Brown   PetscReal **x, v[7];
512c4762a1bSJed Brown   MatStencil  col[7], row;
513c4762a1bSJed Brown   Vec         localX;
514c4762a1bSJed Brown   PetscBool   assembled;
515c4762a1bSJed Brown 
516c4762a1bSJed Brown   PetscFunctionBegin;
517c4762a1bSJed Brown   /* Get local mesh boundaries */
5189566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(user->dm, &localX));
519c4762a1bSJed Brown 
5209566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(user->dm, &xs, &ys, NULL, &xm, &ym, NULL));
5219566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(user->dm, &gxs, &gys, NULL, &gxm, &gym, NULL));
522c4762a1bSJed Brown 
523c4762a1bSJed Brown   /* Scatter ghost points to local vector */
5249566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(user->dm, X, INSERT_VALUES, localX));
5259566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(user->dm, X, INSERT_VALUES, localX));
526c4762a1bSJed Brown 
527c4762a1bSJed Brown   /* Get pointers to vector data */
5289566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(user->dm, localX, (void **)&x));
529c4762a1bSJed Brown 
530c4762a1bSJed Brown   /* Initialize matrix entries to zero */
5319566063dSJacob Faibussowitsch   PetscCall(MatAssembled(Hessian, &assembled));
5329566063dSJacob Faibussowitsch   if (assembled) PetscCall(MatZeroEntries(Hessian));
533c4762a1bSJed Brown 
534c4762a1bSJed Brown   /* Set various matrix options */
5359566063dSJacob Faibussowitsch   PetscCall(MatSetOption(Hessian, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE));
536c4762a1bSJed Brown 
537c4762a1bSJed Brown   /* Compute Hessian over the locally owned part of the mesh */
538c4762a1bSJed Brown   for (j = ys; j < ys + ym; j++) {
539c4762a1bSJed Brown     for (i = xs; i < xs + xm; i++) {
540c4762a1bSJed Brown       xc  = x[j][i];
541c4762a1bSJed Brown       xlt = xrb = xl = xr = xb = xt = xc;
542c4762a1bSJed Brown 
543c4762a1bSJed Brown       /* Left side */
544c4762a1bSJed Brown       if (i == 0) {
545c4762a1bSJed Brown         xl  = user->left[j - ys + 1];
546c4762a1bSJed Brown         xlt = user->left[j - ys + 2];
547c4762a1bSJed Brown       } else {
548c4762a1bSJed Brown         xl = x[j][i - 1];
549c4762a1bSJed Brown       }
550c4762a1bSJed Brown 
551c4762a1bSJed Brown       if (j == 0) {
552c4762a1bSJed Brown         xb  = user->bottom[i - xs + 1];
553c4762a1bSJed Brown         xrb = user->bottom[i - xs + 2];
554c4762a1bSJed Brown       } else {
555c4762a1bSJed Brown         xb = x[j - 1][i];
556c4762a1bSJed Brown       }
557c4762a1bSJed Brown 
558c4762a1bSJed Brown       if (i + 1 == mx) {
559c4762a1bSJed Brown         xr  = user->right[j - ys + 1];
560c4762a1bSJed Brown         xrb = user->right[j - ys];
561c4762a1bSJed Brown       } else {
562c4762a1bSJed Brown         xr = x[j][i + 1];
563c4762a1bSJed Brown       }
564c4762a1bSJed Brown 
565c4762a1bSJed Brown       if (j + 1 == my) {
566c4762a1bSJed Brown         xt  = user->top[i - xs + 1];
567c4762a1bSJed Brown         xlt = user->top[i - xs];
568c4762a1bSJed Brown       } else {
569c4762a1bSJed Brown         xt = x[j + 1][i];
570c4762a1bSJed Brown       }
571c4762a1bSJed Brown 
572ad540459SPierre Jolivet       if (i > 0 && j + 1 < my) xlt = x[j + 1][i - 1];
573ad540459SPierre Jolivet       if (j > 0 && i + 1 < mx) xrb = x[j - 1][i + 1];
574c4762a1bSJed Brown 
575c4762a1bSJed Brown       d1 = (xc - xl) / hx;
576c4762a1bSJed Brown       d2 = (xc - xr) / hx;
577c4762a1bSJed Brown       d3 = (xc - xt) / hy;
578c4762a1bSJed Brown       d4 = (xc - xb) / hy;
579c4762a1bSJed Brown       d5 = (xrb - xr) / hy;
580c4762a1bSJed Brown       d6 = (xrb - xb) / hx;
581c4762a1bSJed Brown       d7 = (xlt - xl) / hy;
582c4762a1bSJed Brown       d8 = (xlt - xt) / hx;
583c4762a1bSJed Brown 
584c4762a1bSJed Brown       f1 = PetscSqrtReal(1.0 + d1 * d1 + d7 * d7);
585c4762a1bSJed Brown       f2 = PetscSqrtReal(1.0 + d1 * d1 + d4 * d4);
586c4762a1bSJed Brown       f3 = PetscSqrtReal(1.0 + d3 * d3 + d8 * d8);
587c4762a1bSJed Brown       f4 = PetscSqrtReal(1.0 + d3 * d3 + d2 * d2);
588c4762a1bSJed Brown       f5 = PetscSqrtReal(1.0 + d2 * d2 + d5 * d5);
589c4762a1bSJed Brown       f6 = PetscSqrtReal(1.0 + d4 * d4 + d6 * d6);
590c4762a1bSJed Brown 
5919371c9d4SSatish Balay       hl = (-hydhx * (1.0 + d7 * d7) + d1 * d7) / (f1 * f1 * f1) + (-hydhx * (1.0 + d4 * d4) + d1 * d4) / (f2 * f2 * f2);
5929371c9d4SSatish Balay       hr = (-hydhx * (1.0 + d5 * d5) + d2 * d5) / (f5 * f5 * f5) + (-hydhx * (1.0 + d3 * d3) + d2 * d3) / (f4 * f4 * f4);
5939371c9d4SSatish Balay       ht = (-hxdhy * (1.0 + d8 * d8) + d3 * d8) / (f3 * f3 * f3) + (-hxdhy * (1.0 + d2 * d2) + d2 * d3) / (f4 * f4 * f4);
5949371c9d4SSatish Balay       hb = (-hxdhy * (1.0 + d6 * d6) + d4 * d6) / (f6 * f6 * f6) + (-hxdhy * (1.0 + d1 * d1) + d1 * d4) / (f2 * f2 * f2);
595c4762a1bSJed Brown 
596c4762a1bSJed Brown       hbr = -d2 * d5 / (f5 * f5 * f5) - d4 * d6 / (f6 * f6 * f6);
597c4762a1bSJed Brown       htl = -d1 * d7 / (f1 * f1 * f1) - d3 * d8 / (f3 * f3 * f3);
598c4762a1bSJed Brown 
5999371c9d4SSatish Balay       hc = hydhx * (1.0 + d7 * d7) / (f1 * f1 * f1) + hxdhy * (1.0 + d8 * d8) / (f3 * f3 * f3) + hydhx * (1.0 + d5 * d5) / (f5 * f5 * f5) + hxdhy * (1.0 + d6 * d6) / (f6 * f6 * f6) + (hxdhy * (1.0 + d1 * d1) + hydhx * (1.0 + d4 * d4) - 2 * d1 * d4) / (f2 * f2 * f2) + (hxdhy * (1.0 + d2 * d2) + hydhx * (1.0 + d3 * d3) - 2 * d2 * d3) / (f4 * f4 * f4);
600c4762a1bSJed Brown 
6019371c9d4SSatish Balay       hl /= 2.0;
6029371c9d4SSatish Balay       hr /= 2.0;
6039371c9d4SSatish Balay       ht /= 2.0;
6049371c9d4SSatish Balay       hb /= 2.0;
6059371c9d4SSatish Balay       hbr /= 2.0;
6069371c9d4SSatish Balay       htl /= 2.0;
6079371c9d4SSatish Balay       hc /= 2.0;
608c4762a1bSJed Brown 
6099371c9d4SSatish Balay       row.j = j;
6109371c9d4SSatish Balay       row.i = i;
611c4762a1bSJed Brown       k     = 0;
612c4762a1bSJed Brown       if (j > 0) {
613c4762a1bSJed Brown         v[k]     = hb;
6149371c9d4SSatish Balay         col[k].j = j - 1;
6159371c9d4SSatish Balay         col[k].i = i;
616c4762a1bSJed Brown         k++;
617c4762a1bSJed Brown       }
618c4762a1bSJed Brown 
619c4762a1bSJed Brown       if (j > 0 && i < mx - 1) {
620c4762a1bSJed Brown         v[k]     = hbr;
6219371c9d4SSatish Balay         col[k].j = j - 1;
6229371c9d4SSatish Balay         col[k].i = i + 1;
623c4762a1bSJed Brown         k++;
624c4762a1bSJed Brown       }
625c4762a1bSJed Brown 
626c4762a1bSJed Brown       if (i > 0) {
627c4762a1bSJed Brown         v[k]     = hl;
6289371c9d4SSatish Balay         col[k].j = j;
6299371c9d4SSatish Balay         col[k].i = i - 1;
630c4762a1bSJed Brown         k++;
631c4762a1bSJed Brown       }
632c4762a1bSJed Brown 
633c4762a1bSJed Brown       v[k]     = hc;
6349371c9d4SSatish Balay       col[k].j = j;
6359371c9d4SSatish Balay       col[k].i = i;
636c4762a1bSJed Brown       k++;
637c4762a1bSJed Brown 
638c4762a1bSJed Brown       if (i < mx - 1) {
639c4762a1bSJed Brown         v[k]     = hr;
6409371c9d4SSatish Balay         col[k].j = j;
6419371c9d4SSatish Balay         col[k].i = i + 1;
642c4762a1bSJed Brown         k++;
643c4762a1bSJed Brown       }
644c4762a1bSJed Brown 
645c4762a1bSJed Brown       if (i > 0 && j < my - 1) {
646c4762a1bSJed Brown         v[k]     = htl;
6479371c9d4SSatish Balay         col[k].j = j + 1;
6489371c9d4SSatish Balay         col[k].i = i - 1;
649c4762a1bSJed Brown         k++;
650c4762a1bSJed Brown       }
651c4762a1bSJed Brown 
652c4762a1bSJed Brown       if (j < my - 1) {
653c4762a1bSJed Brown         v[k]     = ht;
6549371c9d4SSatish Balay         col[k].j = j + 1;
6559371c9d4SSatish Balay         col[k].i = i;
656c4762a1bSJed Brown         k++;
657c4762a1bSJed Brown       }
658c4762a1bSJed Brown 
659c4762a1bSJed Brown       /*
660c4762a1bSJed Brown          Set matrix values using local numbering, which was defined
661c4762a1bSJed Brown          earlier, in the main routine.
662c4762a1bSJed Brown       */
6639566063dSJacob Faibussowitsch       PetscCall(MatSetValuesStencil(Hessian, 1, &row, k, col, v, INSERT_VALUES));
664c4762a1bSJed Brown     }
665c4762a1bSJed Brown   }
666c4762a1bSJed Brown 
6679566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(user->dm, localX, (void **)&x));
6689566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(user->dm, &localX));
669c4762a1bSJed Brown 
6709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Hessian, MAT_FINAL_ASSEMBLY));
6719566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Hessian, MAT_FINAL_ASSEMBLY));
672c4762a1bSJed Brown 
6739566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(199.0 * xm * ym));
6743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
675c4762a1bSJed Brown }
676c4762a1bSJed Brown 
677c4762a1bSJed Brown /* ------------------------------------------------------------------- */
678c4762a1bSJed Brown /*
679c4762a1bSJed Brown    MSA_BoundaryConditions -  Calculates the boundary conditions for
680c4762a1bSJed Brown    the region.
681c4762a1bSJed Brown 
682c4762a1bSJed Brown    Input Parameter:
683c4762a1bSJed Brown .  user - user-defined application context
684c4762a1bSJed Brown 
685c4762a1bSJed Brown    Output Parameter:
686c4762a1bSJed Brown .  user - user-defined application context
687c4762a1bSJed Brown */
688d71ae5a4SJacob Faibussowitsch static PetscErrorCode MSA_BoundaryConditions(AppCtx *user)
689d71ae5a4SJacob Faibussowitsch {
690c4762a1bSJed Brown   PetscInt   i, j, k, limit = 0, maxits = 5;
691c4762a1bSJed Brown   PetscInt   xs, ys, xm, ym, gxs, gys, gxm, gym;
692c4762a1bSJed Brown   PetscInt   mx = user->mx, my = user->my;
693c4762a1bSJed Brown   PetscInt   bsize = 0, lsize = 0, tsize = 0, rsize = 0;
694c4762a1bSJed Brown   PetscReal  one = 1.0, two = 2.0, three = 3.0, tol = 1e-10;
695c4762a1bSJed Brown   PetscReal  fnorm, det, hx, hy, xt = 0, yt = 0;
696c4762a1bSJed Brown   PetscReal  u1, u2, nf1, nf2, njac11, njac12, njac21, njac22;
697c4762a1bSJed Brown   PetscReal  b = -0.5, t = 0.5, l = -0.5, r = 0.5;
698c4762a1bSJed Brown   PetscReal *boundary;
699c4762a1bSJed Brown   PetscBool  flg;
700c4762a1bSJed Brown 
701c4762a1bSJed Brown   PetscFunctionBegin;
702c4762a1bSJed Brown   /* Get local mesh boundaries */
7039566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(user->dm, &xs, &ys, NULL, &xm, &ym, NULL));
7049566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(user->dm, &gxs, &gys, NULL, &gxm, &gym, NULL));
705c4762a1bSJed Brown 
706c4762a1bSJed Brown   bsize = xm + 2;
707c4762a1bSJed Brown   lsize = ym + 2;
708c4762a1bSJed Brown   rsize = ym + 2;
709c4762a1bSJed Brown   tsize = xm + 2;
710c4762a1bSJed Brown 
7119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(bsize, &user->bottom));
7129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(tsize, &user->top));
7139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(lsize, &user->left));
7149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rsize, &user->right));
715c4762a1bSJed Brown 
7169371c9d4SSatish Balay   hx = (r - l) / (mx + 1);
7179371c9d4SSatish Balay   hy = (t - b) / (my + 1);
718c4762a1bSJed Brown 
719c4762a1bSJed Brown   for (j = 0; j < 4; j++) {
720c4762a1bSJed Brown     if (j == 0) {
721c4762a1bSJed Brown       yt       = b;
722c4762a1bSJed Brown       xt       = l + hx * xs;
723c4762a1bSJed Brown       limit    = bsize;
724c4762a1bSJed Brown       boundary = user->bottom;
725c4762a1bSJed Brown     } else if (j == 1) {
726c4762a1bSJed Brown       yt       = t;
727c4762a1bSJed Brown       xt       = l + hx * xs;
728c4762a1bSJed Brown       limit    = tsize;
729c4762a1bSJed Brown       boundary = user->top;
730c4762a1bSJed Brown     } else if (j == 2) {
731c4762a1bSJed Brown       yt       = b + hy * ys;
732c4762a1bSJed Brown       xt       = l;
733c4762a1bSJed Brown       limit    = lsize;
734c4762a1bSJed Brown       boundary = user->left;
735c4762a1bSJed Brown     } else { /* if (j==3) */
736c4762a1bSJed Brown       yt       = b + hy * ys;
737c4762a1bSJed Brown       xt       = r;
738c4762a1bSJed Brown       limit    = rsize;
739c4762a1bSJed Brown       boundary = user->right;
740c4762a1bSJed Brown     }
741c4762a1bSJed Brown 
742c4762a1bSJed Brown     for (i = 0; i < limit; i++) {
743c4762a1bSJed Brown       u1 = xt;
744c4762a1bSJed Brown       u2 = -yt;
745c4762a1bSJed Brown       for (k = 0; k < maxits; k++) {
746c4762a1bSJed Brown         nf1   = u1 + u1 * u2 * u2 - u1 * u1 * u1 / three - xt;
747c4762a1bSJed Brown         nf2   = -u2 - u1 * u1 * u2 + u2 * u2 * u2 / three - yt;
748c4762a1bSJed Brown         fnorm = PetscSqrtReal(nf1 * nf1 + nf2 * nf2);
749c4762a1bSJed Brown         if (fnorm <= tol) break;
750c4762a1bSJed Brown         njac11 = one + u2 * u2 - u1 * u1;
751c4762a1bSJed Brown         njac12 = two * u1 * u2;
752c4762a1bSJed Brown         njac21 = -two * u1 * u2;
753c4762a1bSJed Brown         njac22 = -one - u1 * u1 + u2 * u2;
754c4762a1bSJed Brown         det    = njac11 * njac22 - njac21 * njac12;
755c4762a1bSJed Brown         u1     = u1 - (njac22 * nf1 - njac12 * nf2) / det;
756c4762a1bSJed Brown         u2     = u2 - (njac11 * nf2 - njac21 * nf1) / det;
757c4762a1bSJed Brown       }
758c4762a1bSJed Brown 
759c4762a1bSJed Brown       boundary[i] = u1 * u1 - u2 * u2;
760c4762a1bSJed Brown       if (j == 0 || j == 1) {
761c4762a1bSJed Brown         xt = xt + hx;
762c4762a1bSJed Brown       } else { /*  if (j==2 || j==3) */
763c4762a1bSJed Brown         yt = yt + hy;
764c4762a1bSJed Brown       }
765c4762a1bSJed Brown     }
766c4762a1bSJed Brown   }
767c4762a1bSJed Brown 
768c4762a1bSJed Brown   /* Scale the boundary if desired */
769c4762a1bSJed Brown   if (1 == 1) {
770c4762a1bSJed Brown     PetscReal scl = 1.0;
771c4762a1bSJed Brown 
7729566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(NULL, NULL, "-bottom", &scl, &flg));
773c4762a1bSJed Brown     if (flg) {
774c4762a1bSJed Brown       for (i = 0; i < bsize; i++) user->bottom[i] *= scl;
775c4762a1bSJed Brown     }
776c4762a1bSJed Brown 
7779566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(NULL, NULL, "-top", &scl, &flg));
778c4762a1bSJed Brown     if (flg) {
779c4762a1bSJed Brown       for (i = 0; i < tsize; i++) user->top[i] *= scl;
780c4762a1bSJed Brown     }
781c4762a1bSJed Brown 
7829566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(NULL, NULL, "-right", &scl, &flg));
783c4762a1bSJed Brown     if (flg) {
784c4762a1bSJed Brown       for (i = 0; i < rsize; i++) user->right[i] *= scl;
785c4762a1bSJed Brown     }
786c4762a1bSJed Brown 
7879566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetReal(NULL, NULL, "-left", &scl, &flg));
788c4762a1bSJed Brown     if (flg) {
789c4762a1bSJed Brown       for (i = 0; i < lsize; i++) user->left[i] *= scl;
790c4762a1bSJed Brown     }
791c4762a1bSJed Brown   }
7923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
793c4762a1bSJed Brown }
794c4762a1bSJed Brown 
795c4762a1bSJed Brown /* ------------------------------------------------------------------- */
796c4762a1bSJed Brown /*
797c4762a1bSJed Brown    MSA_InitialPoint - Calculates the initial guess in one of three ways.
798c4762a1bSJed Brown 
799c4762a1bSJed Brown    Input Parameters:
800c4762a1bSJed Brown .  user - user-defined application context
801c4762a1bSJed Brown .  X - vector for initial guess
802c4762a1bSJed Brown 
803c4762a1bSJed Brown    Output Parameters:
804c4762a1bSJed Brown .  X - newly computed initial guess
805c4762a1bSJed Brown */
806d71ae5a4SJacob Faibussowitsch static PetscErrorCode MSA_InitialPoint(AppCtx *user, Vec X)
807d71ae5a4SJacob Faibussowitsch {
808c4762a1bSJed Brown   PetscInt  start2 = -1, i, j;
809c4762a1bSJed Brown   PetscReal start1 = 0;
810c4762a1bSJed Brown   PetscBool flg1, flg2;
811c4762a1bSJed Brown 
812c4762a1bSJed Brown   PetscFunctionBegin;
8139566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetReal(NULL, NULL, "-start", &start1, &flg1));
8149566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetInt(NULL, NULL, "-random", &start2, &flg2));
815c4762a1bSJed Brown 
816c4762a1bSJed Brown   if (flg1) { /* The zero vector is reasonable */
8179566063dSJacob Faibussowitsch     PetscCall(VecSet(X, start1));
818c4762a1bSJed Brown   } else if (flg2 && start2 > 0) { /* Try a random start between -0.5 and 0.5 */
8199371c9d4SSatish Balay     PetscRandom rctx;
8209371c9d4SSatish Balay     PetscReal   np5 = -0.5;
821c4762a1bSJed Brown 
8229566063dSJacob Faibussowitsch     PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rctx));
8239566063dSJacob Faibussowitsch     PetscCall(VecSetRandom(X, rctx));
8249566063dSJacob Faibussowitsch     PetscCall(PetscRandomDestroy(&rctx));
8259566063dSJacob Faibussowitsch     PetscCall(VecShift(X, np5));
826c4762a1bSJed Brown   } else { /* Take an average of the boundary conditions */
827c4762a1bSJed Brown     PetscInt    xs, xm, ys, ym;
828c4762a1bSJed Brown     PetscInt    mx = user->mx, my = user->my;
829c4762a1bSJed Brown     PetscReal **x;
830c4762a1bSJed Brown 
831c4762a1bSJed Brown     /* Get local mesh boundaries */
8329566063dSJacob Faibussowitsch     PetscCall(DMDAGetCorners(user->dm, &xs, &ys, NULL, &xm, &ym, NULL));
833c4762a1bSJed Brown 
834c4762a1bSJed Brown     /* Get pointers to vector data */
8359566063dSJacob Faibussowitsch     PetscCall(DMDAVecGetArray(user->dm, X, (void **)&x));
836c4762a1bSJed Brown 
837c4762a1bSJed Brown     /* Perform local computations */
838c4762a1bSJed Brown     for (j = ys; j < ys + ym; j++) {
839ad540459SPierre Jolivet       for (i = xs; i < xs + xm; i++) x[j][i] = (((j + 1) * user->bottom[i - xs + 1] + (my - j + 1) * user->top[i - xs + 1]) / (my + 2) + ((i + 1) * user->left[j - ys + 1] + (mx - i + 1) * user->right[j - ys + 1]) / (mx + 2)) / 2.0;
840c4762a1bSJed Brown     }
8419566063dSJacob Faibussowitsch     PetscCall(DMDAVecRestoreArray(user->dm, X, (void **)&x));
8429566063dSJacob Faibussowitsch     PetscCall(PetscLogFlops(9.0 * xm * ym));
843c4762a1bSJed Brown   }
8443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
845c4762a1bSJed Brown }
846c4762a1bSJed Brown 
847c4762a1bSJed Brown /*-----------------------------------------------------------------------*/
848d71ae5a4SJacob Faibussowitsch PetscErrorCode My_Monitor(Tao tao, void *ctx)
849d71ae5a4SJacob Faibussowitsch {
850c4762a1bSJed Brown   Vec X;
851c4762a1bSJed Brown 
852c4762a1bSJed Brown   PetscFunctionBegin;
8539566063dSJacob Faibussowitsch   PetscCall(TaoGetSolution(tao, &X));
8549566063dSJacob Faibussowitsch   PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
8553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
856c4762a1bSJed Brown }
857c4762a1bSJed Brown 
858c4762a1bSJed Brown /*TEST
859c4762a1bSJed Brown 
860c4762a1bSJed Brown    build:
861c4762a1bSJed Brown       requires: !complex
862c4762a1bSJed Brown 
863c4762a1bSJed Brown    test:
864*9f1eecfaSStefano Zampini       args: -tao_smonitor -tao_type lmvm -da_grid_x 10 -da_grid_y 8 -tao_gatol 1.e-3
865c4762a1bSJed Brown       requires: !single
866c4762a1bSJed Brown 
867c4762a1bSJed Brown    test:
868c4762a1bSJed Brown       suffix: 2
869c4762a1bSJed Brown       nsize: 2
870c4762a1bSJed Brown       args: -tao_smonitor -tao_type nls -tao_nls_ksp_max_it 15 -tao_gatol 1.e-4
871c4762a1bSJed Brown       filter: grep -v "nls ksp"
872c4762a1bSJed Brown       requires: !single
873c4762a1bSJed Brown 
874c4762a1bSJed Brown    test:
8754936d809SStefano Zampini       suffix: 2_snes
8764936d809SStefano Zampini       nsize: 2
8774936d809SStefano Zampini       args: -tao_smonitor -tao_type snes -ksp_converged_maxits -ksp_max_it 15 -snes_atol 1.e-4
8784936d809SStefano Zampini       filter: grep -v "nls ksp"
8794936d809SStefano Zampini       requires: !single
8804936d809SStefano Zampini 
8814936d809SStefano Zampini    test:
882c4762a1bSJed Brown       suffix: 3
883c4762a1bSJed Brown       nsize: 3
884*9f1eecfaSStefano Zampini       args: -tao_smonitor -tao_type cg -tao_cg_type fr -da_grid_x 10 -da_grid_y 10 -tao_gatol 1.e-3
885c4762a1bSJed Brown       requires: !single
886c4762a1bSJed Brown 
887c4762a1bSJed Brown    test:
8884936d809SStefano Zampini       suffix: 3_snes
8894936d809SStefano Zampini       nsize: 3
890*9f1eecfaSStefano Zampini       args: -tao_smonitor -tao_type snes -snes_type ncg -snes_ncg_type fr -da_grid_x 10 -da_grid_y 10 -snes_atol 1.e-4
8914936d809SStefano Zampini       requires: !single
8924936d809SStefano Zampini 
8934936d809SStefano Zampini    test:
8944936d809SStefano Zampini       suffix: 4_snes_ngmres
895*9f1eecfaSStefano Zampini       args: -tao_type snes -snes_type ngmres -npc_snes_type ncg -da_grid_x 10 -da_grid_y 10 -snes_atol 1.e-4 -npc_snes_ncg_type fr  -snes_converged_reason -snes_monitor ::ascii_info_detail -snes_ngmres_monitor -snes_ngmres_select_type {{linesearch difference}separate output}
8964936d809SStefano Zampini       requires: !single
8974936d809SStefano Zampini 
8984936d809SStefano Zampini    test:
899c4762a1bSJed Brown       suffix: 5
900c4762a1bSJed Brown       nsize: 2
901*9f1eecfaSStefano Zampini       args: -tao_smonitor -tao_type bmrm -da_grid_x 10 -da_grid_y 8 -tao_gatol 1.e-3
902c4762a1bSJed Brown       requires: !single
903c4762a1bSJed Brown 
904c4762a1bSJed Brown TEST*/
905