1c4762a1bSJed Brown 2c4762a1bSJed Brown #include <petscsnes.h> 3c4762a1bSJed Brown #include <petscdm.h> 4c4762a1bSJed Brown #include <petscdmda.h> 5c4762a1bSJed Brown 6c4762a1bSJed Brown static const char help[] = "Parallel version of the minimum surface area problem in 2D using DMDA.\n\ 7c4762a1bSJed Brown It solves a system of nonlinear equations in mixed\n\ 8c4762a1bSJed Brown complementarity form.This example is based on a\n\ 9c4762a1bSJed Brown problem from the MINPACK-2 test suite. Given a rectangular 2-D domain and\n\ 10c4762a1bSJed Brown boundary values along the edges of the domain, the objective is to find the\n\ 11c4762a1bSJed Brown surface with the minimal area that satisfies the boundary conditions.\n\ 12c4762a1bSJed Brown This application solves this problem using complimentarity -- We are actually\n\ 13c4762a1bSJed Brown solving the system (grad f)_i >= 0, if x_i == l_i \n\ 14c4762a1bSJed Brown (grad f)_i = 0, if l_i < x_i < u_i \n\ 15c4762a1bSJed Brown (grad f)_i <= 0, if x_i == u_i \n\ 16c4762a1bSJed Brown where f is the function to be minimized. \n\ 17c4762a1bSJed Brown \n\ 18c4762a1bSJed Brown The command line options are:\n\ 19c4762a1bSJed Brown -da_grid_x <nx>, where <nx> = number of grid points in the 1st coordinate direction\n\ 20c4762a1bSJed Brown -da_grid_y <ny>, where <ny> = number of grid points in the 2nd coordinate direction\n\ 21c4762a1bSJed Brown -start <st>, where <st> =0 for zero vector, and an average of the boundary conditions otherwise\n\ 22c4762a1bSJed Brown -lb <value>, lower bound on the variables\n\ 23c4762a1bSJed Brown -ub <value>, upper bound on the variables\n\n"; 24c4762a1bSJed Brown 25c4762a1bSJed Brown /* 26c4762a1bSJed Brown User-defined application context - contains data needed by the 27c4762a1bSJed Brown application-provided call-back routines, FormJacobian() and 28c4762a1bSJed Brown FormFunction(). 29c4762a1bSJed Brown */ 30c4762a1bSJed Brown 31c4762a1bSJed Brown /* 32c4762a1bSJed Brown This is a new version of the ../tests/ex8.c code 33c4762a1bSJed Brown 34c4762a1bSJed Brown Run, for example, with the options ./ex58 -snes_vi_monitor -ksp_monitor -mg_levels_ksp_monitor -pc_type mg -pc_mg_levels 2 -pc_mg_galerkin pmat -ksp_type fgmres 35c4762a1bSJed Brown 36c4762a1bSJed Brown Or to run with grid sequencing on the nonlinear problem (note that you do not need to provide the number of 37c4762a1bSJed Brown multigrid levels, it will be determined automatically based on the number of refinements done) 38c4762a1bSJed Brown 39c4762a1bSJed Brown ./ex58 -pc_type mg -ksp_monitor -snes_view -pc_mg_galerkin pmat -snes_grid_sequence 3 40c4762a1bSJed Brown -mg_levels_ksp_monitor -snes_vi_monitor -mg_levels_pc_type sor -pc_mg_type full 41c4762a1bSJed Brown 42c4762a1bSJed Brown */ 43c4762a1bSJed Brown 44c4762a1bSJed Brown typedef struct { 45c4762a1bSJed Brown PetscScalar *bottom, *top, *left, *right; 46c4762a1bSJed Brown PetscScalar lb, ub; 47c4762a1bSJed Brown } AppCtx; 48c4762a1bSJed Brown 49c4762a1bSJed Brown /* -------- User-defined Routines --------- */ 50c4762a1bSJed Brown 51c4762a1bSJed Brown extern PetscErrorCode FormBoundaryConditions(SNES, AppCtx **); 52c4762a1bSJed Brown extern PetscErrorCode DestroyBoundaryConditions(AppCtx **); 53c4762a1bSJed Brown extern PetscErrorCode ComputeInitialGuess(SNES, Vec, void *); 54c4762a1bSJed Brown extern PetscErrorCode FormGradient(SNES, Vec, Vec, void *); 55c4762a1bSJed Brown extern PetscErrorCode FormJacobian(SNES, Vec, Mat, Mat, void *); 56c4762a1bSJed Brown extern PetscErrorCode FormBounds(SNES, Vec, Vec); 57c4762a1bSJed Brown 58*9371c9d4SSatish Balay int main(int argc, char **argv) { 59c4762a1bSJed Brown Vec x, r; /* solution and residual vectors */ 60c4762a1bSJed Brown SNES snes; /* nonlinear solver context */ 61c4762a1bSJed Brown Mat J; /* Jacobian matrix */ 62c4762a1bSJed Brown DM da; 63c4762a1bSJed Brown 64327415f7SBarry Smith PetscFunctionBeginUser; 659566063dSJacob Faibussowitsch PetscCall(PetscInitialize(&argc, &argv, (char *)0, help)); 66c4762a1bSJed Brown 67c4762a1bSJed Brown /* Create distributed array to manage the 2d grid */ 689566063dSJacob Faibussowitsch PetscCall(DMDACreate2d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_BOX, 4, 4, PETSC_DECIDE, PETSC_DECIDE, 1, 1, NULL, NULL, &da)); 699566063dSJacob Faibussowitsch PetscCall(DMSetFromOptions(da)); 709566063dSJacob Faibussowitsch PetscCall(DMSetUp(da)); 71c4762a1bSJed Brown 72c4762a1bSJed Brown /* Extract global vectors from DMDA; */ 739566063dSJacob Faibussowitsch PetscCall(DMCreateGlobalVector(da, &x)); 749566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &r)); 75c4762a1bSJed Brown 769566063dSJacob Faibussowitsch PetscCall(DMSetMatType(da, MATAIJ)); 779566063dSJacob Faibussowitsch PetscCall(DMCreateMatrix(da, &J)); 78c4762a1bSJed Brown 79c4762a1bSJed Brown /* Create nonlinear solver context */ 809566063dSJacob Faibussowitsch PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes)); 819566063dSJacob Faibussowitsch PetscCall(SNESSetDM(snes, da)); 82c4762a1bSJed Brown 83c4762a1bSJed Brown /* Set function evaluation and Jacobian evaluation routines */ 849566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, r, FormGradient, NULL)); 859566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, J, J, FormJacobian, NULL)); 86c4762a1bSJed Brown 879566063dSJacob Faibussowitsch PetscCall(SNESSetComputeApplicationContext(snes, (PetscErrorCode(*)(SNES, void **))FormBoundaryConditions, (PetscErrorCode(*)(void **))DestroyBoundaryConditions)); 88c4762a1bSJed Brown 899566063dSJacob Faibussowitsch PetscCall(SNESSetComputeInitialGuess(snes, ComputeInitialGuess, NULL)); 90c4762a1bSJed Brown 919566063dSJacob Faibussowitsch PetscCall(SNESVISetComputeVariableBounds(snes, FormBounds)); 92c4762a1bSJed Brown 939566063dSJacob Faibussowitsch PetscCall(SNESSetFromOptions(snes)); 94c4762a1bSJed Brown 95c4762a1bSJed Brown /* Solve the application */ 969566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes, NULL, x)); 97c4762a1bSJed Brown 98c4762a1bSJed Brown /* Free memory */ 999566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x)); 1009566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 1019566063dSJacob Faibussowitsch PetscCall(MatDestroy(&J)); 1029566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&snes)); 103c4762a1bSJed Brown 104c4762a1bSJed Brown /* Free user-created data structures */ 1059566063dSJacob Faibussowitsch PetscCall(DMDestroy(&da)); 106c4762a1bSJed Brown 1079566063dSJacob Faibussowitsch PetscCall(PetscFinalize()); 108b122ec5aSJacob Faibussowitsch return 0; 109c4762a1bSJed Brown } 110c4762a1bSJed Brown 111c4762a1bSJed Brown /* -------------------------------------------------------------------- */ 112c4762a1bSJed Brown 113c4762a1bSJed Brown /* FormBounds - sets the upper and lower bounds 114c4762a1bSJed Brown 115c4762a1bSJed Brown Input Parameters: 116c4762a1bSJed Brown . snes - the SNES context 117c4762a1bSJed Brown 118c4762a1bSJed Brown Output Parameters: 119c4762a1bSJed Brown . xl - lower bounds 120c4762a1bSJed Brown . xu - upper bounds 121c4762a1bSJed Brown */ 122*9371c9d4SSatish Balay PetscErrorCode FormBounds(SNES snes, Vec xl, Vec xu) { 123c4762a1bSJed Brown AppCtx *ctx; 124c4762a1bSJed Brown 125c4762a1bSJed Brown PetscFunctionBeginUser; 1269566063dSJacob Faibussowitsch PetscCall(SNESGetApplicationContext(snes, &ctx)); 1279566063dSJacob Faibussowitsch PetscCall(VecSet(xl, ctx->lb)); 1289566063dSJacob Faibussowitsch PetscCall(VecSet(xu, ctx->ub)); 129c4762a1bSJed Brown PetscFunctionReturn(0); 130c4762a1bSJed Brown } 131c4762a1bSJed Brown 132c4762a1bSJed Brown /* -------------------------------------------------------------------- */ 133c4762a1bSJed Brown 134c4762a1bSJed Brown /* FormGradient - Evaluates gradient of f. 135c4762a1bSJed Brown 136c4762a1bSJed Brown Input Parameters: 137c4762a1bSJed Brown . snes - the SNES context 138c4762a1bSJed Brown . X - input vector 139c4762a1bSJed Brown . ptr - optional user-defined context, as set by SNESSetFunction() 140c4762a1bSJed Brown 141c4762a1bSJed Brown Output Parameters: 142c4762a1bSJed Brown . G - vector containing the newly evaluated gradient 143c4762a1bSJed Brown */ 144*9371c9d4SSatish Balay PetscErrorCode FormGradient(SNES snes, Vec X, Vec G, void *ptr) { 145c4762a1bSJed Brown AppCtx *user; 146c4762a1bSJed Brown PetscInt i, j; 147c4762a1bSJed Brown PetscInt mx, my; 148c4762a1bSJed Brown PetscScalar hx, hy, hydhx, hxdhy; 149c4762a1bSJed Brown PetscScalar f1, f2, f3, f4, f5, f6, d1, d2, d3, d4, d5, d6, d7, d8, xc, xl, xr, xt, xb, xlt, xrb; 150c4762a1bSJed Brown PetscScalar df1dxc, df2dxc, df3dxc, df4dxc, df5dxc, df6dxc; 151c4762a1bSJed Brown PetscScalar **g, **x; 152c4762a1bSJed Brown PetscInt xs, xm, ys, ym; 153c4762a1bSJed Brown Vec localX; 154c4762a1bSJed Brown DM da; 155c4762a1bSJed Brown 156c4762a1bSJed Brown PetscFunctionBeginUser; 1579566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &da)); 1589566063dSJacob Faibussowitsch PetscCall(SNESGetApplicationContext(snes, &user)); 1599566063dSJacob Faibussowitsch PetscCall(DMDAGetInfo(da, PETSC_IGNORE, &mx, &my, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE)); 160*9371c9d4SSatish Balay hx = 1.0 / (mx + 1); 161*9371c9d4SSatish Balay hy = 1.0 / (my + 1); 162*9371c9d4SSatish Balay hydhx = hy / hx; 163*9371c9d4SSatish Balay hxdhy = hx / hy; 164c4762a1bSJed Brown 1659566063dSJacob Faibussowitsch PetscCall(VecSet(G, 0.0)); 166c4762a1bSJed Brown 167c4762a1bSJed Brown /* Get local vector */ 1689566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(da, &localX)); 169c4762a1bSJed Brown /* Get ghost points */ 1709566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, localX)); 1719566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, localX)); 172c4762a1bSJed Brown /* Get pointer to local vector data */ 1739566063dSJacob Faibussowitsch PetscCall(DMDAVecGetArray(da, localX, &x)); 1749566063dSJacob Faibussowitsch PetscCall(DMDAVecGetArray(da, G, &g)); 175c4762a1bSJed Brown 1769566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL)); 177c4762a1bSJed Brown /* Compute function over the locally owned part of the mesh */ 178c4762a1bSJed Brown for (j = ys; j < ys + ym; j++) { 179c4762a1bSJed Brown for (i = xs; i < xs + xm; i++) { 180c4762a1bSJed Brown xc = x[j][i]; 181c4762a1bSJed Brown xlt = xrb = xl = xr = xb = xt = xc; 182c4762a1bSJed Brown 183c4762a1bSJed Brown if (i == 0) { /* left side */ 184c4762a1bSJed Brown xl = user->left[j + 1]; 185c4762a1bSJed Brown xlt = user->left[j + 2]; 186c4762a1bSJed Brown } else xl = x[j][i - 1]; 187c4762a1bSJed Brown 188c4762a1bSJed Brown if (j == 0) { /* bottom side */ 189c4762a1bSJed Brown xb = user->bottom[i + 1]; 190c4762a1bSJed Brown xrb = user->bottom[i + 2]; 191c4762a1bSJed Brown } else xb = x[j - 1][i]; 192c4762a1bSJed Brown 193c4762a1bSJed Brown if (i + 1 == mx) { /* right side */ 194c4762a1bSJed Brown xr = user->right[j + 1]; 195c4762a1bSJed Brown xrb = user->right[j]; 196c4762a1bSJed Brown } else xr = x[j][i + 1]; 197c4762a1bSJed Brown 198c4762a1bSJed Brown if (j + 1 == 0 + my) { /* top side */ 199c4762a1bSJed Brown xt = user->top[i + 1]; 200c4762a1bSJed Brown xlt = user->top[i]; 201c4762a1bSJed Brown } else xt = x[j + 1][i]; 202c4762a1bSJed Brown 203c4762a1bSJed Brown if (i > 0 && j + 1 < my) xlt = x[j + 1][i - 1]; /* left top side */ 204c4762a1bSJed Brown if (j > 0 && i + 1 < mx) xrb = x[j - 1][i + 1]; /* right bottom */ 205c4762a1bSJed Brown 206c4762a1bSJed Brown d1 = (xc - xl); 207c4762a1bSJed Brown d2 = (xc - xr); 208c4762a1bSJed Brown d3 = (xc - xt); 209c4762a1bSJed Brown d4 = (xc - xb); 210c4762a1bSJed Brown d5 = (xr - xrb); 211c4762a1bSJed Brown d6 = (xrb - xb); 212c4762a1bSJed Brown d7 = (xlt - xl); 213c4762a1bSJed Brown d8 = (xt - xlt); 214c4762a1bSJed Brown 215c4762a1bSJed Brown df1dxc = d1 * hydhx; 216c4762a1bSJed Brown df2dxc = (d1 * hydhx + d4 * hxdhy); 217c4762a1bSJed Brown df3dxc = d3 * hxdhy; 218c4762a1bSJed Brown df4dxc = (d2 * hydhx + d3 * hxdhy); 219c4762a1bSJed Brown df5dxc = d2 * hydhx; 220c4762a1bSJed Brown df6dxc = d4 * hxdhy; 221c4762a1bSJed Brown 222c4762a1bSJed Brown d1 /= hx; 223c4762a1bSJed Brown d2 /= hx; 224c4762a1bSJed Brown d3 /= hy; 225c4762a1bSJed Brown d4 /= hy; 226c4762a1bSJed Brown d5 /= hy; 227c4762a1bSJed Brown d6 /= hx; 228c4762a1bSJed Brown d7 /= hy; 229c4762a1bSJed Brown d8 /= hx; 230c4762a1bSJed Brown 231c4762a1bSJed Brown f1 = PetscSqrtScalar(1.0 + d1 * d1 + d7 * d7); 232c4762a1bSJed Brown f2 = PetscSqrtScalar(1.0 + d1 * d1 + d4 * d4); 233c4762a1bSJed Brown f3 = PetscSqrtScalar(1.0 + d3 * d3 + d8 * d8); 234c4762a1bSJed Brown f4 = PetscSqrtScalar(1.0 + d3 * d3 + d2 * d2); 235c4762a1bSJed Brown f5 = PetscSqrtScalar(1.0 + d2 * d2 + d5 * d5); 236c4762a1bSJed Brown f6 = PetscSqrtScalar(1.0 + d4 * d4 + d6 * d6); 237c4762a1bSJed Brown 238c4762a1bSJed Brown df1dxc /= f1; 239c4762a1bSJed Brown df2dxc /= f2; 240c4762a1bSJed Brown df3dxc /= f3; 241c4762a1bSJed Brown df4dxc /= f4; 242c4762a1bSJed Brown df5dxc /= f5; 243c4762a1bSJed Brown df6dxc /= f6; 244c4762a1bSJed Brown 245c4762a1bSJed Brown g[j][i] = (df1dxc + df2dxc + df3dxc + df4dxc + df5dxc + df6dxc) / 2.0; 246c4762a1bSJed Brown } 247c4762a1bSJed Brown } 248c4762a1bSJed Brown 249c4762a1bSJed Brown /* Restore vectors */ 2509566063dSJacob Faibussowitsch PetscCall(DMDAVecRestoreArray(da, localX, &x)); 2519566063dSJacob Faibussowitsch PetscCall(DMDAVecRestoreArray(da, G, &g)); 2529566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(da, &localX)); 2539566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(67.0 * mx * my)); 254c4762a1bSJed Brown PetscFunctionReturn(0); 255c4762a1bSJed Brown } 256c4762a1bSJed Brown 257c4762a1bSJed Brown /* ------------------------------------------------------------------- */ 258c4762a1bSJed Brown /* 259c4762a1bSJed Brown FormJacobian - Evaluates Jacobian matrix. 260c4762a1bSJed Brown 261c4762a1bSJed Brown Input Parameters: 262c4762a1bSJed Brown . snes - SNES context 263c4762a1bSJed Brown . X - input vector 264c4762a1bSJed Brown . ptr - optional user-defined context, as set by SNESSetJacobian() 265c4762a1bSJed Brown 266c4762a1bSJed Brown Output Parameters: 267c4762a1bSJed Brown . tH - Jacobian matrix 268c4762a1bSJed Brown 269c4762a1bSJed Brown */ 270*9371c9d4SSatish Balay PetscErrorCode FormJacobian(SNES snes, Vec X, Mat H, Mat tHPre, void *ptr) { 271c4762a1bSJed Brown AppCtx *user; 272c4762a1bSJed Brown PetscInt i, j, k; 273c4762a1bSJed Brown PetscInt mx, my; 274c4762a1bSJed Brown MatStencil row, col[7]; 275c4762a1bSJed Brown PetscScalar hx, hy, hydhx, hxdhy; 276c4762a1bSJed Brown PetscScalar f1, f2, f3, f4, f5, f6, d1, d2, d3, d4, d5, d6, d7, d8, xc, xl, xr, xt, xb, xlt, xrb; 277c4762a1bSJed Brown PetscScalar hl, hr, ht, hb, hc, htl, hbr; 278c4762a1bSJed Brown PetscScalar **x, v[7]; 279c4762a1bSJed Brown PetscBool assembled; 280c4762a1bSJed Brown PetscInt xs, xm, ys, ym; 281c4762a1bSJed Brown Vec localX; 282c4762a1bSJed Brown DM da; 283c4762a1bSJed Brown 284c4762a1bSJed Brown PetscFunctionBeginUser; 2859566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &da)); 2869566063dSJacob Faibussowitsch PetscCall(SNESGetApplicationContext(snes, &user)); 2879566063dSJacob Faibussowitsch PetscCall(DMDAGetInfo(da, PETSC_IGNORE, &mx, &my, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE)); 288*9371c9d4SSatish Balay hx = 1.0 / (mx + 1); 289*9371c9d4SSatish Balay hy = 1.0 / (my + 1); 290*9371c9d4SSatish Balay hydhx = hy / hx; 291*9371c9d4SSatish Balay hxdhy = hx / hy; 292c4762a1bSJed Brown 293c4762a1bSJed Brown /* Set various matrix options */ 2949566063dSJacob Faibussowitsch PetscCall(MatAssembled(H, &assembled)); 2959566063dSJacob Faibussowitsch if (assembled) PetscCall(MatZeroEntries(H)); 296c4762a1bSJed Brown 297c4762a1bSJed Brown /* Get local vector */ 2989566063dSJacob Faibussowitsch PetscCall(DMGetLocalVector(da, &localX)); 299c4762a1bSJed Brown /* Get ghost points */ 3009566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, localX)); 3019566063dSJacob Faibussowitsch PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, localX)); 302c4762a1bSJed Brown 303c4762a1bSJed Brown /* Get pointers to vector data */ 3049566063dSJacob Faibussowitsch PetscCall(DMDAVecGetArray(da, localX, &x)); 305c4762a1bSJed Brown 3069566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL)); 307c4762a1bSJed Brown /* Compute Jacobian over the locally owned part of the mesh */ 308c4762a1bSJed Brown for (j = ys; j < ys + ym; j++) { 309c4762a1bSJed Brown for (i = xs; i < xs + xm; i++) { 310c4762a1bSJed Brown xc = x[j][i]; 311c4762a1bSJed Brown xlt = xrb = xl = xr = xb = xt = xc; 312c4762a1bSJed Brown 313c4762a1bSJed Brown /* Left */ 314c4762a1bSJed Brown if (i == 0) { 315c4762a1bSJed Brown xl = user->left[j + 1]; 316c4762a1bSJed Brown xlt = user->left[j + 2]; 317c4762a1bSJed Brown } else xl = x[j][i - 1]; 318c4762a1bSJed Brown 319c4762a1bSJed Brown /* Bottom */ 320c4762a1bSJed Brown if (j == 0) { 321c4762a1bSJed Brown xb = user->bottom[i + 1]; 322c4762a1bSJed Brown xrb = user->bottom[i + 2]; 323c4762a1bSJed Brown } else xb = x[j - 1][i]; 324c4762a1bSJed Brown 325c4762a1bSJed Brown /* Right */ 326c4762a1bSJed Brown if (i + 1 == mx) { 327c4762a1bSJed Brown xr = user->right[j + 1]; 328c4762a1bSJed Brown xrb = user->right[j]; 329c4762a1bSJed Brown } else xr = x[j][i + 1]; 330c4762a1bSJed Brown 331c4762a1bSJed Brown /* Top */ 332c4762a1bSJed Brown if (j + 1 == my) { 333c4762a1bSJed Brown xt = user->top[i + 1]; 334c4762a1bSJed Brown xlt = user->top[i]; 335c4762a1bSJed Brown } else xt = x[j + 1][i]; 336c4762a1bSJed Brown 337c4762a1bSJed Brown /* Top left */ 338c4762a1bSJed Brown if (i > 0 && j + 1 < my) xlt = x[j + 1][i - 1]; 339c4762a1bSJed Brown 340c4762a1bSJed Brown /* Bottom right */ 341c4762a1bSJed Brown if (j > 0 && i + 1 < mx) xrb = x[j - 1][i + 1]; 342c4762a1bSJed Brown 343c4762a1bSJed Brown d1 = (xc - xl) / hx; 344c4762a1bSJed Brown d2 = (xc - xr) / hx; 345c4762a1bSJed Brown d3 = (xc - xt) / hy; 346c4762a1bSJed Brown d4 = (xc - xb) / hy; 347c4762a1bSJed Brown d5 = (xrb - xr) / hy; 348c4762a1bSJed Brown d6 = (xrb - xb) / hx; 349c4762a1bSJed Brown d7 = (xlt - xl) / hy; 350c4762a1bSJed Brown d8 = (xlt - xt) / hx; 351c4762a1bSJed Brown 352c4762a1bSJed Brown f1 = PetscSqrtScalar(1.0 + d1 * d1 + d7 * d7); 353c4762a1bSJed Brown f2 = PetscSqrtScalar(1.0 + d1 * d1 + d4 * d4); 354c4762a1bSJed Brown f3 = PetscSqrtScalar(1.0 + d3 * d3 + d8 * d8); 355c4762a1bSJed Brown f4 = PetscSqrtScalar(1.0 + d3 * d3 + d2 * d2); 356c4762a1bSJed Brown f5 = PetscSqrtScalar(1.0 + d2 * d2 + d5 * d5); 357c4762a1bSJed Brown f6 = PetscSqrtScalar(1.0 + d4 * d4 + d6 * d6); 358c4762a1bSJed Brown 359*9371c9d4SSatish Balay hl = (-hydhx * (1.0 + d7 * d7) + d1 * d7) / (f1 * f1 * f1) + (-hydhx * (1.0 + d4 * d4) + d1 * d4) / (f2 * f2 * f2); 360*9371c9d4SSatish Balay hr = (-hydhx * (1.0 + d5 * d5) + d2 * d5) / (f5 * f5 * f5) + (-hydhx * (1.0 + d3 * d3) + d2 * d3) / (f4 * f4 * f4); 361*9371c9d4SSatish Balay ht = (-hxdhy * (1.0 + d8 * d8) + d3 * d8) / (f3 * f3 * f3) + (-hxdhy * (1.0 + d2 * d2) + d2 * d3) / (f4 * f4 * f4); 362*9371c9d4SSatish Balay hb = (-hxdhy * (1.0 + d6 * d6) + d4 * d6) / (f6 * f6 * f6) + (-hxdhy * (1.0 + d1 * d1) + d1 * d4) / (f2 * f2 * f2); 363c4762a1bSJed Brown 364c4762a1bSJed Brown hbr = -d2 * d5 / (f5 * f5 * f5) - d4 * d6 / (f6 * f6 * f6); 365c4762a1bSJed Brown htl = -d1 * d7 / (f1 * f1 * f1) - d3 * d8 / (f3 * f3 * f3); 366c4762a1bSJed Brown 367*9371c9d4SSatish 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.0 * d1 * d4) / (f2 * f2 * f2) + (hxdhy * (1.0 + d2 * d2) + hydhx * (1.0 + d3 * d3) - 2.0 * d2 * d3) / (f4 * f4 * f4); 368c4762a1bSJed Brown 369*9371c9d4SSatish Balay hl /= 2.0; 370*9371c9d4SSatish Balay hr /= 2.0; 371*9371c9d4SSatish Balay ht /= 2.0; 372*9371c9d4SSatish Balay hb /= 2.0; 373*9371c9d4SSatish Balay hbr /= 2.0; 374*9371c9d4SSatish Balay htl /= 2.0; 375*9371c9d4SSatish Balay hc /= 2.0; 376c4762a1bSJed Brown 377c4762a1bSJed Brown k = 0; 378*9371c9d4SSatish Balay row.i = i; 379*9371c9d4SSatish Balay row.j = j; 380c4762a1bSJed Brown /* Bottom */ 381c4762a1bSJed Brown if (j > 0) { 382c4762a1bSJed Brown v[k] = hb; 383*9371c9d4SSatish Balay col[k].i = i; 384*9371c9d4SSatish Balay col[k].j = j - 1; 385*9371c9d4SSatish Balay k++; 386c4762a1bSJed Brown } 387c4762a1bSJed Brown 388c4762a1bSJed Brown /* Bottom right */ 389c4762a1bSJed Brown if (j > 0 && i < mx - 1) { 390c4762a1bSJed Brown v[k] = hbr; 391*9371c9d4SSatish Balay col[k].i = i + 1; 392*9371c9d4SSatish Balay col[k].j = j - 1; 393*9371c9d4SSatish Balay k++; 394c4762a1bSJed Brown } 395c4762a1bSJed Brown 396c4762a1bSJed Brown /* left */ 397c4762a1bSJed Brown if (i > 0) { 398c4762a1bSJed Brown v[k] = hl; 399*9371c9d4SSatish Balay col[k].i = i - 1; 400*9371c9d4SSatish Balay col[k].j = j; 401*9371c9d4SSatish Balay k++; 402c4762a1bSJed Brown } 403c4762a1bSJed Brown 404c4762a1bSJed Brown /* Centre */ 405*9371c9d4SSatish Balay v[k] = hc; 406*9371c9d4SSatish Balay col[k].i = row.i; 407*9371c9d4SSatish Balay col[k].j = row.j; 408*9371c9d4SSatish Balay k++; 409c4762a1bSJed Brown 410c4762a1bSJed Brown /* Right */ 411c4762a1bSJed Brown if (i < mx - 1) { 412c4762a1bSJed Brown v[k] = hr; 413*9371c9d4SSatish Balay col[k].i = i + 1; 414*9371c9d4SSatish Balay col[k].j = j; 415*9371c9d4SSatish Balay k++; 416c4762a1bSJed Brown } 417c4762a1bSJed Brown 418c4762a1bSJed Brown /* Top left */ 419c4762a1bSJed Brown if (i > 0 && j < my - 1) { 420c4762a1bSJed Brown v[k] = htl; 421*9371c9d4SSatish Balay col[k].i = i - 1; 422*9371c9d4SSatish Balay col[k].j = j + 1; 423*9371c9d4SSatish Balay k++; 424c4762a1bSJed Brown } 425c4762a1bSJed Brown 426c4762a1bSJed Brown /* Top */ 427c4762a1bSJed Brown if (j < my - 1) { 428c4762a1bSJed Brown v[k] = ht; 429*9371c9d4SSatish Balay col[k].i = i; 430*9371c9d4SSatish Balay col[k].j = j + 1; 431*9371c9d4SSatish Balay k++; 432c4762a1bSJed Brown } 433c4762a1bSJed Brown 4349566063dSJacob Faibussowitsch PetscCall(MatSetValuesStencil(H, 1, &row, k, col, v, INSERT_VALUES)); 435c4762a1bSJed Brown } 436c4762a1bSJed Brown } 437c4762a1bSJed Brown 438c4762a1bSJed Brown /* Assemble the matrix */ 4399566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(H, MAT_FINAL_ASSEMBLY)); 4409566063dSJacob Faibussowitsch PetscCall(DMDAVecRestoreArray(da, localX, &x)); 4419566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(H, MAT_FINAL_ASSEMBLY)); 4429566063dSJacob Faibussowitsch PetscCall(DMRestoreLocalVector(da, &localX)); 443c4762a1bSJed Brown 4449566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(199.0 * mx * my)); 445c4762a1bSJed Brown PetscFunctionReturn(0); 446c4762a1bSJed Brown } 447c4762a1bSJed Brown 448c4762a1bSJed Brown /* ------------------------------------------------------------------- */ 449c4762a1bSJed Brown /* 450c4762a1bSJed Brown FormBoundaryConditions - Calculates the boundary conditions for 451c4762a1bSJed Brown the region. 452c4762a1bSJed Brown 453c4762a1bSJed Brown Input Parameter: 454c4762a1bSJed Brown . user - user-defined application context 455c4762a1bSJed Brown 456c4762a1bSJed Brown Output Parameter: 457c4762a1bSJed Brown . user - user-defined application context 458c4762a1bSJed Brown */ 459*9371c9d4SSatish Balay PetscErrorCode FormBoundaryConditions(SNES snes, AppCtx **ouser) { 460c4762a1bSJed Brown PetscInt i, j, k, limit = 0, maxits = 5; 461c4762a1bSJed Brown PetscInt mx, my; 462c4762a1bSJed Brown PetscInt bsize = 0, lsize = 0, tsize = 0, rsize = 0; 463c4762a1bSJed Brown PetscScalar one = 1.0, two = 2.0, three = 3.0; 464c4762a1bSJed Brown PetscScalar det, hx, hy, xt = 0, yt = 0; 465c4762a1bSJed Brown PetscReal fnorm, tol = 1e-10; 466c4762a1bSJed Brown PetscScalar u1, u2, nf1, nf2, njac11, njac12, njac21, njac22; 467c4762a1bSJed Brown PetscScalar b = -0.5, t = 0.5, l = -0.5, r = 0.5; 468c4762a1bSJed Brown PetscScalar *boundary; 469c4762a1bSJed Brown AppCtx *user; 470c4762a1bSJed Brown DM da; 471c4762a1bSJed Brown 472c4762a1bSJed Brown PetscFunctionBeginUser; 4739566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &da)); 4749566063dSJacob Faibussowitsch PetscCall(PetscNew(&user)); 475c4762a1bSJed Brown *ouser = user; 476c4762a1bSJed Brown user->lb = .05; 477c4762a1bSJed Brown user->ub = PETSC_INFINITY; 4789566063dSJacob Faibussowitsch PetscCall(DMDAGetInfo(da, PETSC_IGNORE, &mx, &my, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE)); 479c4762a1bSJed Brown 480c4762a1bSJed Brown /* Check if lower and upper bounds are set */ 4819566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetScalar(NULL, NULL, "-lb", &user->lb, 0)); 4829566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetScalar(NULL, NULL, "-ub", &user->ub, 0)); 483*9371c9d4SSatish Balay bsize = mx + 2; 484*9371c9d4SSatish Balay lsize = my + 2; 485*9371c9d4SSatish Balay rsize = my + 2; 486*9371c9d4SSatish Balay tsize = mx + 2; 487c4762a1bSJed Brown 4889566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bsize, &user->bottom)); 4899566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(tsize, &user->top)); 4909566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(lsize, &user->left)); 4919566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(rsize, &user->right)); 492c4762a1bSJed Brown 493*9371c9d4SSatish Balay hx = (r - l) / (mx + 1.0); 494*9371c9d4SSatish Balay hy = (t - b) / (my + 1.0); 495c4762a1bSJed Brown 496c4762a1bSJed Brown for (j = 0; j < 4; j++) { 497c4762a1bSJed Brown if (j == 0) { 498c4762a1bSJed Brown yt = b; 499c4762a1bSJed Brown xt = l; 500c4762a1bSJed Brown limit = bsize; 501c4762a1bSJed Brown boundary = user->bottom; 502c4762a1bSJed Brown } else if (j == 1) { 503c4762a1bSJed Brown yt = t; 504c4762a1bSJed Brown xt = l; 505c4762a1bSJed Brown limit = tsize; 506c4762a1bSJed Brown boundary = user->top; 507c4762a1bSJed Brown } else if (j == 2) { 508c4762a1bSJed Brown yt = b; 509c4762a1bSJed Brown xt = l; 510c4762a1bSJed Brown limit = lsize; 511c4762a1bSJed Brown boundary = user->left; 512c4762a1bSJed Brown } else { /* if (j==3) */ 513c4762a1bSJed Brown yt = b; 514c4762a1bSJed Brown xt = r; 515c4762a1bSJed Brown limit = rsize; 516c4762a1bSJed Brown boundary = user->right; 517c4762a1bSJed Brown } 518c4762a1bSJed Brown 519c4762a1bSJed Brown for (i = 0; i < limit; i++) { 520c4762a1bSJed Brown u1 = xt; 521c4762a1bSJed Brown u2 = -yt; 522c4762a1bSJed Brown for (k = 0; k < maxits; k++) { 523c4762a1bSJed Brown nf1 = u1 + u1 * u2 * u2 - u1 * u1 * u1 / three - xt; 524c4762a1bSJed Brown nf2 = -u2 - u1 * u1 * u2 + u2 * u2 * u2 / three - yt; 525c4762a1bSJed Brown fnorm = PetscRealPart(PetscSqrtScalar(nf1 * nf1 + nf2 * nf2)); 526c4762a1bSJed Brown if (fnorm <= tol) break; 527c4762a1bSJed Brown njac11 = one + u2 * u2 - u1 * u1; 528c4762a1bSJed Brown njac12 = two * u1 * u2; 529c4762a1bSJed Brown njac21 = -two * u1 * u2; 530c4762a1bSJed Brown njac22 = -one - u1 * u1 + u2 * u2; 531c4762a1bSJed Brown det = njac11 * njac22 - njac21 * njac12; 532c4762a1bSJed Brown u1 = u1 - (njac22 * nf1 - njac12 * nf2) / det; 533c4762a1bSJed Brown u2 = u2 - (njac11 * nf2 - njac21 * nf1) / det; 534c4762a1bSJed Brown } 535c4762a1bSJed Brown 536c4762a1bSJed Brown boundary[i] = u1 * u1 - u2 * u2; 537c4762a1bSJed Brown if (j == 0 || j == 1) xt = xt + hx; 538c4762a1bSJed Brown else yt = yt + hy; /* if (j==2 || j==3) */ 539c4762a1bSJed Brown } 540c4762a1bSJed Brown } 541c4762a1bSJed Brown PetscFunctionReturn(0); 542c4762a1bSJed Brown } 543c4762a1bSJed Brown 544*9371c9d4SSatish Balay PetscErrorCode DestroyBoundaryConditions(AppCtx **ouser) { 545c4762a1bSJed Brown AppCtx *user = *ouser; 546c4762a1bSJed Brown 547c4762a1bSJed Brown PetscFunctionBeginUser; 5489566063dSJacob Faibussowitsch PetscCall(PetscFree(user->bottom)); 5499566063dSJacob Faibussowitsch PetscCall(PetscFree(user->top)); 5509566063dSJacob Faibussowitsch PetscCall(PetscFree(user->left)); 5519566063dSJacob Faibussowitsch PetscCall(PetscFree(user->right)); 5529566063dSJacob Faibussowitsch PetscCall(PetscFree(*ouser)); 553c4762a1bSJed Brown PetscFunctionReturn(0); 554c4762a1bSJed Brown } 555c4762a1bSJed Brown 556c4762a1bSJed Brown /* ------------------------------------------------------------------- */ 557c4762a1bSJed Brown /* 558c4762a1bSJed Brown ComputeInitialGuess - Calculates the initial guess 559c4762a1bSJed Brown 560c4762a1bSJed Brown Input Parameters: 561c4762a1bSJed Brown . user - user-defined application context 562c4762a1bSJed Brown . X - vector for initial guess 563c4762a1bSJed Brown 564c4762a1bSJed Brown Output Parameters: 565c4762a1bSJed Brown . X - newly computed initial guess 566c4762a1bSJed Brown */ 567*9371c9d4SSatish Balay PetscErrorCode ComputeInitialGuess(SNES snes, Vec X, void *dummy) { 568c4762a1bSJed Brown PetscInt i, j, mx, my; 569c4762a1bSJed Brown DM da; 570c4762a1bSJed Brown AppCtx *user; 571c4762a1bSJed Brown PetscScalar **x; 572c4762a1bSJed Brown PetscInt xs, xm, ys, ym; 573c4762a1bSJed Brown 574c4762a1bSJed Brown PetscFunctionBeginUser; 5759566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &da)); 5769566063dSJacob Faibussowitsch PetscCall(SNESGetApplicationContext(snes, &user)); 577c4762a1bSJed Brown 5789566063dSJacob Faibussowitsch PetscCall(DMDAGetCorners(da, &xs, &ys, NULL, &xm, &ym, NULL)); 5799566063dSJacob Faibussowitsch PetscCall(DMDAGetInfo(da, PETSC_IGNORE, &mx, &my, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE, PETSC_IGNORE)); 580c4762a1bSJed Brown 581c4762a1bSJed Brown /* Get pointers to vector data */ 5829566063dSJacob Faibussowitsch PetscCall(DMDAVecGetArray(da, X, &x)); 583c4762a1bSJed Brown /* Perform local computations */ 584c4762a1bSJed Brown for (j = ys; j < ys + ym; j++) { 585*9371c9d4SSatish Balay for (i = xs; i < xs + xm; i++) { x[j][i] = (((j + 1.0) * user->bottom[i + 1] + (my - j + 1.0) * user->top[i + 1]) / (my + 2.0) + ((i + 1.0) * user->left[j + 1] + (mx - i + 1.0) * user->right[j + 1]) / (mx + 2.0)) / 2.0; } 586c4762a1bSJed Brown } 587c4762a1bSJed Brown /* Restore vectors */ 5889566063dSJacob Faibussowitsch PetscCall(DMDAVecRestoreArray(da, X, &x)); 589c4762a1bSJed Brown PetscFunctionReturn(0); 590c4762a1bSJed Brown } 591c4762a1bSJed Brown 592c4762a1bSJed Brown /*TEST 593c4762a1bSJed Brown 594c4762a1bSJed Brown test: 595c4762a1bSJed Brown args: -snes_type vinewtonrsls -pc_type mg -ksp_monitor_short -pc_mg_galerkin pmat -da_refine 5 -snes_vi_monitor -pc_mg_type full -snes_max_it 100 -snes_converged_reason 596c4762a1bSJed Brown requires: !single 597c4762a1bSJed Brown 598c4762a1bSJed Brown test: 599c4762a1bSJed Brown suffix: 2 600c4762a1bSJed Brown args: -snes_type vinewtonssls -pc_type mg -ksp_monitor_short -pc_mg_galerkin pmat -da_refine 5 -snes_vi_monitor -pc_mg_type full -snes_max_it 100 -snes_converged_reason 601c4762a1bSJed Brown requires: !single 602c4762a1bSJed Brown 603c4762a1bSJed Brown TEST*/ 604