1 #define PETSCSNES_DLL 2 3 #include "src/snes/impls/ls/ls.h" 4 5 /* 6 Checks if J^T F = 0 which implies we've found a local minimum of the function, 7 but not a zero. In the case when one cannot compute J^T F we use the fact that 8 0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More 9 for this trick. 10 */ 11 #undef __FUNCT__ 12 #define __FUNCT__ "SNESLSCheckLocalMin_Private" 13 PetscErrorCode SNESLSCheckLocalMin_Private(Mat A,Vec F,Vec W,PetscReal fnorm,PetscTruth *ismin) 14 { 15 PetscReal a1; 16 PetscErrorCode ierr; 17 PetscTruth hastranspose; 18 19 PetscFunctionBegin; 20 *ismin = PETSC_FALSE; 21 ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr); 22 if (hastranspose) { 23 /* Compute || J^T F|| */ 24 ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr); 25 ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr); 26 ierr = PetscInfo1(0,"|| J^T F|| %G near zero implies found a local minimum\n",a1/fnorm);CHKERRQ(ierr); 27 if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE; 28 } else { 29 Vec work; 30 PetscScalar result; 31 PetscReal wnorm; 32 33 ierr = VecSetRandom(W,PETSC_NULL);CHKERRQ(ierr); 34 ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr); 35 ierr = VecDuplicate(W,&work);CHKERRQ(ierr); 36 ierr = MatMult(A,W,work);CHKERRQ(ierr); 37 ierr = VecDot(F,work,&result);CHKERRQ(ierr); 38 ierr = VecDestroy(work);CHKERRQ(ierr); 39 a1 = PetscAbsScalar(result)/(fnorm*wnorm); 40 ierr = PetscInfo1(0,"(F^T J random)/(|| F ||*||random|| %G near zero implies found a local minimum\n",a1);CHKERRQ(ierr); 41 if (a1 < 1.e-4) *ismin = PETSC_TRUE; 42 } 43 PetscFunctionReturn(0); 44 } 45 46 /* 47 Checks if J^T(F - J*X) = 0 48 */ 49 #undef __FUNCT__ 50 #define __FUNCT__ "SNESLSCheckResidual_Private" 51 PetscErrorCode SNESLSCheckResidual_Private(Mat A,Vec F,Vec X,Vec W1,Vec W2) 52 { 53 PetscReal a1,a2; 54 PetscErrorCode ierr; 55 PetscTruth hastranspose; 56 57 PetscFunctionBegin; 58 ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr); 59 if (hastranspose) { 60 ierr = MatMult(A,X,W1);CHKERRQ(ierr); 61 ierr = VecAXPY(W1,-1.0,F);CHKERRQ(ierr); 62 63 /* Compute || J^T W|| */ 64 ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr); 65 ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr); 66 ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr); 67 if (a1) { 68 ierr = PetscInfo1(0,"||J^T(F-Ax)||/||F-AX|| %G near zero implies inconsistent rhs\n",a2/a1);CHKERRQ(ierr); 69 } 70 } 71 PetscFunctionReturn(0); 72 } 73 74 /* -------------------------------------------------------------------- 75 76 This file implements a truncated Newton method with a line search, 77 for solving a system of nonlinear equations, using the KSP, Vec, 78 and Mat interfaces for linear solvers, vectors, and matrices, 79 respectively. 80 81 The following basic routines are required for each nonlinear solver: 82 SNESCreate_XXX() - Creates a nonlinear solver context 83 SNESSetFromOptions_XXX() - Sets runtime options 84 SNESSolve_XXX() - Solves the nonlinear system 85 SNESDestroy_XXX() - Destroys the nonlinear solver context 86 The suffix "_XXX" denotes a particular implementation, in this case 87 we use _LS (e.g., SNESCreate_LS, SNESSolve_LS) for solving 88 systems of nonlinear equations with a line search (LS) method. 89 These routines are actually called via the common user interface 90 routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and 91 SNESDestroy(), so the application code interface remains identical 92 for all nonlinear solvers. 93 94 Another key routine is: 95 SNESSetUp_XXX() - Prepares for the use of a nonlinear solver 96 by setting data structures and options. The interface routine SNESSetUp() 97 is not usually called directly by the user, but instead is called by 98 SNESSolve() if necessary. 99 100 Additional basic routines are: 101 SNESView_XXX() - Prints details of runtime options that 102 have actually been used. 103 These are called by application codes via the interface routines 104 SNESView(). 105 106 The various types of solvers (preconditioners, Krylov subspace methods, 107 nonlinear solvers, timesteppers) are all organized similarly, so the 108 above description applies to these categories also. 109 110 -------------------------------------------------------------------- */ 111 /* 112 SNESSolve_LS - Solves a nonlinear system with a truncated Newton 113 method with a line search. 114 115 Input Parameters: 116 . snes - the SNES context 117 118 Output Parameter: 119 . outits - number of iterations until termination 120 121 Application Interface Routine: SNESSolve() 122 123 Notes: 124 This implements essentially a truncated Newton method with a 125 line search. By default a cubic backtracking line search 126 is employed, as described in the text "Numerical Methods for 127 Unconstrained Optimization and Nonlinear Equations" by Dennis 128 and Schnabel. 129 */ 130 #undef __FUNCT__ 131 #define __FUNCT__ "SNESSolve_LS" 132 PetscErrorCode SNESSolve_LS(SNES snes) 133 { 134 SNES_LS *neP = (SNES_LS*)snes->data; 135 PetscErrorCode ierr; 136 PetscInt maxits,i,lits; 137 PetscTruth lssucceed; 138 MatStructure flg = DIFFERENT_NONZERO_PATTERN; 139 PetscReal fnorm,gnorm,xnorm,ynorm; 140 Vec Y,X,F,G,W,TMP; 141 KSPConvergedReason kspreason; 142 143 PetscFunctionBegin; 144 snes->numFailures = 0; 145 snes->numLinearSolveFailures = 0; 146 snes->reason = SNES_CONVERGED_ITERATING; 147 148 maxits = snes->max_its; /* maximum number of iterations */ 149 X = snes->vec_sol; /* solution vector */ 150 F = snes->vec_func; /* residual vector */ 151 Y = snes->work[0]; /* work vectors */ 152 G = snes->work[1]; 153 W = snes->work[2]; 154 155 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 156 snes->iter = 0; 157 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 158 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); 159 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 160 if (fnorm != fnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 161 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 162 snes->norm = fnorm; 163 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 164 SNESLogConvHistory(snes,fnorm,0); 165 SNESMonitor(snes,0,fnorm); 166 167 /* set parameter for default relative tolerance convergence test */ 168 snes->ttol = fnorm*snes->rtol; 169 if (snes->ops->converged) { 170 ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 171 } 172 if (snes->reason) PetscFunctionReturn(0); 173 174 for (i=0; i<maxits; i++) { 175 176 /* Call general purpose update function */ 177 if (snes->ops->update) { 178 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 179 } 180 181 /* Solve J Y = F, where J is Jacobian matrix */ 182 ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 183 ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); 184 ierr = SNES_KSPSolve(snes,snes->ksp,F,Y);CHKERRQ(ierr); 185 ierr = KSPGetConvergedReason(snes->ksp,&kspreason);CHKERRQ(ierr); 186 if (kspreason < 0) { 187 if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { 188 snes->reason = SNES_DIVERGED_LINEAR_SOLVE; 189 PetscFunctionReturn(0); 190 } 191 } 192 ierr = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr); 193 snes->linear_its += lits; 194 ierr = PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);CHKERRQ(ierr); 195 196 if (neP->precheckstep) { 197 PetscTruth changed_y = PETSC_FALSE; 198 ierr = (*neP->precheckstep)(snes,X,Y,neP->precheck,&changed_y);CHKERRQ(ierr); 199 } 200 201 if (PetscLogPrintInfo){ 202 ierr = SNESLSCheckResidual_Private(snes->jacobian,F,Y,G,W);CHKERRQ(ierr); 203 } 204 205 /* Compute a (scaled) negative update in the line search routine: 206 Y <- X - lambda*Y 207 and evaluate G = function(Y) (depends on the line search). 208 */ 209 ierr = VecCopy(Y,snes->vec_sol_update_always);CHKERRQ(ierr); 210 ynorm = 1; gnorm = fnorm; 211 ierr = (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr); 212 ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed);CHKERRQ(ierr); 213 TMP = F; F = G; snes->vec_func_always = F; G = TMP; 214 TMP = X; X = W; snes->vec_sol_always = X; W = TMP; 215 fnorm = gnorm; 216 if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break; 217 218 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 219 snes->iter = i+1; 220 snes->norm = fnorm; 221 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 222 SNESLogConvHistory(snes,fnorm,lits); 223 SNESMonitor(snes,i+1,fnorm); 224 225 if (!lssucceed) { 226 PetscTruth ismin; 227 if (++snes->numFailures >= snes->maxFailures) { 228 snes->reason = SNES_DIVERGED_LS_FAILURE; 229 ierr = SNESLSCheckLocalMin_Private(snes->jacobian,F,W,fnorm,&ismin);CHKERRQ(ierr); 230 if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; 231 break; 232 } 233 } 234 235 /* Test for convergence */ 236 if (snes->ops->converged) { 237 ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); /* xnorm = || X || */ 238 ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 239 if (snes->reason) break; 240 } 241 } 242 if (X != snes->vec_sol) { 243 ierr = VecCopy(X,snes->vec_sol);CHKERRQ(ierr); 244 } 245 if (F != snes->vec_func) { 246 ierr = VecCopy(F,snes->vec_func);CHKERRQ(ierr); 247 } 248 snes->vec_sol_always = snes->vec_sol; 249 snes->vec_func_always = snes->vec_func; 250 if (i == maxits) { 251 ierr = PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);CHKERRQ(ierr); 252 snes->reason = SNES_DIVERGED_MAX_IT; 253 } 254 PetscFunctionReturn(0); 255 } 256 /* -------------------------------------------------------------------------- */ 257 /* 258 SNESSetUp_LS - Sets up the internal data structures for the later use 259 of the SNESLS nonlinear solver. 260 261 Input Parameter: 262 . snes - the SNES context 263 . x - the solution vector 264 265 Application Interface Routine: SNESSetUp() 266 267 Notes: 268 For basic use of the SNES solvers, the user need not explicitly call 269 SNESSetUp(), since these actions will automatically occur during 270 the call to SNESSolve(). 271 */ 272 #undef __FUNCT__ 273 #define __FUNCT__ "SNESSetUp_LS" 274 PetscErrorCode SNESSetUp_LS(SNES snes) 275 { 276 PetscErrorCode ierr; 277 278 PetscFunctionBegin; 279 if (!snes->work) { 280 snes->nwork = 4; 281 ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr); 282 ierr = PetscLogObjectParents(snes,snes->nwork,snes->work);CHKERRQ(ierr); 283 snes->vec_sol_update_always = snes->work[3]; 284 } 285 PetscFunctionReturn(0); 286 } 287 /* -------------------------------------------------------------------------- */ 288 /* 289 SNESDestroy_LS - Destroys the private SNES_LS context that was created 290 with SNESCreate_LS(). 291 292 Input Parameter: 293 . snes - the SNES context 294 295 Application Interface Routine: SNESDestroy() 296 */ 297 #undef __FUNCT__ 298 #define __FUNCT__ "SNESDestroy_LS" 299 PetscErrorCode SNESDestroy_LS(SNES snes) 300 { 301 PetscErrorCode ierr; 302 303 PetscFunctionBegin; 304 if (snes->nwork) { 305 ierr = VecDestroyVecs(snes->work,snes->nwork);CHKERRQ(ierr); 306 } 307 ierr = PetscFree(snes->data);CHKERRQ(ierr); 308 309 /* clear composed functions */ 310 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C","",PETSC_NULL);CHKERRQ(ierr); 311 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C","",PETSC_NULL);CHKERRQ(ierr); 312 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C","",PETSC_NULL);CHKERRQ(ierr); 313 314 PetscFunctionReturn(0); 315 } 316 /* -------------------------------------------------------------------------- */ 317 #undef __FUNCT__ 318 #define __FUNCT__ "SNESLineSearchNo" 319 320 /*@C 321 SNESLineSearchNo - This routine is not a line search at all; 322 it simply uses the full Newton step. Thus, this routine is intended 323 to serve as a template and is not recommended for general use. 324 325 Collective on SNES and Vec 326 327 Input Parameters: 328 + snes - nonlinear context 329 . lsctx - optional context for line search (not used here) 330 . x - current iterate 331 . f - residual evaluated at x 332 . y - search direction 333 . w - work vector 334 - fnorm - 2-norm of f 335 336 Output Parameters: 337 + g - residual evaluated at new iterate y 338 . w - new iterate 339 . gnorm - 2-norm of g 340 . ynorm - 2-norm of search length 341 - flag - PETSC_TRUE on success, PETSC_FALSE on failure 342 343 Options Database Key: 344 . -snes_ls basic - Activates SNESLineSearchNo() 345 346 Level: advanced 347 348 .keywords: SNES, nonlinear, line search, cubic 349 350 .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(), 351 SNESLineSearchSet(), SNESLineSearchNoNorms() 352 @*/ 353 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchNo(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag) 354 { 355 PetscErrorCode ierr; 356 SNES_LS *neP = (SNES_LS*)snes->data; 357 PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE; 358 359 PetscFunctionBegin; 360 *flag = PETSC_TRUE; 361 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 362 ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr); /* ynorm = || y || */ 363 ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr); /* w <- x - y */ 364 if (neP->postcheckstep) { 365 ierr = (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);CHKERRQ(ierr); 366 } 367 if (changed_y) { 368 ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr); /* w <- x - y */ 369 } 370 ierr = SNESComputeFunction(snes,w,g); 371 if (PetscExceptionValue(ierr)) { 372 PetscErrorCode pierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr); 373 } 374 CHKERRQ(ierr); 375 376 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); /* gnorm = || g || */ 377 if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 378 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 379 PetscFunctionReturn(0); 380 } 381 /* -------------------------------------------------------------------------- */ 382 #undef __FUNCT__ 383 #define __FUNCT__ "SNESLineSearchNoNorms" 384 385 /*@C 386 SNESLineSearchNoNorms - This routine is not a line search at 387 all; it simply uses the full Newton step. This version does not 388 even compute the norm of the function or search direction; this 389 is intended only when you know the full step is fine and are 390 not checking for convergence of the nonlinear iteration (for 391 example, you are running always for a fixed number of Newton steps). 392 393 Collective on SNES and Vec 394 395 Input Parameters: 396 + snes - nonlinear context 397 . lsctx - optional context for line search (not used here) 398 . x - current iterate 399 . f - residual evaluated at x 400 . y - search direction 401 . w - work vector 402 - fnorm - 2-norm of f 403 404 Output Parameters: 405 + g - residual evaluated at new iterate y 406 . w - new iterate 407 . gnorm - not changed 408 . ynorm - not changed 409 - flag - set to PETSC_TRUE indicating a successful line search 410 411 Options Database Key: 412 . -snes_ls basicnonorms - Activates SNESLineSearchNoNorms() 413 414 Notes: 415 SNESLineSearchNoNorms() must be used in conjunction with 416 either the options 417 $ -snes_no_convergence_test -snes_max_it <its> 418 or alternatively a user-defined custom test set via 419 SNESSetConvergenceTest(); or a -snes_max_it of 1, 420 otherwise, the SNES solver will generate an error. 421 422 During the final iteration this will not evaluate the function at 423 the solution point. This is to save a function evaluation while 424 using pseudo-timestepping. 425 426 The residual norms printed by monitoring routines such as 427 SNESMonitorDefault() (as activated via -snes_monitor) will not be 428 correct, since they are not computed. 429 430 Level: advanced 431 432 .keywords: SNES, nonlinear, line search, cubic 433 434 .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(), 435 SNESLineSearchSet(), SNESLineSearchNo() 436 @*/ 437 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchNoNorms(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag) 438 { 439 PetscErrorCode ierr; 440 SNES_LS *neP = (SNES_LS*)snes->data; 441 PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE; 442 443 PetscFunctionBegin; 444 *flag = PETSC_TRUE; 445 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 446 ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr); /* w <- x - y */ 447 if (neP->postcheckstep) { 448 ierr = (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);CHKERRQ(ierr); 449 } 450 if (changed_y) { 451 ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr); /* w <- x - y */ 452 } 453 454 /* don't evaluate function the last time through */ 455 if (snes->iter < snes->max_its-1) { 456 ierr = SNESComputeFunction(snes,w,g); 457 if (PetscExceptionValue(ierr)) { 458 PetscErrorCode pierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr); 459 } 460 CHKERRQ(ierr); 461 } 462 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 463 PetscFunctionReturn(0); 464 } 465 /* -------------------------------------------------------------------------- */ 466 #undef __FUNCT__ 467 #define __FUNCT__ "SNESLineSearchCubic" 468 /*@C 469 SNESLineSearchCubic - Performs a cubic line search (default line search method). 470 471 Collective on SNES 472 473 Input Parameters: 474 + snes - nonlinear context 475 . lsctx - optional context for line search (not used here) 476 . x - current iterate 477 . f - residual evaluated at x 478 . y - search direction 479 . w - work vector 480 - fnorm - 2-norm of f 481 482 Output Parameters: 483 + g - residual evaluated at new iterate y 484 . w - new iterate 485 . gnorm - 2-norm of g 486 . ynorm - 2-norm of search length 487 - flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure. 488 489 Options Database Key: 490 $ -snes_ls cubic - Activates SNESLineSearchCubic() 491 492 Notes: 493 This line search is taken from "Numerical Methods for Unconstrained 494 Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 495 496 Level: advanced 497 498 .keywords: SNES, nonlinear, line search, cubic 499 500 .seealso: SNESLineSearchQuadratic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms() 501 @*/ 502 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchCubic(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag) 503 { 504 /* 505 Note that for line search purposes we work with with the related 506 minimization problem: 507 min z(x): R^n -> R, 508 where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2. 509 */ 510 511 PetscReal steptol,initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength; 512 PetscReal maxstep,minlambda,alpha,lambda,lambdatemp; 513 #if defined(PETSC_USE_COMPLEX) 514 PetscScalar cinitslope,clambda; 515 #endif 516 PetscErrorCode ierr; 517 PetscInt count; 518 SNES_LS *neP = (SNES_LS*)snes->data; 519 PetscScalar scale; 520 PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE; 521 522 PetscFunctionBegin; 523 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 524 *flag = PETSC_TRUE; 525 alpha = neP->alpha; 526 maxstep = neP->maxstep; 527 steptol = neP->steptol; 528 529 ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr); 530 if (!*ynorm) { 531 ierr = PetscInfo(snes,"Search direction and size is 0\n");CHKERRQ(ierr); 532 *gnorm = fnorm; 533 ierr = VecCopy(x,w);CHKERRQ(ierr); 534 ierr = VecCopy(f,g);CHKERRQ(ierr); 535 *flag = PETSC_FALSE; 536 goto theend1; 537 } 538 if (*ynorm > maxstep) { /* Step too big, so scale back */ 539 scale = maxstep/(*ynorm); 540 ierr = PetscInfo2(snes,"Scaling step by %G old ynorm %G\n",PetscRealPart(scale),*ynorm);CHKERRQ(ierr); 541 ierr = VecScale(y,scale);CHKERRQ(ierr); 542 *ynorm = maxstep; 543 } 544 ierr = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr); 545 minlambda = steptol/rellength; 546 ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr); 547 #if defined(PETSC_USE_COMPLEX) 548 ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr); 549 initslope = PetscRealPart(cinitslope); 550 #else 551 ierr = VecDot(f,w,&initslope);CHKERRQ(ierr); 552 #endif 553 if (initslope > 0.0) initslope = -initslope; 554 if (initslope == 0.0) initslope = -1.0; 555 556 ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr); 557 if (snes->nfuncs >= snes->max_funcs) { 558 ierr = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr); 559 *flag = PETSC_FALSE; 560 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 561 goto theend1; 562 } 563 ierr = SNESComputeFunction(snes,w,g); 564 if (PetscExceptionValue(ierr)) { 565 PetscErrorCode pierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr); 566 } 567 CHKERRQ(ierr); 568 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 569 if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 570 if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */ 571 ierr = PetscInfo(snes,"Using full step\n");CHKERRQ(ierr); 572 goto theend1; 573 } 574 575 /* Fit points with quadratic */ 576 lambda = 1.0; 577 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 578 lambdaprev = lambda; 579 gnormprev = *gnorm; 580 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 581 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 582 else lambda = lambdatemp; 583 584 #if defined(PETSC_USE_COMPLEX) 585 clambda = lambda; ierr = VecWAXPY(w,-clambda,y,x);CHKERRQ(ierr); 586 #else 587 ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr); 588 #endif 589 if (snes->nfuncs >= snes->max_funcs) { 590 ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr); 591 *flag = PETSC_FALSE; 592 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 593 goto theend1; 594 } 595 ierr = SNESComputeFunction(snes,w,g); 596 if (PetscExceptionValue(ierr)) { 597 PetscErrorCode pierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr); 598 } 599 CHKERRQ(ierr); 600 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 601 if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 602 if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */ 603 ierr = PetscInfo1(snes,"Quadratically determined step, lambda=%18.16e\n",lambda);CHKERRQ(ierr); 604 goto theend1; 605 } 606 607 /* Fit points with cubic */ 608 count = 1; 609 while (count < 10000) { 610 if (lambda <= minlambda) { /* bad luck; use full step */ 611 ierr = PetscInfo1(snes,"Unable to find good step length! %D \n",count);CHKERRQ(ierr); 612 ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr); 613 *flag = PETSC_FALSE; 614 break; 615 } 616 t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope; 617 t2 = .5*(gnormprev*gnormprev - fnorm*fnorm) - lambdaprev*initslope; 618 a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 619 b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 620 d = b*b - 3*a*initslope; 621 if (d < 0.0) d = 0.0; 622 if (a == 0.0) { 623 lambdatemp = -initslope/(2.0*b); 624 } else { 625 lambdatemp = (-b + sqrt(d))/(3.0*a); 626 } 627 lambdaprev = lambda; 628 gnormprev = *gnorm; 629 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 630 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 631 else lambda = lambdatemp; 632 #if defined(PETSC_USE_COMPLEX) 633 clambda = lambda; 634 ierr = VecWAXPY(w,-clambda,y,x);CHKERRQ(ierr); 635 #else 636 ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr); 637 #endif 638 if (snes->nfuncs >= snes->max_funcs) { 639 ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr); 640 ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr); 641 *flag = PETSC_FALSE; 642 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 643 break; 644 } 645 ierr = SNESComputeFunction(snes,w,g); 646 if (PetscExceptionValue(ierr)) { 647 PetscErrorCode pierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr); 648 } 649 CHKERRQ(ierr); 650 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 651 if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 652 if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* is reduction enough? */ 653 ierr = PetscInfo1(snes,"Cubically determined step, lambda=%18.16e\n",lambda);CHKERRQ(ierr); 654 break; 655 } else { 656 ierr = PetscInfo1(snes,"Cubic step no good, shrinking lambda, lambda=%18.16e\n",lambda);CHKERRQ(ierr); 657 } 658 count++; 659 } 660 if (count >= 10000) { 661 SETERRQ(PETSC_ERR_LIB, "Lambda was decreased more than 10,000 times, so something is probably wrong with the function evaluation"); 662 } 663 theend1: 664 /* Optional user-defined check for line search step validity */ 665 if (neP->postcheckstep && *flag) { 666 ierr = (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);CHKERRQ(ierr); 667 if (changed_y) { 668 ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr); 669 } 670 if (changed_y || changed_w) { /* recompute the function if the step has changed */ 671 ierr = SNESComputeFunction(snes,w,g); 672 if (PetscExceptionValue(ierr)) { 673 PetscErrorCode pierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr); 674 } 675 CHKERRQ(ierr); 676 ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr); 677 if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 678 ierr = VecNormBegin(w,NORM_2,ynorm);CHKERRQ(ierr); 679 ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr); 680 ierr = VecNormEnd(w,NORM_2,ynorm);CHKERRQ(ierr); 681 } 682 } 683 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 684 PetscFunctionReturn(0); 685 } 686 /* -------------------------------------------------------------------------- */ 687 #undef __FUNCT__ 688 #define __FUNCT__ "SNESLineSearchQuadratic" 689 /*@C 690 SNESLineSearchQuadratic - Performs a quadratic line search. 691 692 Collective on SNES and Vec 693 694 Input Parameters: 695 + snes - the SNES context 696 . lsctx - optional context for line search (not used here) 697 . x - current iterate 698 . f - residual evaluated at x 699 . y - search direction 700 . w - work vector 701 - fnorm - 2-norm of f 702 703 Output Parameters: 704 + g - residual evaluated at new iterate w 705 . w - new iterate (x + alpha*y) 706 . gnorm - 2-norm of g 707 . ynorm - 2-norm of search length 708 - flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure. 709 710 Options Database Key: 711 . -snes_ls quadratic - Activates SNESLineSearchQuadratic() 712 713 Notes: 714 Use SNESLineSearchSet() to set this routine within the SNESLS method. 715 716 Level: advanced 717 718 .keywords: SNES, nonlinear, quadratic, line search 719 720 .seealso: SNESLineSearchCubic(), SNESLineSearchNo(), SNESLineSearchSet(), SNESLineSearchNoNorms() 721 @*/ 722 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchQuadratic(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag) 723 { 724 /* 725 Note that for line search purposes we work with with the related 726 minimization problem: 727 min z(x): R^n -> R, 728 where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2. 729 */ 730 PetscReal steptol,initslope,maxstep,minlambda,alpha,lambda,lambdatemp,rellength; 731 #if defined(PETSC_USE_COMPLEX) 732 PetscScalar cinitslope,clambda; 733 #endif 734 PetscErrorCode ierr; 735 PetscInt count; 736 SNES_LS *neP = (SNES_LS*)snes->data; 737 PetscScalar scale; 738 PetscTruth changed_w = PETSC_FALSE,changed_y = PETSC_FALSE; 739 740 PetscFunctionBegin; 741 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 742 *flag = PETSC_TRUE; 743 alpha = neP->alpha; 744 maxstep = neP->maxstep; 745 steptol = neP->steptol; 746 747 ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr); 748 if (*ynorm == 0.0) { 749 ierr = PetscInfo(snes,"Search direction and size is 0\n");CHKERRQ(ierr); 750 *gnorm = fnorm; 751 ierr = VecCopy(x,w);CHKERRQ(ierr); 752 ierr = VecCopy(f,g);CHKERRQ(ierr); 753 *flag = PETSC_FALSE; 754 goto theend2; 755 } 756 if (*ynorm > maxstep) { /* Step too big, so scale back */ 757 scale = maxstep/(*ynorm); 758 ierr = VecScale(y,scale);CHKERRQ(ierr); 759 *ynorm = maxstep; 760 } 761 ierr = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr); 762 minlambda = steptol/rellength; 763 ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr); 764 #if defined(PETSC_USE_COMPLEX) 765 ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr); 766 initslope = PetscRealPart(cinitslope); 767 #else 768 ierr = VecDot(f,w,&initslope);CHKERRQ(ierr); 769 #endif 770 if (initslope > 0.0) initslope = -initslope; 771 if (initslope == 0.0) initslope = -1.0; 772 773 ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr); 774 if (snes->nfuncs >= snes->max_funcs) { 775 ierr = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr); 776 *flag = PETSC_FALSE; 777 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 778 goto theend2; 779 } 780 ierr = SNESComputeFunction(snes,w,g); 781 if (PetscExceptionValue(ierr)) { 782 PetscErrorCode pierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr); 783 } 784 CHKERRQ(ierr); 785 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 786 if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 787 if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */ 788 ierr = PetscInfo(snes,"Using full step\n");CHKERRQ(ierr); 789 goto theend2; 790 } 791 792 /* Fit points with quadratic */ 793 lambda = 1.0; 794 count = 1; 795 while (PETSC_TRUE) { 796 if (lambda <= minlambda) { /* bad luck; use full step */ 797 ierr = PetscInfo1(snes,"Unable to find good step length! %D \n",count);CHKERRQ(ierr); 798 ierr = PetscInfo5(snes,"fnorm=%G, gnorm=%G, ynorm=%G, lambda=%G, initial slope=%G\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr); 799 ierr = VecCopy(x,w);CHKERRQ(ierr); 800 *flag = PETSC_FALSE; 801 break; 802 } 803 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 804 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 805 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 806 else lambda = lambdatemp; 807 808 #if defined(PETSC_USE_COMPLEX) 809 clambda = lambda; ierr = VecWAXPY(w,-clambda,y,x);CHKERRQ(ierr); 810 #else 811 ierr = VecWAXPY(w,-lambda,y,x);CHKERRQ(ierr); 812 #endif 813 if (snes->nfuncs >= snes->max_funcs) { 814 ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr); 815 ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope);CHKERRQ(ierr); 816 *flag = PETSC_FALSE; 817 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 818 break; 819 } 820 ierr = SNESComputeFunction(snes,w,g); 821 if (PetscExceptionValue(ierr)) { 822 PetscErrorCode pierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr); 823 } 824 CHKERRQ(ierr); 825 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 826 if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 827 if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */ 828 ierr = PetscInfo1(snes,"Quadratically determined step, lambda=%G\n",lambda);CHKERRQ(ierr); 829 break; 830 } 831 count++; 832 } 833 theend2: 834 /* Optional user-defined check for line search step validity */ 835 if (neP->postcheckstep) { 836 ierr = (*neP->postcheckstep)(snes,x,y,w,neP->postcheck,&changed_y,&changed_w);CHKERRQ(ierr); 837 if (changed_y) { 838 ierr = VecWAXPY(w,-1.0,y,x);CHKERRQ(ierr); 839 } 840 if (changed_y || changed_w) { /* recompute the function if the step has changed */ 841 ierr = SNESComputeFunction(snes,w,g); 842 if (PetscExceptionValue(ierr)) { 843 PetscErrorCode pierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(pierr); 844 } 845 CHKERRQ(ierr); 846 ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr); 847 ierr = VecNormBegin(w,NORM_2,ynorm);CHKERRQ(ierr); 848 ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr); 849 ierr = VecNormEnd(w,NORM_2,ynorm);CHKERRQ(ierr); 850 if (*gnorm != *gnorm) SETERRQ(PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 851 } 852 } 853 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 854 PetscFunctionReturn(0); 855 } 856 857 /* -------------------------------------------------------------------------- */ 858 #undef __FUNCT__ 859 #define __FUNCT__ "SNESLineSearchSet" 860 /*@C 861 SNESLineSearchSet - Sets the line search routine to be used 862 by the method SNESLS. 863 864 Input Parameters: 865 + snes - nonlinear context obtained from SNESCreate() 866 . lsctx - optional user-defined context for use by line search 867 - func - pointer to int function 868 869 Collective on SNES 870 871 Available Routines: 872 + SNESLineSearchCubic() - default line search 873 . SNESLineSearchQuadratic() - quadratic line search 874 . SNESLineSearchNo() - the full Newton step (actually not a line search) 875 - SNESLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel) 876 877 Options Database Keys: 878 + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search 879 . -snes_ls_alpha <alpha> - Sets alpha 880 . -snes_ls_maxstep <max> - Sets maxstep 881 - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code 882 will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length 883 the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x) 884 885 Calling sequence of func: 886 .vb 887 func (SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w, 888 PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag) 889 .ve 890 891 Input parameters for func: 892 + snes - nonlinear context 893 . lsctx - optional user-defined context for line search 894 . x - current iterate 895 . f - residual evaluated at x 896 . y - search direction 897 . w - work vector 898 - fnorm - 2-norm of f 899 900 Output parameters for func: 901 + g - residual evaluated at new iterate y 902 . w - new iterate 903 . gnorm - 2-norm of g 904 . ynorm - 2-norm of search length 905 - flag - set to PETSC_TRUE if the line search succeeds; PETSC_FALSE on failure. 906 907 Level: advanced 908 909 .keywords: SNES, nonlinear, set, line search, routine 910 911 .seealso: SNESLineSearchCubic(), SNESLineSearchQuadratic(), SNESLineSearchNo(), SNESLineSearchNoNorms(), 912 SNESLineSearchSetPostCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams(), SNESLineSearchSetPreCheck() 913 @*/ 914 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSet(SNES snes,PetscErrorCode (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void *lsctx) 915 { 916 PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void*); 917 918 PetscFunctionBegin; 919 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSet_C",(void (**)(void))&f);CHKERRQ(ierr); 920 if (f) { 921 ierr = (*f)(snes,func,lsctx);CHKERRQ(ierr); 922 } 923 PetscFunctionReturn(0); 924 } 925 926 typedef PetscErrorCode (*FCN2)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*); /* force argument to next function to not be extern C*/ 927 /* -------------------------------------------------------------------------- */ 928 EXTERN_C_BEGIN 929 #undef __FUNCT__ 930 #define __FUNCT__ "SNESLineSearchSet_LS" 931 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSet_LS(SNES snes,FCN2 func,void *lsctx) 932 { 933 PetscFunctionBegin; 934 ((SNES_LS *)(snes->data))->LineSearch = func; 935 ((SNES_LS *)(snes->data))->lsP = lsctx; 936 PetscFunctionReturn(0); 937 } 938 EXTERN_C_END 939 /* -------------------------------------------------------------------------- */ 940 #undef __FUNCT__ 941 #define __FUNCT__ "SNESLineSearchSetPostCheck" 942 /*@C 943 SNESLineSearchSetPostCheck - Sets a routine to check the validity of new iterate computed 944 by the line search routine in the Newton-based method SNESLS. 945 946 Input Parameters: 947 + snes - nonlinear context obtained from SNESCreate() 948 . func - pointer to function 949 - checkctx - optional user-defined context for use by step checking routine 950 951 Collective on SNES 952 953 Calling sequence of func: 954 .vb 955 int func (SNES snes, Vec x,Vec y,Vec w,void *checkctx, PetscTruth *changed_y,PetscTruth *changed_w) 956 .ve 957 where func returns an error code of 0 on success and a nonzero 958 on failure. 959 960 Input parameters for func: 961 + snes - nonlinear context 962 . checkctx - optional user-defined context for use by step checking routine 963 . x - previous iterate 964 . y - new search direction and length 965 - w - current candidate iterate 966 967 Output parameters for func: 968 + y - search direction (possibly changed) 969 . w - current iterate (possibly modified) 970 . changed_y - indicates search direction was changed by this routine 971 - changed_w - indicates current iterate was changed by this routine 972 973 Level: advanced 974 975 Notes: All line searches accept the new iterate computed by the line search checking routine. 976 977 Only one of changed_y and changed_w can be PETSC_TRUE 978 979 On input w = x + y 980 981 SNESLineSearchNo() and SNESLineSearchNoNorms() (1) compute a candidate iterate u_{i+1}, (2) pass control 982 to the checking routine, and then (3) compute the corresponding nonlinear 983 function f(u_{i+1}) with the (possibly altered) iterate u_{i+1}. 984 985 SNESLineSearchQuadratic() and SNESLineSearchCubic() (1) compute a candidate iterate u_{i+1} as well as a 986 candidate nonlinear function f(u_{i+1}), (2) pass control to the checking 987 routine, and then (3) force a re-evaluation of f(u_{i+1}) if any changes 988 were made to the candidate iterate in the checking routine (as indicated 989 by flag=PETSC_TRUE). The overhead of this extra function re-evaluation can be 990 very costly, so use this feature with caution! 991 992 .keywords: SNES, nonlinear, set, line search check, step check, routine 993 994 .seealso: SNESLineSearchSet(), SNESLineSearchSetPreCheck() 995 @*/ 996 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSetPostCheck(SNES snes,PetscErrorCode (*func)(SNES,Vec,Vec,Vec,void*,PetscTruth*,PetscTruth*),void *checkctx) 997 { 998 PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,Vec,Vec,Vec,void*,PetscTruth*,PetscTruth*),void*); 999 1000 PetscFunctionBegin; 1001 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSetPostCheck_C",(void (**)(void))&f);CHKERRQ(ierr); 1002 if (f) { 1003 ierr = (*f)(snes,func,checkctx);CHKERRQ(ierr); 1004 } 1005 PetscFunctionReturn(0); 1006 } 1007 #undef __FUNCT__ 1008 #define __FUNCT__ "SNESLineSearchSetPreCheck" 1009 /*@C 1010 SNESLineSearchSetPreCheck - Sets a routine to check the validity of a new direction given by the linear solve 1011 before the line search is called. 1012 1013 Input Parameters: 1014 + snes - nonlinear context obtained from SNESCreate() 1015 . func - pointer to function 1016 - checkctx - optional user-defined context for use by step checking routine 1017 1018 Collective on SNES 1019 1020 Calling sequence of func: 1021 .vb 1022 int func (SNES snes, Vec x,Vec y,void *checkctx, PetscTruth *changed_y) 1023 .ve 1024 where func returns an error code of 0 on success and a nonzero 1025 on failure. 1026 1027 Input parameters for func: 1028 + snes - nonlinear context 1029 . checkctx - optional user-defined context for use by step checking routine 1030 . x - previous iterate 1031 - y - new search direction and length 1032 1033 Output parameters for func: 1034 + y - search direction (possibly changed) 1035 - changed_y - indicates search direction was changed by this routine 1036 1037 Level: advanced 1038 1039 Notes: All line searches accept the new iterate computed by the line search checking routine. 1040 1041 .keywords: SNES, nonlinear, set, line search check, step check, routine 1042 1043 .seealso: SNESLineSearchSet(), SNESLineSearchSetPostCheck(), SNESSetUpdate() 1044 @*/ 1045 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSetPreCheck(SNES snes,PetscErrorCode (*func)(SNES,Vec,Vec,void*,PetscTruth*),void *checkctx) 1046 { 1047 PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,Vec,Vec,void*,PetscTruth*),void*); 1048 1049 PetscFunctionBegin; 1050 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchSetPreCheck_C",(void (**)(void))&f);CHKERRQ(ierr); 1051 if (f) { 1052 ierr = (*f)(snes,func,checkctx);CHKERRQ(ierr); 1053 } 1054 PetscFunctionReturn(0); 1055 } 1056 1057 /* -------------------------------------------------------------------------- */ 1058 typedef PetscErrorCode (*FCN1)(SNES,Vec,Vec,Vec,void*,PetscTruth*,PetscTruth*); /* force argument to next function to not be extern C*/ 1059 typedef PetscErrorCode (*FCN3)(SNES,Vec,Vec,void*,PetscTruth*); /* force argument to next function to not be extern C*/ 1060 EXTERN_C_BEGIN 1061 #undef __FUNCT__ 1062 #define __FUNCT__ "SNESLineSearchSetPostCheck_LS" 1063 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSetPostCheck_LS(SNES snes,FCN1 func,void *checkctx) 1064 { 1065 PetscFunctionBegin; 1066 ((SNES_LS *)(snes->data))->postcheckstep = func; 1067 ((SNES_LS *)(snes->data))->postcheck = checkctx; 1068 PetscFunctionReturn(0); 1069 } 1070 EXTERN_C_END 1071 1072 EXTERN_C_BEGIN 1073 #undef __FUNCT__ 1074 #define __FUNCT__ "SNESLineSearchSetPreCheck_LS" 1075 PetscErrorCode PETSCSNES_DLLEXPORT SNESLineSearchSetPreCheck_LS(SNES snes,FCN3 func,void *checkctx) 1076 { 1077 PetscFunctionBegin; 1078 ((SNES_LS *)(snes->data))->precheckstep = func; 1079 ((SNES_LS *)(snes->data))->precheck = checkctx; 1080 PetscFunctionReturn(0); 1081 } 1082 EXTERN_C_END 1083 1084 /* 1085 SNESView_LS - Prints info from the SNESLS data structure. 1086 1087 Input Parameters: 1088 . SNES - the SNES context 1089 . viewer - visualization context 1090 1091 Application Interface Routine: SNESView() 1092 */ 1093 #undef __FUNCT__ 1094 #define __FUNCT__ "SNESView_LS" 1095 static PetscErrorCode SNESView_LS(SNES snes,PetscViewer viewer) 1096 { 1097 SNES_LS *ls = (SNES_LS *)snes->data; 1098 const char *cstr; 1099 PetscErrorCode ierr; 1100 PetscTruth iascii; 1101 1102 PetscFunctionBegin; 1103 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr); 1104 if (iascii) { 1105 if (ls->LineSearch == SNESLineSearchNo) cstr = "SNESLineSearchNo"; 1106 else if (ls->LineSearch == SNESLineSearchQuadratic) cstr = "SNESLineSearchQuadratic"; 1107 else if (ls->LineSearch == SNESLineSearchCubic) cstr = "SNESLineSearchCubic"; 1108 else cstr = "unknown"; 1109 ierr = PetscViewerASCIIPrintf(viewer," line search variant: %s\n",cstr);CHKERRQ(ierr); 1110 ierr = PetscViewerASCIIPrintf(viewer," alpha=%G, maxstep=%G, steptol=%G\n",ls->alpha,ls->maxstep,ls->steptol);CHKERRQ(ierr); 1111 } else { 1112 SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ LS",((PetscObject)viewer)->type_name); 1113 } 1114 PetscFunctionReturn(0); 1115 } 1116 /* -------------------------------------------------------------------------- */ 1117 /* 1118 SNESSetFromOptions_LS - Sets various parameters for the SNESLS method. 1119 1120 Input Parameter: 1121 . snes - the SNES context 1122 1123 Application Interface Routine: SNESSetFromOptions() 1124 */ 1125 #undef __FUNCT__ 1126 #define __FUNCT__ "SNESSetFromOptions_LS" 1127 static PetscErrorCode SNESSetFromOptions_LS(SNES snes) 1128 { 1129 SNES_LS *ls = (SNES_LS *)snes->data; 1130 const char *lses[] = {"basic","basicnonorms","quadratic","cubic"}; 1131 PetscErrorCode ierr; 1132 PetscInt indx; 1133 PetscTruth flg; 1134 1135 PetscFunctionBegin; 1136 ierr = PetscOptionsHead("SNES Line search options");CHKERRQ(ierr); 1137 ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);CHKERRQ(ierr); 1138 ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);CHKERRQ(ierr); 1139 ierr = PetscOptionsReal("-snes_ls_steptol","Step must be greater than","None",ls->steptol,&ls->steptol,0);CHKERRQ(ierr); 1140 1141 ierr = PetscOptionsEList("-snes_ls","Line search used","SNESLineSearchSet",lses,4,"cubic",&indx,&flg);CHKERRQ(ierr); 1142 if (flg) { 1143 switch (indx) { 1144 case 0: 1145 ierr = SNESLineSearchSet(snes,SNESLineSearchNo,PETSC_NULL);CHKERRQ(ierr); 1146 break; 1147 case 1: 1148 ierr = SNESLineSearchSet(snes,SNESLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr); 1149 break; 1150 case 2: 1151 ierr = SNESLineSearchSet(snes,SNESLineSearchQuadratic,PETSC_NULL);CHKERRQ(ierr); 1152 break; 1153 case 3: 1154 ierr = SNESLineSearchSet(snes,SNESLineSearchCubic,PETSC_NULL);CHKERRQ(ierr); 1155 break; 1156 } 1157 } 1158 ierr = PetscOptionsTail();CHKERRQ(ierr); 1159 PetscFunctionReturn(0); 1160 } 1161 /* -------------------------------------------------------------------------- */ 1162 #undef __FUNCT__ 1163 #define __FUNCT__ "SNESConverged_LS" 1164 /*@C 1165 SNESConverged_LS - Monitors the convergence of the line search 1166 method SNESLS for solving systems of nonlinear equations (default). 1167 1168 Collective on SNES 1169 1170 Input Parameters: 1171 + snes - the SNES context 1172 . it - the iteration (0 indicates before any Newton steps) 1173 . xnorm - 2-norm of current iterate 1174 . pnorm - 2-norm of current step 1175 . fnorm - 2-norm of function at current iterate 1176 - dummy - unused context 1177 1178 Output Parameter: 1179 . reason - one of 1180 $ SNES_CONVERGED_FNORM_ABS - (fnorm < abstol), 1181 $ SNES_CONVERGED_PNORM_RELATIVE - (pnorm < xtol*xnorm), 1182 $ SNES_CONVERGED_FNORM_RELATIVE - (fnorm < rtol*fnorm0), 1183 $ SNES_DIVERGED_FUNCTION_COUNT - (nfct > maxf), 1184 $ SNES_DIVERGED_FNORM_NAN - (fnorm == NaN), 1185 $ SNES_CONVERGED_ITERATING - (otherwise), 1186 1187 where 1188 + maxf - maximum number of function evaluations, 1189 set with SNESSetTolerances() 1190 . nfct - number of function evaluations, 1191 . abstol - absolute function norm tolerance, 1192 set with SNESSetTolerances() 1193 - rtol - relative function norm tolerance, set with SNESSetTolerances() 1194 1195 Level: intermediate 1196 1197 .keywords: SNES, nonlinear, default, converged, convergence 1198 1199 .seealso: SNESSetConvergenceTest() 1200 @*/ 1201 PetscErrorCode PETSCSNES_DLLEXPORT SNESConverged_LS(SNES snes,PetscInt it,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy) 1202 { 1203 PetscErrorCode ierr; 1204 PetscFunctionBegin; 1205 PetscValidHeaderSpecific(snes,SNES_COOKIE,1); 1206 PetscValidType(snes,1); 1207 PetscValidPointer(reason,6); 1208 ierr = SNESDefaultConverged(snes,it,xnorm,pnorm,fnorm,reason,dummy);CHKERRQ(ierr); 1209 PetscFunctionReturn(0); 1210 } 1211 /* -------------------------------------------------------------------------- */ 1212 /*MC 1213 SNESLS - Newton based nonlinear solver that uses a line search 1214 1215 Options Database: 1216 + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search 1217 . -snes_ls_alpha <alpha> - Sets alpha 1218 . -snes_ls_maxstep <max> - Sets maxstep 1219 - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code 1220 will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length 1221 the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x) 1222 1223 Notes: This is the default nonlinear solver in SNES 1224 1225 Level: beginner 1226 1227 .seealso: SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(), 1228 SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(), 1229 SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck() 1230 1231 M*/ 1232 EXTERN_C_BEGIN 1233 #undef __FUNCT__ 1234 #define __FUNCT__ "SNESCreate_LS" 1235 PetscErrorCode PETSCSNES_DLLEXPORT SNESCreate_LS(SNES snes) 1236 { 1237 PetscErrorCode ierr; 1238 SNES_LS *neP; 1239 1240 PetscFunctionBegin; 1241 snes->ops->setup = SNESSetUp_LS; 1242 snes->ops->solve = SNESSolve_LS; 1243 snes->ops->destroy = SNESDestroy_LS; 1244 snes->ops->converged = SNESConverged_LS; 1245 snes->ops->setfromoptions = SNESSetFromOptions_LS; 1246 snes->ops->view = SNESView_LS; 1247 snes->nwork = 0; 1248 1249 ierr = PetscNew(SNES_LS,&neP);CHKERRQ(ierr); 1250 ierr = PetscLogObjectMemory(snes,sizeof(SNES_LS));CHKERRQ(ierr); 1251 snes->data = (void*)neP; 1252 neP->alpha = 1.e-4; 1253 neP->maxstep = 1.e8; 1254 neP->steptol = 1.e-12; 1255 neP->LineSearch = SNESLineSearchCubic; 1256 neP->lsP = PETSC_NULL; 1257 neP->postcheckstep = PETSC_NULL; 1258 neP->postcheck = PETSC_NULL; 1259 neP->precheckstep = PETSC_NULL; 1260 neP->precheck = PETSC_NULL; 1261 1262 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSet_C", 1263 "SNESLineSearchSet_LS", 1264 SNESLineSearchSet_LS);CHKERRQ(ierr); 1265 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPostCheck_C", 1266 "SNESLineSearchSetPostCheck_LS", 1267 SNESLineSearchSetPostCheck_LS);CHKERRQ(ierr); 1268 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchSetPreCheck_C", 1269 "SNESLineSearchSetPreCheck_LS", 1270 SNESLineSearchSetPreCheck_LS);CHKERRQ(ierr); 1271 1272 PetscFunctionReturn(0); 1273 } 1274 EXTERN_C_END 1275 1276 1277 1278