1 /* Program usage: mpiexec -n 1 eptorsion1 [-help] [all TAO options] */ 2 3 /* ---------------------------------------------------------------------- 4 5 Elastic-plastic torsion problem. 6 7 The elastic plastic torsion problem arises from the determination 8 of the stress field on an infinitely long cylindrical bar, which is 9 equivalent to the solution of the following problem: 10 11 min{ .5 * integral(||gradient(v(x))||^2 dx) - C * integral(v(x) dx)} 12 13 where C is the torsion angle per unit length. 14 15 The multiprocessor version of this code is eptorsion2.c. 16 17 ---------------------------------------------------------------------- */ 18 19 /* 20 Include "petsctao.h" so that we can use TAO solvers. Note that this 21 file automatically includes files for lower-level support, such as those 22 provided by the PETSc library: 23 petsc.h - base PETSc routines petscvec.h - vectors 24 petscsys.h - system routines petscmat.h - matrices 25 petscis.h - index sets petscksp.h - Krylov subspace methods 26 petscviewer.h - viewers petscpc.h - preconditioners 27 */ 28 29 #include <petsctao.h> 30 31 static char help[]= 32 "Demonstrates use of the TAO package to solve \n\ 33 unconstrained minimization problems on a single processor. This example \n\ 34 is based on the Elastic-Plastic Torsion (dept) problem from the MINPACK-2 \n\ 35 test suite.\n\ 36 The command line options are:\n\ 37 -mx <xg>, where <xg> = number of grid points in the 1st coordinate direction\n\ 38 -my <yg>, where <yg> = number of grid points in the 2nd coordinate direction\n\ 39 -par <param>, where <param> = angle of twist per unit length\n\n"; 40 41 /* 42 User-defined application context - contains data needed by the 43 application-provided call-back routines, FormFunction(), 44 FormGradient(), and FormHessian(). 45 */ 46 47 typedef struct { 48 PetscReal param; /* nonlinearity parameter */ 49 PetscInt mx, my; /* discretization in x- and y-directions */ 50 PetscInt ndim; /* problem dimension */ 51 Vec s, y, xvec; /* work space for computing Hessian */ 52 PetscReal hx, hy; /* mesh spacing in x- and y-directions */ 53 } AppCtx; 54 55 /* -------- User-defined Routines --------- */ 56 57 PetscErrorCode FormInitialGuess(AppCtx*,Vec); 58 PetscErrorCode FormFunction(Tao,Vec,PetscReal*,void*); 59 PetscErrorCode FormGradient(Tao,Vec,Vec,void*); 60 PetscErrorCode FormHessian(Tao,Vec,Mat,Mat, void*); 61 PetscErrorCode HessianProductMat(Mat,Vec,Vec); 62 PetscErrorCode HessianProduct(void*,Vec,Vec); 63 PetscErrorCode MatrixFreeHessian(Tao,Vec,Mat,Mat,void*); 64 PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal *,Vec,void *); 65 66 PetscErrorCode main(int argc,char **argv) 67 { 68 PetscInt mx=10; /* discretization in x-direction */ 69 PetscInt my=10; /* discretization in y-direction */ 70 Vec x; /* solution, gradient vectors */ 71 PetscBool flg; /* A return value when checking for use options */ 72 Tao tao; /* Tao solver context */ 73 Mat H; /* Hessian matrix */ 74 AppCtx user; /* application context */ 75 PetscMPIInt size; /* number of processes */ 76 PetscReal one=1.0; 77 78 PetscBool test_lmvm = PETSC_FALSE; 79 KSP ksp; 80 PC pc; 81 Mat M; 82 Vec in, out, out2; 83 PetscReal mult_solve_dist; 84 85 /* Initialize TAO,PETSc */ 86 PetscCall(PetscInitialize(&argc,&argv,(char *)0,help)); 87 PetscCallMPI(MPI_Comm_size(MPI_COMM_WORLD,&size)); 88 PetscCheck(size == 1,PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"Incorrect number of processors"); 89 90 /* Specify default parameters for the problem, check for command-line overrides */ 91 user.param = 5.0; 92 PetscCall(PetscOptionsGetInt(NULL,NULL,"-my",&my,&flg)); 93 PetscCall(PetscOptionsGetInt(NULL,NULL,"-mx",&mx,&flg)); 94 PetscCall(PetscOptionsGetReal(NULL,NULL,"-par",&user.param,&flg)); 95 PetscCall(PetscOptionsGetBool(NULL,NULL,"-test_lmvm",&test_lmvm,&flg)); 96 97 PetscCall(PetscPrintf(PETSC_COMM_SELF,"\n---- Elastic-Plastic Torsion Problem -----\n")); 98 PetscCall(PetscPrintf(PETSC_COMM_SELF,"mx: %D my: %D \n\n",mx,my)); 99 user.ndim = mx * my; user.mx = mx; user.my = my; 100 user.hx = one/(mx+1); user.hy = one/(my+1); 101 102 /* Allocate vectors */ 103 PetscCall(VecCreateSeq(PETSC_COMM_SELF,user.ndim,&user.y)); 104 PetscCall(VecDuplicate(user.y,&user.s)); 105 PetscCall(VecDuplicate(user.y,&x)); 106 107 /* Create TAO solver and set desired solution method */ 108 PetscCall(TaoCreate(PETSC_COMM_SELF,&tao)); 109 PetscCall(TaoSetType(tao,TAOLMVM)); 110 111 /* Set solution vector with an initial guess */ 112 PetscCall(FormInitialGuess(&user,x)); 113 PetscCall(TaoSetSolution(tao,x)); 114 115 /* Set routine for function and gradient evaluation */ 116 PetscCall(TaoSetObjectiveAndGradient(tao,NULL,FormFunctionGradient,(void *)&user)); 117 118 /* From command line options, determine if using matrix-free hessian */ 119 PetscCall(PetscOptionsHasName(NULL,NULL,"-my_tao_mf",&flg)); 120 if (flg) { 121 PetscCall(MatCreateShell(PETSC_COMM_SELF,user.ndim,user.ndim,user.ndim,user.ndim,(void*)&user,&H)); 122 PetscCall(MatShellSetOperation(H,MATOP_MULT,(void(*)(void))HessianProductMat)); 123 PetscCall(MatSetOption(H,MAT_SYMMETRIC,PETSC_TRUE)); 124 125 PetscCall(TaoSetHessian(tao,H,H,MatrixFreeHessian,(void *)&user)); 126 } else { 127 PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF,user.ndim,user.ndim,5,NULL,&H)); 128 PetscCall(MatSetOption(H,MAT_SYMMETRIC,PETSC_TRUE)); 129 PetscCall(TaoSetHessian(tao,H,H,FormHessian,(void *)&user)); 130 } 131 132 /* Test the LMVM matrix */ 133 if (test_lmvm) { 134 PetscCall(PetscOptionsSetValue(NULL, "-tao_type", "bntr")); 135 PetscCall(PetscOptionsSetValue(NULL, "-tao_bnk_pc_type", "lmvm")); 136 } 137 138 /* Check for any TAO command line options */ 139 PetscCall(TaoSetFromOptions(tao)); 140 141 /* SOLVE THE APPLICATION */ 142 PetscCall(TaoSolve(tao)); 143 144 /* Test the LMVM matrix */ 145 if (test_lmvm) { 146 PetscCall(TaoGetKSP(tao, &ksp)); 147 PetscCall(KSPGetPC(ksp, &pc)); 148 PetscCall(PCLMVMGetMatLMVM(pc, &M)); 149 PetscCall(VecDuplicate(x, &in)); 150 PetscCall(VecDuplicate(x, &out)); 151 PetscCall(VecDuplicate(x, &out2)); 152 PetscCall(VecSet(in, 5.0)); 153 PetscCall(MatMult(M, in, out)); 154 PetscCall(MatSolve(M, out, out2)); 155 PetscCall(VecAXPY(out2, -1.0, in)); 156 PetscCall(VecNorm(out2, NORM_2, &mult_solve_dist)); 157 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)tao), "error between MatMult and MatSolve: %e\n", mult_solve_dist)); 158 PetscCall(VecDestroy(&in)); 159 PetscCall(VecDestroy(&out)); 160 PetscCall(VecDestroy(&out2)); 161 } 162 163 PetscCall(TaoDestroy(&tao)); 164 PetscCall(VecDestroy(&user.s)); 165 PetscCall(VecDestroy(&user.y)); 166 PetscCall(VecDestroy(&x)); 167 PetscCall(MatDestroy(&H)); 168 169 PetscCall(PetscFinalize()); 170 return 0; 171 } 172 173 /* ------------------------------------------------------------------- */ 174 /* 175 FormInitialGuess - Computes an initial approximation to the solution. 176 177 Input Parameters: 178 . user - user-defined application context 179 . X - vector 180 181 Output Parameters: 182 . X - vector 183 */ 184 PetscErrorCode FormInitialGuess(AppCtx *user,Vec X) 185 { 186 PetscReal hx = user->hx, hy = user->hy, temp; 187 PetscReal val; 188 PetscInt i, j, k, nx = user->mx, ny = user->my; 189 190 /* Compute initial guess */ 191 PetscFunctionBeginUser; 192 for (j=0; j<ny; j++) { 193 temp = PetscMin(j+1,ny-j)*hy; 194 for (i=0; i<nx; i++) { 195 k = nx*j + i; 196 val = PetscMin((PetscMin(i+1,nx-i))*hx,temp); 197 PetscCall(VecSetValues(X,1,&k,&val,ADD_VALUES)); 198 } 199 } 200 PetscCall(VecAssemblyBegin(X)); 201 PetscCall(VecAssemblyEnd(X)); 202 PetscFunctionReturn(0); 203 } 204 205 /* ------------------------------------------------------------------- */ 206 /* 207 FormFunctionGradient - Evaluates the function and corresponding gradient. 208 209 Input Parameters: 210 tao - the Tao context 211 X - the input vector 212 ptr - optional user-defined context, as set by TaoSetFunction() 213 214 Output Parameters: 215 f - the newly evaluated function 216 G - the newly evaluated gradient 217 */ 218 PetscErrorCode FormFunctionGradient(Tao tao,Vec X,PetscReal *f,Vec G,void *ptr) 219 { 220 PetscFunctionBeginUser; 221 PetscCall(FormFunction(tao,X,f,ptr)); 222 PetscCall(FormGradient(tao,X,G,ptr)); 223 PetscFunctionReturn(0); 224 } 225 226 /* ------------------------------------------------------------------- */ 227 /* 228 FormFunction - Evaluates the function, f(X). 229 230 Input Parameters: 231 . tao - the Tao context 232 . X - the input vector 233 . ptr - optional user-defined context, as set by TaoSetFunction() 234 235 Output Parameters: 236 . f - the newly evaluated function 237 */ 238 PetscErrorCode FormFunction(Tao tao,Vec X,PetscReal *f,void *ptr) 239 { 240 AppCtx *user = (AppCtx *) ptr; 241 PetscReal hx = user->hx, hy = user->hy, area, three = 3.0, p5 = 0.5; 242 PetscReal zero = 0.0, vb, vl, vr, vt, dvdx, dvdy, flin = 0.0, fquad = 0.0; 243 PetscReal v, cdiv3 = user->param/three; 244 const PetscScalar *x; 245 PetscInt nx = user->mx, ny = user->my, i, j, k; 246 247 PetscFunctionBeginUser; 248 /* Get pointer to vector data */ 249 PetscCall(VecGetArrayRead(X,&x)); 250 251 /* Compute function contributions over the lower triangular elements */ 252 for (j=-1; j<ny; j++) { 253 for (i=-1; i<nx; i++) { 254 k = nx*j + i; 255 v = zero; 256 vr = zero; 257 vt = zero; 258 if (i >= 0 && j >= 0) v = x[k]; 259 if (i < nx-1 && j > -1) vr = x[k+1]; 260 if (i > -1 && j < ny-1) vt = x[k+nx]; 261 dvdx = (vr-v)/hx; 262 dvdy = (vt-v)/hy; 263 fquad += dvdx*dvdx + dvdy*dvdy; 264 flin -= cdiv3*(v+vr+vt); 265 } 266 } 267 268 /* Compute function contributions over the upper triangular elements */ 269 for (j=0; j<=ny; j++) { 270 for (i=0; i<=nx; i++) { 271 k = nx*j + i; 272 vb = zero; 273 vl = zero; 274 v = zero; 275 if (i < nx && j > 0) vb = x[k-nx]; 276 if (i > 0 && j < ny) vl = x[k-1]; 277 if (i < nx && j < ny) v = x[k]; 278 dvdx = (v-vl)/hx; 279 dvdy = (v-vb)/hy; 280 fquad = fquad + dvdx*dvdx + dvdy*dvdy; 281 flin = flin - cdiv3*(vb+vl+v); 282 } 283 } 284 285 /* Restore vector */ 286 PetscCall(VecRestoreArrayRead(X,&x)); 287 288 /* Scale the function */ 289 area = p5*hx*hy; 290 *f = area*(p5*fquad+flin); 291 292 PetscCall(PetscLogFlops(24.0*nx*ny)); 293 PetscFunctionReturn(0); 294 } 295 296 /* ------------------------------------------------------------------- */ 297 /* 298 FormGradient - Evaluates the gradient, G(X). 299 300 Input Parameters: 301 . tao - the Tao context 302 . X - input vector 303 . ptr - optional user-defined context 304 305 Output Parameters: 306 . G - vector containing the newly evaluated gradient 307 */ 308 PetscErrorCode FormGradient(Tao tao,Vec X,Vec G,void *ptr) 309 { 310 AppCtx *user = (AppCtx *) ptr; 311 PetscReal zero=0.0, p5=0.5, three = 3.0, area, val; 312 PetscInt nx = user->mx, ny = user->my, ind, i, j, k; 313 PetscReal hx = user->hx, hy = user->hy; 314 PetscReal vb, vl, vr, vt, dvdx, dvdy; 315 PetscReal v, cdiv3 = user->param/three; 316 const PetscScalar *x; 317 318 PetscFunctionBeginUser; 319 /* Initialize gradient to zero */ 320 PetscCall(VecSet(G, zero)); 321 322 /* Get pointer to vector data */ 323 PetscCall(VecGetArrayRead(X,&x)); 324 325 /* Compute gradient contributions over the lower triangular elements */ 326 for (j=-1; j<ny; j++) { 327 for (i=-1; i<nx; i++) { 328 k = nx*j + i; 329 v = zero; 330 vr = zero; 331 vt = zero; 332 if (i >= 0 && j >= 0) v = x[k]; 333 if (i < nx-1 && j > -1) vr = x[k+1]; 334 if (i > -1 && j < ny-1) vt = x[k+nx]; 335 dvdx = (vr-v)/hx; 336 dvdy = (vt-v)/hy; 337 if (i != -1 && j != -1) { 338 ind = k; val = - dvdx/hx - dvdy/hy - cdiv3; 339 PetscCall(VecSetValues(G,1,&ind,&val,ADD_VALUES)); 340 } 341 if (i != nx-1 && j != -1) { 342 ind = k+1; val = dvdx/hx - cdiv3; 343 PetscCall(VecSetValues(G,1,&ind,&val,ADD_VALUES)); 344 } 345 if (i != -1 && j != ny-1) { 346 ind = k+nx; val = dvdy/hy - cdiv3; 347 PetscCall(VecSetValues(G,1,&ind,&val,ADD_VALUES)); 348 } 349 } 350 } 351 352 /* Compute gradient contributions over the upper triangular elements */ 353 for (j=0; j<=ny; j++) { 354 for (i=0; i<=nx; i++) { 355 k = nx*j + i; 356 vb = zero; 357 vl = zero; 358 v = zero; 359 if (i < nx && j > 0) vb = x[k-nx]; 360 if (i > 0 && j < ny) vl = x[k-1]; 361 if (i < nx && j < ny) v = x[k]; 362 dvdx = (v-vl)/hx; 363 dvdy = (v-vb)/hy; 364 if (i != nx && j != 0) { 365 ind = k-nx; val = - dvdy/hy - cdiv3; 366 PetscCall(VecSetValues(G,1,&ind,&val,ADD_VALUES)); 367 } 368 if (i != 0 && j != ny) { 369 ind = k-1; val = - dvdx/hx - cdiv3; 370 PetscCall(VecSetValues(G,1,&ind,&val,ADD_VALUES)); 371 } 372 if (i != nx && j != ny) { 373 ind = k; val = dvdx/hx + dvdy/hy - cdiv3; 374 PetscCall(VecSetValues(G,1,&ind,&val,ADD_VALUES)); 375 } 376 } 377 } 378 PetscCall(VecRestoreArrayRead(X,&x)); 379 380 /* Assemble gradient vector */ 381 PetscCall(VecAssemblyBegin(G)); 382 PetscCall(VecAssemblyEnd(G)); 383 384 /* Scale the gradient */ 385 area = p5*hx*hy; 386 PetscCall(VecScale(G, area)); 387 PetscCall(PetscLogFlops(24.0*nx*ny)); 388 PetscFunctionReturn(0); 389 } 390 391 /* ------------------------------------------------------------------- */ 392 /* 393 FormHessian - Forms the Hessian matrix. 394 395 Input Parameters: 396 . tao - the Tao context 397 . X - the input vector 398 . ptr - optional user-defined context, as set by TaoSetHessian() 399 400 Output Parameters: 401 . H - Hessian matrix 402 . PrecH - optionally different preconditioning Hessian 403 . flag - flag indicating matrix structure 404 405 Notes: 406 This routine is intended simply as an example of the interface 407 to a Hessian evaluation routine. Since this example compute the 408 Hessian a column at a time, it is not particularly efficient and 409 is not recommended. 410 */ 411 PetscErrorCode FormHessian(Tao tao,Vec X,Mat H,Mat Hpre, void *ptr) 412 { 413 AppCtx *user = (AppCtx *) ptr; 414 PetscInt i,j, ndim = user->ndim; 415 PetscReal *y, zero = 0.0, one = 1.0; 416 PetscBool assembled; 417 418 PetscFunctionBeginUser; 419 user->xvec = X; 420 421 /* Initialize Hessian entries and work vector to zero */ 422 PetscCall(MatAssembled(H,&assembled)); 423 if (assembled)PetscCall(MatZeroEntries(H)); 424 425 PetscCall(VecSet(user->s, zero)); 426 427 /* Loop over matrix columns to compute entries of the Hessian */ 428 for (j=0; j<ndim; j++) { 429 PetscCall(VecSetValues(user->s,1,&j,&one,INSERT_VALUES)); 430 PetscCall(VecAssemblyBegin(user->s)); 431 PetscCall(VecAssemblyEnd(user->s)); 432 433 PetscCall(HessianProduct(ptr,user->s,user->y)); 434 435 PetscCall(VecSetValues(user->s,1,&j,&zero,INSERT_VALUES)); 436 PetscCall(VecAssemblyBegin(user->s)); 437 PetscCall(VecAssemblyEnd(user->s)); 438 439 PetscCall(VecGetArray(user->y,&y)); 440 for (i=0; i<ndim; i++) { 441 if (y[i] != zero) { 442 PetscCall(MatSetValues(H,1,&i,1,&j,&y[i],ADD_VALUES)); 443 } 444 } 445 PetscCall(VecRestoreArray(user->y,&y)); 446 } 447 PetscCall(MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY)); 448 PetscCall(MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY)); 449 PetscFunctionReturn(0); 450 } 451 452 /* ------------------------------------------------------------------- */ 453 /* 454 MatrixFreeHessian - Sets a pointer for use in computing Hessian-vector 455 products. 456 457 Input Parameters: 458 . tao - the Tao context 459 . X - the input vector 460 . ptr - optional user-defined context, as set by TaoSetHessian() 461 462 Output Parameters: 463 . H - Hessian matrix 464 . PrecH - optionally different preconditioning Hessian 465 . flag - flag indicating matrix structure 466 */ 467 PetscErrorCode MatrixFreeHessian(Tao tao,Vec X,Mat H,Mat PrecH, void *ptr) 468 { 469 AppCtx *user = (AppCtx *) ptr; 470 471 /* Sets location of vector for use in computing matrix-vector products of the form H(X)*y */ 472 PetscFunctionBeginUser; 473 user->xvec = X; 474 PetscFunctionReturn(0); 475 } 476 477 /* ------------------------------------------------------------------- */ 478 /* 479 HessianProductMat - Computes the matrix-vector product 480 y = mat*svec. 481 482 Input Parameters: 483 . mat - input matrix 484 . svec - input vector 485 486 Output Parameters: 487 . y - solution vector 488 */ 489 PetscErrorCode HessianProductMat(Mat mat,Vec svec,Vec y) 490 { 491 void *ptr; 492 493 PetscFunctionBeginUser; 494 PetscCall(MatShellGetContext(mat,&ptr)); 495 PetscCall(HessianProduct(ptr,svec,y)); 496 PetscFunctionReturn(0); 497 } 498 499 /* ------------------------------------------------------------------- */ 500 /* 501 Hessian Product - Computes the matrix-vector product: 502 y = f''(x)*svec. 503 504 Input Parameters: 505 . ptr - pointer to the user-defined context 506 . svec - input vector 507 508 Output Parameters: 509 . y - product vector 510 */ 511 PetscErrorCode HessianProduct(void *ptr,Vec svec,Vec y) 512 { 513 AppCtx *user = (AppCtx *)ptr; 514 PetscReal p5 = 0.5, zero = 0.0, one = 1.0, hx, hy, val, area; 515 const PetscScalar *x, *s; 516 PetscReal v, vb, vl, vr, vt, hxhx, hyhy; 517 PetscInt nx, ny, i, j, k, ind; 518 519 PetscFunctionBeginUser; 520 nx = user->mx; 521 ny = user->my; 522 hx = user->hx; 523 hy = user->hy; 524 hxhx = one/(hx*hx); 525 hyhy = one/(hy*hy); 526 527 /* Get pointers to vector data */ 528 PetscCall(VecGetArrayRead(user->xvec,&x)); 529 PetscCall(VecGetArrayRead(svec,&s)); 530 531 /* Initialize product vector to zero */ 532 PetscCall(VecSet(y, zero)); 533 534 /* Compute f''(x)*s over the lower triangular elements */ 535 for (j=-1; j<ny; j++) { 536 for (i=-1; i<nx; i++) { 537 k = nx*j + i; 538 v = zero; 539 vr = zero; 540 vt = zero; 541 if (i != -1 && j != -1) v = s[k]; 542 if (i != nx-1 && j != -1) { 543 vr = s[k+1]; 544 ind = k+1; val = hxhx*(vr-v); 545 PetscCall(VecSetValues(y,1,&ind,&val,ADD_VALUES)); 546 } 547 if (i != -1 && j != ny-1) { 548 vt = s[k+nx]; 549 ind = k+nx; val = hyhy*(vt-v); 550 PetscCall(VecSetValues(y,1,&ind,&val,ADD_VALUES)); 551 } 552 if (i != -1 && j != -1) { 553 ind = k; val = hxhx*(v-vr) + hyhy*(v-vt); 554 PetscCall(VecSetValues(y,1,&ind,&val,ADD_VALUES)); 555 } 556 } 557 } 558 559 /* Compute f''(x)*s over the upper triangular elements */ 560 for (j=0; j<=ny; j++) { 561 for (i=0; i<=nx; i++) { 562 k = nx*j + i; 563 v = zero; 564 vl = zero; 565 vb = zero; 566 if (i != nx && j != ny) v = s[k]; 567 if (i != nx && j != 0) { 568 vb = s[k-nx]; 569 ind = k-nx; val = hyhy*(vb-v); 570 PetscCall(VecSetValues(y,1,&ind,&val,ADD_VALUES)); 571 } 572 if (i != 0 && j != ny) { 573 vl = s[k-1]; 574 ind = k-1; val = hxhx*(vl-v); 575 PetscCall(VecSetValues(y,1,&ind,&val,ADD_VALUES)); 576 } 577 if (i != nx && j != ny) { 578 ind = k; val = hxhx*(v-vl) + hyhy*(v-vb); 579 PetscCall(VecSetValues(y,1,&ind,&val,ADD_VALUES)); 580 } 581 } 582 } 583 /* Restore vector data */ 584 PetscCall(VecRestoreArrayRead(svec,&s)); 585 PetscCall(VecRestoreArrayRead(user->xvec,&x)); 586 587 /* Assemble vector */ 588 PetscCall(VecAssemblyBegin(y)); 589 PetscCall(VecAssemblyEnd(y)); 590 591 /* Scale resulting vector by area */ 592 area = p5*hx*hy; 593 PetscCall(VecScale(y, area)); 594 PetscCall(PetscLogFlops(18.0*nx*ny)); 595 PetscFunctionReturn(0); 596 } 597 598 /*TEST 599 600 build: 601 requires: !complex 602 603 test: 604 suffix: 1 605 args: -tao_smonitor -tao_type ntl -tao_gatol 1.e-4 606 607 test: 608 suffix: 2 609 args: -tao_smonitor -tao_type ntr -tao_gatol 1.e-4 610 611 test: 612 suffix: 3 613 args: -tao_smonitor -tao_type bntr -tao_gatol 1.e-4 -my_tao_mf -tao_test_hessian 614 615 test: 616 suffix: 4 617 args: -tao_smonitor -tao_gatol 1e-3 -tao_type bqnls 618 619 test: 620 suffix: 5 621 args: -tao_smonitor -tao_gatol 1e-3 -tao_type blmvm 622 623 test: 624 suffix: 6 625 args: -tao_smonitor -tao_gatol 1e-3 -tao_type bqnktr -tao_bqnk_mat_type lmvmsr1 626 627 TEST*/ 628