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