1 /*$Id: ls.c,v 1.172 2001/08/07 03:04:11 balay Exp $*/ 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 int SNESLSCheckLocalMin_Private(Mat A,Vec F,Vec W,PetscReal fnorm,PetscTruth *ismin) 14 { 15 PetscReal a1; 16 int 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 PetscLogInfo(0,"SNESSolve_LS: || J^T F|| %g near zero implies found a local minimum\n",a1/fnorm); 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(PETSC_NULL,W);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 PetscLogInfo(0,"SNESSolve_LS: (F^T J random)/(|| F ||*||random|| %g near zero implies found a local minimum\n",a1); 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 int SNESLSCheckResidual_Private(Mat A,Vec F,Vec X,Vec W1,Vec W2) 52 { 53 PetscReal a1,a2; 54 int ierr; 55 PetscTruth hastranspose; 56 PetscScalar mone = -1.0; 57 58 PetscFunctionBegin; 59 ierr = MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);CHKERRQ(ierr); 60 if (hastranspose) { 61 ierr = MatMult(A,X,W1);CHKERRQ(ierr); 62 ierr = VecAXPY(&mone,F,W1);CHKERRQ(ierr); 63 64 /* Compute || J^T W|| */ 65 ierr = MatMultTranspose(A,W1,W2);CHKERRQ(ierr); 66 ierr = VecNorm(W1,NORM_2,&a1);CHKERRQ(ierr); 67 ierr = VecNorm(W2,NORM_2,&a2);CHKERRQ(ierr); 68 if (a1 != 0) { 69 PetscLogInfo(0,"SNESSolve_LS: ||J^T(F-Ax)||/||F-AX|| %g near zero implies inconsistent rhs\n",a2/a1); 70 } 71 } 72 PetscFunctionReturn(0); 73 } 74 75 /* -------------------------------------------------------------------- 76 77 This file implements a truncated Newton method with a line search, 78 for solving a system of nonlinear equations, using the KSP, Vec, 79 and Mat interfaces for linear solvers, vectors, and matrices, 80 respectively. 81 82 The following basic routines are required for each nonlinear solver: 83 SNESCreate_XXX() - Creates a nonlinear solver context 84 SNESSetFromOptions_XXX() - Sets runtime options 85 SNESSolve_XXX() - Solves the nonlinear system 86 SNESDestroy_XXX() - Destroys the nonlinear solver context 87 The suffix "_XXX" denotes a particular implementation, in this case 88 we use _LS (e.g., SNESCreate_LS, SNESSolve_LS) for solving 89 systems of nonlinear equations with a line search (LS) method. 90 These routines are actually called via the common user interface 91 routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and 92 SNESDestroy(), so the application code interface remains identical 93 for all nonlinear solvers. 94 95 Another key routine is: 96 SNESSetUp_XXX() - Prepares for the use of a nonlinear solver 97 by setting data structures and options. The interface routine SNESSetUp() 98 is not usually called directly by the user, but instead is called by 99 SNESSolve() if necessary. 100 101 Additional basic routines are: 102 SNESView_XXX() - Prints details of runtime options that 103 have actually been used. 104 These are called by application codes via the interface routines 105 SNESView(). 106 107 The various types of solvers (preconditioners, Krylov subspace methods, 108 nonlinear solvers, timesteppers) are all organized similarly, so the 109 above description applies to these categories also. 110 111 -------------------------------------------------------------------- */ 112 /* 113 SNESSolve_LS - Solves a nonlinear system with a truncated Newton 114 method with a line search. 115 116 Input Parameters: 117 . snes - the SNES context 118 119 Output Parameter: 120 . outits - number of iterations until termination 121 122 Application Interface Routine: SNESSolve() 123 124 Notes: 125 This implements essentially a truncated Newton method with a 126 line search. By default a cubic backtracking line search 127 is employed, as described in the text "Numerical Methods for 128 Unconstrained Optimization and Nonlinear Equations" by Dennis 129 and Schnabel. 130 */ 131 #undef __FUNCT__ 132 #define __FUNCT__ "SNESSolve_LS" 133 int SNESSolve_LS(SNES snes) 134 { 135 SNES_LS *neP = (SNES_LS*)snes->data; 136 int maxits,i,ierr,lits,lsfail; 137 MatStructure flg = DIFFERENT_NONZERO_PATTERN; 138 PetscReal fnorm,gnorm,xnorm,ynorm; 139 Vec Y,X,F,G,W,TMP; 140 KSP ksp; 141 142 PetscFunctionBegin; 143 ierr = SNESGetKSP(snes,&ksp);CHKERRQ(ierr); 144 snes->reason = SNES_CONVERGED_ITERATING; 145 146 maxits = snes->max_its; /* maximum number of iterations */ 147 X = snes->vec_sol; /* solution vector */ 148 F = snes->vec_func; /* residual vector */ 149 Y = snes->work[0]; /* work vectors */ 150 G = snes->work[1]; 151 W = snes->work[2]; 152 153 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 154 snes->iter = 0; 155 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 156 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); /* F(X) */ 157 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 158 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 159 snes->norm = fnorm; 160 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 161 SNESLogConvHistory(snes,fnorm,0); 162 SNESMonitor(snes,0,fnorm); 163 164 if (fnorm < snes->atol) {snes->reason = SNES_CONVERGED_FNORM_ABS; PetscFunctionReturn(0);} 165 166 /* set parameter for default relative tolerance convergence test */ 167 snes->ttol = fnorm*snes->rtol; 168 169 for (i=0; i<maxits; i++) { 170 171 /* Call general purpose update function */ 172 if (snes->update != PETSC_NULL) { 173 ierr = (*snes->update)(snes, snes->iter);CHKERRQ(ierr); 174 } 175 176 /* Solve J Y = F, where J is Jacobian matrix */ 177 ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 178 ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); 179 ierr = KSPSetRhs(snes->ksp,F);CHKERRQ(ierr); 180 ierr = KSPSetSolution(snes->ksp,Y);CHKERRQ(ierr); 181 ierr = KSPSolve(snes->ksp);CHKERRQ(ierr); 182 ierr = KSPGetIterationNumber(ksp,&lits);CHKERRQ(ierr); 183 184 if (PetscLogPrintInfo){ 185 ierr = SNESLSCheckResidual_Private(snes->jacobian,F,Y,G,W);CHKERRQ(ierr); 186 } 187 188 /* should check what happened to the linear solve? */ 189 snes->linear_its += lits; 190 PetscLogInfo(snes,"SNESSolve_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits); 191 192 /* Compute a (scaled) negative update in the line search routine: 193 Y <- X - lambda*Y 194 and evaluate G(Y) = function(Y)) 195 */ 196 ierr = VecCopy(Y,snes->vec_sol_update_always);CHKERRQ(ierr); 197 ierr = (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);CHKERRQ(ierr); 198 PetscLogInfo(snes,"SNESSolve_LS: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail); 199 200 TMP = F; F = G; snes->vec_func_always = F; G = TMP; 201 TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 202 fnorm = gnorm; 203 204 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 205 snes->iter = i+1; 206 snes->norm = fnorm; 207 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 208 SNESLogConvHistory(snes,fnorm,lits); 209 SNESMonitor(snes,i+1,fnorm); 210 211 if (lsfail) { 212 PetscTruth ismin; 213 214 if (++snes->numFailures >= snes->maxFailures) { 215 snes->reason = SNES_DIVERGED_LS_FAILURE; 216 ierr = SNESLSCheckLocalMin_Private(snes->jacobian,F,W,fnorm,&ismin);CHKERRQ(ierr); 217 if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; 218 break; 219 } 220 } 221 222 /* Test for convergence */ 223 if (snes->converged) { 224 ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); /* xnorm = || X || */ 225 ierr = (*snes->converged)(snes,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 226 if (snes->reason) { 227 break; 228 } 229 } 230 } 231 if (X != snes->vec_sol) { 232 ierr = VecCopy(X,snes->vec_sol);CHKERRQ(ierr); 233 } 234 if (F != snes->vec_func) { 235 ierr = VecCopy(F,snes->vec_func);CHKERRQ(ierr); 236 } 237 snes->vec_sol_always = snes->vec_sol; 238 snes->vec_func_always = snes->vec_func; 239 if (i == maxits) { 240 PetscLogInfo(snes,"SNESSolve_LS: Maximum number of iterations has been reached: %d\n",maxits); 241 snes->reason = SNES_DIVERGED_MAX_IT; 242 } 243 PetscFunctionReturn(0); 244 } 245 /* -------------------------------------------------------------------------- */ 246 /* 247 SNESSetUp_LS - Sets up the internal data structures for the later use 248 of the SNESLS nonlinear solver. 249 250 Input Parameter: 251 . snes - the SNES context 252 . x - the solution vector 253 254 Application Interface Routine: SNESSetUp() 255 256 Notes: 257 For basic use of the SNES solvers, the user need not explicitly call 258 SNESSetUp(), since these actions will automatically occur during 259 the call to SNESSolve(). 260 */ 261 #undef __FUNCT__ 262 #define __FUNCT__ "SNESSetUp_LS" 263 int SNESSetUp_LS(SNES snes) 264 { 265 int ierr; 266 267 PetscFunctionBegin; 268 snes->nwork = 4; 269 ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr); 270 PetscLogObjectParents(snes,snes->nwork,snes->work); 271 snes->vec_sol_update_always = snes->work[3]; 272 PetscFunctionReturn(0); 273 } 274 /* -------------------------------------------------------------------------- */ 275 /* 276 SNESDestroy_LS - Destroys the private SNES_LS context that was created 277 with SNESCreate_LS(). 278 279 Input Parameter: 280 . snes - the SNES context 281 282 Application Interface Routine: SNESDestroy() 283 */ 284 #undef __FUNCT__ 285 #define __FUNCT__ "SNESDestroy_LS" 286 int SNESDestroy_LS(SNES snes) 287 { 288 int ierr; 289 290 PetscFunctionBegin; 291 if (snes->nwork) { 292 ierr = VecDestroyVecs(snes->work,snes->nwork);CHKERRQ(ierr); 293 } 294 ierr = PetscFree(snes->data);CHKERRQ(ierr); 295 PetscFunctionReturn(0); 296 } 297 /* -------------------------------------------------------------------------- */ 298 #undef __FUNCT__ 299 #define __FUNCT__ "SNESNoLineSearch" 300 301 /*@C 302 SNESNoLineSearch - This routine is not a line search at all; 303 it simply uses the full Newton step. Thus, this routine is intended 304 to serve as a template and is not recommended for general use. 305 306 Collective on SNES and Vec 307 308 Input Parameters: 309 + snes - nonlinear context 310 . lsctx - optional context for line search (not used here) 311 . x - current iterate 312 . f - residual evaluated at x 313 . y - search direction (contains new iterate on output) 314 . w - work vector 315 - fnorm - 2-norm of f 316 317 Output Parameters: 318 + g - residual evaluated at new iterate y 319 . y - new iterate (contains search direction on input) 320 . gnorm - 2-norm of g 321 . ynorm - 2-norm of search length 322 - flag - set to 0, indicating a successful line search 323 324 Options Database Key: 325 . -snes_ls basic - Activates SNESNoLineSearch() 326 327 Level: advanced 328 329 .keywords: SNES, nonlinear, line search, cubic 330 331 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 332 SNESSetLineSearch(), SNESNoLineSearchNoNorms() 333 @*/ 334 int SNESNoLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag) 335 { 336 int ierr; 337 PetscScalar mone = -1.0; 338 SNES_LS *neP = (SNES_LS*)snes->data; 339 PetscTruth change_y = PETSC_FALSE; 340 341 PetscFunctionBegin; 342 *flag = 0; 343 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 344 ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr); /* ynorm = || y || */ 345 ierr = VecAYPX(&mone,x,y);CHKERRQ(ierr); /* y <- y - x */ 346 if (neP->CheckStep) { 347 ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr); 348 } 349 ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); /* Compute F(y) */ 350 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); /* gnorm = || g || */ 351 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 352 PetscFunctionReturn(0); 353 } 354 /* -------------------------------------------------------------------------- */ 355 #undef __FUNCT__ 356 #define __FUNCT__ "SNESNoLineSearchNoNorms" 357 358 /*@C 359 SNESNoLineSearchNoNorms - This routine is not a line search at 360 all; it simply uses the full Newton step. This version does not 361 even compute the norm of the function or search direction; this 362 is intended only when you know the full step is fine and are 363 not checking for convergence of the nonlinear iteration (for 364 example, you are running always for a fixed number of Newton steps). 365 366 Collective on SNES and Vec 367 368 Input Parameters: 369 + snes - nonlinear context 370 . lsctx - optional context for line search (not used here) 371 . x - current iterate 372 . f - residual evaluated at x 373 . y - search direction (contains new iterate on output) 374 . w - work vector 375 - fnorm - 2-norm of f 376 377 Output Parameters: 378 + g - residual evaluated at new iterate y 379 . gnorm - not changed 380 . ynorm - not changed 381 - flag - set to 0, indicating a successful line search 382 383 Options Database Key: 384 . -snes_ls basicnonorms - Activates SNESNoLineSearchNoNorms() 385 386 Notes: 387 SNESNoLineSearchNoNorms() must be used in conjunction with 388 either the options 389 $ -snes_no_convergence_test -snes_max_it <its> 390 or alternatively a user-defined custom test set via 391 SNESSetConvergenceTest(); or a -snes_max_it of 1, 392 otherwise, the SNES solver will generate an error. 393 394 During the final iteration this will not evaluate the function at 395 the solution point. This is to save a function evaluation while 396 using pseudo-timestepping. 397 398 The residual norms printed by monitoring routines such as 399 SNESDefaultMonitor() (as activated via -snes_monitor) will not be 400 correct, since they are not computed. 401 402 Level: advanced 403 404 .keywords: SNES, nonlinear, line search, cubic 405 406 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 407 SNESSetLineSearch(), SNESNoLineSearch() 408 @*/ 409 int SNESNoLineSearchNoNorms(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag) 410 { 411 int ierr; 412 PetscScalar mone = -1.0; 413 SNES_LS *neP = (SNES_LS*)snes->data; 414 PetscTruth change_y = PETSC_FALSE; 415 416 PetscFunctionBegin; 417 *flag = 0; 418 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 419 ierr = VecAYPX(&mone,x,y);CHKERRQ(ierr); /* y <- y - x */ 420 if (neP->CheckStep) { 421 ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr); 422 } 423 424 /* don't evaluate function the last time through */ 425 if (snes->iter < snes->max_its-1) { 426 ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); /* Compute F(y) */ 427 } 428 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 429 PetscFunctionReturn(0); 430 } 431 /* -------------------------------------------------------------------------- */ 432 #undef __FUNCT__ 433 #define __FUNCT__ "SNESCubicLineSearch" 434 /*@C 435 SNESCubicLineSearch - Performs a cubic line search (default line search method). 436 437 Collective on SNES 438 439 Input Parameters: 440 + snes - nonlinear context 441 . lsctx - optional context for line search (not used here) 442 . x - current iterate 443 . f - residual evaluated at x 444 . y - search direction (contains new iterate on output) 445 . w - work vector 446 - fnorm - 2-norm of f 447 448 Output Parameters: 449 + g - residual evaluated at new iterate y 450 . y - new iterate (contains search direction on input) 451 . gnorm - 2-norm of g 452 . ynorm - 2-norm of search length 453 - flag - 0 if line search succeeds; -1 on failure. 454 455 Options Database Key: 456 $ -snes_ls cubic - Activates SNESCubicLineSearch() 457 458 Notes: 459 This line search is taken from "Numerical Methods for Unconstrained 460 Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 461 462 Level: advanced 463 464 .keywords: SNES, nonlinear, line search, cubic 465 466 .seealso: SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms() 467 @*/ 468 int SNESCubicLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag) 469 { 470 /* 471 Note that for line search purposes we work with with the related 472 minimization problem: 473 min z(x): R^n -> R, 474 where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2. 475 */ 476 477 PetscReal steptol,initslope,lambdaprev,gnormprev,a,b,d,t1,t2,rellength; 478 PetscReal maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg; 479 #if defined(PETSC_USE_COMPLEX) 480 PetscScalar cinitslope,clambda; 481 #endif 482 int ierr,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 = 0; 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 = -1; 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 = -1; 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 - 0 if line search succeeds; -1 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 int SNESQuadraticLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *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 int ierr,count; 669 SNES_LS *neP = (SNES_LS*)snes->data; 670 PetscScalar mone = -1.0,scale; 671 PetscTruth change_y = PETSC_FALSE; 672 673 PetscFunctionBegin; 674 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 675 *flag = 0; 676 alpha = neP->alpha; 677 maxstep = neP->maxstep; 678 steptol = neP->steptol; 679 680 ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr); 681 if (*ynorm == 0.0) { 682 PetscLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n"); 683 *gnorm = fnorm; 684 ierr = VecCopy(x,y);CHKERRQ(ierr); 685 ierr = VecCopy(f,g);CHKERRQ(ierr); 686 *flag = -1; 687 goto theend2; 688 } 689 if (*ynorm > maxstep) { /* Step too big, so scale back */ 690 scale = maxstep/(*ynorm); 691 ierr = VecScale(&scale,y);CHKERRQ(ierr); 692 *ynorm = maxstep; 693 } 694 ierr = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr); 695 minlambda = steptol/rellength; 696 ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr); 697 #if defined(PETSC_USE_COMPLEX) 698 ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr); 699 initslope = PetscRealPart(cinitslope); 700 #else 701 ierr = VecDot(f,w,&initslope);CHKERRQ(ierr); 702 #endif 703 if (initslope > 0.0) initslope = -initslope; 704 if (initslope == 0.0) initslope = -1.0; 705 706 ierr = VecCopy(y,w);CHKERRQ(ierr); 707 ierr = VecAYPX(&mone,x,w);CHKERRQ(ierr); 708 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 709 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 710 if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */ 711 ierr = VecCopy(w,y);CHKERRQ(ierr); 712 PetscLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n"); 713 goto theend2; 714 } 715 716 /* Fit points with quadratic */ 717 lambda = 1.0; 718 count = 1; 719 while (PETSC_TRUE) { 720 if (lambda <= minlambda) { /* bad luck; use full step */ 721 PetscLogInfo(snes,"SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 722 PetscLogInfo(snes,"SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",fnorm,*gnorm,*ynorm,lambda,initslope); 723 ierr = VecCopy(x,y);CHKERRQ(ierr); 724 *flag = -1; break; 725 } 726 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 727 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 728 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 729 else lambda = lambdatemp; 730 ierr = VecCopy(x,w);CHKERRQ(ierr); 731 lambdaneg = -lambda; 732 #if defined(PETSC_USE_COMPLEX) 733 clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr); 734 #else 735 ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr); 736 #endif 737 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 738 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 739 if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */ 740 ierr = VecCopy(w,y);CHKERRQ(ierr); 741 PetscLogInfo(snes,"SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda); 742 break; 743 } 744 count++; 745 } 746 theend2: 747 /* Optional user-defined check for line search step validity */ 748 if (neP->CheckStep) { 749 ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr); 750 if (change_y == PETSC_TRUE) { /* recompute the function if the step has changed */ 751 ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); 752 ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr); 753 ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr); 754 ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr); 755 ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr); 756 } 757 } 758 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 759 PetscFunctionReturn(0); 760 } 761 762 /* -------------------------------------------------------------------------- */ 763 #undef __FUNCT__ 764 #define __FUNCT__ "SNESSetLineSearch" 765 /*@C 766 SNESSetLineSearch - Sets the line search routine to be used 767 by the method SNESLS. 768 769 Input Parameters: 770 + snes - nonlinear context obtained from SNESCreate() 771 . lsctx - optional user-defined context for use by line search 772 - func - pointer to int function 773 774 Collective on SNES 775 776 Available Routines: 777 + SNESCubicLineSearch() - default line search 778 . SNESQuadraticLineSearch() - quadratic line search 779 . SNESNoLineSearch() - the full Newton step (actually not a line search) 780 - SNESNoLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel) 781 782 Options Database Keys: 783 + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search 784 . -snes_ls_alpha <alpha> - Sets alpha 785 . -snes_ls_maxstep <max> - Sets maxstep 786 - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code 787 will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length 788 the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x) 789 790 Calling sequence of func: 791 .vb 792 func (SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w, 793 PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,*flag) 794 .ve 795 796 Input parameters for func: 797 + snes - nonlinear context 798 . lsctx - optional user-defined context for line search 799 . x - current iterate 800 . f - residual evaluated at x 801 . y - search direction (contains new iterate on output) 802 . w - work vector 803 - fnorm - 2-norm of f 804 805 Output parameters for func: 806 + g - residual evaluated at new iterate y 807 . y - new iterate (contains search direction on input) 808 . gnorm - 2-norm of g 809 . ynorm - 2-norm of search length 810 - flag - set to 0 if the line search succeeds; a nonzero integer 811 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 int SNESSetLineSearch(SNES snes,int (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*),void *lsctx) 821 { 822 int ierr,(*f)(SNES,int (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*),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 int (*FCN2)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*); /* force argument to next function to not be extern C*/ 833 /* -------------------------------------------------------------------------- */ 834 EXTERN_C_BEGIN 835 #undef __FUNCT__ 836 #define __FUNCT__ "SNESSetLineSearch_LS" 837 int 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 int SNESSetLineSearchCheck(SNES snes,int (*func)(SNES,void*,Vec,PetscTruth*),void *checkctx) 899 { 900 int ierr,(*f)(SNES,int (*)(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 int (*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 int 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 int 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 int SNESView_LS(SNES snes,PetscViewer viewer) 958 { 959 SNES_LS *ls = (SNES_LS *)snes->data; 960 const char *cstr; 961 int ierr; 962 PetscTruth isascii; 963 964 PetscFunctionBegin; 965 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr); 966 if (isascii) { 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(1,"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 int SNESSetFromOptions_LS(SNES snes) 990 { 991 SNES_LS *ls = (SNES_LS *)snes->data; 992 const char *lses[] = {"basic","basicnonorms","quadratic","cubic"}; 993 int ierr,indx; 994 PetscTruth flg; 995 996 PetscFunctionBegin; 997 ierr = PetscOptionsHead("SNES Line search options");CHKERRQ(ierr); 998 ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);CHKERRQ(ierr); 999 ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);CHKERRQ(ierr); 1000 ierr = PetscOptionsReal("-snes_ls_steptol","Step must be greater than","None",ls->steptol,&ls->steptol,0);CHKERRQ(ierr); 1001 1002 ierr = PetscOptionsEList("-snes_ls","Line search used","SNESSetLineSearch",lses,4,"cubic",&indx,&flg);CHKERRQ(ierr); 1003 if (flg) { 1004 switch (indx) { 1005 case 0: 1006 ierr = SNESSetLineSearch(snes,SNESNoLineSearch,PETSC_NULL);CHKERRQ(ierr); 1007 break; 1008 case 1: 1009 ierr = SNESSetLineSearch(snes,SNESNoLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr); 1010 break; 1011 case 2: 1012 ierr = SNESSetLineSearch(snes,SNESQuadraticLineSearch,PETSC_NULL);CHKERRQ(ierr); 1013 break; 1014 case 3: 1015 ierr = SNESSetLineSearch(snes,SNESCubicLineSearch,PETSC_NULL);CHKERRQ(ierr); 1016 break; 1017 } 1018 } 1019 ierr = PetscOptionsTail();CHKERRQ(ierr); 1020 PetscFunctionReturn(0); 1021 } 1022 /* -------------------------------------------------------------------------- */ 1023 /*MC 1024 SNESLS - Newton based nonlinear solver that uses a line search 1025 1026 Options Database: 1027 + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search 1028 . -snes_ls_alpha <alpha> - Sets alpha 1029 . -snes_ls_maxstep <max> - Sets maxstep 1030 - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code 1031 will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length 1032 the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x) 1033 1034 Notes: This is the default nonlinear solver in SNES 1035 1036 .seealso: SNESCreate(), SNES, SNESSetType(), SNESTR, SNESSetLineSearch(), 1037 SNESSetLineSearchCheck(), SNESNoLineSearch(), SNESCubicLineSearch(), SNESQuadraticLineSearch(), 1038 SNESSetLineSearch(), SNESNoLineSearchNoNorms() 1039 1040 M*/ 1041 EXTERN_C_BEGIN 1042 #undef __FUNCT__ 1043 #define __FUNCT__ "SNESCreate_LS" 1044 int SNESCreate_LS(SNES snes) 1045 { 1046 int ierr; 1047 SNES_LS *neP; 1048 1049 PetscFunctionBegin; 1050 snes->setup = SNESSetUp_LS; 1051 snes->solve = SNESSolve_LS; 1052 snes->destroy = SNESDestroy_LS; 1053 snes->converged = SNESConverged_LS; 1054 snes->printhelp = SNESPrintHelp_LS; 1055 snes->setfromoptions = SNESSetFromOptions_LS; 1056 snes->view = SNESView_LS; 1057 snes->nwork = 0; 1058 1059 ierr = PetscNew(SNES_LS,&neP);CHKERRQ(ierr); 1060 PetscLogObjectMemory(snes,sizeof(SNES_LS)); 1061 snes->data = (void*)neP; 1062 neP->alpha = 1.e-4; 1063 neP->maxstep = 1.e8; 1064 neP->steptol = 1.e-12; 1065 neP->LineSearch = SNESCubicLineSearch; 1066 neP->lsP = PETSC_NULL; 1067 neP->CheckStep = PETSC_NULL; 1068 neP->checkP = PETSC_NULL; 1069 1070 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearch_C","SNESSetLineSearch_LS",SNESSetLineSearch_LS);CHKERRQ(ierr); 1071 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearchCheck_C","SNESSetLineSearchCheck_LS",SNESSetLineSearchCheck_LS);CHKERRQ(ierr); 1072 1073 PetscFunctionReturn(0); 1074 } 1075 EXTERN_C_END 1076 1077 1078 1079