1 2 #include "src/snes/impls/ls/ls.h" 3 4 /* 5 Checks if J^T F = 0 which implies we've found a local minimum of the function, 6 but not a zero. In the case when one cannot compute J^T F we use the fact that 7 0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More 8 for this trick. 9 */ 10 #undef __FUNCT__ 11 #define __FUNCT__ "SNESLSCheckLocalMin_Private" 12 PetscErrorCode SNESLSCheckLocalMin_Private(Mat A,Vec F,Vec W,PetscReal fnorm,PetscTruth *ismin) 13 { 14 PetscReal a1; 15 PetscErrorCode ierr; 16 PetscTruth hastranspose; 17 18 PetscFunctionBegin; 19 *ismin = PETSC_FALSE; 20 ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr); 21 if (hastranspose) { 22 /* Compute || J^T F|| */ 23 ierr = MatMultTranspose(A,F,W);CHKERRQ(ierr); 24 ierr = VecNorm(W,NORM_2,&a1);CHKERRQ(ierr); 25 PetscLogInfo(0,"SNESSolve_LS: || J^T F|| %g near zero implies found a local minimum\n",a1/fnorm); 26 if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE; 27 } else { 28 Vec work; 29 PetscScalar result; 30 PetscReal wnorm; 31 32 ierr = VecSetRandom(PETSC_NULL,W);CHKERRQ(ierr); 33 ierr = VecNorm(W,NORM_2,&wnorm);CHKERRQ(ierr); 34 ierr = VecDuplicate(W,&work);CHKERRQ(ierr); 35 ierr = MatMult(A,W,work);CHKERRQ(ierr); 36 ierr = VecDot(F,work,&result);CHKERRQ(ierr); 37 ierr = VecDestroy(work);CHKERRQ(ierr); 38 a1 = PetscAbsScalar(result)/(fnorm*wnorm); 39 PetscLogInfo(0,"SNESSolve_LS: (F^T J random)/(|| F ||*||random|| %g near zero implies found a local minimum\n",a1); 40 if (a1 < 1.e-4) *ismin = PETSC_TRUE; 41 } 42 PetscFunctionReturn(0); 43 } 44 45 /* 46 Checks if J^T(F - J*X) = 0 47 */ 48 #undef __FUNCT__ 49 #define __FUNCT__ "SNESLSCheckResidual_Private" 50 PetscErrorCode SNESLSCheckResidual_Private(Mat A,Vec F,Vec X,Vec W1,Vec W2) 51 { 52 PetscReal a1,a2; 53 PetscErrorCode ierr; 54 PetscTruth hastranspose; 55 PetscScalar mone = -1.0; 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(&mone,F,W1);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 != 0) { 68 PetscLogInfo(0,"SNESSolve_LS: ||J^T(F-Ax)||/||F-AX|| %g near zero implies inconsistent rhs\n",a2/a1); 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 KSP ksp; 142 143 PetscFunctionBegin; 144 ierr = SNESGetKSP(snes,&ksp);CHKERRQ(ierr); 145 snes->reason = SNES_CONVERGED_ITERATING; 146 147 maxits = snes->max_its; /* maximum number of iterations */ 148 X = snes->vec_sol; /* solution vector */ 149 F = snes->vec_func; /* residual vector */ 150 Y = snes->work[0]; /* work vectors */ 151 G = snes->work[1]; 152 W = snes->work[2]; 153 154 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 155 snes->iter = 0; 156 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 157 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); /* F(X) */ 158 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 159 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 160 snes->norm = fnorm; 161 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 162 SNESLogConvHistory(snes,fnorm,0); 163 SNESMonitor(snes,0,fnorm); 164 165 if (fnorm < snes->abstol) {snes->reason = SNES_CONVERGED_FNORM_ABS; PetscFunctionReturn(0);} 166 167 /* set parameter for default relative tolerance convergence test */ 168 snes->ttol = fnorm*snes->rtol; 169 170 for (i=0; i<maxits; i++) { 171 172 /* Call general purpose update function */ 173 if (snes->update != PETSC_NULL) { 174 ierr = (*snes->update)(snes, snes->iter);CHKERRQ(ierr); 175 } 176 177 /* Solve J Y = F, where J is Jacobian matrix */ 178 ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 179 ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); 180 ierr = KSPSolve(snes->ksp,F,Y);CHKERRQ(ierr); 181 ierr = KSPGetIterationNumber(ksp,&lits);CHKERRQ(ierr); 182 183 if (PetscLogPrintInfo){ 184 ierr = SNESLSCheckResidual_Private(snes->jacobian,F,Y,G,W);CHKERRQ(ierr); 185 } 186 187 /* should check what happened to the linear solve? */ 188 snes->linear_its += lits; 189 PetscLogInfo(snes,"SNESSolve_LS: iter=%D, linear solve iterations=%D\n",snes->iter,lits); 190 191 /* Compute a (scaled) negative update in the line search routine: 192 Y <- X - lambda*Y 193 and evaluate G(Y) = function(Y)) 194 */ 195 ierr = VecCopy(Y,snes->vec_sol_update_always);CHKERRQ(ierr); 196 ierr = (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lssucceed);CHKERRQ(ierr); 197 PetscLogInfo(snes,"SNESSolve_LS: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",fnorm,gnorm,ynorm,(int)lssucceed); 198 199 TMP = F; F = G; snes->vec_func_always = F; G = TMP; 200 TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 201 fnorm = gnorm; 202 203 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 204 snes->iter = i+1; 205 snes->norm = fnorm; 206 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 207 SNESLogConvHistory(snes,fnorm,lits); 208 SNESMonitor(snes,i+1,fnorm); 209 210 if (!lssucceed) { 211 PetscTruth ismin; 212 213 if (++snes->numFailures >= snes->maxFailures) { 214 snes->reason = SNES_DIVERGED_LS_FAILURE; 215 ierr = SNESLSCheckLocalMin_Private(snes->jacobian,F,W,fnorm,&ismin);CHKERRQ(ierr); 216 if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; 217 break; 218 } 219 } 220 221 /* Test for convergence */ 222 if (snes->converged) { 223 ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); /* xnorm = || X || */ 224 ierr = (*snes->converged)(snes,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 225 if (snes->reason) { 226 break; 227 } 228 } 229 } 230 if (X != snes->vec_sol) { 231 ierr = VecCopy(X,snes->vec_sol);CHKERRQ(ierr); 232 } 233 if (F != snes->vec_func) { 234 ierr = VecCopy(F,snes->vec_func);CHKERRQ(ierr); 235 } 236 snes->vec_sol_always = snes->vec_sol; 237 snes->vec_func_always = snes->vec_func; 238 if (i == maxits) { 239 PetscLogInfo(snes,"SNESSolve_LS: Maximum number of iterations has been reached: %D\n",maxits); 240 snes->reason = SNES_DIVERGED_MAX_IT; 241 } 242 PetscFunctionReturn(0); 243 } 244 /* -------------------------------------------------------------------------- */ 245 /* 246 SNESSetUp_LS - Sets up the internal data structures for the later use 247 of the SNESLS nonlinear solver. 248 249 Input Parameter: 250 . snes - the SNES context 251 . x - the solution vector 252 253 Application Interface Routine: SNESSetUp() 254 255 Notes: 256 For basic use of the SNES solvers, the user need not explicitly call 257 SNESSetUp(), since these actions will automatically occur during 258 the call to SNESSolve(). 259 */ 260 #undef __FUNCT__ 261 #define __FUNCT__ "SNESSetUp_LS" 262 PetscErrorCode SNESSetUp_LS(SNES snes) 263 { 264 PetscErrorCode ierr; 265 266 PetscFunctionBegin; 267 snes->nwork = 4; 268 ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr); 269 PetscLogObjectParents(snes,snes->nwork,snes->work); 270 snes->vec_sol_update_always = snes->work[3]; 271 PetscFunctionReturn(0); 272 } 273 /* -------------------------------------------------------------------------- */ 274 /* 275 SNESDestroy_LS - Destroys the private SNES_LS context that was created 276 with SNESCreate_LS(). 277 278 Input Parameter: 279 . snes - the SNES context 280 281 Application Interface Routine: SNESDestroy() 282 */ 283 #undef __FUNCT__ 284 #define __FUNCT__ "SNESDestroy_LS" 285 PetscErrorCode SNESDestroy_LS(SNES snes) 286 { 287 PetscErrorCode ierr; 288 289 PetscFunctionBegin; 290 if (snes->nwork) { 291 ierr = VecDestroyVecs(snes->work,snes->nwork);CHKERRQ(ierr); 292 } 293 ierr = PetscFree(snes->data);CHKERRQ(ierr); 294 PetscFunctionReturn(0); 295 } 296 /* -------------------------------------------------------------------------- */ 297 #undef __FUNCT__ 298 #define __FUNCT__ "SNESNoLineSearch" 299 300 /*@C 301 SNESNoLineSearch - This routine is not a line search at all; 302 it simply uses the full Newton step. Thus, this routine is intended 303 to serve as a template and is not recommended for general use. 304 305 Collective on SNES and Vec 306 307 Input Parameters: 308 + snes - nonlinear context 309 . lsctx - optional context for line search (not used here) 310 . x - current iterate 311 . f - residual evaluated at x 312 . y - search direction (contains new iterate on output) 313 . w - work vector 314 - fnorm - 2-norm of f 315 316 Output Parameters: 317 + g - residual evaluated at new iterate y 318 . y - new iterate (contains search direction on input) 319 . gnorm - 2-norm of g 320 . ynorm - 2-norm of search length 321 - flag - PETSC_TRUE on success, PETSC_FALSE on failure 322 323 Options Database Key: 324 . -snes_ls basic - Activates SNESNoLineSearch() 325 326 Level: advanced 327 328 .keywords: SNES, nonlinear, line search, cubic 329 330 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 331 SNESSetLineSearch(), SNESNoLineSearchNoNorms() 332 @*/ 333 PetscErrorCode SNESNoLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag) 334 { 335 PetscErrorCode ierr; 336 PetscScalar mone = -1.0; 337 SNES_LS *neP = (SNES_LS*)snes->data; 338 PetscTruth change_y = PETSC_FALSE; 339 340 PetscFunctionBegin; 341 *flag = PETSC_TRUE; 342 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 343 ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr); /* ynorm = || y || */ 344 ierr = VecAYPX(&mone,x,y);CHKERRQ(ierr); /* y <- y - x */ 345 if (neP->CheckStep) { 346 ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr); 347 } 348 ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); /* Compute F(y) */ 349 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); /* gnorm = || g || */ 350 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 351 PetscFunctionReturn(0); 352 } 353 /* -------------------------------------------------------------------------- */ 354 #undef __FUNCT__ 355 #define __FUNCT__ "SNESNoLineSearchNoNorms" 356 357 /*@C 358 SNESNoLineSearchNoNorms - This routine is not a line search at 359 all; it simply uses the full Newton step. This version does not 360 even compute the norm of the function or search direction; this 361 is intended only when you know the full step is fine and are 362 not checking for convergence of the nonlinear iteration (for 363 example, you are running always for a fixed number of Newton steps). 364 365 Collective on SNES and Vec 366 367 Input Parameters: 368 + snes - nonlinear context 369 . lsctx - optional context for line search (not used here) 370 . x - current iterate 371 . f - residual evaluated at x 372 . y - search direction (contains new iterate on output) 373 . w - work vector 374 - fnorm - 2-norm of f 375 376 Output Parameters: 377 + g - residual evaluated at new iterate y 378 . gnorm - not changed 379 . ynorm - not changed 380 - flag - set to PETSC_TRUE indicating a successful line search 381 382 Options Database Key: 383 . -snes_ls basicnonorms - Activates SNESNoLineSearchNoNorms() 384 385 Notes: 386 SNESNoLineSearchNoNorms() must be used in conjunction with 387 either the options 388 $ -snes_no_convergence_test -snes_max_it <its> 389 or alternatively a user-defined custom test set via 390 SNESSetConvergenceTest(); or a -snes_max_it of 1, 391 otherwise, the SNES solver will generate an error. 392 393 During the final iteration this will not evaluate the function at 394 the solution point. This is to save a function evaluation while 395 using pseudo-timestepping. 396 397 The residual norms printed by monitoring routines such as 398 SNESDefaultMonitor() (as activated via -snes_monitor) will not be 399 correct, since they are not computed. 400 401 Level: advanced 402 403 .keywords: SNES, nonlinear, line search, cubic 404 405 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 406 SNESSetLineSearch(), SNESNoLineSearch() 407 @*/ 408 PetscErrorCode SNESNoLineSearchNoNorms(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag) 409 { 410 PetscErrorCode ierr; 411 PetscScalar mone = -1.0; 412 SNES_LS *neP = (SNES_LS*)snes->data; 413 PetscTruth change_y = PETSC_FALSE; 414 415 PetscFunctionBegin; 416 *flag = PETSC_TRUE; 417 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 418 ierr = VecAYPX(&mone,x,y);CHKERRQ(ierr); /* y <- y - x */ 419 if (neP->CheckStep) { 420 ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr); 421 } 422 423 /* don't evaluate function the last time through */ 424 if (snes->iter < snes->max_its-1) { 425 ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); /* Compute F(y) */ 426 } 427 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 428 PetscFunctionReturn(0); 429 } 430 /* -------------------------------------------------------------------------- */ 431 #undef __FUNCT__ 432 #define __FUNCT__ "SNESCubicLineSearch" 433 /*@C 434 SNESCubicLineSearch - Performs a cubic line search (default line search method). 435 436 Collective on SNES 437 438 Input Parameters: 439 + snes - nonlinear context 440 . lsctx - optional context for line search (not used here) 441 . x - current iterate 442 . f - residual evaluated at x 443 . y - search direction (contains new iterate on output) 444 . w - work vector 445 - fnorm - 2-norm of f 446 447 Output Parameters: 448 + g - residual evaluated at new iterate y 449 . y - new iterate (contains search direction on input) 450 . gnorm - 2-norm of g 451 . ynorm - 2-norm of search length 452 - flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure. 453 454 Options Database Key: 455 $ -snes_ls cubic - Activates SNESCubicLineSearch() 456 457 Notes: 458 This line search is taken from "Numerical Methods for Unconstrained 459 Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 460 461 Level: advanced 462 463 .keywords: SNES, nonlinear, line search, cubic 464 465 .seealso: SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms() 466 @*/ 467 PetscErrorCode SNESCubicLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag) 468 { 469 /* 470 Note that for line search purposes we work with with the related 471 minimization problem: 472 min z(x): R^n -> R, 473 where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2. 474 */ 475 476 PetscReal steptol,initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength; 477 PetscReal maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg; 478 #if defined(PETSC_USE_COMPLEX) 479 PetscScalar cinitslope,clambda; 480 #endif 481 PetscErrorCode ierr; 482 PetscInt count; 483 SNES_LS *neP = (SNES_LS*)snes->data; 484 PetscScalar mone = -1.0,scale; 485 PetscTruth change_y = PETSC_FALSE; 486 487 PetscFunctionBegin; 488 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 489 *flag = PETSC_TRUE; 490 alpha = neP->alpha; 491 maxstep = neP->maxstep; 492 steptol = neP->steptol; 493 494 ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr); 495 if (*ynorm == 0.0) { 496 PetscLogInfo(snes,"SNESCubicLineSearch: Search direction and size is 0\n"); 497 *gnorm = fnorm; 498 ierr = VecCopy(x,y);CHKERRQ(ierr); 499 ierr = VecCopy(f,g);CHKERRQ(ierr); 500 *flag = PETSC_FALSE; 501 goto theend1; 502 } 503 if (*ynorm > maxstep) { /* Step too big, so scale back */ 504 scale = maxstep/(*ynorm); 505 #if defined(PETSC_USE_COMPLEX) 506 PetscLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g old ynorm %g\n",PetscRealPart(scale),*ynorm); 507 #else 508 PetscLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g old ynorm %g\n",scale,*ynorm); 509 #endif 510 ierr = VecScale(&scale,y);CHKERRQ(ierr); 511 *ynorm = maxstep; 512 } 513 ierr = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr); 514 minlambda = steptol/rellength; 515 ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr); 516 #if defined(PETSC_USE_COMPLEX) 517 ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr); 518 initslope = PetscRealPart(cinitslope); 519 #else 520 ierr = VecDot(f,w,&initslope);CHKERRQ(ierr); 521 #endif 522 if (initslope > 0.0) initslope = -initslope; 523 if (initslope == 0.0) initslope = -1.0; 524 525 ierr = VecCopy(y,w);CHKERRQ(ierr); 526 ierr = VecAYPX(&mone,x,w);CHKERRQ(ierr); 527 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 528 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 529 if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */ 530 ierr = VecCopy(w,y);CHKERRQ(ierr); 531 PetscLogInfo(snes,"SNESCubicLineSearch: Using full step\n"); 532 goto theend1; 533 } 534 535 /* Fit points with quadratic */ 536 lambda = 1.0; 537 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 538 lambdaprev = lambda; 539 gnormprev = *gnorm; 540 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 541 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 542 else lambda = lambdatemp; 543 ierr = VecCopy(x,w);CHKERRQ(ierr); 544 lambdaneg = -lambda; 545 #if defined(PETSC_USE_COMPLEX) 546 clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr); 547 #else 548 ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr); 549 #endif 550 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 551 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 552 if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */ 553 ierr = VecCopy(w,y);CHKERRQ(ierr); 554 PetscLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%18.16e\n",lambda); 555 goto theend1; 556 } 557 558 /* Fit points with cubic */ 559 count = 1; 560 while (count < 10000) { 561 if (lambda <= minlambda) { /* bad luck; use full step */ 562 PetscLogInfo(snes,"SNESCubicLineSearch:Unable to find good step length! %D \n",count); 563 PetscLogInfo(snes,"SNESCubicLineSearch:fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n",fnorm,*gnorm,*ynorm,lambda,initslope); 564 ierr = VecCopy(x,y);CHKERRQ(ierr); 565 *flag = PETSC_FALSE; break; 566 } 567 t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope; 568 t2 = .5*(gnormprev*gnormprev - fnorm*fnorm) - lambdaprev*initslope; 569 a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 570 b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 571 d = b*b - 3*a*initslope; 572 if (d < 0.0) d = 0.0; 573 if (a == 0.0) { 574 lambdatemp = -initslope/(2.0*b); 575 } else { 576 lambdatemp = (-b + sqrt(d))/(3.0*a); 577 } 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 ierr = VecCopy(x,w);CHKERRQ(ierr); 584 lambdaneg = -lambda; 585 #if defined(PETSC_USE_COMPLEX) 586 clambda = lambdaneg; 587 ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr); 588 #else 589 ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr); 590 #endif 591 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 592 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 593 if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* is reduction enough? */ 594 ierr = VecCopy(w,y);CHKERRQ(ierr); 595 PetscLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%18.16e\n",lambda); 596 goto theend1; 597 } else { 598 PetscLogInfo(snes,"SNESCubicLineSearch: Cubic step no good, shrinking lambda, lambda=%18.16e\n",lambda); 599 } 600 count++; 601 } 602 if (count >= 10000) { 603 SETERRQ(PETSC_ERR_LIB, "Lambda was decreased more than 10,000 times, so something is probably wrong with the function evaluation"); 604 } 605 theend1: 606 /* Optional user-defined check for line search step validity */ 607 if (neP->CheckStep) { 608 ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr); 609 if (change_y == PETSC_TRUE) { /* recompute the function if the step has changed */ 610 ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); 611 ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr); 612 ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr); 613 ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr); 614 ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr); 615 } 616 } 617 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 618 PetscFunctionReturn(0); 619 } 620 /* -------------------------------------------------------------------------- */ 621 #undef __FUNCT__ 622 #define __FUNCT__ "SNESQuadraticLineSearch" 623 /*@C 624 SNESQuadraticLineSearch - Performs a quadratic line search. 625 626 Collective on SNES and Vec 627 628 Input Parameters: 629 + snes - the SNES context 630 . lsctx - optional context for line search (not used here) 631 . x - current iterate 632 . f - residual evaluated at x 633 . y - search direction (contains new iterate on output) 634 . w - work vector 635 - fnorm - 2-norm of f 636 637 Output Parameters: 638 + g - residual evaluated at new iterate y 639 . y - new iterate (contains search direction on input) 640 . gnorm - 2-norm of g 641 . ynorm - 2-norm of search length 642 - flag - PETSC_TRUE if line search succeeds; PETSC_FALSE on failure. 643 644 Options Database Key: 645 . -snes_ls quadratic - Activates SNESQuadraticLineSearch() 646 647 Notes: 648 Use SNESSetLineSearch() to set this routine within the SNESLS method. 649 650 Level: advanced 651 652 .keywords: SNES, nonlinear, quadratic, line search 653 654 .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms() 655 @*/ 656 PetscErrorCode SNESQuadraticLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag) 657 { 658 /* 659 Note that for line search purposes we work with with the related 660 minimization problem: 661 min z(x): R^n -> R, 662 where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2. 663 */ 664 PetscReal steptol,initslope,maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg,rellength; 665 #if defined(PETSC_USE_COMPLEX) 666 PetscScalar cinitslope,clambda; 667 #endif 668 PetscErrorCode ierr; 669 PetscInt count; 670 SNES_LS *neP = (SNES_LS*)snes->data; 671 PetscScalar mone = -1.0,scale; 672 PetscTruth change_y = PETSC_FALSE; 673 674 PetscFunctionBegin; 675 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 676 *flag = PETSC_TRUE; 677 alpha = neP->alpha; 678 maxstep = neP->maxstep; 679 steptol = neP->steptol; 680 681 ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr); 682 if (*ynorm == 0.0) { 683 PetscLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n"); 684 *gnorm = fnorm; 685 ierr = VecCopy(x,y);CHKERRQ(ierr); 686 ierr = VecCopy(f,g);CHKERRQ(ierr); 687 *flag = PETSC_FALSE; 688 goto theend2; 689 } 690 if (*ynorm > maxstep) { /* Step too big, so scale back */ 691 scale = maxstep/(*ynorm); 692 ierr = VecScale(&scale,y);CHKERRQ(ierr); 693 *ynorm = maxstep; 694 } 695 ierr = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr); 696 minlambda = steptol/rellength; 697 ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr); 698 #if defined(PETSC_USE_COMPLEX) 699 ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr); 700 initslope = PetscRealPart(cinitslope); 701 #else 702 ierr = VecDot(f,w,&initslope);CHKERRQ(ierr); 703 #endif 704 if (initslope > 0.0) initslope = -initslope; 705 if (initslope == 0.0) initslope = -1.0; 706 707 ierr = VecCopy(y,w);CHKERRQ(ierr); 708 ierr = VecAYPX(&mone,x,w);CHKERRQ(ierr); 709 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 710 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 711 if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */ 712 ierr = VecCopy(w,y);CHKERRQ(ierr); 713 PetscLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n"); 714 goto theend2; 715 } 716 717 /* Fit points with quadratic */ 718 lambda = 1.0; 719 count = 1; 720 while (PETSC_TRUE) { 721 if (lambda <= minlambda) { /* bad luck; use full step */ 722 PetscLogInfo(snes,"SNESQuadraticLineSearch:Unable to find good step length! %D \n",count); 723 PetscLogInfo(snes,"SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",fnorm,*gnorm,*ynorm,lambda,initslope); 724 ierr = VecCopy(x,y);CHKERRQ(ierr); 725 *flag = PETSC_FALSE; break; 726 } 727 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 728 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 729 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 730 else lambda = lambdatemp; 731 ierr = VecCopy(x,w);CHKERRQ(ierr); 732 lambdaneg = -lambda; 733 #if defined(PETSC_USE_COMPLEX) 734 clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr); 735 #else 736 ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr); 737 #endif 738 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 739 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 740 if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */ 741 ierr = VecCopy(w,y);CHKERRQ(ierr); 742 PetscLogInfo(snes,"SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda); 743 break; 744 } 745 count++; 746 } 747 theend2: 748 /* Optional user-defined check for line search step validity */ 749 if (neP->CheckStep) { 750 ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr); 751 if (change_y == PETSC_TRUE) { /* recompute the function if the step has changed */ 752 ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); 753 ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr); 754 ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr); 755 ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr); 756 ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr); 757 } 758 } 759 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 760 PetscFunctionReturn(0); 761 } 762 763 /* -------------------------------------------------------------------------- */ 764 #undef __FUNCT__ 765 #define __FUNCT__ "SNESSetLineSearch" 766 /*@C 767 SNESSetLineSearch - Sets the line search routine to be used 768 by the method SNESLS. 769 770 Input Parameters: 771 + snes - nonlinear context obtained from SNESCreate() 772 . lsctx - optional user-defined context for use by line search 773 - func - pointer to int function 774 775 Collective on SNES 776 777 Available Routines: 778 + SNESCubicLineSearch() - default line search 779 . SNESQuadraticLineSearch() - quadratic line search 780 . SNESNoLineSearch() - the full Newton step (actually not a line search) 781 - SNESNoLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel) 782 783 Options Database Keys: 784 + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search 785 . -snes_ls_alpha <alpha> - Sets alpha 786 . -snes_ls_maxstep <max> - Sets maxstep 787 - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code 788 will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length 789 the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x) 790 791 Calling sequence of func: 792 .vb 793 func (SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w, 794 PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,PetscTruth *flag) 795 .ve 796 797 Input parameters for func: 798 + snes - nonlinear context 799 . lsctx - optional user-defined context for line search 800 . x - current iterate 801 . f - residual evaluated at x 802 . y - search direction (contains new iterate on output) 803 . w - work vector 804 - fnorm - 2-norm of f 805 806 Output parameters for func: 807 + g - residual evaluated at new iterate y 808 . y - new iterate (contains search direction on input) 809 . gnorm - 2-norm of g 810 . ynorm - 2-norm of search length 811 - flag - set to PETSC_TRUE if the line search succeeds; PETSC_FALSE on failure. 812 813 Level: advanced 814 815 .keywords: SNES, nonlinear, set, line search, routine 816 817 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESNoLineSearchNoNorms(), 818 SNESSetLineSearchCheck(), SNESSetLineSearchParams(), SNESGetLineSearchParams() 819 @*/ 820 PetscErrorCode SNESSetLineSearch(SNES snes,PetscErrorCode (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void *lsctx) 821 { 822 PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*),void*); 823 824 PetscFunctionBegin; 825 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearch_C",(void (**)(void))&f);CHKERRQ(ierr); 826 if (f) { 827 ierr = (*f)(snes,func,lsctx);CHKERRQ(ierr); 828 } 829 PetscFunctionReturn(0); 830 } 831 832 typedef PetscErrorCode (*FCN2)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,PetscTruth*); /* force argument to next function to not be extern C*/ 833 /* -------------------------------------------------------------------------- */ 834 EXTERN_C_BEGIN 835 #undef __FUNCT__ 836 #define __FUNCT__ "SNESSetLineSearch_LS" 837 PetscErrorCode SNESSetLineSearch_LS(SNES snes,FCN2 func,void *lsctx) 838 { 839 PetscFunctionBegin; 840 ((SNES_LS *)(snes->data))->LineSearch = func; 841 ((SNES_LS *)(snes->data))->lsP = lsctx; 842 PetscFunctionReturn(0); 843 } 844 EXTERN_C_END 845 /* -------------------------------------------------------------------------- */ 846 #undef __FUNCT__ 847 #define __FUNCT__ "SNESSetLineSearchCheck" 848 /*@C 849 SNESSetLineSearchCheck - Sets a routine to check the validity of new iterate computed 850 by the line search routine in the Newton-based method SNESLS. 851 852 Input Parameters: 853 + snes - nonlinear context obtained from SNESCreate() 854 . func - pointer to int function 855 - checkctx - optional user-defined context for use by step checking routine 856 857 Collective on SNES 858 859 Calling sequence of func: 860 .vb 861 int func (SNES snes, void *checkctx, Vec x, PetscTruth *flag) 862 .ve 863 where func returns an error code of 0 on success and a nonzero 864 on failure. 865 866 Input parameters for func: 867 + snes - nonlinear context 868 . checkctx - optional user-defined context for use by step checking routine 869 - x - current candidate iterate 870 871 Output parameters for func: 872 + x - current iterate (possibly modified) 873 - flag - flag indicating whether x has been modified (either 874 PETSC_TRUE of PETSC_FALSE) 875 876 Level: advanced 877 878 Notes: 879 SNESNoLineSearch() and SNESNoLineSearchNoNorms() accept the new 880 iterate computed by the line search checking routine. In particular, 881 these routines (1) compute a candidate iterate u_{i+1}, (2) pass control 882 to the checking routine, and then (3) compute the corresponding nonlinear 883 function f(u_{i+1}) with the (possibly altered) iterate u_{i+1}. 884 885 SNESQuadraticLineSearch() and SNESCubicLineSearch() also accept the 886 new iterate computed by the line search checking routine. In particular, 887 these routines (1) compute a candidate iterate u_{i+1} as well as a 888 candidate nonlinear function f(u_{i+1}), (2) pass control to the checking 889 routine, and then (3) force a re-evaluation of f(u_{i+1}) if any changes 890 were made to the candidate iterate in the checking routine (as indicated 891 by flag=PETSC_TRUE). The overhead of this function re-evaluation can be 892 very costly, so use this feature with caution! 893 894 .keywords: SNES, nonlinear, set, line search check, step check, routine 895 896 .seealso: SNESSetLineSearch() 897 @*/ 898 PetscErrorCode SNESSetLineSearchCheck(SNES snes,PetscErrorCode (*func)(SNES,void*,Vec,PetscTruth*),void *checkctx) 899 { 900 PetscErrorCode ierr,(*f)(SNES,PetscErrorCode (*)(SNES,void*,Vec,PetscTruth*),void*); 901 902 PetscFunctionBegin; 903 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearchCheck_C",(void (**)(void))&f);CHKERRQ(ierr); 904 if (f) { 905 ierr = (*f)(snes,func,checkctx);CHKERRQ(ierr); 906 } 907 PetscFunctionReturn(0); 908 } 909 /* -------------------------------------------------------------------------- */ 910 typedef PetscErrorCode (*FCN)(SNES,void*,Vec,PetscTruth*); /* force argument to next function to not be extern C*/ 911 EXTERN_C_BEGIN 912 #undef __FUNCT__ 913 #define __FUNCT__ "SNESSetLineSearchCheck_LS" 914 PetscErrorCode SNESSetLineSearchCheck_LS(SNES snes,FCN func,void *checkctx) 915 { 916 PetscFunctionBegin; 917 ((SNES_LS *)(snes->data))->CheckStep = func; 918 ((SNES_LS *)(snes->data))->checkP = checkctx; 919 PetscFunctionReturn(0); 920 } 921 EXTERN_C_END 922 /* -------------------------------------------------------------------------- */ 923 /* 924 SNESPrintHelp_LS - Prints all options for the SNES_LS method. 925 926 Input Parameter: 927 . snes - the SNES context 928 929 Application Interface Routine: SNESPrintHelp() 930 */ 931 #undef __FUNCT__ 932 #define __FUNCT__ "SNESPrintHelp_LS" 933 static PetscErrorCode SNESPrintHelp_LS(SNES snes,char *p) 934 { 935 SNES_LS *ls = (SNES_LS *)snes->data; 936 937 PetscFunctionBegin; 938 (*PetscHelpPrintf)(snes->comm," method SNES_LS (ls) for systems of nonlinear equations:\n"); 939 (*PetscHelpPrintf)(snes->comm," %ssnes_ls [cubic,quadratic,basic,basicnonorms,...]\n",p); 940 (*PetscHelpPrintf)(snes->comm," %ssnes_ls_alpha <alpha> (default %g)\n",p,ls->alpha); 941 (*PetscHelpPrintf)(snes->comm," %ssnes_ls_maxstep <max> (default %g)\n",p,ls->maxstep); 942 (*PetscHelpPrintf)(snes->comm," %ssnes_ls_steptol <tol> (default %g)\n",p,ls->steptol); 943 PetscFunctionReturn(0); 944 } 945 946 /* 947 SNESView_LS - Prints info from the SNESLS data structure. 948 949 Input Parameters: 950 . SNES - the SNES context 951 . viewer - visualization context 952 953 Application Interface Routine: SNESView() 954 */ 955 #undef __FUNCT__ 956 #define __FUNCT__ "SNESView_LS" 957 static PetscErrorCode SNESView_LS(SNES snes,PetscViewer viewer) 958 { 959 SNES_LS *ls = (SNES_LS *)snes->data; 960 const char *cstr; 961 PetscErrorCode ierr; 962 PetscTruth iascii; 963 964 PetscFunctionBegin; 965 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr); 966 if (iascii) { 967 if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch"; 968 else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch"; 969 else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch"; 970 else cstr = "unknown"; 971 ierr = PetscViewerASCIIPrintf(viewer," line search variant: %s\n",cstr);CHKERRQ(ierr); 972 ierr = PetscViewerASCIIPrintf(viewer," alpha=%g, maxstep=%g, steptol=%g\n",ls->alpha,ls->maxstep,ls->steptol);CHKERRQ(ierr); 973 } else { 974 SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ LS",((PetscObject)viewer)->type_name); 975 } 976 PetscFunctionReturn(0); 977 } 978 /* -------------------------------------------------------------------------- */ 979 /* 980 SNESSetFromOptions_LS - Sets various parameters for the SNESLS method. 981 982 Input Parameter: 983 . snes - the SNES context 984 985 Application Interface Routine: SNESSetFromOptions() 986 */ 987 #undef __FUNCT__ 988 #define __FUNCT__ "SNESSetFromOptions_LS" 989 static PetscErrorCode SNESSetFromOptions_LS(SNES snes) 990 { 991 SNES_LS *ls = (SNES_LS *)snes->data; 992 const char *lses[] = {"basic","basicnonorms","quadratic","cubic"}; 993 PetscErrorCode ierr; 994 PetscInt indx; 995 PetscTruth flg; 996 997 PetscFunctionBegin; 998 ierr = PetscOptionsHead("SNES Line search options");CHKERRQ(ierr); 999 ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);CHKERRQ(ierr); 1000 ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);CHKERRQ(ierr); 1001 ierr = PetscOptionsReal("-snes_ls_steptol","Step must be greater than","None",ls->steptol,&ls->steptol,0);CHKERRQ(ierr); 1002 1003 ierr = PetscOptionsEList("-snes_ls","Line search used","SNESSetLineSearch",lses,4,"cubic",&indx,&flg);CHKERRQ(ierr); 1004 if (flg) { 1005 switch (indx) { 1006 case 0: 1007 ierr = SNESSetLineSearch(snes,SNESNoLineSearch,PETSC_NULL);CHKERRQ(ierr); 1008 break; 1009 case 1: 1010 ierr = SNESSetLineSearch(snes,SNESNoLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr); 1011 break; 1012 case 2: 1013 ierr = SNESSetLineSearch(snes,SNESQuadraticLineSearch,PETSC_NULL);CHKERRQ(ierr); 1014 break; 1015 case 3: 1016 ierr = SNESSetLineSearch(snes,SNESCubicLineSearch,PETSC_NULL);CHKERRQ(ierr); 1017 break; 1018 } 1019 } 1020 ierr = PetscOptionsTail();CHKERRQ(ierr); 1021 PetscFunctionReturn(0); 1022 } 1023 /* -------------------------------------------------------------------------- */ 1024 /*MC 1025 SNESLS - Newton based nonlinear solver that uses a line search 1026 1027 Options Database: 1028 + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search 1029 . -snes_ls_alpha <alpha> - Sets alpha 1030 . -snes_ls_maxstep <max> - Sets maxstep 1031 - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code 1032 will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length 1033 the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x) 1034 1035 Notes: This is the default nonlinear solver in SNES 1036 1037 Level: beginner 1038 1039 .seealso: SNESCreate(), SNES, SNESSetType(), SNESTR, SNESSetLineSearch(), 1040 SNESSetLineSearchCheck(), SNESNoLineSearch(), SNESCubicLineSearch(), SNESQuadraticLineSearch(), 1041 SNESSetLineSearch(), SNESNoLineSearchNoNorms() 1042 1043 M*/ 1044 EXTERN_C_BEGIN 1045 #undef __FUNCT__ 1046 #define __FUNCT__ "SNESCreate_LS" 1047 PetscErrorCode SNESCreate_LS(SNES snes) 1048 { 1049 PetscErrorCode ierr; 1050 SNES_LS *neP; 1051 1052 PetscFunctionBegin; 1053 snes->setup = SNESSetUp_LS; 1054 snes->solve = SNESSolve_LS; 1055 snes->destroy = SNESDestroy_LS; 1056 snes->converged = SNESConverged_LS; 1057 snes->printhelp = SNESPrintHelp_LS; 1058 snes->setfromoptions = SNESSetFromOptions_LS; 1059 snes->view = SNESView_LS; 1060 snes->nwork = 0; 1061 1062 ierr = PetscNew(SNES_LS,&neP);CHKERRQ(ierr); 1063 PetscLogObjectMemory(snes,sizeof(SNES_LS)); 1064 snes->data = (void*)neP; 1065 neP->alpha = 1.e-4; 1066 neP->maxstep = 1.e8; 1067 neP->steptol = 1.e-12; 1068 neP->LineSearch = SNESCubicLineSearch; 1069 neP->lsP = PETSC_NULL; 1070 neP->CheckStep = PETSC_NULL; 1071 neP->checkP = PETSC_NULL; 1072 1073 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearch_C","SNESSetLineSearch_LS",SNESSetLineSearch_LS);CHKERRQ(ierr); 1074 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearchCheck_C","SNESSetLineSearchCheck_LS",SNESSetLineSearchCheck_LS);CHKERRQ(ierr); 1075 1076 PetscFunctionReturn(0); 1077 } 1078 EXTERN_C_END 1079 1080 1081 1082