1 #include <petsc/private/linesearchimpl.h> /*I "petscsnes.h" I*/ 2 #include <petsc/private/snesimpl.h> 3 4 typedef struct { 5 PetscReal alpha; /* sufficient decrease parameter */ 6 } SNESLineSearch_BT; 7 8 /*@ 9 SNESLineSearchBTSetAlpha - Sets the descent parameter, alpha, in the BT linesearch variant. 10 11 Input Parameters: 12 + linesearch - linesearch context 13 - alpha - The descent parameter 14 15 Level: intermediate 16 17 .seealso: SNESLineSearchSetLambda(), SNESLineSearchGetTolerances() SNESLINESEARCHBT 18 @*/ 19 PetscErrorCode SNESLineSearchBTSetAlpha(SNESLineSearch linesearch, PetscReal alpha) 20 { 21 SNESLineSearch_BT *bt = (SNESLineSearch_BT*)linesearch->data; 22 23 PetscFunctionBegin; 24 PetscValidHeaderSpecific(linesearch,SNESLINESEARCH_CLASSID,1); 25 bt->alpha = alpha; 26 PetscFunctionReturn(0); 27 } 28 29 /*@ 30 SNESLineSearchBTGetAlpha - Gets the descent parameter, alpha, in the BT linesearch variant. 31 32 Input Parameters: 33 . linesearch - linesearch context 34 35 Output Parameters: 36 . alpha - The descent parameter 37 38 Level: intermediate 39 40 .seealso: SNESLineSearchGetLambda(), SNESLineSearchGetTolerances() SNESLINESEARCHBT 41 @*/ 42 PetscErrorCode SNESLineSearchBTGetAlpha(SNESLineSearch linesearch, PetscReal *alpha) 43 { 44 SNESLineSearch_BT *bt = (SNESLineSearch_BT*)linesearch->data; 45 46 PetscFunctionBegin; 47 PetscValidHeaderSpecific(linesearch,SNESLINESEARCH_CLASSID,1); 48 *alpha = bt->alpha; 49 PetscFunctionReturn(0); 50 } 51 52 static PetscErrorCode SNESLineSearchApply_BT(SNESLineSearch linesearch) 53 { 54 PetscBool changed_y,changed_w; 55 PetscErrorCode ierr; 56 Vec X,F,Y,W,G; 57 SNES snes; 58 PetscReal fnorm, xnorm, ynorm, gnorm; 59 PetscReal lambda,lambdatemp,lambdaprev,minlambda,maxstep,initslope,alpha,stol; 60 PetscReal t1,t2,a,b,d; 61 PetscReal f; 62 PetscReal g,gprev; 63 PetscViewer monitor; 64 PetscInt max_its,count; 65 SNESLineSearch_BT *bt = (SNESLineSearch_BT*)linesearch->data; 66 Mat jac; 67 PetscErrorCode (*objective)(SNES,Vec,PetscReal*,void*); 68 69 PetscFunctionBegin; 70 CHKERRQ(SNESLineSearchGetVecs(linesearch, &X, &F, &Y, &W, &G)); 71 CHKERRQ(SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm)); 72 CHKERRQ(SNESLineSearchGetLambda(linesearch, &lambda)); 73 CHKERRQ(SNESLineSearchGetSNES(linesearch, &snes)); 74 CHKERRQ(SNESLineSearchGetDefaultMonitor(linesearch, &monitor)); 75 CHKERRQ(SNESLineSearchGetTolerances(linesearch,&minlambda,&maxstep,NULL,NULL,NULL,&max_its)); 76 CHKERRQ(SNESGetTolerances(snes,NULL,NULL,&stol,NULL,NULL)); 77 CHKERRQ(SNESGetObjective(snes,&objective,NULL)); 78 alpha = bt->alpha; 79 80 CHKERRQ(SNESGetJacobian(snes, &jac, NULL, NULL, NULL)); 81 PetscCheckFalse(!jac && !objective,PetscObjectComm((PetscObject)linesearch), PETSC_ERR_USER, "SNESLineSearchBT requires a Jacobian matrix"); 82 83 CHKERRQ(SNESLineSearchPreCheck(linesearch,X,Y,&changed_y)); 84 CHKERRQ(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED)); 85 86 CHKERRQ(VecNormBegin(Y, NORM_2, &ynorm)); 87 CHKERRQ(VecNormBegin(X, NORM_2, &xnorm)); 88 CHKERRQ(VecNormEnd(Y, NORM_2, &ynorm)); 89 CHKERRQ(VecNormEnd(X, NORM_2, &xnorm)); 90 91 if (ynorm == 0.0) { 92 if (monitor) { 93 CHKERRQ(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel)); 94 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Initial direction and size is 0\n")); 95 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 96 } 97 CHKERRQ(VecCopy(X,W)); 98 CHKERRQ(VecCopy(F,G)); 99 CHKERRQ(SNESLineSearchSetNorms(linesearch,xnorm,fnorm,ynorm)); 100 CHKERRQ(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT)); 101 PetscFunctionReturn(0); 102 } 103 if (ynorm > maxstep) { /* Step too big, so scale back */ 104 if (monitor) { 105 CHKERRQ(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel)); 106 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Scaling step by %14.12e old ynorm %14.12e\n", (double)(maxstep/ynorm),(double)ynorm)); 107 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 108 } 109 CHKERRQ(VecScale(Y,maxstep/(ynorm))); 110 ynorm = maxstep; 111 } 112 113 /* if the SNES has an objective set, use that instead of the function value */ 114 if (objective) { 115 CHKERRQ(SNESComputeObjective(snes,X,&f)); 116 } else { 117 f = fnorm*fnorm; 118 } 119 120 /* compute the initial slope */ 121 if (objective) { 122 /* slope comes from the function (assumed to be the gradient of the objective */ 123 CHKERRQ(VecDotRealPart(Y,F,&initslope)); 124 } else { 125 /* slope comes from the normal equations */ 126 CHKERRQ(MatMult(jac,Y,W)); 127 CHKERRQ(VecDotRealPart(F,W,&initslope)); 128 if (initslope > 0.0) initslope = -initslope; 129 if (initslope == 0.0) initslope = -1.0; 130 } 131 132 while (PETSC_TRUE) { 133 CHKERRQ(VecWAXPY(W,-lambda,Y,X)); 134 if (linesearch->ops->viproject) { 135 CHKERRQ((*linesearch->ops->viproject)(snes, W)); 136 } 137 if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) { 138 CHKERRQ(PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n")); 139 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 140 CHKERRQ(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION)); 141 PetscFunctionReturn(0); 142 } 143 144 if (objective) { 145 CHKERRQ(SNESComputeObjective(snes,W,&g)); 146 } else { 147 CHKERRQ((*linesearch->ops->snesfunc)(snes,W,G)); 148 if (linesearch->ops->vinorm) { 149 gnorm = fnorm; 150 CHKERRQ((*linesearch->ops->vinorm)(snes, G, W, &gnorm)); 151 } else { 152 CHKERRQ(VecNorm(G,NORM_2,&gnorm)); 153 } 154 g = PetscSqr(gnorm); 155 } 156 CHKERRQ(SNESLineSearchMonitor(linesearch)); 157 158 if (!PetscIsInfOrNanReal(g)) break; 159 if (monitor) { 160 CHKERRQ(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel)); 161 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: objective function at lambdas = %g is Inf or Nan, cutting lambda\n",(double)lambda)); 162 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 163 } 164 if (lambda <= minlambda) { 165 SNESCheckFunctionNorm(snes,g); 166 } 167 lambda = .5*lambda; 168 } 169 170 if (!objective) { 171 CHKERRQ(PetscInfo(snes,"Initial fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm)); 172 } 173 if (.5*g <= .5*f + lambda*alpha*initslope) { /* Sufficient reduction or step tolerance convergence */ 174 if (monitor) { 175 CHKERRQ(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel)); 176 if (!objective) { 177 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Using full step: fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm)); 178 } else { 179 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Using full step: obj %14.12e obj %14.12e\n", (double)f, (double)g)); 180 } 181 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 182 } 183 } else { 184 /* Since the full step didn't work and the step is tiny, quit */ 185 if (stol*xnorm > ynorm) { 186 CHKERRQ(SNESLineSearchSetNorms(linesearch,xnorm,fnorm,ynorm)); 187 CHKERRQ(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_SUCCEEDED)); 188 if (monitor) { 189 CHKERRQ(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel)); 190 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Ended due to ynorm < stol*xnorm (%14.12e < %14.12e).\n",(double)ynorm,(double)stol*xnorm)); 191 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 192 } 193 PetscFunctionReturn(0); 194 } 195 /* Fit points with quadratic */ 196 lambdatemp = -initslope/(g - f - 2.0*lambda*initslope); 197 lambdaprev = lambda; 198 gprev = g; 199 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 200 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 201 else lambda = lambdatemp; 202 203 CHKERRQ(VecWAXPY(W,-lambda,Y,X)); 204 if (linesearch->ops->viproject) { 205 CHKERRQ((*linesearch->ops->viproject)(snes, W)); 206 } 207 if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) { 208 CHKERRQ(PetscInfo(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs)); 209 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 210 CHKERRQ(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION)); 211 PetscFunctionReturn(0); 212 } 213 if (objective) { 214 CHKERRQ(SNESComputeObjective(snes,W,&g)); 215 } else { 216 CHKERRQ((*linesearch->ops->snesfunc)(snes,W,G)); 217 if (linesearch->ops->vinorm) { 218 gnorm = fnorm; 219 CHKERRQ((*linesearch->ops->vinorm)(snes, G, W, &gnorm)); 220 } else { 221 CHKERRQ(VecNorm(G,NORM_2,&gnorm)); 222 } 223 g = PetscSqr(gnorm); 224 } 225 if (PetscIsInfOrNanReal(g)) { 226 CHKERRQ(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_NANORINF)); 227 CHKERRQ(PetscInfo(snes,"Aborted due to Nan or Inf in function evaluation\n")); 228 PetscFunctionReturn(0); 229 } 230 if (monitor) { 231 CHKERRQ(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel)); 232 if (!objective) { 233 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: gnorm after quadratic fit %14.12e\n",(double)gnorm)); 234 } else { 235 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: obj after quadratic fit %14.12e\n",(double)g)); 236 } 237 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 238 } 239 if (.5*g < .5*f + lambda*alpha*initslope) { /* sufficient reduction */ 240 if (monitor) { 241 CHKERRQ(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel)); 242 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Quadratically determined step, lambda=%18.16e\n",(double)lambda)); 243 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 244 } 245 } else { 246 /* Fit points with cubic */ 247 for (count = 0; count < max_its; count++) { 248 if (lambda <= minlambda) { 249 if (monitor) { 250 CHKERRQ(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel)); 251 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: unable to find good step length! After %D tries \n",count)); 252 if (!objective) { 253 ierr = PetscViewerASCIIPrintf(monitor," Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", 254 (double)fnorm, (double)gnorm, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope);CHKERRQ(ierr); 255 } else { 256 ierr = PetscViewerASCIIPrintf(monitor," Line search: obj(0)=%18.16e, obj=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", 257 (double)f, (double)g, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope);CHKERRQ(ierr); 258 } 259 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 260 } 261 CHKERRQ(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_REDUCT)); 262 PetscFunctionReturn(0); 263 } 264 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 265 t1 = .5*(g - f) - lambda*initslope; 266 t2 = .5*(gprev - f) - lambdaprev*initslope; 267 a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 268 b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 269 d = b*b - 3*a*initslope; 270 if (d < 0.0) d = 0.0; 271 if (a == 0.0) lambdatemp = -initslope/(2.0*b); 272 else lambdatemp = (-b + PetscSqrtReal(d))/(3.0*a); 273 274 } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) { 275 lambdatemp = -initslope/(g - f - 2.0*initslope); 276 } else SETERRQ(PetscObjectComm((PetscObject)linesearch), PETSC_ERR_SUP, "unsupported line search order for type bt"); 277 lambdaprev = lambda; 278 gprev = g; 279 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 280 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 281 else lambda = lambdatemp; 282 CHKERRQ(VecWAXPY(W,-lambda,Y,X)); 283 if (linesearch->ops->viproject) { 284 CHKERRQ((*linesearch->ops->viproject)(snes,W)); 285 } 286 if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) { 287 CHKERRQ(PetscInfo(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count)); 288 if (!objective) { 289 ierr = PetscInfo(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", 290 (double)fnorm,(double)gnorm,(double)ynorm,(double)lambda,(double)initslope);CHKERRQ(ierr); 291 } 292 CHKERRQ(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_FUNCTION)); 293 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 294 PetscFunctionReturn(0); 295 } 296 if (objective) { 297 CHKERRQ(SNESComputeObjective(snes,W,&g)); 298 } else { 299 CHKERRQ((*linesearch->ops->snesfunc)(snes,W,G)); 300 if (linesearch->ops->vinorm) { 301 gnorm = fnorm; 302 CHKERRQ((*linesearch->ops->vinorm)(snes, G, W, &gnorm)); 303 } else { 304 CHKERRQ(VecNorm(G,NORM_2,&gnorm)); 305 } 306 g = PetscSqr(gnorm); 307 } 308 if (PetscIsInfOrNanReal(g)) { 309 CHKERRQ(SNESLineSearchSetReason(linesearch, SNES_LINESEARCH_FAILED_NANORINF)); 310 CHKERRQ(PetscInfo(snes,"Aborted due to Nan or Inf in function evaluation\n")); 311 PetscFunctionReturn(0); 312 } 313 if (.5*g < .5*f + lambda*alpha*initslope) { /* is reduction enough? */ 314 if (monitor) { 315 CHKERRQ(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel)); 316 if (!objective) { 317 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 318 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Cubically determined step, current gnorm %14.12e lambda=%18.16e\n",(double)gnorm,(double)lambda)); 319 } else { 320 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Quadratically determined step, current gnorm %14.12e lambda=%18.16e\n",(double)gnorm,(double)lambda)); 321 } 322 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 323 } else { 324 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 325 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Cubically determined step, obj %14.12e lambda=%18.16e\n",(double)g,(double)lambda)); 326 } else { 327 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Quadratically determined step, obj %14.12e lambda=%18.16e\n",(double)g,(double)lambda)); 328 } 329 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 330 } 331 } 332 break; 333 } else if (monitor) { 334 CHKERRQ(PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel)); 335 if (!objective) { 336 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 337 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Cubic step no good, shrinking lambda, current gnorm %12.12e lambda=%18.16e\n",(double)gnorm,(double)lambda)); 338 } else { 339 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Quadratic step no good, shrinking lambda, current gnorm %12.12e lambda=%18.16e\n",(double)gnorm,(double)lambda)); 340 } 341 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 342 } else { 343 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 344 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Cubic step no good, shrinking lambda, obj %12.12e lambda=%18.16e\n",(double)g,(double)lambda)); 345 } else { 346 CHKERRQ(PetscViewerASCIIPrintf(monitor," Line search: Quadratic step no good, shrinking lambda, obj %12.12e lambda=%18.16e\n",(double)g,(double)lambda)); 347 } 348 CHKERRQ(PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel)); 349 } 350 } 351 } 352 } 353 } 354 355 /* postcheck */ 356 /* update Y to lambda*Y so that W is consistent with X - lambda*Y */ 357 CHKERRQ(VecScale(Y,lambda)); 358 CHKERRQ(SNESLineSearchPostCheck(linesearch,X,Y,W,&changed_y,&changed_w)); 359 if (changed_y) { 360 CHKERRQ(VecWAXPY(W,-1.0,Y,X)); 361 if (linesearch->ops->viproject) { 362 CHKERRQ((*linesearch->ops->viproject)(snes, W)); 363 } 364 } 365 if (changed_y || changed_w || objective) { /* recompute the function norm if the step has changed or the objective isn't the norm */ 366 CHKERRQ((*linesearch->ops->snesfunc)(snes,W,G)); 367 if (linesearch->ops->vinorm) { 368 gnorm = fnorm; 369 CHKERRQ((*linesearch->ops->vinorm)(snes, G, W, &gnorm)); 370 } else { 371 CHKERRQ(VecNorm(G,NORM_2,&gnorm)); 372 } 373 CHKERRQ(VecNorm(Y,NORM_2,&ynorm)); 374 if (PetscIsInfOrNanReal(gnorm)) { 375 CHKERRQ(SNESLineSearchSetReason(linesearch,SNES_LINESEARCH_FAILED_NANORINF)); 376 CHKERRQ(PetscInfo(snes,"Aborted due to Nan or Inf in function evaluation\n")); 377 PetscFunctionReturn(0); 378 } 379 } 380 381 /* copy the solution over */ 382 CHKERRQ(VecCopy(W, X)); 383 CHKERRQ(VecCopy(G, F)); 384 CHKERRQ(VecNorm(X, NORM_2, &xnorm)); 385 CHKERRQ(SNESLineSearchSetLambda(linesearch, lambda)); 386 CHKERRQ(SNESLineSearchSetNorms(linesearch, xnorm, gnorm, ynorm)); 387 PetscFunctionReturn(0); 388 } 389 390 PetscErrorCode SNESLineSearchView_BT(SNESLineSearch linesearch, PetscViewer viewer) 391 { 392 PetscBool iascii; 393 SNESLineSearch_BT *bt = (SNESLineSearch_BT*)linesearch->data; 394 395 PetscFunctionBegin; 396 CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii)); 397 if (iascii) { 398 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 399 CHKERRQ(PetscViewerASCIIPrintf(viewer, " interpolation: cubic\n")); 400 } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) { 401 CHKERRQ(PetscViewerASCIIPrintf(viewer, " interpolation: quadratic\n")); 402 } 403 CHKERRQ(PetscViewerASCIIPrintf(viewer, " alpha=%e\n", (double)bt->alpha)); 404 } 405 PetscFunctionReturn(0); 406 } 407 408 static PetscErrorCode SNESLineSearchDestroy_BT(SNESLineSearch linesearch) 409 { 410 PetscFunctionBegin; 411 CHKERRQ(PetscFree(linesearch->data)); 412 PetscFunctionReturn(0); 413 } 414 415 static PetscErrorCode SNESLineSearchSetFromOptions_BT(PetscOptionItems *PetscOptionsObject,SNESLineSearch linesearch) 416 { 417 SNESLineSearch_BT *bt = (SNESLineSearch_BT*)linesearch->data; 418 419 PetscFunctionBegin; 420 CHKERRQ(PetscOptionsHead(PetscOptionsObject,"SNESLineSearch BT options")); 421 CHKERRQ(PetscOptionsReal("-snes_linesearch_alpha", "Descent tolerance", "SNESLineSearchBT", bt->alpha, &bt->alpha, NULL)); 422 CHKERRQ(PetscOptionsTail()); 423 PetscFunctionReturn(0); 424 } 425 426 /*MC 427 SNESLINESEARCHBT - Backtracking line search. 428 429 This line search finds the minimum of a polynomial fitting of the L2 norm of the 430 function or the objective function if it is provided with SNESSetObjective(). If this fit does not satisfy the conditions for progress, the interval shrinks 431 and the fit is reattempted at most max_it times or until lambda is below minlambda. 432 433 Options Database Keys: 434 + -snes_linesearch_alpha <1e\-4> - slope descent parameter 435 . -snes_linesearch_damping <1.0> - initial step length 436 . -snes_linesearch_maxstep <length> - if the length the initial step is larger than this then the 437 step is scaled back to be of this length at the beginning of the line search 438 . -snes_linesearch_max_it <40> - maximum number of shrinking step 439 . -snes_linesearch_minlambda <1e\-12> - minimum step length allowed 440 - -snes_linesearch_order <cubic,quadratic> - order of the approximation 441 442 Level: advanced 443 444 Notes: 445 This line search is taken from "Numerical Methods for Unconstrained 446 Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 447 448 This line search will always produce a step that is less than or equal to, in length, the full step size. 449 450 .seealso: SNESLineSearchCreate(), SNESLineSearchSetType() 451 M*/ 452 PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_BT(SNESLineSearch linesearch) 453 { 454 455 SNESLineSearch_BT *bt; 456 457 PetscFunctionBegin; 458 linesearch->ops->apply = SNESLineSearchApply_BT; 459 linesearch->ops->destroy = SNESLineSearchDestroy_BT; 460 linesearch->ops->setfromoptions = SNESLineSearchSetFromOptions_BT; 461 linesearch->ops->reset = NULL; 462 linesearch->ops->view = SNESLineSearchView_BT; 463 linesearch->ops->setup = NULL; 464 465 CHKERRQ(PetscNewLog(linesearch,&bt)); 466 467 linesearch->data = (void*)bt; 468 linesearch->max_its = 40; 469 linesearch->order = SNES_LINESEARCH_ORDER_CUBIC; 470 bt->alpha = 1e-4; 471 PetscFunctionReturn(0); 472 } 473