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