1 #ifdef PETSC_RCS_HEADER 2 static char vcid[] = "$Id: ls.c,v 1.92 1997/07/09 20:59:51 balay Exp curfman $"; 3 #endif 4 5 #include <math.h> 6 #include "src/snes/impls/ls/ls.h" 7 #include "pinclude/pviewer.h" 8 9 /* 10 Implements a line search variant of Newton's Method 11 for solving systems of nonlinear equations. 12 13 Input parameters: 14 . snes - nonlinear context obtained from SNESCreate() 15 16 Output Parameters: 17 . outits - Number of global iterations until termination. 18 19 Notes: 20 This implements essentially a truncated Newton method with a 21 line search. By default a cubic backtracking line search 22 is employed, as described in the text "Numerical Methods for 23 Unconstrained Optimization and Nonlinear Equations" by Dennis 24 and Schnabel. 25 */ 26 27 #undef __FUNC__ 28 #define __FUNC__ "SNESSolve_EQ_LS" 29 int SNESSolve_EQ_LS(SNES snes,int *outits) 30 { 31 SNES_LS *neP = (SNES_LS *) snes->data; 32 int maxits, i, history_len, ierr, lits, lsfail; 33 MatStructure flg = DIFFERENT_NONZERO_PATTERN; 34 double fnorm, gnorm, xnorm, ynorm, *history; 35 Vec Y, X, F, G, W, TMP; 36 37 history = snes->conv_hist; /* convergence history */ 38 history_len = snes->conv_hist_size; /* convergence history length */ 39 maxits = snes->max_its; /* maximum number of iterations */ 40 X = snes->vec_sol; /* solution vector */ 41 F = snes->vec_func; /* residual vector */ 42 Y = snes->work[0]; /* work vectors */ 43 G = snes->work[1]; 44 W = snes->work[2]; 45 46 snes->iter = 0; 47 ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* F(X) */ 48 ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr); /* fnorm <- ||F|| */ 49 snes->norm = fnorm; 50 if (history) history[0] = fnorm; 51 SNESMonitor(snes,0,fnorm); 52 53 if (fnorm < snes->atol) {*outits = 0; return 0;} 54 55 /* set parameter for default relative tolerance convergence test */ 56 snes->ttol = fnorm*snes->rtol; 57 58 for ( i=0; i<maxits; i++ ) { 59 snes->iter = i+1; 60 61 /* Solve J Y = F, where J is Jacobian matrix */ 62 ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg); CHKERRQ(ierr); 63 ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr); 64 ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr); 65 snes->linear_its += PetscAbsInt(lits); 66 PLogInfo(snes,"SNESSolve_EQ_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits); 67 68 /* Compute a (scaled) negative update in the line search routine: 69 Y <- X - lambda*Y 70 and evaluate G(Y) = function(Y)) 71 */ 72 ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr); 73 ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); CHKERRQ(ierr); 74 PLogInfo(snes,"SNESSolve_EQ_LS: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail); 75 if (lsfail) snes->nfailures++; 76 77 TMP = F; F = G; snes->vec_func_always = F; G = TMP; 78 TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 79 fnorm = gnorm; 80 81 snes->norm = fnorm; 82 if (history && history_len > i+1) history[i+1] = fnorm; 83 SNESMonitor(snes,i+1,fnorm); 84 85 /* Test for convergence */ 86 if (snes->converged) { 87 ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 88 if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) { 89 break; 90 } 91 } 92 } 93 if (X != snes->vec_sol) { 94 ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr); 95 snes->vec_sol_always = snes->vec_sol; 96 snes->vec_func_always = snes->vec_func; 97 } 98 if (i == maxits) { 99 PLogInfo(snes, 100 "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits); 101 i--; 102 } 103 if (history) snes->conv_act_size = (history_len < i+1) ? history_len : i+1; 104 *outits = i+1; 105 return 0; 106 } 107 /* ------------------------------------------------------------ */ 108 #undef __FUNC__ 109 #define __FUNC__ "SNESSetUp_EQ_LS" 110 int SNESSetUp_EQ_LS(SNES snes ) 111 { 112 int ierr; 113 snes->nwork = 4; 114 ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr); 115 PLogObjectParents(snes,snes->nwork,snes->work); 116 snes->vec_sol_update_always = snes->work[3]; 117 return 0; 118 } 119 /* ------------------------------------------------------------ */ 120 #undef __FUNC__ 121 #define __FUNC__ "SNESDestroy_EQ_LS" /* ADIC Ignore */ 122 int SNESDestroy_EQ_LS(PetscObject obj) 123 { 124 SNES snes = (SNES) obj; 125 int ierr; 126 if (snes->nwork) { 127 ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr); 128 } 129 PetscFree(snes->data); 130 return 0; 131 } 132 /* ------------------------------------------------------------ */ 133 #undef __FUNC__ 134 #define __FUNC__ "SNESNoLineSearch" 135 /*ARGSUSED*/ 136 /*@C 137 SNESNoLineSearch - This routine is not a line search at all; 138 it simply uses the full Newton step. Thus, this routine is intended 139 to serve as a template and is not recommended for general use. 140 141 Input Parameters: 142 . snes - nonlinear context 143 . x - current iterate 144 . f - residual evaluated at x 145 . y - search direction (contains new iterate on output) 146 . w - work vector 147 . fnorm - 2-norm of f 148 149 Output Parameters: 150 . g - residual evaluated at new iterate y 151 . y - new iterate (contains search direction on input) 152 . gnorm - 2-norm of g 153 . ynorm - 2-norm of search length 154 . flag - set to 0, indicating a successful line search 155 156 Options Database Key: 157 $ -snes_eq_ls basic 158 159 .keywords: SNES, nonlinear, line search, cubic 160 161 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 162 SNESSetLineSearch() 163 @*/ 164 int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 165 double fnorm, double *ynorm, double *gnorm,int *flag ) 166 { 167 int ierr; 168 Scalar mone = -1.0; 169 170 *flag = 0; 171 PLogEventBegin(SNES_LineSearch,snes,x,f,g); 172 ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr); /* ynorm = || y || */ 173 ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr); /* y <- y - x */ 174 ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y) */ 175 ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); /* gnorm = || g || */ 176 PLogEventEnd(SNES_LineSearch,snes,x,f,g); 177 return 0; 178 } 179 /* ------------------------------------------------------------------ */ 180 #undef __FUNC__ 181 #define __FUNC__ "SNESNoLineSearchNoNorms" 182 /*ARGSUSED*/ 183 /*@C 184 SNESNoLineSearchNoNorms - This routine is not a line search at 185 all; it simply uses the full Newton step. This version does not 186 even compute the norm of the function or search direction; this 187 is intended only when you know the full step is fine and are 188 not checking for convergence of the nonlinear iteration (for 189 example, you are running always for a fixed number of Newton 190 steps). 191 192 Input Parameters: 193 . snes - nonlinear context 194 . x - current iterate 195 . f - residual evaluated at x 196 . y - search direction (contains new iterate on output) 197 . w - work vector 198 . fnorm - 2-norm of f 199 200 Output Parameters: 201 . g - residual evaluated at new iterate y 202 . gnorm - not changed 203 . ynorm - not changed 204 . flag - set to 0, indicating a successful line search 205 206 Options Database Key: 207 $ -snes_eq_ls basicnonorms 208 209 .keywords: SNES, nonlinear, line search, cubic 210 211 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 212 SNESSetLineSearch(), SNESNoLineSearch() 213 @*/ 214 int SNESNoLineSearchNoNorms(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 215 double fnorm, double *ynorm, double *gnorm,int *flag ) 216 { 217 int ierr; 218 Scalar mone = -1.0; 219 220 *flag = 0; 221 PLogEventBegin(SNES_LineSearch,snes,x,f,g); 222 ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr); /* y <- y - x */ 223 ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y) */ 224 PLogEventEnd(SNES_LineSearch,snes,x,f,g); 225 return 0; 226 } 227 /* ------------------------------------------------------------------ */ 228 #undef __FUNC__ 229 #define __FUNC__ "SNESCubicLineSearch" 230 /*@C 231 SNESCubicLineSearch - Performs a cubic line search (default line search method). 232 233 Input Parameters: 234 . snes - nonlinear context 235 . x - current iterate 236 . f - residual evaluated at x 237 . y - search direction (contains new iterate on output) 238 . w - work vector 239 . fnorm - 2-norm of f 240 241 Output Parameters: 242 . g - residual evaluated at new iterate y 243 . y - new iterate (contains search direction on input) 244 . gnorm - 2-norm of g 245 . ynorm - 2-norm of search length 246 . flag - 0 if line search succeeds; -1 on failure. 247 248 Options Database Key: 249 $ -snes_eq_ls cubic 250 251 Notes: 252 This line search is taken from "Numerical Methods for Unconstrained 253 Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 254 255 .keywords: SNES, nonlinear, line search, cubic 256 257 .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 258 @*/ 259 int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w, 260 double fnorm,double *ynorm,double *gnorm,int *flag) 261 { 262 /* 263 Note that for line search purposes we work with with the related 264 minimization problem: 265 min z(x): R^n -> R, 266 where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2. 267 */ 268 269 double steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2; 270 double maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg; 271 #if defined(PETSC_COMPLEX) 272 Scalar cinitslope, clambda; 273 #endif 274 int ierr, count; 275 SNES_LS *neP = (SNES_LS *) snes->data; 276 Scalar mone = -1.0,scale; 277 278 PLogEventBegin(SNES_LineSearch,snes,x,f,g); 279 *flag = 0; 280 alpha = neP->alpha; 281 maxstep = neP->maxstep; 282 steptol = neP->steptol; 283 284 ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr); 285 if (*ynorm < snes->atol) { 286 PLogInfo(snes,"SNESCubicLineSearch: Search direction and size are nearly 0\n"); 287 *gnorm = fnorm; 288 ierr = VecCopy(x,y); CHKERRQ(ierr); 289 ierr = VecCopy(f,g); CHKERRQ(ierr); 290 goto theend1; 291 } 292 if (*ynorm > maxstep) { /* Step too big, so scale back */ 293 scale = maxstep/(*ynorm); 294 #if defined(PETSC_COMPLEX) 295 PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale)); 296 #else 297 PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale); 298 #endif 299 ierr = VecScale(&scale,y); CHKERRQ(ierr); 300 *ynorm = maxstep; 301 } 302 minlambda = steptol/(*ynorm); 303 ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 304 #if defined(PETSC_COMPLEX) 305 ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 306 initslope = real(cinitslope); 307 #else 308 ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 309 #endif 310 if (initslope > 0.0) initslope = -initslope; 311 if (initslope == 0.0) initslope = -1.0; 312 313 ierr = VecCopy(y,w); CHKERRQ(ierr); 314 ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 315 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 316 ierr = VecNorm(g,NORM_2,gnorm); 317 if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* Sufficient reduction */ 318 ierr = VecCopy(w,y); CHKERRQ(ierr); 319 PLogInfo(snes,"SNESCubicLineSearch: Using full step\n"); 320 goto theend1; 321 } 322 323 /* Fit points with quadratic */ 324 lambda = 1.0; count = 0; 325 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 326 lambdaprev = lambda; 327 gnormprev = *gnorm; 328 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 329 else lambda = lambdatemp; 330 ierr = VecCopy(x,w); CHKERRQ(ierr); 331 lambdaneg = -lambda; 332 #if defined(PETSC_COMPLEX) 333 clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 334 #else 335 ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 336 #endif 337 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 338 ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 339 if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* sufficient reduction */ 340 ierr = VecCopy(w,y); CHKERRQ(ierr); 341 PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda); 342 goto theend1; 343 } 344 345 /* Fit points with cubic */ 346 count = 1; 347 while (1) { 348 if (lambda <= minlambda) { /* bad luck; use full step */ 349 PLogInfo(snes,"SNESCubicLineSearch:Unable to find good step length! %d \n",count); 350 PLogInfo(snes,"SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 351 fnorm,*gnorm,*ynorm,lambda,initslope); 352 ierr = VecCopy(w,y); CHKERRQ(ierr); 353 *flag = -1; break; 354 } 355 t1 = ((*gnorm)*(*gnorm) - fnorm*fnorm)*0.5 - lambda*initslope; 356 t2 = (gnormprev*gnormprev - fnorm*fnorm)*0.5 - lambdaprev*initslope; 357 a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 358 b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 359 d = b*b - 3*a*initslope; 360 if (d < 0.0) d = 0.0; 361 if (a == 0.0) { 362 lambdatemp = -initslope/(2.0*b); 363 } else { 364 lambdatemp = (-b + sqrt(d))/(3.0*a); 365 } 366 if (lambdatemp > .5*lambda) { 367 lambdatemp = .5*lambda; 368 } 369 lambdaprev = lambda; 370 gnormprev = *gnorm; 371 if (lambdatemp <= .1*lambda) { 372 lambda = .1*lambda; 373 } 374 else lambda = lambdatemp; 375 ierr = VecCopy( x, w ); CHKERRQ(ierr); 376 lambdaneg = -lambda; 377 #if defined(PETSC_COMPLEX) 378 clambda = lambdaneg; 379 ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 380 #else 381 ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 382 #endif 383 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 384 ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 385 if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* is reduction enough? */ 386 ierr = VecCopy(w,y); CHKERRQ(ierr); 387 PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda); 388 goto theend1; 389 } else { 390 PLogInfo(snes,"SNESCubicLineSearch: Cubic step no good, shrinking lambda, lambda=%g\n",lambda); 391 } 392 count++; 393 } 394 theend1: 395 PLogEventEnd(SNES_LineSearch,snes,x,f,g); 396 return 0; 397 } 398 /* ------------------------------------------------------------------ */ 399 #undef __FUNC__ 400 #define __FUNC__ "SNESQuadraticLineSearch" 401 /*@C 402 SNESQuadraticLineSearch - Performs a quadratic line search. 403 404 Input Parameters: 405 . snes - the SNES context 406 . x - current iterate 407 . f - residual evaluated at x 408 . y - search direction (contains new iterate on output) 409 . w - work vector 410 . fnorm - 2-norm of f 411 412 Output Parameters: 413 . g - residual evaluated at new iterate y 414 . y - new iterate (contains search direction on input) 415 . gnorm - 2-norm of g 416 . ynorm - 2-norm of search length 417 . flag - 0 if line search succeeds; -1 on failure. 418 419 Options Database Key: 420 $ -snes_eq_ls quadratic 421 422 Notes: 423 Use SNESSetLineSearch() 424 to set this routine within the SNES_EQ_LS method. 425 426 .keywords: SNES, nonlinear, quadratic, line search 427 428 .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 429 @*/ 430 int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 431 double fnorm, double *ynorm, double *gnorm,int *flag) 432 { 433 /* 434 Note that for line search purposes we work with with the related 435 minimization problem: 436 min z(x): R^n -> R, 437 where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2. 438 */ 439 double steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp; 440 #if defined(PETSC_COMPLEX) 441 Scalar cinitslope,clambda; 442 #endif 443 int ierr,count; 444 SNES_LS *neP = (SNES_LS *) snes->data; 445 Scalar mone = -1.0,scale; 446 447 PLogEventBegin(SNES_LineSearch,snes,x,f,g); 448 *flag = 0; 449 alpha = neP->alpha; 450 maxstep = neP->maxstep; 451 steptol = neP->steptol; 452 453 VecNorm(y, NORM_2,ynorm ); 454 if (*ynorm == 0.0) { 455 PLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n"); 456 goto theend2; 457 } 458 if (*ynorm > maxstep) { /* Step too big, so scale back */ 459 scale = maxstep/(*ynorm); 460 ierr = VecScale(&scale,y); CHKERRQ(ierr); 461 *ynorm = maxstep; 462 } 463 minlambda = steptol/(*ynorm); 464 ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 465 #if defined(PETSC_COMPLEX) 466 ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 467 initslope = real(cinitslope); 468 #else 469 ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 470 #endif 471 if (initslope > 0.0) initslope = -initslope; 472 if (initslope == 0.0) initslope = -1.0; 473 474 ierr = VecCopy(y,w); CHKERRQ(ierr); 475 ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 476 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 477 ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 478 if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* Sufficient reduction */ 479 ierr = VecCopy(w,y); CHKERRQ(ierr); 480 PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n"); 481 goto theend2; 482 } 483 484 /* Fit points with quadratic */ 485 lambda = 1.0; count = 0; 486 count = 1; 487 while (1) { 488 if (lambda <= minlambda) { /* bad luck; use full step */ 489 PLogInfo(snes, 490 "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 491 PLogInfo(snes, 492 "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 493 fnorm,*gnorm,*ynorm,lambda,initslope); 494 ierr = VecCopy(w,y); CHKERRQ(ierr); 495 *flag = -1; break; 496 } 497 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 498 lambdaprev = lambda; 499 gnormprev = *gnorm; 500 if (lambdatemp <= .1*lambda) { 501 lambda = .1*lambda; 502 } else lambda = lambdatemp; 503 ierr = VecCopy(x,w); CHKERRQ(ierr); 504 lambda = -lambda; 505 #if defined(PETSC_COMPLEX) 506 clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 507 #else 508 ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 509 #endif 510 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 511 ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 512 if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* sufficient reduction */ 513 ierr = VecCopy(w,y); CHKERRQ(ierr); 514 PLogInfo(snes, 515 "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda); 516 break; 517 } 518 count++; 519 } 520 theend2: 521 PLogEventEnd(SNES_LineSearch,snes,x,f,g); 522 return 0; 523 } 524 /* ------------------------------------------------------------ */ 525 #undef __FUNC__ 526 #define __FUNC__ "SNESSetLineSearch" /* ADIC Ignore */ 527 /*@C 528 SNESSetLineSearch - Sets the line search routine to be used 529 by the method SNES_EQ_LS. 530 531 Input Parameters: 532 . snes - nonlinear context obtained from SNESCreate() 533 . func - pointer to int function 534 535 Available Routines: 536 . SNESCubicLineSearch() - default line search 537 . SNESQuadraticLineSearch() - quadratic line search 538 . SNESNoLineSearch() - the full Newton step (actually not a line search) 539 540 Options Database Keys: 541 $ -snes_eq_ls [basic,quadratic,cubic] 542 $ -snes_eq_ls_alpha <alpha> 543 $ -snes_eq_ls_maxstep <max> 544 $ -snes_eq_ls_steptol <steptol> 545 546 Calling sequence of func: 547 func (SNES snes, Vec x, Vec f, Vec g, Vec y, 548 Vec w, double fnorm, double *ynorm, 549 double *gnorm, *flag) 550 551 Input parameters for func: 552 . snes - nonlinear context 553 . x - current iterate 554 . f - residual evaluated at x 555 . y - search direction (contains new iterate on output) 556 . w - work vector 557 . fnorm - 2-norm of f 558 559 Output parameters for func: 560 . g - residual evaluated at new iterate y 561 . y - new iterate (contains search direction on input) 562 . gnorm - 2-norm of g 563 . ynorm - 2-norm of search length 564 . flag - set to 0 if the line search succeeds; a nonzero integer 565 on failure. 566 567 .keywords: SNES, nonlinear, set, line search, routine 568 569 .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch() 570 @*/ 571 int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 572 double,double*,double*,int*)) 573 { 574 if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func; 575 return 0; 576 } 577 /* ------------------------------------------------------------------ */ 578 #undef __FUNC__ 579 #define __FUNC__ "SNESPrintHelp_EQ_LS" /* ADIC Ignore */ 580 static int SNESPrintHelp_EQ_LS(SNES snes,char *p) 581 { 582 SNES_LS *ls = (SNES_LS *)snes->data; 583 584 PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n"); 585 PetscPrintf(snes->comm," %ssnes_eq_ls [basic,quadratic,cubic]\n",p); 586 PetscPrintf(snes->comm," %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha); 587 PetscPrintf(snes->comm," %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep); 588 PetscPrintf(snes->comm," %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol); 589 return 0; 590 } 591 /* ------------------------------------------------------------------ */ 592 #undef __FUNC__ 593 #define __FUNC__ "SNESView_EQ_LS" /* ADIC Ignore */ 594 static int SNESView_EQ_LS(PetscObject obj,Viewer viewer) 595 { 596 SNES snes = (SNES)obj; 597 SNES_LS *ls = (SNES_LS *)snes->data; 598 FILE *fd; 599 char *cstr; 600 int ierr; 601 ViewerType vtype; 602 603 ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 604 if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 605 ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 606 if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch"; 607 else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch"; 608 else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch"; 609 else cstr = "unknown"; 610 PetscFPrintf(snes->comm,fd," line search variant: %s\n",cstr); 611 PetscFPrintf(snes->comm,fd," alpha=%g, maxstep=%g, steptol=%g\n", 612 ls->alpha,ls->maxstep,ls->steptol); 613 } 614 return 0; 615 } 616 /* ------------------------------------------------------------------ */ 617 #undef __FUNC__ 618 #define __FUNC__ "SNESSetFromOptions_EQ_LS" 619 static int SNESSetFromOptions_EQ_LS(SNES snes) 620 { 621 SNES_LS *ls = (SNES_LS *)snes->data; 622 char ver[16]; 623 double tmp; 624 int ierr,flg; 625 626 ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr); 627 if (flg) { 628 ls->alpha = tmp; 629 } 630 ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr); 631 if (flg) { 632 ls->maxstep = tmp; 633 } 634 ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr); 635 if (flg) { 636 ls->steptol = tmp; 637 } 638 ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr); 639 if (flg) { 640 if (!PetscStrcmp(ver,"basic")) { 641 SNESSetLineSearch(snes,SNESNoLineSearch); 642 } 643 else if (!PetscStrcmp(ver,"basicnonorms")) { 644 SNESSetLineSearch(snes,SNESNoLineSearchNoNorms); 645 } 646 else if (!PetscStrcmp(ver,"quadratic")) { 647 SNESSetLineSearch(snes,SNESQuadraticLineSearch); 648 } 649 else if (!PetscStrcmp(ver,"cubic")) { 650 SNESSetLineSearch(snes,SNESCubicLineSearch); 651 } 652 else {SETERRQ(1,0,"Unknown line search");} 653 } 654 return 0; 655 } 656 /* ------------------------------------------------------------ */ 657 #undef __FUNC__ 658 #define __FUNC__ "SNESCreate_EQ_LS" 659 int SNESCreate_EQ_LS(SNES snes ) 660 { 661 SNES_LS *neP; 662 663 if (snes->method_class != SNES_NONLINEAR_EQUATIONS) SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only"); 664 snes->type = SNES_EQ_LS; 665 snes->setup = SNESSetUp_EQ_LS; 666 snes->solve = SNESSolve_EQ_LS; 667 snes->destroy = SNESDestroy_EQ_LS; 668 snes->converged = SNESConverged_EQ_LS; 669 snes->printhelp = SNESPrintHelp_EQ_LS; 670 snes->setfromoptions = SNESSetFromOptions_EQ_LS; 671 snes->view = SNESView_EQ_LS; 672 snes->nwork = 0; 673 674 neP = PetscNew(SNES_LS); CHKPTRQ(neP); 675 PLogObjectMemory(snes,sizeof(SNES_LS)); 676 snes->data = (void *) neP; 677 neP->alpha = 1.e-4; 678 neP->maxstep = 1.e8; 679 neP->steptol = 1.e-12; 680 neP->LineSearch = SNESCubicLineSearch; 681 return 0; 682 } 683 684