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 SLES, 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,int *outits) 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 141 PetscFunctionBegin; 142 snes->reason = SNES_CONVERGED_ITERATING; 143 144 maxits = snes->max_its; /* maximum number of iterations */ 145 X = snes->vec_sol; /* solution vector */ 146 F = snes->vec_func; /* residual vector */ 147 Y = snes->work[0]; /* work vectors */ 148 G = snes->work[1]; 149 W = snes->work[2]; 150 151 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 152 snes->iter = 0; 153 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 154 ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr); /* F(X) */ 155 ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 156 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 157 snes->norm = fnorm; 158 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 159 SNESLogConvHistory(snes,fnorm,0); 160 SNESMonitor(snes,0,fnorm); 161 162 if (fnorm < snes->atol) {*outits = 0; snes->reason = SNES_CONVERGED_FNORM_ABS; PetscFunctionReturn(0);} 163 164 /* set parameter for default relative tolerance convergence test */ 165 snes->ttol = fnorm*snes->rtol; 166 167 for (i=0; i<maxits; i++) { 168 169 /* Call general purpose update function */ 170 if (snes->update != PETSC_NULL) { 171 ierr = (*snes->update)(snes, snes->iter);CHKERRQ(ierr); 172 } 173 174 /* Solve J Y = F, where J is Jacobian matrix */ 175 ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);CHKERRQ(ierr); 176 ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg);CHKERRQ(ierr); 177 ierr = SLESSolve(snes->sles,F,Y,&lits);CHKERRQ(ierr); 178 179 if (PetscLogPrintInfo){ 180 ierr = SNESLSCheckResidual_Private(snes->jacobian,F,Y,G,W);CHKERRQ(ierr); 181 } 182 183 /* should check what happened to the linear solve? */ 184 snes->linear_its += lits; 185 PetscLogInfo(snes,"SNESSolve_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits); 186 187 /* Compute a (scaled) negative update in the line search routine: 188 Y <- X - lambda*Y 189 and evaluate G(Y) = function(Y)) 190 */ 191 ierr = VecCopy(Y,snes->vec_sol_update_always);CHKERRQ(ierr); 192 ierr = (*neP->LineSearch)(snes,neP->lsP,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);CHKERRQ(ierr); 193 PetscLogInfo(snes,"SNESSolve_LS: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail); 194 195 TMP = F; F = G; snes->vec_func_always = F; G = TMP; 196 TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 197 fnorm = gnorm; 198 199 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 200 snes->iter = i+1; 201 snes->norm = fnorm; 202 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 203 SNESLogConvHistory(snes,fnorm,lits); 204 SNESMonitor(snes,i+1,fnorm); 205 206 if (lsfail) { 207 PetscTruth ismin; 208 209 if (++snes->numFailures >= snes->maxFailures) { 210 snes->reason = SNES_DIVERGED_LS_FAILURE; 211 ierr = SNESLSCheckLocalMin_Private(snes->jacobian,F,W,fnorm,&ismin);CHKERRQ(ierr); 212 if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN; 213 break; 214 } 215 } 216 217 /* Test for convergence */ 218 if (snes->converged) { 219 ierr = VecNorm(X,NORM_2,&xnorm);CHKERRQ(ierr); /* xnorm = || X || */ 220 ierr = (*snes->converged)(snes,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 221 if (snes->reason) { 222 break; 223 } 224 } 225 } 226 if (X != snes->vec_sol) { 227 ierr = VecCopy(X,snes->vec_sol);CHKERRQ(ierr); 228 } 229 if (F != snes->vec_func) { 230 ierr = VecCopy(F,snes->vec_func);CHKERRQ(ierr); 231 } 232 snes->vec_sol_always = snes->vec_sol; 233 snes->vec_func_always = snes->vec_func; 234 if (i == maxits) { 235 PetscLogInfo(snes,"SNESSolve_LS: Maximum number of iterations has been reached: %d\n",maxits); 236 i--; 237 snes->reason = SNES_DIVERGED_MAX_IT; 238 } 239 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 240 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 241 *outits = i+1; 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 int SNESSetUp_LS(SNES snes) 263 { 264 int 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 int SNESDestroy_LS(SNES snes) 286 { 287 int 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 - set to 0, indicating a successful line search 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 int SNESNoLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag) 334 { 335 int 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 = 0; 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 0, 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 int SNESNoLineSearchNoNorms(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag) 409 { 410 int 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 = 0; 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 - 0 if line search succeeds; -1 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 int SNESCubicLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *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 int ierr,count; 482 SNES_LS *neP = (SNES_LS*)snes->data; 483 PetscScalar mone = -1.0,scale; 484 PetscTruth change_y = PETSC_FALSE; 485 486 PetscFunctionBegin; 487 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 488 *flag = 0; 489 alpha = neP->alpha; 490 maxstep = neP->maxstep; 491 steptol = neP->steptol; 492 493 ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr); 494 if (*ynorm == 0.0) { 495 PetscLogInfo(snes,"SNESCubicLineSearch: Search direction and size is 0\n"); 496 *gnorm = fnorm; 497 ierr = VecCopy(x,y);CHKERRQ(ierr); 498 ierr = VecCopy(f,g);CHKERRQ(ierr); 499 *flag = -1; 500 goto theend1; 501 } 502 if (*ynorm > maxstep) { /* Step too big, so scale back */ 503 scale = maxstep/(*ynorm); 504 #if defined(PETSC_USE_COMPLEX) 505 PetscLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g old ynorm %g\n",PetscRealPart(scale),*ynorm); 506 #else 507 PetscLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g old ynorm %g\n",scale,*ynorm); 508 #endif 509 ierr = VecScale(&scale,y);CHKERRQ(ierr); 510 *ynorm = maxstep; 511 } 512 ierr = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr); 513 minlambda = steptol/rellength; 514 ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr); 515 #if defined(PETSC_USE_COMPLEX) 516 ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr); 517 initslope = PetscRealPart(cinitslope); 518 #else 519 ierr = VecDot(f,w,&initslope);CHKERRQ(ierr); 520 #endif 521 if (initslope > 0.0) initslope = -initslope; 522 if (initslope == 0.0) initslope = -1.0; 523 524 ierr = VecCopy(y,w);CHKERRQ(ierr); 525 ierr = VecAYPX(&mone,x,w);CHKERRQ(ierr); 526 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 527 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 528 if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */ 529 ierr = VecCopy(w,y);CHKERRQ(ierr); 530 PetscLogInfo(snes,"SNESCubicLineSearch: Using full step\n"); 531 goto theend1; 532 } 533 534 /* Fit points with quadratic */ 535 lambda = 1.0; 536 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 537 lambdaprev = lambda; 538 gnormprev = *gnorm; 539 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 540 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 541 else lambda = lambdatemp; 542 ierr = VecCopy(x,w);CHKERRQ(ierr); 543 lambdaneg = -lambda; 544 #if defined(PETSC_USE_COMPLEX) 545 clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr); 546 #else 547 ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr); 548 #endif 549 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 550 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 551 if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */ 552 ierr = VecCopy(w,y);CHKERRQ(ierr); 553 PetscLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%18.16e\n",lambda); 554 goto theend1; 555 } 556 557 /* Fit points with cubic */ 558 count = 1; 559 while (count < 10000) { 560 if (lambda <= minlambda) { /* bad luck; use full step */ 561 PetscLogInfo(snes,"SNESCubicLineSearch:Unable to find good step length! %d \n",count); 562 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); 563 ierr = VecCopy(x,y);CHKERRQ(ierr); 564 *flag = -1; break; 565 } 566 t1 = .5*((*gnorm)*(*gnorm) - fnorm*fnorm) - lambda*initslope; 567 t2 = .5*(gnormprev*gnormprev - fnorm*fnorm) - lambdaprev*initslope; 568 a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 569 b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 570 d = b*b - 3*a*initslope; 571 if (d < 0.0) d = 0.0; 572 if (a == 0.0) { 573 lambdatemp = -initslope/(2.0*b); 574 } else { 575 lambdatemp = (-b + sqrt(d))/(3.0*a); 576 } 577 lambdaprev = lambda; 578 gnormprev = *gnorm; 579 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 580 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 581 else lambda = lambdatemp; 582 ierr = VecCopy(x,w);CHKERRQ(ierr); 583 lambdaneg = -lambda; 584 #if defined(PETSC_USE_COMPLEX) 585 clambda = lambdaneg; 586 ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr); 587 #else 588 ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr); 589 #endif 590 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 591 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 592 if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* is reduction enough? */ 593 ierr = VecCopy(w,y);CHKERRQ(ierr); 594 PetscLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%18.16e\n",lambda); 595 goto theend1; 596 } else { 597 PetscLogInfo(snes,"SNESCubicLineSearch: Cubic step no good, shrinking lambda, lambda=%18.16e\n",lambda); 598 } 599 count++; 600 } 601 if (count >= 10000) { 602 SETERRQ(PETSC_ERR_LIB, "Lambda was decreased more than 10,000 times, so something is probably wrong with the function evaluation"); 603 } 604 theend1: 605 /* Optional user-defined check for line search step validity */ 606 if (neP->CheckStep) { 607 ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr); 608 if (change_y == PETSC_TRUE) { /* recompute the function if the step has changed */ 609 ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); 610 ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr); 611 ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr); 612 ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr); 613 ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr); 614 } 615 } 616 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 617 PetscFunctionReturn(0); 618 } 619 /* -------------------------------------------------------------------------- */ 620 #undef __FUNCT__ 621 #define __FUNCT__ "SNESQuadraticLineSearch" 622 /*@C 623 SNESQuadraticLineSearch - Performs a quadratic line search. 624 625 Collective on SNES and Vec 626 627 Input Parameters: 628 + snes - the SNES context 629 . lsctx - optional context for line search (not used here) 630 . x - current iterate 631 . f - residual evaluated at x 632 . y - search direction (contains new iterate on output) 633 . w - work vector 634 - fnorm - 2-norm of f 635 636 Output Parameters: 637 + g - residual evaluated at new iterate y 638 . y - new iterate (contains search direction on input) 639 . gnorm - 2-norm of g 640 . ynorm - 2-norm of search length 641 - flag - 0 if line search succeeds; -1 on failure. 642 643 Options Database Key: 644 . -snes_ls quadratic - Activates SNESQuadraticLineSearch() 645 646 Notes: 647 Use SNESSetLineSearch() to set this routine within the SNESLS method. 648 649 Level: advanced 650 651 .keywords: SNES, nonlinear, quadratic, line search 652 653 .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch(), SNESNoLineSearchNoNorms() 654 @*/ 655 int SNESQuadraticLineSearch(SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w,PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,int *flag) 656 { 657 /* 658 Note that for line search purposes we work with with the related 659 minimization problem: 660 min z(x): R^n -> R, 661 where z(x) = .5 * fnorm*fnorm,and fnorm = || f ||_2. 662 */ 663 PetscReal steptol,initslope,maxstep,minlambda,alpha,lambda,lambdatemp,lambdaneg,rellength; 664 #if defined(PETSC_USE_COMPLEX) 665 PetscScalar cinitslope,clambda; 666 #endif 667 int ierr,count; 668 SNES_LS *neP = (SNES_LS*)snes->data; 669 PetscScalar mone = -1.0,scale; 670 PetscTruth change_y = PETSC_FALSE; 671 672 PetscFunctionBegin; 673 ierr = PetscLogEventBegin(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 674 *flag = 0; 675 alpha = neP->alpha; 676 maxstep = neP->maxstep; 677 steptol = neP->steptol; 678 679 ierr = VecNorm(y,NORM_2,ynorm);CHKERRQ(ierr); 680 if (*ynorm == 0.0) { 681 PetscLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n"); 682 *gnorm = fnorm; 683 ierr = VecCopy(x,y);CHKERRQ(ierr); 684 ierr = VecCopy(f,g);CHKERRQ(ierr); 685 *flag = -1; 686 goto theend2; 687 } 688 if (*ynorm > maxstep) { /* Step too big, so scale back */ 689 scale = maxstep/(*ynorm); 690 ierr = VecScale(&scale,y);CHKERRQ(ierr); 691 *ynorm = maxstep; 692 } 693 ierr = VecMaxPointwiseDivide(y,x,&rellength);CHKERRQ(ierr); 694 minlambda = steptol/rellength; 695 ierr = MatMult(snes->jacobian,y,w);CHKERRQ(ierr); 696 #if defined(PETSC_USE_COMPLEX) 697 ierr = VecDot(f,w,&cinitslope);CHKERRQ(ierr); 698 initslope = PetscRealPart(cinitslope); 699 #else 700 ierr = VecDot(f,w,&initslope);CHKERRQ(ierr); 701 #endif 702 if (initslope > 0.0) initslope = -initslope; 703 if (initslope == 0.0) initslope = -1.0; 704 705 ierr = VecCopy(y,w);CHKERRQ(ierr); 706 ierr = VecAYPX(&mone,x,w);CHKERRQ(ierr); 707 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 708 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 709 if (.5*(*gnorm)*(*gnorm) <= .5*fnorm*fnorm + alpha*initslope) { /* Sufficient reduction */ 710 ierr = VecCopy(w,y);CHKERRQ(ierr); 711 PetscLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n"); 712 goto theend2; 713 } 714 715 /* Fit points with quadratic */ 716 lambda = 1.0; 717 count = 1; 718 while (PETSC_TRUE) { 719 if (lambda <= minlambda) { /* bad luck; use full step */ 720 PetscLogInfo(snes,"SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 721 PetscLogInfo(snes,"SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n",fnorm,*gnorm,*ynorm,lambda,initslope); 722 ierr = VecCopy(x,y);CHKERRQ(ierr); 723 *flag = -1; break; 724 } 725 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 726 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 727 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 728 else lambda = lambdatemp; 729 ierr = VecCopy(x,w);CHKERRQ(ierr); 730 lambdaneg = -lambda; 731 #if defined(PETSC_USE_COMPLEX) 732 clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w);CHKERRQ(ierr); 733 #else 734 ierr = VecAXPY(&lambdaneg,y,w);CHKERRQ(ierr); 735 #endif 736 ierr = SNESComputeFunction(snes,w,g);CHKERRQ(ierr); 737 ierr = VecNorm(g,NORM_2,gnorm);CHKERRQ(ierr); 738 if (.5*(*gnorm)*(*gnorm) < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */ 739 ierr = VecCopy(w,y);CHKERRQ(ierr); 740 PetscLogInfo(snes,"SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda); 741 break; 742 } 743 count++; 744 } 745 theend2: 746 /* Optional user-defined check for line search step validity */ 747 if (neP->CheckStep) { 748 ierr = (*neP->CheckStep)(snes,neP->checkP,y,&change_y);CHKERRQ(ierr); 749 if (change_y == PETSC_TRUE) { /* recompute the function if the step has changed */ 750 ierr = SNESComputeFunction(snes,y,g);CHKERRQ(ierr); 751 ierr = VecNormBegin(y,NORM_2,ynorm);CHKERRQ(ierr); 752 ierr = VecNormBegin(g,NORM_2,gnorm);CHKERRQ(ierr); 753 ierr = VecNormEnd(y,NORM_2,ynorm);CHKERRQ(ierr); 754 ierr = VecNormEnd(g,NORM_2,gnorm);CHKERRQ(ierr); 755 } 756 } 757 ierr = PetscLogEventEnd(SNES_LineSearch,snes,x,f,g);CHKERRQ(ierr); 758 PetscFunctionReturn(0); 759 } 760 /* -------------------------------------------------------------------------- */ 761 #undef __FUNCT__ 762 #define __FUNCT__ "SNESSetLineSearch" 763 /*@C 764 SNESSetLineSearch - Sets the line search routine to be used 765 by the method SNESLS. 766 767 Input Parameters: 768 + snes - nonlinear context obtained from SNESCreate() 769 . lsctx - optional user-defined context for use by line search 770 - func - pointer to int function 771 772 Collective on SNES 773 774 Available Routines: 775 + SNESCubicLineSearch() - default line search 776 . SNESQuadraticLineSearch() - quadratic line search 777 . SNESNoLineSearch() - the full Newton step (actually not a line search) 778 - SNESNoLineSearchNoNorms() - the full Newton step (calculating no norms; faster in parallel) 779 780 Options Database Keys: 781 + -snes_ls [cubic,quadratic,basic,basicnonorms] - Selects line search 782 . -snes_ls_alpha <alpha> - Sets alpha 783 . -snes_ls_maxstep <max> - Sets maxstep 784 - -snes_ls_steptol <steptol> - Sets steptol, this is the minimum step size that the line search code 785 will accept; min p[i]/x[i] < steptol. The -snes_stol <stol> is the minimum step length 786 the default convergence test will use and is based on 2-norm(p) < stol*2-norm(x) 787 788 Calling sequence of func: 789 .vb 790 func (SNES snes,void *lsctx,Vec x,Vec f,Vec g,Vec y,Vec w, 791 PetscReal fnorm,PetscReal *ynorm,PetscReal *gnorm,*flag) 792 .ve 793 794 Input parameters for func: 795 + snes - nonlinear context 796 . lsctx - optional user-defined context for line search 797 . x - current iterate 798 . f - residual evaluated at x 799 . y - search direction (contains new iterate on output) 800 . w - work vector 801 - fnorm - 2-norm of f 802 803 Output parameters for func: 804 + g - residual evaluated at new iterate y 805 . y - new iterate (contains search direction on input) 806 . gnorm - 2-norm of g 807 . ynorm - 2-norm of search length 808 - flag - set to 0 if the line search succeeds; a nonzero integer 809 on failure. 810 811 Level: advanced 812 813 .keywords: SNES, nonlinear, set, line search, routine 814 815 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), SNESNoLineSearch(), SNESNoLineSearchNoNorms(), 816 SNESSetLineSearchCheck(), SNESSetLineSearchParams(), SNESGetLineSearchParams() 817 @*/ 818 int SNESSetLineSearch(SNES snes,int (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*),void *lsctx) 819 { 820 int ierr,(*f)(SNES,int (*)(SNES,void*,Vec,Vec,Vec,Vec,Vec,PetscReal,PetscReal*,PetscReal*,int*),void*); 821 822 PetscFunctionBegin; 823 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearch_C",(void (**)(void))&f);CHKERRQ(ierr); 824 if (f) { 825 ierr = (*f)(snes,func,lsctx);CHKERRQ(ierr); 826 } 827 PetscFunctionReturn(0); 828 } 829 /* -------------------------------------------------------------------------- */ 830 EXTERN_C_BEGIN 831 #undef __FUNCT__ 832 #define __FUNCT__ "SNESSetLineSearch_LS" 833 int SNESSetLineSearch_LS(SNES snes,int (*func)(SNES,void*,Vec,Vec,Vec,Vec,Vec, 834 PetscReal,PetscReal*,PetscReal*,int*),void *lsctx) 835 { 836 PetscFunctionBegin; 837 ((SNES_LS *)(snes->data))->LineSearch = func; 838 ((SNES_LS *)(snes->data))->lsP = lsctx; 839 PetscFunctionReturn(0); 840 } 841 EXTERN_C_END 842 /* -------------------------------------------------------------------------- */ 843 #undef __FUNCT__ 844 #define __FUNCT__ "SNESSetLineSearchCheck" 845 /*@C 846 SNESSetLineSearchCheck - Sets a routine to check the validity of new iterate computed 847 by the line search routine in the Newton-based method SNESLS. 848 849 Input Parameters: 850 + snes - nonlinear context obtained from SNESCreate() 851 . func - pointer to int function 852 - checkctx - optional user-defined context for use by step checking routine 853 854 Collective on SNES 855 856 Calling sequence of func: 857 .vb 858 int func (SNES snes, void *checkctx, Vec x, PetscTruth *flag) 859 .ve 860 where func returns an error code of 0 on success and a nonzero 861 on failure. 862 863 Input parameters for func: 864 + snes - nonlinear context 865 . checkctx - optional user-defined context for use by step checking routine 866 - x - current candidate iterate 867 868 Output parameters for func: 869 + x - current iterate (possibly modified) 870 - flag - flag indicating whether x has been modified (either 871 PETSC_TRUE of PETSC_FALSE) 872 873 Level: advanced 874 875 Notes: 876 SNESNoLineSearch() and SNESNoLineSearchNoNorms() accept the new 877 iterate computed by the line search checking routine. In particular, 878 these routines (1) compute a candidate iterate u_{i+1}, (2) pass control 879 to the checking routine, and then (3) compute the corresponding nonlinear 880 function f(u_{i+1}) with the (possibly altered) iterate u_{i+1}. 881 882 SNESQuadraticLineSearch() and SNESCubicLineSearch() also accept the 883 new iterate computed by the line search checking routine. In particular, 884 these routines (1) compute a candidate iterate u_{i+1} as well as a 885 candidate nonlinear function f(u_{i+1}), (2) pass control to the checking 886 routine, and then (3) force a re-evaluation of f(u_{i+1}) if any changes 887 were made to the candidate iterate in the checking routine (as indicated 888 by flag=PETSC_TRUE). The overhead of this function re-evaluation can be 889 very costly, so use this feature with caution! 890 891 .keywords: SNES, nonlinear, set, line search check, step check, routine 892 893 .seealso: SNESSetLineSearch() 894 @*/ 895 int SNESSetLineSearchCheck(SNES snes,int (*func)(SNES,void*,Vec,PetscTruth*),void *checkctx) 896 { 897 int ierr,(*f)(SNES,int (*)(SNES,void*,Vec,PetscTruth*),void*); 898 899 PetscFunctionBegin; 900 ierr = PetscObjectQueryFunction((PetscObject)snes,"SNESSetLineSearchCheck_C",(void (**)(void))&f);CHKERRQ(ierr); 901 if (f) { 902 ierr = (*f)(snes,func,checkctx);CHKERRQ(ierr); 903 } 904 PetscFunctionReturn(0); 905 } 906 /* -------------------------------------------------------------------------- */ 907 EXTERN_C_BEGIN 908 #undef __FUNCT__ 909 #define __FUNCT__ "SNESSetLineSearchCheck_LS" 910 int SNESSetLineSearchCheck_LS(SNES snes,int (*func)(SNES,void*,Vec,PetscTruth*),void *checkctx) 911 { 912 PetscFunctionBegin; 913 ((SNES_LS *)(snes->data))->CheckStep = func; 914 ((SNES_LS *)(snes->data))->checkP = checkctx; 915 PetscFunctionReturn(0); 916 } 917 EXTERN_C_END 918 /* -------------------------------------------------------------------------- */ 919 /* 920 SNESPrintHelp_LS - Prints all options for the SNES_LS method. 921 922 Input Parameter: 923 . snes - the SNES context 924 925 Application Interface Routine: SNESPrintHelp() 926 */ 927 #undef __FUNCT__ 928 #define __FUNCT__ "SNESPrintHelp_LS" 929 static int SNESPrintHelp_LS(SNES snes,char *p) 930 { 931 SNES_LS *ls = (SNES_LS *)snes->data; 932 933 PetscFunctionBegin; 934 (*PetscHelpPrintf)(snes->comm," method SNES_LS (ls) for systems of nonlinear equations:\n"); 935 (*PetscHelpPrintf)(snes->comm," %ssnes_ls [cubic,quadratic,basic,basicnonorms,...]\n",p); 936 (*PetscHelpPrintf)(snes->comm," %ssnes_ls_alpha <alpha> (default %g)\n",p,ls->alpha); 937 (*PetscHelpPrintf)(snes->comm," %ssnes_ls_maxstep <max> (default %g)\n",p,ls->maxstep); 938 (*PetscHelpPrintf)(snes->comm," %ssnes_ls_steptol <tol> (default %g)\n",p,ls->steptol); 939 PetscFunctionReturn(0); 940 } 941 942 /* 943 SNESView_LS - Prints info from the SNESLS data structure. 944 945 Input Parameters: 946 . SNES - the SNES context 947 . viewer - visualization context 948 949 Application Interface Routine: SNESView() 950 */ 951 #undef __FUNCT__ 952 #define __FUNCT__ "SNESView_LS" 953 static int SNESView_LS(SNES snes,PetscViewer viewer) 954 { 955 SNES_LS *ls = (SNES_LS *)snes->data; 956 char *cstr; 957 int ierr; 958 PetscTruth isascii; 959 960 PetscFunctionBegin; 961 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr); 962 if (isascii) { 963 if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch"; 964 else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch"; 965 else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch"; 966 else cstr = "unknown"; 967 ierr = PetscViewerASCIIPrintf(viewer," line search variant: %s\n",cstr);CHKERRQ(ierr); 968 ierr = PetscViewerASCIIPrintf(viewer," alpha=%g, maxstep=%g, steptol=%g\n",ls->alpha,ls->maxstep,ls->steptol);CHKERRQ(ierr); 969 } else { 970 SETERRQ1(1,"Viewer type %s not supported for SNES EQ LS",((PetscObject)viewer)->type_name); 971 } 972 PetscFunctionReturn(0); 973 } 974 /* -------------------------------------------------------------------------- */ 975 /* 976 SNESSetFromOptions_LS - Sets various parameters for the SNESLS method. 977 978 Input Parameter: 979 . snes - the SNES context 980 981 Application Interface Routine: SNESSetFromOptions() 982 */ 983 #undef __FUNCT__ 984 #define __FUNCT__ "SNESSetFromOptions_LS" 985 static int SNESSetFromOptions_LS(SNES snes) 986 { 987 SNES_LS *ls = (SNES_LS *)snes->data; 988 char ver[16],*lses[] = {"basic","basicnonorms","quadratic","cubic"}; 989 int ierr; 990 PetscTruth flg; 991 992 PetscFunctionBegin; 993 ierr = PetscOptionsHead("SNES Line search options");CHKERRQ(ierr); 994 ierr = PetscOptionsReal("-snes_ls_alpha","Function norm must decrease by","None",ls->alpha,&ls->alpha,0);CHKERRQ(ierr); 995 ierr = PetscOptionsReal("-snes_ls_maxstep","Step must be less than","None",ls->maxstep,&ls->maxstep,0);CHKERRQ(ierr); 996 ierr = PetscOptionsReal("-snes_ls_steptol","Step must be greater than","None",ls->steptol,&ls->steptol,0);CHKERRQ(ierr); 997 998 ierr = PetscOptionsEList("-snes_ls","Line search used","SNESSetLineSearch",lses,4,"cubic",ver,16,&flg);CHKERRQ(ierr); 999 if (flg) { 1000 PetscTruth isbasic,isnonorms,isquad,iscubic; 1001 1002 ierr = PetscStrcmp(ver,lses[0],&isbasic);CHKERRQ(ierr); 1003 ierr = PetscStrcmp(ver,lses[1],&isnonorms);CHKERRQ(ierr); 1004 ierr = PetscStrcmp(ver,lses[2],&isquad);CHKERRQ(ierr); 1005 ierr = PetscStrcmp(ver,lses[3],&iscubic);CHKERRQ(ierr); 1006 1007 if (isbasic) { 1008 ierr = SNESSetLineSearch(snes,SNESNoLineSearch,PETSC_NULL);CHKERRQ(ierr); 1009 } else if (isnonorms) { 1010 ierr = SNESSetLineSearch(snes,SNESNoLineSearchNoNorms,PETSC_NULL);CHKERRQ(ierr); 1011 } else if (isquad) { 1012 ierr = SNESSetLineSearch(snes,SNESQuadraticLineSearch,PETSC_NULL);CHKERRQ(ierr); 1013 } else if (iscubic) { 1014 ierr = SNESSetLineSearch(snes,SNESCubicLineSearch,PETSC_NULL);CHKERRQ(ierr); 1015 } 1016 else {SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown line search");} 1017 } 1018 ierr = PetscOptionsTail();CHKERRQ(ierr); 1019 PetscFunctionReturn(0); 1020 } 1021 /* -------------------------------------------------------------------------- */ 1022 /* 1023 SNESCreate_LS - Creates a nonlinear solver context for the SNESLS method, 1024 SNES_LS, and sets this as the private data within the generic nonlinear solver 1025 context, SNES, that was created within SNESCreate(). 1026 1027 1028 Input Parameter: 1029 . snes - the SNES context 1030 1031 Application Interface Routine: SNESCreate() 1032 */ 1033 EXTERN_C_BEGIN 1034 #undef __FUNCT__ 1035 #define __FUNCT__ "SNESCreate_LS" 1036 int SNESCreate_LS(SNES snes) 1037 { 1038 int ierr; 1039 SNES_LS *neP; 1040 1041 PetscFunctionBegin; 1042 snes->setup = SNESSetUp_LS; 1043 snes->solve = SNESSolve_LS; 1044 snes->destroy = SNESDestroy_LS; 1045 snes->converged = SNESConverged_LS; 1046 snes->printhelp = SNESPrintHelp_LS; 1047 snes->setfromoptions = SNESSetFromOptions_LS; 1048 snes->view = SNESView_LS; 1049 snes->nwork = 0; 1050 1051 ierr = PetscNew(SNES_LS,&neP);CHKERRQ(ierr); 1052 PetscLogObjectMemory(snes,sizeof(SNES_LS)); 1053 snes->data = (void*)neP; 1054 neP->alpha = 1.e-4; 1055 neP->maxstep = 1.e8; 1056 neP->steptol = 1.e-12; 1057 neP->LineSearch = SNESCubicLineSearch; 1058 neP->lsP = PETSC_NULL; 1059 neP->CheckStep = PETSC_NULL; 1060 neP->checkP = PETSC_NULL; 1061 1062 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearch_C","SNESSetLineSearch_LS",SNESSetLineSearch_LS);CHKERRQ(ierr); 1063 ierr = PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESSetLineSearchCheck_C","SNESSetLineSearchCheck_LS",SNESSetLineSearchCheck_LS);CHKERRQ(ierr); 1064 1065 PetscFunctionReturn(0); 1066 } 1067 EXTERN_C_END 1068 1069 1070 1071