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