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