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