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