1c4762a1bSJed Brown static const char help[] = "Solves obstacle problem in 2D as a variational inequality\n\ 2c4762a1bSJed Brown or nonlinear complementarity problem. This is a form of the Laplace equation in\n\ 3c4762a1bSJed Brown which the solution u is constrained to be above a given function psi. In the\n\ 4c4762a1bSJed Brown problem here an exact solution is known.\n"; 5c4762a1bSJed Brown 6c4762a1bSJed Brown /* On a square S = {-2<x<2,-2<y<2}, the PDE 7c4762a1bSJed Brown u_{xx} + u_{yy} = 0 8c4762a1bSJed Brown is solved on the set where membrane is above obstacle (u(x,y) >= psi(x,y)). 9c4762a1bSJed Brown Here psi is the upper hemisphere of the unit ball. On the boundary of S 10c4762a1bSJed Brown we have Dirichlet boundary conditions from the exact solution. Uses centered 11c4762a1bSJed Brown FD scheme. This example contributed by Ed Bueler. 12c4762a1bSJed Brown 13c4762a1bSJed Brown Example usage: 14c4762a1bSJed Brown * get help: 15c4762a1bSJed Brown ./ex9 -help 16c4762a1bSJed Brown * monitor run: 17c4762a1bSJed Brown ./ex9 -da_refine 2 -snes_vi_monitor 18c4762a1bSJed Brown * use other SNESVI type (default is SNESVINEWTONRSLS): 19c4762a1bSJed Brown ./ex9 -da_refine 2 -snes_vi_monitor -snes_type vinewtonssls 20c4762a1bSJed Brown * use FD evaluation of Jacobian by coloring, instead of analytical: 21c4762a1bSJed Brown ./ex9 -da_refine 2 -snes_fd_color 22c4762a1bSJed Brown * X windows visualizations: 23c4762a1bSJed Brown ./ex9 -snes_monitor_solution draw -draw_pause 1 -da_refine 4 24c4762a1bSJed Brown ./ex9 -snes_vi_monitor_residual -draw_pause 1 -da_refine 4 25c4762a1bSJed Brown * full-cycle multigrid: 26c4762a1bSJed Brown ./ex9 -snes_converged_reason -snes_grid_sequence 4 -pc_type mg 27c4762a1bSJed Brown * serial convergence evidence: 28c4762a1bSJed Brown for M in 3 4 5 6 7; do ./ex9 -snes_grid_sequence $M -pc_type mg; done 29c4762a1bSJed Brown * FIXME sporadic parallel bug: 30c4762a1bSJed Brown mpiexec -n 4 ./ex9 -snes_converged_reason -snes_grid_sequence 4 -pc_type mg 31c4762a1bSJed Brown */ 32c4762a1bSJed Brown 33c4762a1bSJed Brown #include <petsc.h> 34c4762a1bSJed Brown 35c4762a1bSJed Brown /* z = psi(x,y) is the hemispherical obstacle, but made C^1 with "skirt" at r=r0 */ 36c4762a1bSJed Brown PetscReal psi(PetscReal x, PetscReal y) 37c4762a1bSJed Brown { 38c4762a1bSJed Brown const PetscReal r = x * x + y * y,r0 = 0.9,psi0 = PetscSqrtReal(1.0 - r0*r0),dpsi0 = - r0 / psi0; 39c4762a1bSJed Brown if (r <= r0) { 40c4762a1bSJed Brown return PetscSqrtReal(1.0 - r); 41c4762a1bSJed Brown } else { 42c4762a1bSJed Brown return psi0 + dpsi0 * (r - r0); 43c4762a1bSJed Brown } 44c4762a1bSJed Brown } 45c4762a1bSJed Brown 46c4762a1bSJed Brown /* This exact solution solves a 1D radial free-boundary problem for the 47c4762a1bSJed Brown Laplace equation, on the interval 0 < r < 2, with above obstacle psi(x,y). 48c4762a1bSJed Brown The Laplace equation applies where u(r) > psi(r), 49c4762a1bSJed Brown u''(r) + r^-1 u'(r) = 0 50c4762a1bSJed Brown with boundary conditions including free b.c.s at an unknown location r = a: 51c4762a1bSJed Brown u(a) = psi(a), u'(a) = psi'(a), u(2) = 0 52c4762a1bSJed Brown The solution is u(r) = - A log(r) + B on r > a. The boundary conditions 53c4762a1bSJed Brown can then be reduced to a root-finding problem for a: 54c4762a1bSJed Brown a^2 (log(2) - log(a)) = 1 - a^2 55c4762a1bSJed Brown The solution is a = 0.697965148223374 (giving residual 1.5e-15). Then 56c4762a1bSJed Brown A = a^2*(1-a^2)^(-0.5) and B = A*log(2) are as given below in the code. */ 57c4762a1bSJed Brown PetscReal u_exact(PetscReal x, PetscReal y) 58c4762a1bSJed Brown { 59c4762a1bSJed Brown const PetscReal afree = 0.697965148223374, 60c4762a1bSJed Brown A = 0.680259411891719, 61c4762a1bSJed Brown B = 0.471519893402112; 62c4762a1bSJed Brown PetscReal r; 63c4762a1bSJed Brown r = PetscSqrtReal(x * x + y * y); 64c4762a1bSJed Brown return (r <= afree) ? psi(x,y) /* active set; on the obstacle */ 65c4762a1bSJed Brown : - A * PetscLogReal(r) + B; /* solves laplace eqn */ 66c4762a1bSJed Brown } 67c4762a1bSJed Brown 68c4762a1bSJed Brown extern PetscErrorCode FormExactSolution(DMDALocalInfo*,Vec); 69c4762a1bSJed Brown extern PetscErrorCode FormBounds(SNES,Vec,Vec); 70c4762a1bSJed Brown extern PetscErrorCode FormFunctionLocal(DMDALocalInfo*,PetscReal**,PetscReal**,void*); 71c4762a1bSJed Brown extern PetscErrorCode FormJacobianLocal(DMDALocalInfo*,PetscReal**,Mat,Mat,void*); 72c4762a1bSJed Brown 73c4762a1bSJed Brown int main(int argc,char **argv) 74c4762a1bSJed Brown { 75c4762a1bSJed Brown PetscErrorCode ierr; 76c4762a1bSJed Brown SNES snes; 77c4762a1bSJed Brown DM da, da_after; 78c4762a1bSJed Brown Vec u, u_exact; 79c4762a1bSJed Brown DMDALocalInfo info; 80c4762a1bSJed Brown PetscReal error1,errorinf; 81c4762a1bSJed Brown 82c4762a1bSJed Brown ierr = PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr; 83c4762a1bSJed Brown 84c4762a1bSJed Brown ierr = DMDACreate2d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,DM_BOUNDARY_NONE, 85c4762a1bSJed Brown DMDA_STENCIL_STAR,5,5, /* 5x5 coarse grid; override with -da_grid_x,_y */ 86c4762a1bSJed Brown PETSC_DECIDE,PETSC_DECIDE, 87c4762a1bSJed Brown 1,1, /* dof=1 and s = 1 (stencil extends out one cell) */ 88c4762a1bSJed Brown NULL,NULL,&da);CHKERRQ(ierr); 89*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMSetFromOptions(da)); 90*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMSetUp(da)); 91*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMDASetUniformCoordinates(da,-2.0,2.0,-2.0,2.0,0.0,1.0)); 92c4762a1bSJed Brown 93*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMCreateGlobalVector(da,&u)); 94*5f80ce2aSJacob Faibussowitsch CHKERRQ(VecSet(u,0.0)); 95c4762a1bSJed Brown 96*5f80ce2aSJacob Faibussowitsch CHKERRQ(SNESCreate(PETSC_COMM_WORLD,&snes)); 97*5f80ce2aSJacob Faibussowitsch CHKERRQ(SNESSetDM(snes,da)); 98*5f80ce2aSJacob Faibussowitsch CHKERRQ(SNESSetType(snes,SNESVINEWTONRSLS)); 99*5f80ce2aSJacob Faibussowitsch CHKERRQ(SNESVISetComputeVariableBounds(snes,&FormBounds)); 100*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMDASNESSetFunctionLocal(da,INSERT_VALUES,(DMDASNESFunction)FormFunctionLocal,NULL)); 101*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMDASNESSetJacobianLocal(da,(DMDASNESJacobian)FormJacobianLocal,NULL)); 102*5f80ce2aSJacob Faibussowitsch CHKERRQ(SNESSetFromOptions(snes)); 103c4762a1bSJed Brown 104c4762a1bSJed Brown /* solve nonlinear system */ 105*5f80ce2aSJacob Faibussowitsch CHKERRQ(SNESSolve(snes,NULL,u)); 106*5f80ce2aSJacob Faibussowitsch CHKERRQ(VecDestroy(&u)); 107*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMDestroy(&da)); 108c4762a1bSJed Brown /* DMDA after solve may be different, e.g. with -snes_grid_sequence */ 109*5f80ce2aSJacob Faibussowitsch CHKERRQ(SNESGetDM(snes,&da_after)); 110*5f80ce2aSJacob Faibussowitsch CHKERRQ(SNESGetSolution(snes,&u)); /* do not destroy u */ 111*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMDAGetLocalInfo(da_after,&info)); 112*5f80ce2aSJacob Faibussowitsch CHKERRQ(VecDuplicate(u,&u_exact)); 113*5f80ce2aSJacob Faibussowitsch CHKERRQ(FormExactSolution(&info,u_exact)); 114*5f80ce2aSJacob Faibussowitsch CHKERRQ(VecAXPY(u,-1.0,u_exact)); /* u <-- u - u_exact */ 115*5f80ce2aSJacob Faibussowitsch CHKERRQ(VecNorm(u,NORM_1,&error1)); 116c4762a1bSJed Brown error1 /= (PetscReal)info.mx * (PetscReal)info.my; /* average error */ 117*5f80ce2aSJacob Faibussowitsch CHKERRQ(VecNorm(u,NORM_INFINITY,&errorinf)); 118*5f80ce2aSJacob Faibussowitsch CHKERRQ(PetscPrintf(PETSC_COMM_WORLD,"errors on %D x %D grid: av |u-uexact| = %.3e, |u-uexact|_inf = %.3e\n",info.mx,info.my,(double)error1,(double)errorinf)); 119*5f80ce2aSJacob Faibussowitsch CHKERRQ(VecDestroy(&u_exact)); 120*5f80ce2aSJacob Faibussowitsch CHKERRQ(SNESDestroy(&snes)); 121*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMDestroy(&da)); 122c4762a1bSJed Brown ierr = PetscFinalize(); 123c4762a1bSJed Brown return ierr; 124c4762a1bSJed Brown } 125c4762a1bSJed Brown 126c4762a1bSJed Brown PetscErrorCode FormExactSolution(DMDALocalInfo *info, Vec u) 127c4762a1bSJed Brown { 128c4762a1bSJed Brown PetscInt i,j; 129c4762a1bSJed Brown PetscReal **au, dx, dy, x, y; 130c4762a1bSJed Brown dx = 4.0 / (PetscReal)(info->mx-1); 131c4762a1bSJed Brown dy = 4.0 / (PetscReal)(info->my-1); 132*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMDAVecGetArray(info->da, u, &au)); 133c4762a1bSJed Brown for (j=info->ys; j<info->ys+info->ym; j++) { 134c4762a1bSJed Brown y = -2.0 + j * dy; 135c4762a1bSJed Brown for (i=info->xs; i<info->xs+info->xm; i++) { 136c4762a1bSJed Brown x = -2.0 + i * dx; 137c4762a1bSJed Brown au[j][i] = u_exact(x,y); 138c4762a1bSJed Brown } 139c4762a1bSJed Brown } 140*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMDAVecRestoreArray(info->da, u, &au)); 141c4762a1bSJed Brown return 0; 142c4762a1bSJed Brown } 143c4762a1bSJed Brown 144c4762a1bSJed Brown PetscErrorCode FormBounds(SNES snes, Vec Xl, Vec Xu) 145c4762a1bSJed Brown { 146c4762a1bSJed Brown DM da; 147c4762a1bSJed Brown DMDALocalInfo info; 148c4762a1bSJed Brown PetscInt i, j; 149c4762a1bSJed Brown PetscReal **aXl, dx, dy, x, y; 150c4762a1bSJed Brown 151*5f80ce2aSJacob Faibussowitsch CHKERRQ(SNESGetDM(snes,&da)); 152*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMDAGetLocalInfo(da,&info)); 153c4762a1bSJed Brown dx = 4.0 / (PetscReal)(info.mx-1); 154c4762a1bSJed Brown dy = 4.0 / (PetscReal)(info.my-1); 155*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMDAVecGetArray(da, Xl, &aXl)); 156c4762a1bSJed Brown for (j=info.ys; j<info.ys+info.ym; j++) { 157c4762a1bSJed Brown y = -2.0 + j * dy; 158c4762a1bSJed Brown for (i=info.xs; i<info.xs+info.xm; i++) { 159c4762a1bSJed Brown x = -2.0 + i * dx; 160c4762a1bSJed Brown aXl[j][i] = psi(x,y); 161c4762a1bSJed Brown } 162c4762a1bSJed Brown } 163*5f80ce2aSJacob Faibussowitsch CHKERRQ(DMDAVecRestoreArray(da, Xl, &aXl)); 164*5f80ce2aSJacob Faibussowitsch CHKERRQ(VecSet(Xu,PETSC_INFINITY)); 165c4762a1bSJed Brown return 0; 166c4762a1bSJed Brown } 167c4762a1bSJed Brown 168c4762a1bSJed Brown PetscErrorCode FormFunctionLocal(DMDALocalInfo *info, PetscScalar **au, PetscScalar **af, void *user) 169c4762a1bSJed Brown { 170c4762a1bSJed Brown PetscInt i,j; 171c4762a1bSJed Brown PetscReal dx,dy,x,y,ue,un,us,uw; 172c4762a1bSJed Brown 173c4762a1bSJed Brown PetscFunctionBeginUser; 174c4762a1bSJed Brown dx = 4.0 / (PetscReal)(info->mx-1); 175c4762a1bSJed Brown dy = 4.0 / (PetscReal)(info->my-1); 176c4762a1bSJed Brown for (j=info->ys; j<info->ys+info->ym; j++) { 177c4762a1bSJed Brown y = -2.0 + j * dy; 178c4762a1bSJed Brown for (i=info->xs; i<info->xs+info->xm; i++) { 179c4762a1bSJed Brown x = -2.0 + i * dx; 180c4762a1bSJed Brown if (i == 0 || j == 0 || i == info->mx-1 || j == info->my-1) { 181c4762a1bSJed Brown af[j][i] = 4.0 * (au[j][i] - u_exact(x,y)); 182c4762a1bSJed Brown } else { 183c4762a1bSJed Brown uw = (i-1 == 0) ? u_exact(x-dx,y) : au[j][i-1]; 184c4762a1bSJed Brown ue = (i+1 == info->mx-1) ? u_exact(x+dx,y) : au[j][i+1]; 185c4762a1bSJed Brown us = (j-1 == 0) ? u_exact(x,y-dy) : au[j-1][i]; 186c4762a1bSJed Brown un = (j+1 == info->my-1) ? u_exact(x,y+dy) : au[j+1][i]; 187c4762a1bSJed Brown af[j][i] = - (dy/dx) * (uw - 2.0 * au[j][i] + ue) - (dx/dy) * (us - 2.0 * au[j][i] + un); 188c4762a1bSJed Brown } 189c4762a1bSJed Brown } 190c4762a1bSJed Brown } 191*5f80ce2aSJacob Faibussowitsch CHKERRQ(PetscLogFlops(12.0*info->ym*info->xm)); 192c4762a1bSJed Brown PetscFunctionReturn(0); 193c4762a1bSJed Brown } 194c4762a1bSJed Brown 195c4762a1bSJed Brown PetscErrorCode FormJacobianLocal(DMDALocalInfo *info, PetscScalar **au, Mat A, Mat jac, void *user) 196c4762a1bSJed Brown { 197c4762a1bSJed Brown PetscInt i,j,n; 198c4762a1bSJed Brown MatStencil col[5],row; 199c4762a1bSJed Brown PetscReal v[5],dx,dy,oxx,oyy; 200c4762a1bSJed Brown 201c4762a1bSJed Brown PetscFunctionBeginUser; 202c4762a1bSJed Brown dx = 4.0 / (PetscReal)(info->mx-1); 203c4762a1bSJed Brown dy = 4.0 / (PetscReal)(info->my-1); 204c4762a1bSJed Brown oxx = dy / dx; 205c4762a1bSJed Brown oyy = dx / dy; 206c4762a1bSJed Brown for (j=info->ys; j<info->ys+info->ym; j++) { 207c4762a1bSJed Brown for (i=info->xs; i<info->xs+info->xm; i++) { 208c4762a1bSJed Brown row.j = j; row.i = i; 209c4762a1bSJed Brown if (i == 0 || j == 0 || i == info->mx-1 || j == info->my-1) { /* boundary */ 210c4762a1bSJed Brown v[0] = 4.0; 211*5f80ce2aSJacob Faibussowitsch CHKERRQ(MatSetValuesStencil(jac,1,&row,1,&row,v,INSERT_VALUES)); 212c4762a1bSJed Brown } else { /* interior grid points */ 213c4762a1bSJed Brown v[0] = 2.0 * (oxx + oyy); col[0].j = j; col[0].i = i; 214c4762a1bSJed Brown n = 1; 215c4762a1bSJed Brown if (i-1 > 0) { 216c4762a1bSJed Brown v[n] = -oxx; col[n].j = j; col[n++].i = i-1; 217c4762a1bSJed Brown } 218c4762a1bSJed Brown if (i+1 < info->mx-1) { 219c4762a1bSJed Brown v[n] = -oxx; col[n].j = j; col[n++].i = i+1; 220c4762a1bSJed Brown } 221c4762a1bSJed Brown if (j-1 > 0) { 222c4762a1bSJed Brown v[n] = -oyy; col[n].j = j-1; col[n++].i = i; 223c4762a1bSJed Brown } 224c4762a1bSJed Brown if (j+1 < info->my-1) { 225c4762a1bSJed Brown v[n] = -oyy; col[n].j = j+1; col[n++].i = i; 226c4762a1bSJed Brown } 227*5f80ce2aSJacob Faibussowitsch CHKERRQ(MatSetValuesStencil(jac,1,&row,n,col,v,INSERT_VALUES)); 228c4762a1bSJed Brown } 229c4762a1bSJed Brown } 230c4762a1bSJed Brown } 231c4762a1bSJed Brown 232c4762a1bSJed Brown /* Assemble matrix, using the 2-step process: */ 233*5f80ce2aSJacob Faibussowitsch CHKERRQ(MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY)); 234*5f80ce2aSJacob Faibussowitsch CHKERRQ(MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY)); 235c4762a1bSJed Brown if (A != jac) { 236*5f80ce2aSJacob Faibussowitsch CHKERRQ(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY)); 237*5f80ce2aSJacob Faibussowitsch CHKERRQ(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY)); 238c4762a1bSJed Brown } 239*5f80ce2aSJacob Faibussowitsch CHKERRQ(PetscLogFlops(2.0*info->ym*info->xm)); 240c4762a1bSJed Brown PetscFunctionReturn(0); 241c4762a1bSJed Brown } 242c4762a1bSJed Brown 243c4762a1bSJed Brown /*TEST 244c4762a1bSJed Brown 245c4762a1bSJed Brown build: 246c4762a1bSJed Brown requires: !complex 247c4762a1bSJed Brown 248c4762a1bSJed Brown test: 249c4762a1bSJed Brown suffix: 1 250c4762a1bSJed Brown requires: !single 251c4762a1bSJed Brown nsize: 1 252c4762a1bSJed Brown args: -da_refine 1 -snes_monitor_short -snes_type vinewtonrsls 253c4762a1bSJed Brown 254c4762a1bSJed Brown test: 255c4762a1bSJed Brown suffix: 2 256c4762a1bSJed Brown requires: !single 257c4762a1bSJed Brown nsize: 2 258c4762a1bSJed Brown args: -da_refine 1 -snes_monitor_short -snes_type vinewtonssls 259c4762a1bSJed Brown 260c4762a1bSJed Brown test: 261c4762a1bSJed Brown suffix: 3 262c4762a1bSJed Brown requires: !single 263c4762a1bSJed Brown nsize: 2 264c4762a1bSJed Brown args: -snes_grid_sequence 2 -snes_vi_monitor -snes_type vinewtonrsls 265c4762a1bSJed Brown 266c4762a1bSJed Brown test: 267c4762a1bSJed Brown suffix: mg 268c4762a1bSJed Brown requires: !single 269c4762a1bSJed Brown nsize: 4 270c4762a1bSJed Brown args: -snes_grid_sequence 3 -snes_converged_reason -pc_type mg 271c4762a1bSJed Brown 272c4762a1bSJed Brown test: 273c4762a1bSJed Brown suffix: 4 274c4762a1bSJed Brown nsize: 1 275c4762a1bSJed Brown args: -mat_is_symmetric 276c4762a1bSJed Brown 277c4762a1bSJed Brown test: 278c4762a1bSJed Brown suffix: 5 279c4762a1bSJed Brown nsize: 1 280c4762a1bSJed Brown args: -ksp_converged_reason -snes_fd_color 281c4762a1bSJed Brown 282c4762a1bSJed Brown test: 283c4762a1bSJed Brown suffix: 6 284c4762a1bSJed Brown requires: !single 285c4762a1bSJed Brown nsize: 2 286c4762a1bSJed Brown args: -snes_grid_sequence 2 -pc_type mg -snes_monitor_short -ksp_converged_reason 287c4762a1bSJed Brown 288c4762a1bSJed Brown test: 289c4762a1bSJed Brown suffix: 7 290c4762a1bSJed Brown nsize: 2 291c4762a1bSJed Brown args: -da_refine 1 -snes_monitor_short -snes_type composite -snes_composite_type multiplicative -snes_composite_sneses vinewtonrsls,vinewtonssls -sub_0_snes_vi_monitor -sub_1_snes_vi_monitor 292c4762a1bSJed Brown TODO: fix nasty memory leak in SNESCOMPOSITE 293c4762a1bSJed Brown 294c4762a1bSJed Brown test: 295c4762a1bSJed Brown suffix: 8 296c4762a1bSJed Brown nsize: 2 297c4762a1bSJed Brown args: -da_refine 1 -snes_monitor_short -snes_type composite -snes_composite_type additive -snes_composite_sneses vinewtonrsls -sub_0_snes_vi_monitor 298c4762a1bSJed Brown TODO: fix nasty memory leak in SNESCOMPOSITE 299c4762a1bSJed Brown 300c4762a1bSJed Brown test: 301c4762a1bSJed Brown suffix: 9 302c4762a1bSJed Brown nsize: 2 303c4762a1bSJed Brown args: -da_refine 1 -snes_monitor_short -snes_type composite -snes_composite_type additiveoptimal -snes_composite_sneses vinewtonrsls -sub_0_snes_vi_monitor 304c4762a1bSJed Brown TODO: fix nasty memory leak in SNESCOMPOSITE 305c4762a1bSJed Brown 306c4762a1bSJed Brown TEST*/ 307