1 static char help[] = "Newton methods to solve u'' + u^{2} = f in parallel.\n\ 2 This example employs a user-defined monitoring routine and optionally a user-defined\n\ 3 routine to check candidate iterates produced by line search routines.\n\ 4 The command line options include:\n\ 5 -pre_check_iterates : activate checking of iterates\n\ 6 -post_check_iterates : activate checking of iterates\n\ 7 -check_tol <tol>: set tolerance for iterate checking\n\ 8 -user_precond : activate a (trivial) user-defined preconditioner\n\n"; 9 10 /* 11 Include "petscdm.h" so that we can use data management objects (DMs) 12 Include "petscdmda.h" so that we can use distributed arrays (DMDAs). 13 Include "petscsnes.h" so that we can use SNES solvers. Note that this 14 file automatically includes: 15 petscsys.h - base PETSc routines 16 petscvec.h - vectors 17 petscmat.h - matrices 18 petscis.h - index sets 19 petscksp.h - Krylov subspace methods 20 petscviewer.h - viewers 21 petscpc.h - preconditioners 22 petscksp.h - linear solvers 23 */ 24 25 #include <petscdm.h> 26 #include <petscdmda.h> 27 #include <petscsnes.h> 28 29 /* 30 User-defined routines. 31 */ 32 PetscErrorCode FormJacobian(SNES,Vec,Mat,Mat,void*); 33 PetscErrorCode FormFunction(SNES,Vec,Vec,void*); 34 PetscErrorCode FormInitialGuess(Vec); 35 PetscErrorCode Monitor(SNES,PetscInt,PetscReal,void*); 36 PetscErrorCode PreCheck(SNESLineSearch,Vec,Vec,PetscBool*,void*); 37 PetscErrorCode PostCheck(SNESLineSearch,Vec,Vec,Vec,PetscBool*,PetscBool*,void*); 38 PetscErrorCode PostSetSubKSP(SNESLineSearch,Vec,Vec,Vec,PetscBool*,PetscBool*,void*); 39 PetscErrorCode MatrixFreePreconditioner(PC,Vec,Vec); 40 41 /* 42 User-defined application context 43 */ 44 typedef struct { 45 DM da; /* distributed array */ 46 Vec F; /* right-hand-side of PDE */ 47 PetscMPIInt rank; /* rank of processor */ 48 PetscMPIInt size; /* size of communicator */ 49 PetscReal h; /* mesh spacing */ 50 PetscBool sjerr; /* if or not to test jacobian domain error */ 51 } ApplicationCtx; 52 53 /* 54 User-defined context for monitoring 55 */ 56 typedef struct { 57 PetscViewer viewer; 58 } MonitorCtx; 59 60 /* 61 User-defined context for checking candidate iterates that are 62 determined by line search methods 63 */ 64 typedef struct { 65 Vec last_step; /* previous iterate */ 66 PetscReal tolerance; /* tolerance for changes between successive iterates */ 67 ApplicationCtx *user; 68 } StepCheckCtx; 69 70 typedef struct { 71 PetscInt its0; /* num of prevous outer KSP iterations */ 72 } SetSubKSPCtx; 73 74 int main(int argc,char **argv) 75 { 76 SNES snes; /* SNES context */ 77 SNESLineSearch linesearch; /* SNESLineSearch context */ 78 Mat J; /* Jacobian matrix */ 79 ApplicationCtx ctx; /* user-defined context */ 80 Vec x,r,U,F; /* vectors */ 81 MonitorCtx monP; /* monitoring context */ 82 StepCheckCtx checkP; /* step-checking context */ 83 SetSubKSPCtx checkP1; 84 PetscBool pre_check,post_check,post_setsubksp; /* flag indicating whether we're checking candidate iterates */ 85 PetscScalar xp,*FF,*UU,none = -1.0; 86 PetscInt its,N = 5,i,maxit,maxf,xs,xm; 87 PetscReal abstol,rtol,stol,norm; 88 PetscBool flg,viewinitial = PETSC_FALSE; 89 90 PetscCall(PetscInitialize(&argc,&argv,(char*)0,help)); 91 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&ctx.rank)); 92 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&ctx.size)); 93 PetscCall(PetscOptionsGetInt(NULL,NULL,"-n",&N,NULL)); 94 ctx.h = 1.0/(N-1); 95 ctx.sjerr = PETSC_FALSE; 96 PetscCall(PetscOptionsGetBool(NULL,NULL,"-test_jacobian_domain_error",&ctx.sjerr,NULL)); 97 PetscCall(PetscOptionsGetBool(NULL,NULL,"-view_initial",&viewinitial,NULL)); 98 99 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100 Create nonlinear solver context 101 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 102 103 PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes)); 104 105 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 106 Create vector data structures; set function evaluation routine 107 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 108 109 /* 110 Create distributed array (DMDA) to manage parallel grid and vectors 111 */ 112 PetscCall(DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,N,1,1,NULL,&ctx.da)); 113 PetscCall(DMSetFromOptions(ctx.da)); 114 PetscCall(DMSetUp(ctx.da)); 115 116 /* 117 Extract global and local vectors from DMDA; then duplicate for remaining 118 vectors that are the same types 119 */ 120 PetscCall(DMCreateGlobalVector(ctx.da,&x)); 121 PetscCall(VecDuplicate(x,&r)); 122 PetscCall(VecDuplicate(x,&F)); ctx.F = F; 123 PetscCall(VecDuplicate(x,&U)); 124 125 /* 126 Set function evaluation routine and vector. Whenever the nonlinear 127 solver needs to compute the nonlinear function, it will call this 128 routine. 129 - Note that the final routine argument is the user-defined 130 context that provides application-specific data for the 131 function evaluation routine. 132 */ 133 PetscCall(SNESSetFunction(snes,r,FormFunction,&ctx)); 134 135 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 136 Create matrix data structure; set Jacobian evaluation routine 137 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 138 139 PetscCall(MatCreate(PETSC_COMM_WORLD,&J)); 140 PetscCall(MatSetSizes(J,PETSC_DECIDE,PETSC_DECIDE,N,N)); 141 PetscCall(MatSetFromOptions(J)); 142 PetscCall(MatSeqAIJSetPreallocation(J,3,NULL)); 143 PetscCall(MatMPIAIJSetPreallocation(J,3,NULL,3,NULL)); 144 145 /* 146 Set Jacobian matrix data structure and default Jacobian evaluation 147 routine. Whenever the nonlinear solver needs to compute the 148 Jacobian matrix, it will call this routine. 149 - Note that the final routine argument is the user-defined 150 context that provides application-specific data for the 151 Jacobian evaluation routine. 152 */ 153 PetscCall(SNESSetJacobian(snes,J,J,FormJacobian,&ctx)); 154 155 /* 156 Optionally allow user-provided preconditioner 157 */ 158 PetscCall(PetscOptionsHasName(NULL,NULL,"-user_precond",&flg)); 159 if (flg) { 160 KSP ksp; 161 PC pc; 162 PetscCall(SNESGetKSP(snes,&ksp)); 163 PetscCall(KSPGetPC(ksp,&pc)); 164 PetscCall(PCSetType(pc,PCSHELL)); 165 PetscCall(PCShellSetApply(pc,MatrixFreePreconditioner)); 166 } 167 168 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 169 Customize nonlinear solver; set runtime options 170 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 171 172 /* 173 Set an optional user-defined monitoring routine 174 */ 175 PetscCall(PetscViewerDrawOpen(PETSC_COMM_WORLD,0,0,0,0,400,400,&monP.viewer)); 176 PetscCall(SNESMonitorSet(snes,Monitor,&monP,0)); 177 178 /* 179 Set names for some vectors to facilitate monitoring (optional) 180 */ 181 PetscCall(PetscObjectSetName((PetscObject)x,"Approximate Solution")); 182 PetscCall(PetscObjectSetName((PetscObject)U,"Exact Solution")); 183 184 /* 185 Set SNES/KSP/KSP/PC runtime options, e.g., 186 -snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc> 187 */ 188 PetscCall(SNESSetFromOptions(snes)); 189 190 /* 191 Set an optional user-defined routine to check the validity of candidate 192 iterates that are determined by line search methods 193 */ 194 PetscCall(SNESGetLineSearch(snes, &linesearch)); 195 PetscCall(PetscOptionsHasName(NULL,NULL,"-post_check_iterates",&post_check)); 196 197 if (post_check) { 198 PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Activating post step checking routine\n")); 199 PetscCall(SNESLineSearchSetPostCheck(linesearch,PostCheck,&checkP)); 200 PetscCall(VecDuplicate(x,&(checkP.last_step))); 201 202 checkP.tolerance = 1.0; 203 checkP.user = &ctx; 204 205 PetscCall(PetscOptionsGetReal(NULL,NULL,"-check_tol",&checkP.tolerance,NULL)); 206 } 207 208 PetscCall(PetscOptionsHasName(NULL,NULL,"-post_setsubksp",&post_setsubksp)); 209 if (post_setsubksp) { 210 PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Activating post setsubksp\n")); 211 PetscCall(SNESLineSearchSetPostCheck(linesearch,PostSetSubKSP,&checkP1)); 212 } 213 214 PetscCall(PetscOptionsHasName(NULL,NULL,"-pre_check_iterates",&pre_check)); 215 if (pre_check) { 216 PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Activating pre step checking routine\n")); 217 PetscCall(SNESLineSearchSetPreCheck(linesearch,PreCheck,&checkP)); 218 } 219 220 /* 221 Print parameters used for convergence testing (optional) ... just 222 to demonstrate this routine; this information is also printed with 223 the option -snes_view 224 */ 225 PetscCall(SNESGetTolerances(snes,&abstol,&rtol,&stol,&maxit,&maxf)); 226 PetscCall(PetscPrintf(PETSC_COMM_WORLD,"atol=%g, rtol=%g, stol=%g, maxit=%" PetscInt_FMT ", maxf=%" PetscInt_FMT "\n",(double)abstol,(double)rtol,(double)stol,maxit,maxf)); 227 228 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 229 Initialize application: 230 Store right-hand-side of PDE and exact solution 231 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 232 233 /* 234 Get local grid boundaries (for 1-dimensional DMDA): 235 xs, xm - starting grid index, width of local grid (no ghost points) 236 */ 237 PetscCall(DMDAGetCorners(ctx.da,&xs,NULL,NULL,&xm,NULL,NULL)); 238 239 /* 240 Get pointers to vector data 241 */ 242 PetscCall(DMDAVecGetArray(ctx.da,F,&FF)); 243 PetscCall(DMDAVecGetArray(ctx.da,U,&UU)); 244 245 /* 246 Compute local vector entries 247 */ 248 xp = ctx.h*xs; 249 for (i=xs; i<xs+xm; i++) { 250 FF[i] = 6.0*xp + PetscPowScalar(xp+1.e-12,6.0); /* +1.e-12 is to prevent 0^6 */ 251 UU[i] = xp*xp*xp; 252 xp += ctx.h; 253 } 254 255 /* 256 Restore vectors 257 */ 258 PetscCall(DMDAVecRestoreArray(ctx.da,F,&FF)); 259 PetscCall(DMDAVecRestoreArray(ctx.da,U,&UU)); 260 if (viewinitial) { 261 PetscCall(VecView(U,0)); 262 PetscCall(VecView(F,0)); 263 } 264 265 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 266 Evaluate initial guess; then solve nonlinear system 267 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 268 269 /* 270 Note: The user should initialize the vector, x, with the initial guess 271 for the nonlinear solver prior to calling SNESSolve(). In particular, 272 to employ an initial guess of zero, the user should explicitly set 273 this vector to zero by calling VecSet(). 274 */ 275 PetscCall(FormInitialGuess(x)); 276 PetscCall(SNESSolve(snes,NULL,x)); 277 PetscCall(SNESGetIterationNumber(snes,&its)); 278 PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Number of SNES iterations = %" PetscInt_FMT "\n",its)); 279 280 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 281 Check solution and clean up 282 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 283 284 /* 285 Check the error 286 */ 287 PetscCall(VecAXPY(x,none,U)); 288 PetscCall(VecNorm(x,NORM_2,&norm)); 289 PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Norm of error %g Iterations %" PetscInt_FMT "\n",(double)norm,its)); 290 if (ctx.sjerr) { 291 SNESType snestype; 292 PetscCall(SNESGetType(snes,&snestype)); 293 PetscCall(PetscPrintf(PETSC_COMM_WORLD,"SNES Type %s\n",snestype)); 294 } 295 296 /* 297 Free work space. All PETSc objects should be destroyed when they 298 are no longer needed. 299 */ 300 PetscCall(PetscViewerDestroy(&monP.viewer)); 301 if (post_check) PetscCall(VecDestroy(&checkP.last_step)); 302 PetscCall(VecDestroy(&x)); 303 PetscCall(VecDestroy(&r)); 304 PetscCall(VecDestroy(&U)); 305 PetscCall(VecDestroy(&F)); 306 PetscCall(MatDestroy(&J)); 307 PetscCall(SNESDestroy(&snes)); 308 PetscCall(DMDestroy(&ctx.da)); 309 PetscCall(PetscFinalize()); 310 return 0; 311 } 312 313 /* ------------------------------------------------------------------- */ 314 /* 315 FormInitialGuess - Computes initial guess. 316 317 Input/Output Parameter: 318 . x - the solution vector 319 */ 320 PetscErrorCode FormInitialGuess(Vec x) 321 { 322 PetscScalar pfive = .50; 323 324 PetscFunctionBeginUser; 325 PetscCall(VecSet(x,pfive)); 326 PetscFunctionReturn(0); 327 } 328 329 /* ------------------------------------------------------------------- */ 330 /* 331 FormFunction - Evaluates nonlinear function, F(x). 332 333 Input Parameters: 334 . snes - the SNES context 335 . x - input vector 336 . ctx - optional user-defined context, as set by SNESSetFunction() 337 338 Output Parameter: 339 . f - function vector 340 341 Note: 342 The user-defined context can contain any application-specific 343 data needed for the function evaluation. 344 */ 345 PetscErrorCode FormFunction(SNES snes,Vec x,Vec f,void *ctx) 346 { 347 ApplicationCtx *user = (ApplicationCtx*) ctx; 348 DM da = user->da; 349 PetscScalar *xx,*ff,*FF,d; 350 PetscInt i,M,xs,xm; 351 Vec xlocal; 352 353 PetscFunctionBeginUser; 354 PetscCall(DMGetLocalVector(da,&xlocal)); 355 /* 356 Scatter ghost points to local vector, using the 2-step process 357 DMGlobalToLocalBegin(), DMGlobalToLocalEnd(). 358 By placing code between these two statements, computations can 359 be done while messages are in transition. 360 */ 361 PetscCall(DMGlobalToLocalBegin(da,x,INSERT_VALUES,xlocal)); 362 PetscCall(DMGlobalToLocalEnd(da,x,INSERT_VALUES,xlocal)); 363 364 /* 365 Get pointers to vector data. 366 - The vector xlocal includes ghost point; the vectors x and f do 367 NOT include ghost points. 368 - Using DMDAVecGetArray() allows accessing the values using global ordering 369 */ 370 PetscCall(DMDAVecGetArray(da,xlocal,&xx)); 371 PetscCall(DMDAVecGetArray(da,f,&ff)); 372 PetscCall(DMDAVecGetArray(da,user->F,&FF)); 373 374 /* 375 Get local grid boundaries (for 1-dimensional DMDA): 376 xs, xm - starting grid index, width of local grid (no ghost points) 377 */ 378 PetscCall(DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL)); 379 PetscCall(DMDAGetInfo(da,NULL,&M,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)); 380 381 /* 382 Set function values for boundary points; define local interior grid point range: 383 xsi - starting interior grid index 384 xei - ending interior grid index 385 */ 386 if (xs == 0) { /* left boundary */ 387 ff[0] = xx[0]; 388 xs++;xm--; 389 } 390 if (xs+xm == M) { /* right boundary */ 391 ff[xs+xm-1] = xx[xs+xm-1] - 1.0; 392 xm--; 393 } 394 395 /* 396 Compute function over locally owned part of the grid (interior points only) 397 */ 398 d = 1.0/(user->h*user->h); 399 for (i=xs; i<xs+xm; i++) ff[i] = d*(xx[i-1] - 2.0*xx[i] + xx[i+1]) + xx[i]*xx[i] - FF[i]; 400 401 /* 402 Restore vectors 403 */ 404 PetscCall(DMDAVecRestoreArray(da,xlocal,&xx)); 405 PetscCall(DMDAVecRestoreArray(da,f,&ff)); 406 PetscCall(DMDAVecRestoreArray(da,user->F,&FF)); 407 PetscCall(DMRestoreLocalVector(da,&xlocal)); 408 PetscFunctionReturn(0); 409 } 410 411 /* ------------------------------------------------------------------- */ 412 /* 413 FormJacobian - Evaluates Jacobian matrix. 414 415 Input Parameters: 416 . snes - the SNES context 417 . x - input vector 418 . dummy - optional user-defined context (not used here) 419 420 Output Parameters: 421 . jac - Jacobian matrix 422 . B - optionally different preconditioning matrix 423 . flag - flag indicating matrix structure 424 */ 425 PetscErrorCode FormJacobian(SNES snes,Vec x,Mat jac,Mat B,void *ctx) 426 { 427 ApplicationCtx *user = (ApplicationCtx*) ctx; 428 PetscScalar *xx,d,A[3]; 429 PetscInt i,j[3],M,xs,xm; 430 DM da = user->da; 431 432 PetscFunctionBeginUser; 433 if (user->sjerr) { 434 PetscCall(SNESSetJacobianDomainError(snes)); 435 PetscFunctionReturn(0); 436 } 437 /* 438 Get pointer to vector data 439 */ 440 PetscCall(DMDAVecGetArrayRead(da,x,&xx)); 441 PetscCall(DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL)); 442 443 /* 444 Get range of locally owned matrix 445 */ 446 PetscCall(DMDAGetInfo(da,NULL,&M,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)); 447 448 /* 449 Determine starting and ending local indices for interior grid points. 450 Set Jacobian entries for boundary points. 451 */ 452 453 if (xs == 0) { /* left boundary */ 454 i = 0; A[0] = 1.0; 455 456 PetscCall(MatSetValues(jac,1,&i,1,&i,A,INSERT_VALUES)); 457 xs++;xm--; 458 } 459 if (xs+xm == M) { /* right boundary */ 460 i = M-1; 461 A[0] = 1.0; 462 PetscCall(MatSetValues(jac,1,&i,1,&i,A,INSERT_VALUES)); 463 xm--; 464 } 465 466 /* 467 Interior grid points 468 - Note that in this case we set all elements for a particular 469 row at once. 470 */ 471 d = 1.0/(user->h*user->h); 472 for (i=xs; i<xs+xm; i++) { 473 j[0] = i - 1; j[1] = i; j[2] = i + 1; 474 A[0] = A[2] = d; A[1] = -2.0*d + 2.0*xx[i]; 475 PetscCall(MatSetValues(jac,1,&i,3,j,A,INSERT_VALUES)); 476 } 477 478 /* 479 Assemble matrix, using the 2-step process: 480 MatAssemblyBegin(), MatAssemblyEnd(). 481 By placing code between these two statements, computations can be 482 done while messages are in transition. 483 484 Also, restore vector. 485 */ 486 487 PetscCall(MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY)); 488 PetscCall(DMDAVecRestoreArrayRead(da,x,&xx)); 489 PetscCall(MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY)); 490 491 PetscFunctionReturn(0); 492 } 493 494 /* ------------------------------------------------------------------- */ 495 /* 496 Monitor - Optional user-defined monitoring routine that views the 497 current iterate with an x-window plot. Set by SNESMonitorSet(). 498 499 Input Parameters: 500 snes - the SNES context 501 its - iteration number 502 norm - 2-norm function value (may be estimated) 503 ctx - optional user-defined context for private data for the 504 monitor routine, as set by SNESMonitorSet() 505 506 Note: 507 See the manpage for PetscViewerDrawOpen() for useful runtime options, 508 such as -nox to deactivate all x-window output. 509 */ 510 PetscErrorCode Monitor(SNES snes,PetscInt its,PetscReal fnorm,void *ctx) 511 { 512 MonitorCtx *monP = (MonitorCtx*) ctx; 513 Vec x; 514 515 PetscFunctionBeginUser; 516 PetscCall(PetscPrintf(PETSC_COMM_WORLD,"iter = %" PetscInt_FMT ",SNES Function norm %g\n",its,(double)fnorm)); 517 PetscCall(SNESGetSolution(snes,&x)); 518 PetscCall(VecView(x,monP->viewer)); 519 PetscFunctionReturn(0); 520 } 521 522 /* ------------------------------------------------------------------- */ 523 /* 524 PreCheck - Optional user-defined routine that checks the validity of 525 candidate steps of a line search method. Set by SNESLineSearchSetPreCheck(). 526 527 Input Parameters: 528 snes - the SNES context 529 xcurrent - current solution 530 y - search direction and length 531 532 Output Parameters: 533 y - proposed step (search direction and length) (possibly changed) 534 changed_y - tells if the step has changed or not 535 */ 536 PetscErrorCode PreCheck(SNESLineSearch linesearch,Vec xcurrent,Vec y, PetscBool *changed_y, void * ctx) 537 { 538 PetscFunctionBeginUser; 539 *changed_y = PETSC_FALSE; 540 PetscFunctionReturn(0); 541 } 542 543 /* ------------------------------------------------------------------- */ 544 /* 545 PostCheck - Optional user-defined routine that checks the validity of 546 candidate steps of a line search method. Set by SNESLineSearchSetPostCheck(). 547 548 Input Parameters: 549 snes - the SNES context 550 ctx - optional user-defined context for private data for the 551 monitor routine, as set by SNESLineSearchSetPostCheck() 552 xcurrent - current solution 553 y - search direction and length 554 x - the new candidate iterate 555 556 Output Parameters: 557 y - proposed step (search direction and length) (possibly changed) 558 x - current iterate (possibly modified) 559 560 */ 561 PetscErrorCode PostCheck(SNESLineSearch linesearch,Vec xcurrent,Vec y,Vec x,PetscBool *changed_y,PetscBool *changed_x, void * ctx) 562 { 563 PetscInt i,iter,xs,xm; 564 StepCheckCtx *check; 565 ApplicationCtx *user; 566 PetscScalar *xa,*xa_last,tmp; 567 PetscReal rdiff; 568 DM da; 569 SNES snes; 570 571 PetscFunctionBeginUser; 572 *changed_x = PETSC_FALSE; 573 *changed_y = PETSC_FALSE; 574 575 PetscCall(SNESLineSearchGetSNES(linesearch, &snes)); 576 check = (StepCheckCtx*)ctx; 577 user = check->user; 578 PetscCall(SNESGetIterationNumber(snes,&iter)); 579 580 /* iteration 1 indicates we are working on the second iteration */ 581 if (iter > 0) { 582 da = user->da; 583 PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Checking candidate step at iteration %" PetscInt_FMT " with tolerance %g\n",iter,(double)check->tolerance)); 584 585 /* Access local array data */ 586 PetscCall(DMDAVecGetArray(da,check->last_step,&xa_last)); 587 PetscCall(DMDAVecGetArray(da,x,&xa)); 588 PetscCall(DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL)); 589 590 /* 591 If we fail the user-defined check for validity of the candidate iterate, 592 then modify the iterate as we like. (Note that the particular modification 593 below is intended simply to demonstrate how to manipulate this data, not 594 as a meaningful or appropriate choice.) 595 */ 596 for (i=xs; i<xs+xm; i++) { 597 if (!PetscAbsScalar(xa[i])) rdiff = 2*check->tolerance; 598 else rdiff = PetscAbsScalar((xa[i] - xa_last[i])/xa[i]); 599 if (rdiff > check->tolerance) { 600 tmp = xa[i]; 601 xa[i] = .5*(xa[i] + xa_last[i]); 602 *changed_x = PETSC_TRUE; 603 PetscCall(PetscPrintf(PETSC_COMM_WORLD," Altering entry %" PetscInt_FMT ": x=%g, x_last=%g, diff=%g, x_new=%g\n",i,(double)PetscAbsScalar(tmp),(double)PetscAbsScalar(xa_last[i]),(double)rdiff,(double)PetscAbsScalar(xa[i]))); 604 } 605 } 606 PetscCall(DMDAVecRestoreArray(da,check->last_step,&xa_last)); 607 PetscCall(DMDAVecRestoreArray(da,x,&xa)); 608 } 609 PetscCall(VecCopy(x,check->last_step)); 610 PetscFunctionReturn(0); 611 } 612 613 /* ------------------------------------------------------------------- */ 614 /* 615 PostSetSubKSP - Optional user-defined routine that reset SubKSP options when hierarchical bjacobi PC is used 616 e.g, 617 mpiexec -n 8 ./ex3 -nox -n 10000 -ksp_type fgmres -pc_type bjacobi -pc_bjacobi_blocks 4 -sub_ksp_type gmres -sub_ksp_max_it 3 -post_setsubksp -sub_ksp_rtol 1.e-16 618 Set by SNESLineSearchSetPostCheck(). 619 620 Input Parameters: 621 linesearch - the LineSearch context 622 xcurrent - current solution 623 y - search direction and length 624 x - the new candidate iterate 625 626 Output Parameters: 627 y - proposed step (search direction and length) (possibly changed) 628 x - current iterate (possibly modified) 629 630 */ 631 PetscErrorCode PostSetSubKSP(SNESLineSearch linesearch,Vec xcurrent,Vec y,Vec x,PetscBool *changed_y,PetscBool *changed_x, void * ctx) 632 { 633 SetSubKSPCtx *check; 634 PetscInt iter,its,sub_its,maxit; 635 KSP ksp,sub_ksp,*sub_ksps; 636 PC pc; 637 PetscReal ksp_ratio; 638 SNES snes; 639 640 PetscFunctionBeginUser; 641 PetscCall(SNESLineSearchGetSNES(linesearch, &snes)); 642 check = (SetSubKSPCtx*)ctx; 643 PetscCall(SNESGetIterationNumber(snes,&iter)); 644 PetscCall(SNESGetKSP(snes,&ksp)); 645 PetscCall(KSPGetPC(ksp,&pc)); 646 PetscCall(PCBJacobiGetSubKSP(pc,NULL,NULL,&sub_ksps)); 647 sub_ksp = sub_ksps[0]; 648 PetscCall(KSPGetIterationNumber(ksp,&its)); /* outer KSP iteration number */ 649 PetscCall(KSPGetIterationNumber(sub_ksp,&sub_its)); /* inner KSP iteration number */ 650 651 if (iter) { 652 PetscCall(PetscPrintf(PETSC_COMM_WORLD," ...PostCheck snes iteration %" PetscInt_FMT ", ksp_it %" PetscInt_FMT " %" PetscInt_FMT ", subksp_it %" PetscInt_FMT "\n",iter,check->its0,its,sub_its)); 653 ksp_ratio = ((PetscReal)(its))/check->its0; 654 maxit = (PetscInt)(ksp_ratio*sub_its + 0.5); 655 if (maxit < 2) maxit = 2; 656 PetscCall(KSPSetTolerances(sub_ksp,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,maxit)); 657 PetscCall(PetscPrintf(PETSC_COMM_WORLD," ...ksp_ratio %g, new maxit %" PetscInt_FMT "\n\n",(double)ksp_ratio,maxit)); 658 } 659 check->its0 = its; /* save current outer KSP iteration number */ 660 PetscFunctionReturn(0); 661 } 662 663 /* ------------------------------------------------------------------- */ 664 /* 665 MatrixFreePreconditioner - This routine demonstrates the use of a 666 user-provided preconditioner. This code implements just the null 667 preconditioner, which of course is not recommended for general use. 668 669 Input Parameters: 670 + pc - preconditioner 671 - x - input vector 672 673 Output Parameter: 674 . y - preconditioned vector 675 */ 676 PetscErrorCode MatrixFreePreconditioner(PC pc,Vec x,Vec y) 677 { 678 PetscCall(VecCopy(x,y)); 679 return 0; 680 } 681 682 /*TEST 683 684 test: 685 args: -nox -snes_monitor_cancel -snes_monitor_short -ksp_gmres_cgs_refinement_type refine_always 686 687 test: 688 suffix: 2 689 nsize: 3 690 args: -nox -pc_type asm -mat_type mpiaij -snes_monitor_cancel -snes_monitor_short -ksp_gmres_cgs_refinement_type refine_always 691 692 test: 693 suffix: 3 694 nsize: 2 695 args: -nox -snes_monitor_cancel -snes_monitor_short -ksp_gmres_cgs_refinement_type refine_always 696 697 test: 698 suffix: 4 699 args: -nox -pre_check_iterates -post_check_iterates 700 701 test: 702 suffix: 5 703 requires: double !complex !single 704 nsize: 2 705 args: -nox -snes_test_jacobian -snes_test_jacobian_view 706 707 test: 708 suffix: 6 709 requires: double !complex !single 710 nsize: 4 711 args: -test_jacobian_domain_error -snes_converged_reason -snes_check_jacobian_domain_error 1 712 713 test: 714 suffix: 7 715 requires: double !complex !single 716 nsize: 4 717 args: -test_jacobian_domain_error -snes_converged_reason -snes_type newtontr -snes_check_jacobian_domain_error 1 718 719 test: 720 suffix: 8 721 requires: double !complex !single 722 nsize: 4 723 args: -test_jacobian_domain_error -snes_converged_reason -snes_type vinewtonrsls -snes_check_jacobian_domain_error 1 724 725 test: 726 suffix: 9 727 requires: double !complex !single 728 nsize: 4 729 args: -test_jacobian_domain_error -snes_converged_reason -snes_type vinewtonssls -snes_check_jacobian_domain_error 1 730 731 test: 732 suffix: 10 733 requires: double !complex !single 734 nsize: 4 735 args: -test_jacobian_domain_error -snes_converged_reason -snes_type qn -snes_qn_scale_type jacobian -snes_check_jacobian_domain_error 1 736 737 test: 738 suffix: 11 739 requires: double !complex !single 740 nsize: 4 741 args: -test_jacobian_domain_error -snes_converged_reason -snes_type ms -snes_ms_type m62 -snes_ms_damping 0.9 -snes_check_jacobian_domain_error 1 742 743 test: 744 suffix: 12 745 args: -view_initial 746 filter: grep -v "type:" 747 748 test: 749 suffix: 13 750 requires: double !complex !single 751 nsize: 4 752 args: -test_jacobian_domain_error -snes_converged_reason -snes_type newtontrdc -snes_check_jacobian_domain_error 1 753 754 TEST*/ 755