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