1 #include <petscdmda.h> 2 #include <petsctao.h> 3 4 static char help[] = 5 "This example demonstrates use of the TAO package to \n\ 6 solve an unconstrained minimization problem. This example is based on a \n\ 7 problem from the MINPACK-2 test suite. Given a rectangular 2-D domain, \n\ 8 boundary values along the edges of the domain, and a plate represented by \n\ 9 lower boundary conditions, the objective is to find the\n\ 10 surface with the minimal area that satisfies the boundary conditions.\n\ 11 The command line options are:\n\ 12 -mx <xg>, where <xg> = number of grid points in the 1st coordinate direction\n\ 13 -my <yg>, where <yg> = number of grid points in the 2nd coordinate direction\n\ 14 -bmx <bxg>, where <bxg> = number of grid points under plate in 1st direction\n\ 15 -bmy <byg>, where <byg> = number of grid points under plate in 2nd direction\n\ 16 -bheight <ht>, where <ht> = height of the plate\n\ 17 -start <st>, where <st> =0 for zero vector, <st> >0 for random start, and <st> <0 \n\ 18 for an average of the boundary conditions\n\n"; 19 20 /* 21 User-defined application context - contains data needed by the 22 application-provided call-back routines, FormFunctionGradient(), 23 FormHessian(). 24 */ 25 typedef struct { 26 /* problem parameters */ 27 PetscReal bheight; /* Height of plate under the surface */ 28 PetscInt mx, my; /* discretization in x, y directions */ 29 PetscInt bmx,bmy; /* Size of plate under the surface */ 30 Vec Bottom, Top, Left, Right; /* boundary values */ 31 32 /* Working space */ 33 Vec localX, localV; /* ghosted local vector */ 34 DM dm; /* distributed array data structure */ 35 Mat H; 36 } AppCtx; 37 38 /* -------- User-defined Routines --------- */ 39 40 static PetscErrorCode MSA_BoundaryConditions(AppCtx*); 41 static PetscErrorCode MSA_InitialPoint(AppCtx*,Vec); 42 static PetscErrorCode MSA_Plate(Vec,Vec,void*); 43 PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal*,Vec,void*); 44 PetscErrorCode FormHessian(Tao,Vec,Mat,Mat,void*); 45 46 /* For testing matrix free submatrices */ 47 PetscErrorCode MatrixFreeHessian(Tao,Vec,Mat, Mat,void*); 48 PetscErrorCode MyMatMult(Mat,Vec,Vec); 49 50 int main(int argc, char **argv) 51 { 52 PetscInt Nx, Ny; /* number of processors in x- and y- directions */ 53 PetscInt m, N; /* number of local and global elements in vectors */ 54 Vec x,xl,xu; /* solution vector and bounds*/ 55 PetscBool flg; /* A return variable when checking for user options */ 56 Tao tao; /* Tao solver context */ 57 ISLocalToGlobalMapping isltog; /* local-to-global mapping object */ 58 Mat H_shell; /* to test matrix-free submatrices */ 59 AppCtx user; /* user-defined work context */ 60 61 /* Initialize PETSc, TAO */ 62 PetscCall(PetscInitialize(&argc, &argv,(char *)0,help)); 63 64 /* Specify default dimension of the problem */ 65 user.mx = 10; user.my = 10; user.bheight=0.1; 66 67 /* Check for any command line arguments that override defaults */ 68 PetscCall(PetscOptionsGetInt(NULL,NULL,"-mx",&user.mx,&flg)); 69 PetscCall(PetscOptionsGetInt(NULL,NULL,"-my",&user.my,&flg)); 70 PetscCall(PetscOptionsGetReal(NULL,NULL,"-bheight",&user.bheight,&flg)); 71 72 user.bmx = user.mx/2; user.bmy = user.my/2; 73 PetscCall(PetscOptionsGetInt(NULL,NULL,"-bmx",&user.bmx,&flg)); 74 PetscCall(PetscOptionsGetInt(NULL,NULL,"-bmy",&user.bmy,&flg)); 75 76 PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\n---- Minimum Surface Area With Plate Problem -----\n")); 77 PetscCall(PetscPrintf(PETSC_COMM_WORLD,"mx:%" PetscInt_FMT ", my:%" PetscInt_FMT ", bmx:%" PetscInt_FMT ", bmy:%" PetscInt_FMT ", height:%g\n",user.mx,user.my,user.bmx,user.bmy,(double)user.bheight)); 78 79 /* Calculate any derived values from parameters */ 80 N = user.mx*user.my; 81 82 /* Let Petsc determine the dimensions of the local vectors */ 83 Nx = PETSC_DECIDE; Ny = PETSC_DECIDE; 84 85 /* 86 A two dimensional distributed array will help define this problem, 87 which derives from an elliptic PDE on two dimensional domain. From 88 the distributed array, Create the vectors. 89 */ 90 PetscCall(DMDACreate2d(MPI_COMM_WORLD,DM_BOUNDARY_NONE,DM_BOUNDARY_NONE,DMDA_STENCIL_BOX,user.mx,user.my,Nx,Ny,1,1,NULL,NULL,&user.dm)); 91 PetscCall(DMSetFromOptions(user.dm)); 92 PetscCall(DMSetUp(user.dm)); 93 /* 94 Extract global and local vectors from DM; The local vectors are 95 used solely as work space for the evaluation of the function, 96 gradient, and Hessian. Duplicate for remaining vectors that are 97 the same types. 98 */ 99 PetscCall(DMCreateGlobalVector(user.dm,&x)); /* Solution */ 100 PetscCall(DMCreateLocalVector(user.dm,&user.localX)); 101 PetscCall(VecDuplicate(user.localX,&user.localV)); 102 103 PetscCall(VecDuplicate(x,&xl)); 104 PetscCall(VecDuplicate(x,&xu)); 105 106 /* The TAO code begins here */ 107 108 /* 109 Create TAO solver and set desired solution method 110 The method must either be TAOTRON or TAOBLMVM 111 If TAOBLMVM is used, then hessian function is not called. 112 */ 113 PetscCall(TaoCreate(PETSC_COMM_WORLD,&tao)); 114 PetscCall(TaoSetType(tao,TAOBLMVM)); 115 116 /* Set initial solution guess; */ 117 PetscCall(MSA_BoundaryConditions(&user)); 118 PetscCall(MSA_InitialPoint(&user,x)); 119 PetscCall(TaoSetSolution(tao,x)); 120 121 /* Set routines for function, gradient and hessian evaluation */ 122 PetscCall(TaoSetObjectiveAndGradient(tao,NULL,FormFunctionGradient,(void*) &user)); 123 124 PetscCall(VecGetLocalSize(x,&m)); 125 PetscCall(MatCreateAIJ(MPI_COMM_WORLD,m,m,N,N,7,NULL,3,NULL,&(user.H))); 126 PetscCall(MatSetOption(user.H,MAT_SYMMETRIC,PETSC_TRUE)); 127 128 PetscCall(DMGetLocalToGlobalMapping(user.dm,&isltog)); 129 PetscCall(MatSetLocalToGlobalMapping(user.H,isltog,isltog)); 130 PetscCall(PetscOptionsHasName(NULL,NULL,"-matrixfree",&flg)); 131 if (flg) { 132 PetscCall(MatCreateShell(PETSC_COMM_WORLD,m,m,N,N,(void*)&user,&H_shell)); 133 PetscCall(MatShellSetOperation(H_shell,MATOP_MULT,(void(*)(void))MyMatMult)); 134 PetscCall(MatSetOption(H_shell,MAT_SYMMETRIC,PETSC_TRUE)); 135 PetscCall(TaoSetHessian(tao,H_shell,H_shell,MatrixFreeHessian,(void*)&user)); 136 } else { 137 PetscCall(TaoSetHessian(tao,user.H,user.H,FormHessian,(void*)&user)); 138 } 139 140 /* Set Variable bounds */ 141 PetscCall(MSA_Plate(xl,xu,(void*)&user)); 142 PetscCall(TaoSetVariableBounds(tao,xl,xu)); 143 144 /* Check for any tao command line options */ 145 PetscCall(TaoSetFromOptions(tao)); 146 147 /* SOLVE THE APPLICATION */ 148 PetscCall(TaoSolve(tao)); 149 150 PetscCall(TaoView(tao,PETSC_VIEWER_STDOUT_WORLD)); 151 152 /* Free TAO data structures */ 153 PetscCall(TaoDestroy(&tao)); 154 155 /* Free PETSc data structures */ 156 PetscCall(VecDestroy(&x)); 157 PetscCall(VecDestroy(&xl)); 158 PetscCall(VecDestroy(&xu)); 159 PetscCall(MatDestroy(&user.H)); 160 PetscCall(VecDestroy(&user.localX)); 161 PetscCall(VecDestroy(&user.localV)); 162 PetscCall(VecDestroy(&user.Bottom)); 163 PetscCall(VecDestroy(&user.Top)); 164 PetscCall(VecDestroy(&user.Left)); 165 PetscCall(VecDestroy(&user.Right)); 166 PetscCall(DMDestroy(&user.dm)); 167 if (flg) { 168 PetscCall(MatDestroy(&H_shell)); 169 } 170 PetscCall(PetscFinalize()); 171 return 0; 172 } 173 174 /* FormFunctionGradient - Evaluates f(x) and gradient g(x). 175 176 Input Parameters: 177 . tao - the Tao context 178 . X - input vector 179 . userCtx - optional user-defined context, as set by TaoSetObjectiveAndGradient() 180 181 Output Parameters: 182 . fcn - the function value 183 . G - vector containing the newly evaluated gradient 184 185 Notes: 186 In this case, we discretize the domain and Create triangles. The 187 surface of each triangle is planar, whose surface area can be easily 188 computed. The total surface area is found by sweeping through the grid 189 and computing the surface area of the two triangles that have their 190 right angle at the grid point. The diagonal line segments on the 191 grid that define the triangles run from top left to lower right. 192 The numbering of points starts at the lower left and runs left to 193 right, then bottom to top. 194 */ 195 PetscErrorCode FormFunctionGradient(Tao tao, Vec X, PetscReal *fcn, Vec G,void *userCtx) 196 { 197 AppCtx *user = (AppCtx *) userCtx; 198 PetscInt i,j,row; 199 PetscInt mx=user->mx, my=user->my; 200 PetscInt xs,xm,gxs,gxm,ys,ym,gys,gym; 201 PetscReal ft=0; 202 PetscReal zero=0.0; 203 PetscReal hx=1.0/(mx+1),hy=1.0/(my+1), hydhx=hy/hx, hxdhy=hx/hy, area=0.5*hx*hy; 204 PetscReal rhx=mx+1, rhy=my+1; 205 PetscReal f1,f2,f3,f4,f5,f6,d1,d2,d3,d4,d5,d6,d7,d8,xc,xl,xr,xt,xb,xlt,xrb; 206 PetscReal df1dxc,df2dxc,df3dxc,df4dxc,df5dxc,df6dxc; 207 PetscReal *g, *x,*left,*right,*bottom,*top; 208 Vec localX = user->localX, localG = user->localV; 209 210 /* Get local mesh boundaries */ 211 PetscCall(DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL)); 212 PetscCall(DMDAGetGhostCorners(user->dm,&gxs,&gys,NULL,&gxm,&gym,NULL)); 213 214 /* Scatter ghost points to local vector */ 215 PetscCall(DMGlobalToLocalBegin(user->dm,X,INSERT_VALUES,localX)); 216 PetscCall(DMGlobalToLocalEnd(user->dm,X,INSERT_VALUES,localX)); 217 218 /* Initialize vector to zero */ 219 PetscCall(VecSet(localG, zero)); 220 221 /* Get pointers to vector data */ 222 PetscCall(VecGetArray(localX,&x)); 223 PetscCall(VecGetArray(localG,&g)); 224 PetscCall(VecGetArray(user->Top,&top)); 225 PetscCall(VecGetArray(user->Bottom,&bottom)); 226 PetscCall(VecGetArray(user->Left,&left)); 227 PetscCall(VecGetArray(user->Right,&right)); 228 229 /* Compute function over the locally owned part of the mesh */ 230 for (j=ys; j<ys+ym; j++) { 231 for (i=xs; i< xs+xm; i++) { 232 row=(j-gys)*gxm + (i-gxs); 233 234 xc = x[row]; 235 xlt=xrb=xl=xr=xb=xt=xc; 236 237 if (i==0) { /* left side */ 238 xl= left[j-ys+1]; 239 xlt = left[j-ys+2]; 240 } else { 241 xl = x[row-1]; 242 } 243 244 if (j==0) { /* bottom side */ 245 xb=bottom[i-xs+1]; 246 xrb = bottom[i-xs+2]; 247 } else { 248 xb = x[row-gxm]; 249 } 250 251 if (i+1 == gxs+gxm) { /* right side */ 252 xr=right[j-ys+1]; 253 xrb = right[j-ys]; 254 } else { 255 xr = x[row+1]; 256 } 257 258 if (j+1==gys+gym) { /* top side */ 259 xt=top[i-xs+1]; 260 xlt = top[i-xs]; 261 }else { 262 xt = x[row+gxm]; 263 } 264 265 if (i>gxs && j+1<gys+gym) { 266 xlt = x[row-1+gxm]; 267 } 268 if (j>gys && i+1<gxs+gxm) { 269 xrb = x[row+1-gxm]; 270 } 271 272 d1 = (xc-xl); 273 d2 = (xc-xr); 274 d3 = (xc-xt); 275 d4 = (xc-xb); 276 d5 = (xr-xrb); 277 d6 = (xrb-xb); 278 d7 = (xlt-xl); 279 d8 = (xt-xlt); 280 281 df1dxc = d1*hydhx; 282 df2dxc = (d1*hydhx + d4*hxdhy); 283 df3dxc = d3*hxdhy; 284 df4dxc = (d2*hydhx + d3*hxdhy); 285 df5dxc = d2*hydhx; 286 df6dxc = d4*hxdhy; 287 288 d1 *= rhx; 289 d2 *= rhx; 290 d3 *= rhy; 291 d4 *= rhy; 292 d5 *= rhy; 293 d6 *= rhx; 294 d7 *= rhy; 295 d8 *= rhx; 296 297 f1 = PetscSqrtScalar(1.0 + d1*d1 + d7*d7); 298 f2 = PetscSqrtScalar(1.0 + d1*d1 + d4*d4); 299 f3 = PetscSqrtScalar(1.0 + d3*d3 + d8*d8); 300 f4 = PetscSqrtScalar(1.0 + d3*d3 + d2*d2); 301 f5 = PetscSqrtScalar(1.0 + d2*d2 + d5*d5); 302 f6 = PetscSqrtScalar(1.0 + d4*d4 + d6*d6); 303 304 ft = ft + (f2 + f4); 305 306 df1dxc /= f1; 307 df2dxc /= f2; 308 df3dxc /= f3; 309 df4dxc /= f4; 310 df5dxc /= f5; 311 df6dxc /= f6; 312 313 g[row] = (df1dxc+df2dxc+df3dxc+df4dxc+df5dxc+df6dxc) * 0.5; 314 315 } 316 } 317 318 /* Compute triangular areas along the border of the domain. */ 319 if (xs==0) { /* left side */ 320 for (j=ys; j<ys+ym; j++) { 321 d3=(left[j-ys+1] - left[j-ys+2])*rhy; 322 d2=(left[j-ys+1] - x[(j-gys)*gxm])*rhx; 323 ft = ft+PetscSqrtScalar(1.0 + d3*d3 + d2*d2); 324 } 325 } 326 if (ys==0) { /* bottom side */ 327 for (i=xs; i<xs+xm; i++) { 328 d2=(bottom[i+1-xs]-bottom[i-xs+2])*rhx; 329 d3=(bottom[i-xs+1]-x[i-gxs])*rhy; 330 ft = ft+PetscSqrtScalar(1.0 + d3*d3 + d2*d2); 331 } 332 } 333 334 if (xs+xm==mx) { /* right side */ 335 for (j=ys; j< ys+ym; j++) { 336 d1=(x[(j+1-gys)*gxm-1]-right[j-ys+1])*rhx; 337 d4=(right[j-ys]-right[j-ys+1])*rhy; 338 ft = ft+PetscSqrtScalar(1.0 + d1*d1 + d4*d4); 339 } 340 } 341 if (ys+ym==my) { /* top side */ 342 for (i=xs; i<xs+xm; i++) { 343 d1=(x[(gym-1)*gxm + i-gxs] - top[i-xs+1])*rhy; 344 d4=(top[i-xs+1] - top[i-xs])*rhx; 345 ft = ft+PetscSqrtScalar(1.0 + d1*d1 + d4*d4); 346 } 347 } 348 349 if (ys==0 && xs==0) { 350 d1=(left[0]-left[1])*rhy; 351 d2=(bottom[0]-bottom[1])*rhx; 352 ft +=PetscSqrtScalar(1.0 + d1*d1 + d2*d2); 353 } 354 if (ys+ym == my && xs+xm == mx) { 355 d1=(right[ym+1] - right[ym])*rhy; 356 d2=(top[xm+1] - top[xm])*rhx; 357 ft +=PetscSqrtScalar(1.0 + d1*d1 + d2*d2); 358 } 359 360 ft=ft*area; 361 PetscCallMPI(MPI_Allreduce(&ft,fcn,1,MPIU_REAL,MPIU_SUM,MPI_COMM_WORLD)); 362 363 /* Restore vectors */ 364 PetscCall(VecRestoreArray(localX,&x)); 365 PetscCall(VecRestoreArray(localG,&g)); 366 PetscCall(VecRestoreArray(user->Left,&left)); 367 PetscCall(VecRestoreArray(user->Top,&top)); 368 PetscCall(VecRestoreArray(user->Bottom,&bottom)); 369 PetscCall(VecRestoreArray(user->Right,&right)); 370 371 /* Scatter values to global vector */ 372 PetscCall(DMLocalToGlobalBegin(user->dm,localG,INSERT_VALUES,G)); 373 PetscCall(DMLocalToGlobalEnd(user->dm,localG,INSERT_VALUES,G)); 374 375 PetscCall(PetscLogFlops(70.0*xm*ym)); 376 377 return 0; 378 } 379 380 /* ------------------------------------------------------------------- */ 381 /* 382 FormHessian - Evaluates Hessian matrix. 383 384 Input Parameters: 385 . tao - the Tao context 386 . x - input vector 387 . ptr - optional user-defined context, as set by TaoSetHessian() 388 389 Output Parameters: 390 . A - Hessian matrix 391 . B - optionally different preconditioning matrix 392 393 Notes: 394 Due to mesh point reordering with DMs, we must always work 395 with the local mesh points, and then transform them to the new 396 global numbering with the local-to-global mapping. We cannot work 397 directly with the global numbers for the original uniprocessor mesh! 398 399 Two methods are available for imposing this transformation 400 when setting matrix entries: 401 (A) MatSetValuesLocal(), using the local ordering (including 402 ghost points!) 403 - Do the following two steps once, before calling TaoSolve() 404 - Use DMGetISLocalToGlobalMapping() to extract the 405 local-to-global map from the DM 406 - Associate this map with the matrix by calling 407 MatSetLocalToGlobalMapping() 408 - Then set matrix entries using the local ordering 409 by calling MatSetValuesLocal() 410 (B) MatSetValues(), using the global ordering 411 - Use DMGetGlobalIndices() to extract the local-to-global map 412 - Then apply this map explicitly yourself 413 - Set matrix entries using the global ordering by calling 414 MatSetValues() 415 Option (A) seems cleaner/easier in many cases, and is the procedure 416 used in this example. 417 */ 418 PetscErrorCode FormHessian(Tao tao,Vec X,Mat Hptr, Mat Hessian, void *ptr) 419 { 420 AppCtx *user = (AppCtx *) ptr; 421 PetscInt i,j,k,row; 422 PetscInt mx=user->mx, my=user->my; 423 PetscInt xs,xm,gxs,gxm,ys,ym,gys,gym,col[7]; 424 PetscReal hx=1.0/(mx+1), hy=1.0/(my+1), hydhx=hy/hx, hxdhy=hx/hy; 425 PetscReal rhx=mx+1, rhy=my+1; 426 PetscReal f1,f2,f3,f4,f5,f6,d1,d2,d3,d4,d5,d6,d7,d8,xc,xl,xr,xt,xb,xlt,xrb; 427 PetscReal hl,hr,ht,hb,hc,htl,hbr; 428 PetscReal *x,*left,*right,*bottom,*top; 429 PetscReal v[7]; 430 Vec localX = user->localX; 431 PetscBool assembled; 432 433 /* Set various matrix options */ 434 PetscCall(MatSetOption(Hessian,MAT_IGNORE_OFF_PROC_ENTRIES,PETSC_TRUE)); 435 436 /* Initialize matrix entries to zero */ 437 PetscCall(MatAssembled(Hessian,&assembled)); 438 if (assembled) PetscCall(MatZeroEntries(Hessian)); 439 440 /* Get local mesh boundaries */ 441 PetscCall(DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL)); 442 PetscCall(DMDAGetGhostCorners(user->dm,&gxs,&gys,NULL,&gxm,&gym,NULL)); 443 444 /* Scatter ghost points to local vector */ 445 PetscCall(DMGlobalToLocalBegin(user->dm,X,INSERT_VALUES,localX)); 446 PetscCall(DMGlobalToLocalEnd(user->dm,X,INSERT_VALUES,localX)); 447 448 /* Get pointers to vector data */ 449 PetscCall(VecGetArray(localX,&x)); 450 PetscCall(VecGetArray(user->Top,&top)); 451 PetscCall(VecGetArray(user->Bottom,&bottom)); 452 PetscCall(VecGetArray(user->Left,&left)); 453 PetscCall(VecGetArray(user->Right,&right)); 454 455 /* Compute Hessian over the locally owned part of the mesh */ 456 457 for (i=xs; i< xs+xm; i++) { 458 459 for (j=ys; j<ys+ym; j++) { 460 461 row=(j-gys)*gxm + (i-gxs); 462 463 xc = x[row]; 464 xlt=xrb=xl=xr=xb=xt=xc; 465 466 /* Left side */ 467 if (i==gxs) { 468 xl= left[j-ys+1]; 469 xlt = left[j-ys+2]; 470 } else { 471 xl = x[row-1]; 472 } 473 474 if (j==gys) { 475 xb=bottom[i-xs+1]; 476 xrb = bottom[i-xs+2]; 477 } else { 478 xb = x[row-gxm]; 479 } 480 481 if (i+1 == gxs+gxm) { 482 xr=right[j-ys+1]; 483 xrb = right[j-ys]; 484 } else { 485 xr = x[row+1]; 486 } 487 488 if (j+1==gys+gym) { 489 xt=top[i-xs+1]; 490 xlt = top[i-xs]; 491 }else { 492 xt = x[row+gxm]; 493 } 494 495 if (i>gxs && j+1<gys+gym) { 496 xlt = x[row-1+gxm]; 497 } 498 if (j>gys && i+1<gxs+gxm) { 499 xrb = x[row+1-gxm]; 500 } 501 502 d1 = (xc-xl)*rhx; 503 d2 = (xc-xr)*rhx; 504 d3 = (xc-xt)*rhy; 505 d4 = (xc-xb)*rhy; 506 d5 = (xrb-xr)*rhy; 507 d6 = (xrb-xb)*rhx; 508 d7 = (xlt-xl)*rhy; 509 d8 = (xlt-xt)*rhx; 510 511 f1 = PetscSqrtScalar(1.0 + d1*d1 + d7*d7); 512 f2 = PetscSqrtScalar(1.0 + d1*d1 + d4*d4); 513 f3 = PetscSqrtScalar(1.0 + d3*d3 + d8*d8); 514 f4 = PetscSqrtScalar(1.0 + d3*d3 + d2*d2); 515 f5 = PetscSqrtScalar(1.0 + d2*d2 + d5*d5); 516 f6 = PetscSqrtScalar(1.0 + d4*d4 + d6*d6); 517 518 hl = (-hydhx*(1.0+d7*d7)+d1*d7)/(f1*f1*f1)+ 519 (-hydhx*(1.0+d4*d4)+d1*d4)/(f2*f2*f2); 520 hr = (-hydhx*(1.0+d5*d5)+d2*d5)/(f5*f5*f5)+ 521 (-hydhx*(1.0+d3*d3)+d2*d3)/(f4*f4*f4); 522 ht = (-hxdhy*(1.0+d8*d8)+d3*d8)/(f3*f3*f3)+ 523 (-hxdhy*(1.0+d2*d2)+d2*d3)/(f4*f4*f4); 524 hb = (-hxdhy*(1.0+d6*d6)+d4*d6)/(f6*f6*f6)+ 525 (-hxdhy*(1.0+d1*d1)+d1*d4)/(f2*f2*f2); 526 527 hbr = -d2*d5/(f5*f5*f5) - d4*d6/(f6*f6*f6); 528 htl = -d1*d7/(f1*f1*f1) - d3*d8/(f3*f3*f3); 529 530 hc = hydhx*(1.0+d7*d7)/(f1*f1*f1) + hxdhy*(1.0+d8*d8)/(f3*f3*f3) + 531 hydhx*(1.0+d5*d5)/(f5*f5*f5) + hxdhy*(1.0+d6*d6)/(f6*f6*f6) + 532 (hxdhy*(1.0+d1*d1)+hydhx*(1.0+d4*d4)-2*d1*d4)/(f2*f2*f2) + 533 (hxdhy*(1.0+d2*d2)+hydhx*(1.0+d3*d3)-2*d2*d3)/(f4*f4*f4); 534 535 hl*=0.5; hr*=0.5; ht*=0.5; hb*=0.5; hbr*=0.5; htl*=0.5; hc*=0.5; 536 537 k=0; 538 if (j>0) { 539 v[k]=hb; col[k]=row - gxm; k++; 540 } 541 542 if (j>0 && i < mx -1) { 543 v[k]=hbr; col[k]=row - gxm+1; k++; 544 } 545 546 if (i>0) { 547 v[k]= hl; col[k]=row - 1; k++; 548 } 549 550 v[k]= hc; col[k]=row; k++; 551 552 if (i < mx-1) { 553 v[k]= hr; col[k]=row+1; k++; 554 } 555 556 if (i>0 && j < my-1) { 557 v[k]= htl; col[k] = row+gxm-1; k++; 558 } 559 560 if (j < my-1) { 561 v[k]= ht; col[k] = row+gxm; k++; 562 } 563 564 /* 565 Set matrix values using local numbering, which was defined 566 earlier, in the main routine. 567 */ 568 PetscCall(MatSetValuesLocal(Hessian,1,&row,k,col,v,INSERT_VALUES)); 569 570 } 571 } 572 573 /* Restore vectors */ 574 PetscCall(VecRestoreArray(localX,&x)); 575 PetscCall(VecRestoreArray(user->Left,&left)); 576 PetscCall(VecRestoreArray(user->Top,&top)); 577 PetscCall(VecRestoreArray(user->Bottom,&bottom)); 578 PetscCall(VecRestoreArray(user->Right,&right)); 579 580 /* Assemble the matrix */ 581 PetscCall(MatAssemblyBegin(Hessian,MAT_FINAL_ASSEMBLY)); 582 PetscCall(MatAssemblyEnd(Hessian,MAT_FINAL_ASSEMBLY)); 583 584 PetscCall(PetscLogFlops(199.0*xm*ym)); 585 return 0; 586 } 587 588 /* ------------------------------------------------------------------- */ 589 /* 590 MSA_BoundaryConditions - Calculates the boundary conditions for 591 the region. 592 593 Input Parameter: 594 . user - user-defined application context 595 596 Output Parameter: 597 . user - user-defined application context 598 */ 599 static PetscErrorCode MSA_BoundaryConditions(AppCtx * user) 600 { 601 PetscInt i,j,k,maxits=5,limit=0; 602 PetscInt xs,ys,xm,ym,gxs,gys,gxm,gym; 603 PetscInt mx=user->mx,my=user->my; 604 PetscInt bsize=0, lsize=0, tsize=0, rsize=0; 605 PetscReal one=1.0, two=2.0, three=3.0, scl=1.0, tol=1e-10; 606 PetscReal fnorm,det,hx,hy,xt=0,yt=0; 607 PetscReal u1,u2,nf1,nf2,njac11,njac12,njac21,njac22; 608 PetscReal b=-0.5, t=0.5, l=-0.5, r=0.5; 609 PetscReal *boundary; 610 PetscBool flg; 611 Vec Bottom,Top,Right,Left; 612 613 /* Get local mesh boundaries */ 614 PetscCall(DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL)); 615 PetscCall(DMDAGetGhostCorners(user->dm,&gxs,&gys,NULL,&gxm,&gym,NULL)); 616 617 bsize=xm+2; 618 lsize=ym+2; 619 rsize=ym+2; 620 tsize=xm+2; 621 622 PetscCall(VecCreateMPI(MPI_COMM_WORLD,bsize,PETSC_DECIDE,&Bottom)); 623 PetscCall(VecCreateMPI(MPI_COMM_WORLD,tsize,PETSC_DECIDE,&Top)); 624 PetscCall(VecCreateMPI(MPI_COMM_WORLD,lsize,PETSC_DECIDE,&Left)); 625 PetscCall(VecCreateMPI(MPI_COMM_WORLD,rsize,PETSC_DECIDE,&Right)); 626 627 user->Top=Top; 628 user->Left=Left; 629 user->Bottom=Bottom; 630 user->Right=Right; 631 632 hx= (r-l)/(mx+1); hy=(t-b)/(my+1); 633 634 for (j=0; j<4; j++) { 635 if (j==0) { 636 yt=b; 637 xt=l+hx*xs; 638 limit=bsize; 639 VecGetArray(Bottom,&boundary); 640 } else if (j==1) { 641 yt=t; 642 xt=l+hx*xs; 643 limit=tsize; 644 VecGetArray(Top,&boundary); 645 } else if (j==2) { 646 yt=b+hy*ys; 647 xt=l; 648 limit=lsize; 649 VecGetArray(Left,&boundary); 650 } else if (j==3) { 651 yt=b+hy*ys; 652 xt=r; 653 limit=rsize; 654 VecGetArray(Right,&boundary); 655 } 656 657 for (i=0; i<limit; i++) { 658 u1=xt; 659 u2=-yt; 660 for (k=0; k<maxits; k++) { 661 nf1=u1 + u1*u2*u2 - u1*u1*u1/three-xt; 662 nf2=-u2 - u1*u1*u2 + u2*u2*u2/three-yt; 663 fnorm=PetscSqrtScalar(nf1*nf1+nf2*nf2); 664 if (fnorm <= tol) break; 665 njac11=one+u2*u2-u1*u1; 666 njac12=two*u1*u2; 667 njac21=-two*u1*u2; 668 njac22=-one - u1*u1 + u2*u2; 669 det = njac11*njac22-njac21*njac12; 670 u1 = u1-(njac22*nf1-njac12*nf2)/det; 671 u2 = u2-(njac11*nf2-njac21*nf1)/det; 672 } 673 674 boundary[i]=u1*u1-u2*u2; 675 if (j==0 || j==1) { 676 xt=xt+hx; 677 } else if (j==2 || j==3) { 678 yt=yt+hy; 679 } 680 } 681 if (j==0) { 682 PetscCall(VecRestoreArray(Bottom,&boundary)); 683 } else if (j==1) { 684 PetscCall(VecRestoreArray(Top,&boundary)); 685 } else if (j==2) { 686 PetscCall(VecRestoreArray(Left,&boundary)); 687 } else if (j==3) { 688 PetscCall(VecRestoreArray(Right,&boundary)); 689 } 690 } 691 692 /* Scale the boundary if desired */ 693 694 PetscCall(PetscOptionsGetReal(NULL,NULL,"-bottom",&scl,&flg)); 695 if (flg) { 696 PetscCall(VecScale(Bottom, scl)); 697 } 698 PetscCall(PetscOptionsGetReal(NULL,NULL,"-top",&scl,&flg)); 699 if (flg) { 700 PetscCall(VecScale(Top, scl)); 701 } 702 PetscCall(PetscOptionsGetReal(NULL,NULL,"-right",&scl,&flg)); 703 if (flg) { 704 PetscCall(VecScale(Right, scl)); 705 } 706 707 PetscCall(PetscOptionsGetReal(NULL,NULL,"-left",&scl,&flg)); 708 if (flg) { 709 PetscCall(VecScale(Left, scl)); 710 } 711 return 0; 712 } 713 714 /* ------------------------------------------------------------------- */ 715 /* 716 MSA_Plate - Calculates an obstacle for surface to stretch over. 717 718 Input Parameter: 719 . user - user-defined application context 720 721 Output Parameter: 722 . user - user-defined application context 723 */ 724 static PetscErrorCode MSA_Plate(Vec XL,Vec XU,void *ctx) 725 { 726 AppCtx *user=(AppCtx *)ctx; 727 PetscInt i,j,row; 728 PetscInt xs,ys,xm,ym; 729 PetscInt mx=user->mx, my=user->my, bmy, bmx; 730 PetscReal t1,t2,t3; 731 PetscReal *xl, lb=PETSC_NINFINITY, ub=PETSC_INFINITY; 732 PetscBool cylinder; 733 734 user->bmy = PetscMax(0,user->bmy);user->bmy = PetscMin(my,user->bmy); 735 user->bmx = PetscMax(0,user->bmx);user->bmx = PetscMin(mx,user->bmx); 736 bmy=user->bmy; bmx=user->bmx; 737 738 PetscCall(DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL)); 739 740 PetscCall(VecSet(XL, lb)); 741 PetscCall(VecSet(XU, ub)); 742 743 PetscCall(VecGetArray(XL,&xl)); 744 745 PetscCall(PetscOptionsHasName(NULL,NULL,"-cylinder",&cylinder)); 746 /* Compute the optional lower box */ 747 if (cylinder) { 748 for (i=xs; i< xs+xm; i++) { 749 for (j=ys; j<ys+ym; j++) { 750 row=(j-ys)*xm + (i-xs); 751 t1=(2.0*i-mx)*bmy; 752 t2=(2.0*j-my)*bmx; 753 t3=bmx*bmx*bmy*bmy; 754 if (t1*t1 + t2*t2 <= t3) { 755 xl[row] = user->bheight; 756 } 757 } 758 } 759 } else { 760 /* Compute the optional lower box */ 761 for (i=xs; i< xs+xm; i++) { 762 for (j=ys; j<ys+ym; j++) { 763 row=(j-ys)*xm + (i-xs); 764 if (i>=(mx-bmx)/2 && i<mx-(mx-bmx)/2 && 765 j>=(my-bmy)/2 && j<my-(my-bmy)/2) { 766 xl[row] = user->bheight; 767 } 768 } 769 } 770 } 771 PetscCall(VecRestoreArray(XL,&xl)); 772 773 return 0; 774 } 775 776 /* ------------------------------------------------------------------- */ 777 /* 778 MSA_InitialPoint - Calculates the initial guess in one of three ways. 779 780 Input Parameters: 781 . user - user-defined application context 782 . X - vector for initial guess 783 784 Output Parameters: 785 . X - newly computed initial guess 786 */ 787 static PetscErrorCode MSA_InitialPoint(AppCtx * user, Vec X) 788 { 789 PetscInt start=-1,i,j; 790 PetscReal zero=0.0; 791 PetscBool flg; 792 793 PetscCall(PetscOptionsGetInt(NULL,NULL,"-start",&start,&flg)); 794 if (flg && start==0) { /* The zero vector is reasonable */ 795 PetscCall(VecSet(X, zero)); 796 } else if (flg && start>0) { /* Try a random start between -0.5 and 0.5 */ 797 PetscRandom rctx; PetscReal np5=-0.5; 798 799 PetscCall(PetscRandomCreate(MPI_COMM_WORLD,&rctx)); 800 for (i=0; i<start; i++) { 801 PetscCall(VecSetRandom(X, rctx)); 802 } 803 PetscCall(PetscRandomDestroy(&rctx)); 804 PetscCall(VecShift(X, np5)); 805 806 } else { /* Take an average of the boundary conditions */ 807 808 PetscInt row,xs,xm,gxs,gxm,ys,ym,gys,gym; 809 PetscInt mx=user->mx,my=user->my; 810 PetscReal *x,*left,*right,*bottom,*top; 811 Vec localX = user->localX; 812 813 /* Get local mesh boundaries */ 814 PetscCall(DMDAGetCorners(user->dm,&xs,&ys,NULL,&xm,&ym,NULL)); 815 PetscCall(DMDAGetGhostCorners(user->dm,&gxs,&gys,NULL,&gxm,&gym,NULL)); 816 817 /* Get pointers to vector data */ 818 PetscCall(VecGetArray(user->Top,&top)); 819 PetscCall(VecGetArray(user->Bottom,&bottom)); 820 PetscCall(VecGetArray(user->Left,&left)); 821 PetscCall(VecGetArray(user->Right,&right)); 822 823 PetscCall(VecGetArray(localX,&x)); 824 /* Perform local computations */ 825 for (j=ys; j<ys+ym; j++) { 826 for (i=xs; i< xs+xm; i++) { 827 row=(j-gys)*gxm + (i-gxs); 828 x[row] = ((j+1)*bottom[i-xs+1]/my + (my-j+1)*top[i-xs+1]/(my+2)+(i+1)*left[j-ys+1]/mx + (mx-i+1)*right[j-ys+1]/(mx+2))/2.0; 829 } 830 } 831 832 /* Restore vectors */ 833 PetscCall(VecRestoreArray(localX,&x)); 834 835 PetscCall(VecRestoreArray(user->Left,&left)); 836 PetscCall(VecRestoreArray(user->Top,&top)); 837 PetscCall(VecRestoreArray(user->Bottom,&bottom)); 838 PetscCall(VecRestoreArray(user->Right,&right)); 839 840 /* Scatter values into global vector */ 841 PetscCall(DMLocalToGlobalBegin(user->dm,localX,INSERT_VALUES,X)); 842 PetscCall(DMLocalToGlobalEnd(user->dm,localX,INSERT_VALUES,X)); 843 844 } 845 return 0; 846 } 847 848 /* For testing matrix free submatrices */ 849 PetscErrorCode MatrixFreeHessian(Tao tao, Vec x, Mat H, Mat Hpre, void *ptr) 850 { 851 AppCtx *user = (AppCtx*)ptr; 852 PetscFunctionBegin; 853 PetscCall(FormHessian(tao,x,user->H,user->H,ptr)); 854 PetscFunctionReturn(0); 855 } 856 PetscErrorCode MyMatMult(Mat H_shell, Vec X, Vec Y) 857 { 858 void *ptr; 859 AppCtx *user; 860 PetscFunctionBegin; 861 PetscCall(MatShellGetContext(H_shell,&ptr)); 862 user = (AppCtx*)ptr; 863 PetscCall(MatMult(user->H,X,Y)); 864 PetscFunctionReturn(0); 865 } 866 867 /*TEST 868 869 build: 870 requires: !complex 871 872 test: 873 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type tron -tao_gatol 1.e-5 874 requires: !single 875 876 test: 877 suffix: 2 878 nsize: 2 879 args: -tao_smonitor -mx 8 -my 8 -bmx 2 -bmy 5 -bheight 0.3 -tao_type blmvm -tao_gatol 1.e-4 880 requires: !single 881 882 test: 883 suffix: 3 884 nsize: 3 885 args: -tao_smonitor -mx 8 -my 12 -bmx 4 -bmy 10 -bheight 0.1 -tao_type tron -tao_gatol 1.e-5 886 requires: !single 887 888 test: 889 suffix: 4 890 nsize: 3 891 args: -tao_smonitor -mx 8 -my 12 -bmx 4 -bmy 10 -bheight 0.1 -tao_subset_type mask -tao_type tron -tao_gatol 1.e-5 892 requires: !single 893 894 test: 895 suffix: 5 896 nsize: 3 897 args: -tao_smonitor -mx 8 -my 12 -bmx 4 -bmy 10 -bheight 0.1 -tao_subset_type matrixfree -matrixfree -pc_type none -tao_type tron -tao_gatol 1.e-5 898 requires: !single 899 900 test: 901 suffix: 6 902 nsize: 3 903 args: -tao_smonitor -mx 8 -my 12 -bmx 4 -bmy 10 -bheight 0.1 -tao_subset_type matrixfree -matrixfree -tao_type blmvm -tao_gatol 1.e-4 904 requires: !single 905 906 test: 907 suffix: 7 908 nsize: 3 909 args: -tao_smonitor -mx 8 -my 12 -bmx 4 -bmy 10 -bheight 0.1 -tao_subset_type matrixfree -pc_type none -tao_type gpcg -tao_gatol 1.e-5 910 requires: !single 911 912 test: 913 suffix: 8 914 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bncg -tao_bncg_type gd -tao_gatol 1e-4 915 requires: !single 916 917 test: 918 suffix: 9 919 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bncg -tao_gatol 1e-4 920 requires: !single 921 922 test: 923 suffix: 10 924 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bnls -tao_gatol 1e-5 925 requires: !single 926 927 test: 928 suffix: 11 929 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bntr -tao_gatol 1e-5 930 requires: !single 931 932 test: 933 suffix: 12 934 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bntl -tao_gatol 1e-5 935 requires: !single 936 937 test: 938 suffix: 13 939 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bnls -tao_gatol 1e-5 -tao_bnk_max_cg_its 3 940 requires: !single 941 942 test: 943 suffix: 14 944 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bntr -tao_gatol 1e-5 -tao_bnk_max_cg_its 3 945 requires: !single 946 947 test: 948 suffix: 15 949 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bntl -tao_gatol 1e-5 -tao_bnk_max_cg_its 3 950 requires: !single 951 952 test: 953 suffix: 16 954 args: -tao_smonitor -mx 8 -my 8 -bmx 2 -bmy 5 -bheight 0.3 -tao_gatol 1e-4 -tao_type bqnls 955 requires: !single 956 957 test: 958 suffix: 17 959 args: -tao_smonitor -mx 8 -my 8 -bmx 2 -bmy 5 -bheight 0.3 -tao_gatol 1e-4 -tao_type bqnkls -tao_bqnk_mat_type lmvmbfgs 960 requires: !single 961 962 test: 963 suffix: 18 964 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bnls -tao_gatol 1e-5 -tao_mf_hessian 965 requires: !single 966 967 test: 968 suffix: 19 969 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bntr -tao_gatol 1e-5 -tao_mf_hessian 970 requires: !single 971 972 test: 973 suffix: 20 974 args: -tao_smonitor -mx 8 -my 6 -bmx 3 -bmy 3 -bheight 0.2 -tao_type bntl -tao_gatol 1e-5 -tao_mf_hessian 975 976 TEST*/ 977