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