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