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 PetscFunctionBegin; 25 PetscValidHeaderSpecific(linesearch,SNESLINESEARCH_CLASSID,1); 26 bt = (SNESLineSearch_BT *)linesearch->data; 27 bt->alpha = alpha; 28 PetscFunctionReturn(0); 29 } 30 31 32 #undef __FUNCT__ 33 #define __FUNCT__ "SNESLineSearchBTGetAlpha" 34 /*@ 35 SNESLineSearchBTGetAlpha - Gets the descent parameter, alpha, in the BT linesearch variant. 36 37 Input Parameters: 38 . linesearch - linesearch context 39 40 Output Parameters: 41 . alpha - The descent parameter 42 43 Level: intermediate 44 45 .seealso: SNESLineSearchGetLambda(), SNESLineSearchGetTolerances() SNESLINESEARCHBT 46 @*/ 47 PetscErrorCode SNESLineSearchBTGetAlpha(SNESLineSearch linesearch, PetscReal *alpha) 48 { 49 SNESLineSearch_BT *bt; 50 PetscFunctionBegin; 51 PetscValidHeaderSpecific(linesearch,SNESLINESEARCH_CLASSID,1); 52 bt = (SNESLineSearch_BT *)linesearch->data; 53 *alpha = bt->alpha; 54 PetscFunctionReturn(0); 55 } 56 57 #undef __FUNCT__ 58 #define __FUNCT__ "SNESLineSearchApply_BT" 59 static PetscErrorCode SNESLineSearchApply_BT(SNESLineSearch linesearch) 60 { 61 PetscBool changed_y,changed_w; 62 PetscErrorCode ierr; 63 Vec X,F,Y,W,G; 64 SNES snes; 65 PetscReal fnorm, xnorm, ynorm, gnorm; 66 PetscReal lambda,lambdatemp,lambdaprev,minlambda,maxstep,initslope,alpha,stol; 67 PetscReal t1,t2,a,b,d; 68 PetscReal f; 69 PetscReal g,gprev; 70 PetscScalar cinitslope; 71 PetscBool domainerror; 72 PetscViewer monitor; 73 PetscInt max_its,count; 74 SNESLineSearch_BT *bt; 75 Mat jac; 76 SNESObjective obj; 77 78 PetscFunctionBegin; 79 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,PETSC_NULL,PETSC_NULL,PETSC_NULL,&max_its); 86 ierr = SNESGetTolerances(snes,PETSC_NULL,PETSC_NULL,&stol,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 87 ierr = SNESGetObjective(snes,&obj,PETSC_NULL);CHKERRQ(ierr); 88 bt = (SNESLineSearch_BT *)linesearch->data; 89 90 alpha = bt->alpha; 91 92 ierr = SNESGetJacobian(snes, &jac, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 93 94 if (!jac && !obj) SETERRQ(((PetscObject)linesearch)->comm, 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 (obj) { 128 ierr = SNESComputeObjective(snes,X,&f);CHKERRQ(ierr); 129 } else { 130 f = fnorm*fnorm; 131 } 132 133 /* compute the initial slope */ 134 if (obj) { 135 /* slope comes from the function (assumed to be the gradient of the objective */ 136 ierr = VecDot(Y,F,&cinitslope);CHKERRQ(ierr); 137 initslope = PetscRealPart(cinitslope); 138 } else { 139 /* slope comes from the normal equations */ 140 ierr = MatMult(jac,Y,W);CHKERRQ(ierr); 141 ierr = VecDot(F,W,&cinitslope);CHKERRQ(ierr); 142 initslope = PetscRealPart(cinitslope); 143 if (initslope > 0.0) initslope = -initslope; 144 if (initslope == 0.0) initslope = -1.0; 145 } 146 147 ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr); 148 if (linesearch->ops->viproject) { 149 ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); 150 } 151 if (snes->nfuncs >= snes->max_funcs) { 152 ierr = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr); 153 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 154 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 155 PetscFunctionReturn(0); 156 } 157 158 if (obj) { 159 ierr = SNESComputeObjective(snes,W,&g);CHKERRQ(ierr); 160 } else { 161 ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr); 162 ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); 163 if (domainerror) { 164 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 165 PetscFunctionReturn(0); 166 } 167 if (linesearch->ops->vinorm) { 168 gnorm = fnorm; 169 ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr); 170 } else { 171 ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr); 172 } 173 g = PetscSqr(gnorm); 174 } 175 176 if (PetscIsInfOrNanReal(g)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 177 if (!obj) { 178 ierr = PetscInfo2(snes,"Initial fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm);CHKERRQ(ierr); 179 } 180 if (.5*g <= .5*f + lambda*alpha*initslope) { /* Sufficient reduction or step tolerance convergence */ 181 if (monitor) { 182 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 183 if (!obj) { 184 ierr = PetscViewerASCIIPrintf(monitor," Line search: Using full step: fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm);CHKERRQ(ierr); 185 } else { 186 ierr = PetscViewerASCIIPrintf(monitor," Line search: Using full step: obj0 %14.12e obj %14.12e\n", (double)f, (double)g);CHKERRQ(ierr); 187 } 188 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 189 } 190 } else { 191 /* Since the full step didn't work and the step is tiny, quit */ 192 if (stol*xnorm > ynorm) { 193 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 194 ierr = PetscInfo2(monitor,"Aborted due to ynorm < stol*xnorm (%14.12e < %14.12e) and inadequate full step.\n",ynorm,stol*xnorm);CHKERRQ(ierr); 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 = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 213 PetscFunctionReturn(0); 214 } 215 if (obj) { 216 ierr = SNESComputeObjective(snes,W,&g);CHKERRQ(ierr); 217 } else { 218 ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr); 219 ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); 220 if (domainerror) { 221 PetscFunctionReturn(0); 222 } 223 if (linesearch->ops->vinorm) { 224 gnorm = fnorm; 225 ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr); 226 } else { 227 ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr); 228 g = gnorm*gnorm; 229 } 230 } 231 if (PetscIsInfOrNanReal(g)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 232 if (monitor) { 233 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 234 if (!obj) { 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 (!obj) { 255 ierr = PetscViewerASCIIPrintf(monitor, 256 " Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", 257 (double)fnorm, (double)gnorm, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope);CHKERRQ(ierr); 258 } else { 259 ierr = PetscViewerASCIIPrintf(monitor, 260 " Line search: obj(0)=%18.16e, obj=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", 261 (double)f, (double)g, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope);CHKERRQ(ierr); 262 } 263 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 264 } 265 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 266 PetscFunctionReturn(0); 267 } 268 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 269 t1 = .5*(g - f) - lambda*initslope; 270 t2 = .5*(gprev - f) - lambdaprev*initslope; 271 a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 272 b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 273 d = b*b - 3*a*initslope; 274 if (d < 0.0) d = 0.0; 275 if (a == 0.0) { 276 lambdatemp = -initslope/(2.0*b); 277 } else { 278 lambdatemp = (-b + PetscSqrtReal(d))/(3.0*a); 279 } 280 } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) { 281 lambdatemp = -initslope/(g - f - 2.0*initslope); 282 } else { 283 SETERRQ(((PetscObject)linesearch)->comm, PETSC_ERR_SUP, "unsupported line search order for type bt"); 284 } 285 lambdaprev = lambda; 286 gprev = g; 287 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 288 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 289 else lambda = lambdatemp; 290 ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr); 291 if (linesearch->ops->viproject) { 292 ierr = (*linesearch->ops->viproject)(snes,W);CHKERRQ(ierr); 293 } 294 if (snes->nfuncs >= snes->max_funcs) { 295 ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr); 296 if (!obj) { 297 ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", 298 (double)fnorm,(double)gnorm,(double)ynorm,(double)lambda,(double)initslope);CHKERRQ(ierr); 299 } 300 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 301 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 302 PetscFunctionReturn(0); 303 } 304 if (obj) { 305 ierr = SNESComputeObjective(snes,W,&g);CHKERRQ(ierr); 306 } else { 307 ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr); 308 ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); 309 if (domainerror) { 310 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 311 PetscFunctionReturn(0); 312 } 313 if (linesearch->ops->vinorm) { 314 gnorm = fnorm; 315 ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr); 316 } else { 317 ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr); 318 g = gnorm*gnorm; 319 } 320 } 321 if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 322 if (.5*g < .5*f + lambda*alpha*initslope) { /* is reduction enough? */ 323 if (monitor) { 324 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 325 if (!obj) { 326 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 327 ierr = PetscViewerASCIIPrintf(monitor," Line search: Cubically determined step, current gnorm %14.12e lambda=%18.16e\n",(double)gnorm,(double)lambda);CHKERRQ(ierr); 328 } else { 329 ierr = PetscViewerASCIIPrintf(monitor," Line search: Quadratically determined step, current gnorm %14.12e lambda=%18.16e\n",(double)gnorm,(double)lambda);CHKERRQ(ierr); 330 } 331 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 332 } else { 333 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 334 ierr = PetscViewerASCIIPrintf(monitor," Line search: Cubically determined step, obj %14.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr); 335 } else { 336 ierr = PetscViewerASCIIPrintf(monitor," Line search: Quadratically determined step, obj %14.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr); 337 } 338 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 339 } 340 } 341 break; 342 } else { 343 if (monitor) { 344 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 345 if (!obj) { 346 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 347 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); 348 } else { 349 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); 350 } 351 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 352 } else { 353 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 354 ierr = PetscViewerASCIIPrintf(monitor," Line search: Cubic step no good, shrinking lambda, obj %12.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr); 355 } else { 356 ierr = PetscViewerASCIIPrintf(monitor," Line search: Quadratic step no good, shrinking lambda, obj %12.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr); 357 } 358 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 359 } 360 } 361 } 362 } 363 } 364 } 365 366 /* postcheck */ 367 ierr = SNESLineSearchPostCheck(linesearch,X,Y,W,&changed_y,&changed_w);CHKERRQ(ierr); 368 if (changed_y) { 369 ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr); 370 if (linesearch->ops->viproject) { 371 ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); 372 } 373 } 374 if (changed_y || changed_w || obj) { /* recompute the function norm if the step has changed or the objective isn't the norm */ 375 ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr); 376 ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); 377 if (domainerror) { 378 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 379 PetscFunctionReturn(0); 380 } 381 if (linesearch->ops->vinorm) { 382 gnorm = fnorm; 383 ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr); 384 } else { 385 ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr); 386 } 387 ierr = VecNorm(Y,NORM_2,&ynorm);CHKERRQ(ierr); 388 if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 389 390 } 391 392 /* copy the solution over */ 393 ierr = VecCopy(W, X);CHKERRQ(ierr); 394 ierr = VecCopy(G, F);CHKERRQ(ierr); 395 ierr = VecNorm(X, NORM_2, &xnorm);CHKERRQ(ierr); 396 ierr = SNESLineSearchSetLambda(linesearch, lambda);CHKERRQ(ierr); 397 ierr = SNESLineSearchSetNorms(linesearch, xnorm, gnorm, ynorm);CHKERRQ(ierr); 398 PetscFunctionReturn(0); 399 } 400 401 #undef __FUNCT__ 402 #define __FUNCT__ "SNESLineSearchView_BT" 403 PetscErrorCode SNESLineSearchView_BT(SNESLineSearch linesearch, PetscViewer viewer) 404 { 405 PetscErrorCode ierr; 406 PetscBool iascii; 407 SNESLineSearch_BT *bt; 408 PetscFunctionBegin; 409 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 410 bt = (SNESLineSearch_BT*)linesearch->data; 411 if (iascii) { 412 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 413 ierr = PetscViewerASCIIPrintf(viewer, " interpolation: cubic\n");CHKERRQ(ierr); 414 } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) { 415 ierr = PetscViewerASCIIPrintf(viewer, " interpolation: quadratic\n");CHKERRQ(ierr); 416 } 417 ierr = PetscViewerASCIIPrintf(viewer, " alpha=%e\n", bt->alpha);CHKERRQ(ierr); 418 } 419 PetscFunctionReturn(0); 420 } 421 422 423 #undef __FUNCT__ 424 #define __FUNCT__ "SNESLineSearchDestroy_BT" 425 static PetscErrorCode SNESLineSearchDestroy_BT(SNESLineSearch linesearch) 426 { 427 PetscErrorCode ierr; 428 429 PetscFunctionBegin; 430 ierr = PetscFree(linesearch->data);CHKERRQ(ierr); 431 PetscFunctionReturn(0); 432 } 433 434 435 #undef __FUNCT__ 436 #define __FUNCT__ "SNESLineSearchSetFromOptions_BT" 437 static PetscErrorCode SNESLineSearchSetFromOptions_BT(SNESLineSearch linesearch) 438 { 439 440 PetscErrorCode ierr; 441 SNESLineSearch_BT *bt; 442 PetscFunctionBegin; 443 444 bt = (SNESLineSearch_BT*)linesearch->data; 445 446 ierr = PetscOptionsHead("SNESLineSearch BT options");CHKERRQ(ierr); 447 ierr = PetscOptionsReal("-snes_linesearch_alpha", "Descent tolerance", "SNESLineSearchBT", bt->alpha, &bt->alpha, PETSC_NULL);CHKERRQ(ierr); 448 449 ierr = PetscOptionsTail();CHKERRQ(ierr); 450 PetscFunctionReturn(0); 451 } 452 453 454 #undef __FUNCT__ 455 #define __FUNCT__ "SNESLineSearchCreate_BT" 456 /*MC 457 SNESLINESEARCHBT - Backtracking line search. 458 459 This line search finds the minimum of a polynomial fitting of the L2 norm of the 460 function. If this fit does not satisfy the conditions for progress, the interval shrinks 461 and the fit is reattempted at most max_it times or until lambda is below minlambda. 462 463 Options Database Keys: 464 + -snes_linesearch_alpha<1e-4> - slope descent parameter 465 . -snes_linesearch_damping<1.0> - initial step length 466 . -snes_linesearch_max_it<40> - maximum number of shrinking step 467 . -snes_linesearch_minlambda<1e-12> - minimum step length allowed 468 - -snes_linesearch_order<cubic,quadratic> - order of the approximation 469 470 Level: advanced 471 472 Notes: 473 This line search is taken from "Numerical Methods for Unconstrained 474 Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 475 476 .keywords: SNES, SNESLineSearch, damping 477 478 .seealso: SNESLineSearchCreate(), SNESLineSearchSetType() 479 M*/ 480 PETSC_EXTERN_C PetscErrorCode SNESLineSearchCreate_BT(SNESLineSearch linesearch) 481 { 482 483 SNESLineSearch_BT *bt; 484 PetscErrorCode ierr; 485 486 PetscFunctionBegin; 487 linesearch->ops->apply = SNESLineSearchApply_BT; 488 linesearch->ops->destroy = SNESLineSearchDestroy_BT; 489 linesearch->ops->setfromoptions = SNESLineSearchSetFromOptions_BT; 490 linesearch->ops->reset = PETSC_NULL; 491 linesearch->ops->view = SNESLineSearchView_BT; 492 linesearch->ops->setup = PETSC_NULL; 493 494 ierr = PetscNewLog(linesearch, SNESLineSearch_BT, &bt);CHKERRQ(ierr); 495 linesearch->data = (void *)bt; 496 linesearch->max_its = 40; 497 linesearch->order = SNES_LINESEARCH_ORDER_CUBIC; 498 bt->alpha = 1e-4; 499 500 PetscFunctionReturn(0); 501 } 502