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