1 #ifndef lint 2 static char vcid[] = "$Id: ls.c,v 1.90 1997/04/21 21:33:08 curfman Exp bsmith $"; 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 == 0.0) {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 == 0.0) { 286 PLogInfo(snes,"SNESCubicLineSearch: Search direction and size is 0\n"); 287 goto theend1; 288 } 289 if (*ynorm > maxstep) { /* Step too big, so scale back */ 290 scale = maxstep/(*ynorm); 291 #if defined(PETSC_COMPLEX) 292 PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale)); 293 #else 294 PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale); 295 #endif 296 ierr = VecScale(&scale,y); CHKERRQ(ierr); 297 *ynorm = maxstep; 298 } 299 minlambda = steptol/(*ynorm); 300 ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 301 #if defined(PETSC_COMPLEX) 302 ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 303 initslope = real(cinitslope); 304 #else 305 ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 306 #endif 307 if (initslope > 0.0) initslope = -initslope; 308 if (initslope == 0.0) initslope = -1.0; 309 310 ierr = VecCopy(y,w); CHKERRQ(ierr); 311 ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 312 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 313 ierr = VecNorm(g,NORM_2,gnorm); 314 if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* Sufficient reduction */ 315 ierr = VecCopy(w,y); CHKERRQ(ierr); 316 PLogInfo(snes,"SNESCubicLineSearch: Using full step\n"); 317 goto theend1; 318 } 319 320 /* Fit points with quadratic */ 321 lambda = 1.0; count = 0; 322 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 323 lambdaprev = lambda; 324 gnormprev = *gnorm; 325 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 326 else lambda = lambdatemp; 327 ierr = VecCopy(x,w); CHKERRQ(ierr); 328 lambdaneg = -lambda; 329 #if defined(PETSC_COMPLEX) 330 clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 331 #else 332 ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 333 #endif 334 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 335 ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 336 if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* sufficient reduction */ 337 ierr = VecCopy(w,y); CHKERRQ(ierr); 338 PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda); 339 goto theend1; 340 } 341 342 /* Fit points with cubic */ 343 count = 1; 344 while (1) { 345 if (lambda <= minlambda) { /* bad luck; use full step */ 346 PLogInfo(snes,"SNESCubicLineSearch:Unable to find good step length! %d \n",count); 347 PLogInfo(snes,"SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 348 fnorm,*gnorm,*ynorm,lambda,initslope); 349 ierr = VecCopy(w,y); CHKERRQ(ierr); 350 *flag = -1; break; 351 } 352 t1 = ((*gnorm)*(*gnorm) - fnorm*fnorm)*0.5 - lambda*initslope; 353 t2 = (gnormprev*gnormprev - fnorm*fnorm)*0.5 - lambdaprev*initslope; 354 a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 355 b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 356 d = b*b - 3*a*initslope; 357 if (d < 0.0) d = 0.0; 358 if (a == 0.0) { 359 lambdatemp = -initslope/(2.0*b); 360 } else { 361 lambdatemp = (-b + sqrt(d))/(3.0*a); 362 } 363 if (lambdatemp > .5*lambda) { 364 lambdatemp = .5*lambda; 365 } 366 lambdaprev = lambda; 367 gnormprev = *gnorm; 368 if (lambdatemp <= .1*lambda) { 369 lambda = .1*lambda; 370 } 371 else lambda = lambdatemp; 372 ierr = VecCopy( x, w ); CHKERRQ(ierr); 373 lambdaneg = -lambda; 374 #if defined(PETSC_COMPLEX) 375 clambda = lambdaneg; 376 ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 377 #else 378 ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 379 #endif 380 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 381 ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 382 if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* is reduction enough? */ 383 ierr = VecCopy(w,y); CHKERRQ(ierr); 384 PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda); 385 goto theend1; 386 } else { 387 PLogInfo(snes,"SNESCubicLineSearch: Cubic step no good, shrinking lambda, lambda=%g\n",lambda); 388 } 389 count++; 390 } 391 theend1: 392 PLogEventEnd(SNES_LineSearch,snes,x,f,g); 393 return 0; 394 } 395 /* ------------------------------------------------------------------ */ 396 #undef __FUNC__ 397 #define __FUNC__ "SNESQuadraticLineSearch" 398 /*@C 399 SNESQuadraticLineSearch - Performs a quadratic line search. 400 401 Input Parameters: 402 . snes - the SNES context 403 . x - current iterate 404 . f - residual evaluated at x 405 . y - search direction (contains new iterate on output) 406 . w - work vector 407 . fnorm - 2-norm of f 408 409 Output Parameters: 410 . g - residual evaluated at new iterate y 411 . y - new iterate (contains search direction on input) 412 . gnorm - 2-norm of g 413 . ynorm - 2-norm of search length 414 . flag - 0 if line search succeeds; -1 on failure. 415 416 Options Database Key: 417 $ -snes_eq_ls quadratic 418 419 Notes: 420 Use SNESSetLineSearch() 421 to set this routine within the SNES_EQ_LS method. 422 423 .keywords: SNES, nonlinear, quadratic, line search 424 425 .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 426 @*/ 427 int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 428 double fnorm, double *ynorm, double *gnorm,int *flag) 429 { 430 /* 431 Note that for line search purposes we work with with the related 432 minimization problem: 433 min z(x): R^n -> R, 434 where z(x) = .5 * fnorm*fnorm, and fnorm = || f ||_2. 435 */ 436 double steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp; 437 #if defined(PETSC_COMPLEX) 438 Scalar cinitslope,clambda; 439 #endif 440 int ierr,count; 441 SNES_LS *neP = (SNES_LS *) snes->data; 442 Scalar mone = -1.0,scale; 443 444 PLogEventBegin(SNES_LineSearch,snes,x,f,g); 445 *flag = 0; 446 alpha = neP->alpha; 447 maxstep = neP->maxstep; 448 steptol = neP->steptol; 449 450 VecNorm(y, NORM_2,ynorm ); 451 if (*ynorm == 0.0) { 452 PLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n"); 453 goto theend2; 454 } 455 if (*ynorm > maxstep) { /* Step too big, so scale back */ 456 scale = maxstep/(*ynorm); 457 ierr = VecScale(&scale,y); CHKERRQ(ierr); 458 *ynorm = maxstep; 459 } 460 minlambda = steptol/(*ynorm); 461 ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 462 #if defined(PETSC_COMPLEX) 463 ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 464 initslope = real(cinitslope); 465 #else 466 ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 467 #endif 468 if (initslope > 0.0) initslope = -initslope; 469 if (initslope == 0.0) initslope = -1.0; 470 471 ierr = VecCopy(y,w); CHKERRQ(ierr); 472 ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 473 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 474 ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 475 if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* Sufficient reduction */ 476 ierr = VecCopy(w,y); CHKERRQ(ierr); 477 PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n"); 478 goto theend2; 479 } 480 481 /* Fit points with quadratic */ 482 lambda = 1.0; count = 0; 483 count = 1; 484 while (1) { 485 if (lambda <= minlambda) { /* bad luck; use full step */ 486 PLogInfo(snes, 487 "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 488 PLogInfo(snes, 489 "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 490 fnorm,*gnorm,*ynorm,lambda,initslope); 491 ierr = VecCopy(w,y); CHKERRQ(ierr); 492 *flag = -1; break; 493 } 494 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 495 lambdaprev = lambda; 496 gnormprev = *gnorm; 497 if (lambdatemp <= .1*lambda) { 498 lambda = .1*lambda; 499 } else lambda = lambdatemp; 500 ierr = VecCopy(x,w); CHKERRQ(ierr); 501 lambda = -lambda; 502 #if defined(PETSC_COMPLEX) 503 clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 504 #else 505 ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 506 #endif 507 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 508 ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 509 if ((*gnorm)*(*gnorm)*0.5 <= fnorm*fnorm*0.5 + alpha*initslope) { /* sufficient reduction */ 510 ierr = VecCopy(w,y); CHKERRQ(ierr); 511 PLogInfo(snes, 512 "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda); 513 break; 514 } 515 count++; 516 } 517 theend2: 518 PLogEventEnd(SNES_LineSearch,snes,x,f,g); 519 return 0; 520 } 521 /* ------------------------------------------------------------ */ 522 #undef __FUNC__ 523 #define __FUNC__ "SNESSetLineSearch" /* ADIC Ignore */ 524 /*@C 525 SNESSetLineSearch - Sets the line search routine to be used 526 by the method SNES_EQ_LS. 527 528 Input Parameters: 529 . snes - nonlinear context obtained from SNESCreate() 530 . func - pointer to int function 531 532 Available Routines: 533 . SNESCubicLineSearch() - default line search 534 . SNESQuadraticLineSearch() - quadratic line search 535 . SNESNoLineSearch() - the full Newton step (actually not a line search) 536 537 Options Database Keys: 538 $ -snes_eq_ls [basic,quadratic,cubic] 539 $ -snes_eq_ls_alpha <alpha> 540 $ -snes_eq_ls_maxstep <max> 541 $ -snes_eq_ls_steptol <steptol> 542 543 Calling sequence of func: 544 func (SNES snes, Vec x, Vec f, Vec g, Vec y, 545 Vec w, double fnorm, double *ynorm, 546 double *gnorm, *flag) 547 548 Input parameters for func: 549 . snes - nonlinear context 550 . x - current iterate 551 . f - residual evaluated at x 552 . y - search direction (contains new iterate on output) 553 . w - work vector 554 . fnorm - 2-norm of f 555 556 Output parameters for func: 557 . g - residual evaluated at new iterate y 558 . y - new iterate (contains search direction on input) 559 . gnorm - 2-norm of g 560 . ynorm - 2-norm of search length 561 . flag - set to 0 if the line search succeeds; a nonzero integer 562 on failure. 563 564 .keywords: SNES, nonlinear, set, line search, routine 565 566 .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch() 567 @*/ 568 int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 569 double,double*,double*,int*)) 570 { 571 if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func; 572 return 0; 573 } 574 /* ------------------------------------------------------------------ */ 575 #undef __FUNC__ 576 #define __FUNC__ "SNESPrintHelp_EQ_LS" /* ADIC Ignore */ 577 static int SNESPrintHelp_EQ_LS(SNES snes,char *p) 578 { 579 SNES_LS *ls = (SNES_LS *)snes->data; 580 581 PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n"); 582 PetscPrintf(snes->comm," %ssnes_eq_ls [basic,quadratic,cubic]\n",p); 583 PetscPrintf(snes->comm," %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha); 584 PetscPrintf(snes->comm," %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep); 585 PetscPrintf(snes->comm," %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol); 586 return 0; 587 } 588 /* ------------------------------------------------------------------ */ 589 #undef __FUNC__ 590 #define __FUNC__ "SNESView_EQ_LS" /* ADIC Ignore */ 591 static int SNESView_EQ_LS(PetscObject obj,Viewer viewer) 592 { 593 SNES snes = (SNES)obj; 594 SNES_LS *ls = (SNES_LS *)snes->data; 595 FILE *fd; 596 char *cstr; 597 int ierr; 598 ViewerType vtype; 599 600 ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 601 if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 602 ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 603 if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch"; 604 else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch"; 605 else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch"; 606 else cstr = "unknown"; 607 PetscFPrintf(snes->comm,fd," line search variant: %s\n",cstr); 608 PetscFPrintf(snes->comm,fd," alpha=%g, maxstep=%g, steptol=%g\n", 609 ls->alpha,ls->maxstep,ls->steptol); 610 } 611 return 0; 612 } 613 /* ------------------------------------------------------------------ */ 614 #undef __FUNC__ 615 #define __FUNC__ "SNESSetFromOptions_EQ_LS" 616 static int SNESSetFromOptions_EQ_LS(SNES snes) 617 { 618 SNES_LS *ls = (SNES_LS *)snes->data; 619 char ver[16]; 620 double tmp; 621 int ierr,flg; 622 623 ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr); 624 if (flg) { 625 ls->alpha = tmp; 626 } 627 ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr); 628 if (flg) { 629 ls->maxstep = tmp; 630 } 631 ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr); 632 if (flg) { 633 ls->steptol = tmp; 634 } 635 ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr); 636 if (flg) { 637 if (!PetscStrcmp(ver,"basic")) { 638 SNESSetLineSearch(snes,SNESNoLineSearch); 639 } 640 else if (!PetscStrcmp(ver,"basicnonorms")) { 641 SNESSetLineSearch(snes,SNESNoLineSearchNoNorms); 642 } 643 else if (!PetscStrcmp(ver,"quadratic")) { 644 SNESSetLineSearch(snes,SNESQuadraticLineSearch); 645 } 646 else if (!PetscStrcmp(ver,"cubic")) { 647 SNESSetLineSearch(snes,SNESCubicLineSearch); 648 } 649 else {SETERRQ(1,0,"Unknown line search");} 650 } 651 return 0; 652 } 653 /* ------------------------------------------------------------ */ 654 #undef __FUNC__ 655 #define __FUNC__ "SNESCreate_EQ_LS" 656 int SNESCreate_EQ_LS(SNES snes ) 657 { 658 SNES_LS *neP; 659 660 if (snes->method_class != SNES_NONLINEAR_EQUATIONS) SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only"); 661 snes->type = SNES_EQ_LS; 662 snes->setup = SNESSetUp_EQ_LS; 663 snes->solve = SNESSolve_EQ_LS; 664 snes->destroy = SNESDestroy_EQ_LS; 665 snes->converged = SNESConverged_EQ_LS; 666 snes->printhelp = SNESPrintHelp_EQ_LS; 667 snes->setfromoptions = SNESSetFromOptions_EQ_LS; 668 snes->view = SNESView_EQ_LS; 669 snes->nwork = 0; 670 671 neP = PetscNew(SNES_LS); CHKPTRQ(neP); 672 PLogObjectMemory(snes,sizeof(SNES_LS)); 673 snes->data = (void *) neP; 674 neP->alpha = 1.e-4; 675 neP->maxstep = 1.e8; 676 neP->steptol = 1.e-12; 677 neP->LineSearch = SNESCubicLineSearch; 678 return 0; 679 } 680 681