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 g = PetscSqr(gnorm); 171 } else { 172 ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr); 173 g = gnorm*gnorm; 174 } 175 } 176 177 if (PetscIsInfOrNanReal(g)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 178 if (!obj) { 179 ierr = PetscInfo2(snes,"Initial fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm);CHKERRQ(ierr); 180 } 181 if (.5*g <= .5*f + lambda*alpha*initslope) { /* Sufficient reduction or step tolerance convergence */ 182 if (monitor) { 183 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 184 if (!obj) { 185 ierr = PetscViewerASCIIPrintf(monitor," Line search: Using full step: fnorm %14.12e gnorm %14.12e\n", (double)fnorm, (double)gnorm);CHKERRQ(ierr); 186 } else { 187 ierr = PetscViewerASCIIPrintf(monitor," Line search: Using full step: obj0 %14.12e obj %14.12e\n", (double)f, (double)g);CHKERRQ(ierr); 188 } 189 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 190 } 191 } else { 192 /* Since the full step didn't work and the step is tiny, quit */ 193 if (stol*xnorm > ynorm) { 194 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 195 ierr = PetscInfo2(monitor,"Aborted due to ynorm < stol*xnorm (%14.12e < %14.12e) and inadequate full step.\n",ynorm,stol*xnorm);CHKERRQ(ierr); 196 PetscFunctionReturn(0); 197 } 198 /* Fit points with quadratic */ 199 lambdatemp = -initslope/(g - f - 2.0*lambda*initslope); 200 lambdaprev = lambda; 201 gprev = g; 202 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 203 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 204 else lambda = lambdatemp; 205 206 ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr); 207 if (linesearch->ops->viproject) { 208 ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); 209 } 210 if (snes->nfuncs >= snes->max_funcs) { 211 ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr); 212 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 213 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 214 PetscFunctionReturn(0); 215 } 216 if (obj) { 217 ierr = SNESComputeObjective(snes,W,&g);CHKERRQ(ierr); 218 } else { 219 ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr); 220 ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); 221 if (domainerror) { 222 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)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 233 if (monitor) { 234 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 235 if (!obj) { 236 ierr = PetscViewerASCIIPrintf(monitor," Line search: gnorm after quadratic fit %14.12e\n",(double)gnorm);CHKERRQ(ierr); 237 } else { 238 ierr = PetscViewerASCIIPrintf(monitor," Line search: obj after quadratic fit %14.12e\n",(double)g);CHKERRQ(ierr); 239 } 240 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 241 } 242 if (.5*g < .5*f + lambda*alpha*initslope) { /* sufficient reduction */ 243 if (monitor) { 244 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 245 ierr = PetscViewerASCIIPrintf(monitor," Line search: Quadratically determined step, lambda=%18.16e\n",(double)lambda);CHKERRQ(ierr); 246 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 247 } 248 } else { 249 /* Fit points with cubic */ 250 for (count = 0; count < max_its; count++) { 251 if (lambda <= minlambda) { 252 if (monitor) { 253 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 254 ierr = PetscViewerASCIIPrintf(monitor," Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr); 255 if (!obj) { 256 ierr = PetscViewerASCIIPrintf(monitor, 257 " Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", 258 (double)fnorm, (double)gnorm, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope);CHKERRQ(ierr); 259 } else { 260 ierr = PetscViewerASCIIPrintf(monitor, 261 " Line search: obj(0)=%18.16e, obj=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", 262 (double)f, (double)g, (double)ynorm, (double)minlambda, (double)lambda, (double)initslope);CHKERRQ(ierr); 263 } 264 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 265 } 266 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 267 PetscFunctionReturn(0); 268 } 269 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 270 t1 = .5*(g - f) - lambda*initslope; 271 t2 = .5*(gprev - f) - lambdaprev*initslope; 272 a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 273 b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 274 d = b*b - 3*a*initslope; 275 if (d < 0.0) d = 0.0; 276 if (a == 0.0) { 277 lambdatemp = -initslope/(2.0*b); 278 } else { 279 lambdatemp = (-b + PetscSqrtReal(d))/(3.0*a); 280 } 281 } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) { 282 lambdatemp = -initslope/(g - f - 2.0*initslope); 283 } else { 284 SETERRQ(((PetscObject)linesearch)->comm, PETSC_ERR_SUP, "unsupported line search order for type bt"); 285 } 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 (!obj) { 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 (obj) { 306 ierr = SNESComputeObjective(snes,W,&g);CHKERRQ(ierr); 307 } else { 308 ierr = SNESComputeFunction(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)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 323 if (.5*g < .5*f + lambda*alpha*initslope) { /* is reduction enough? */ 324 if (monitor) { 325 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 326 if (!obj) { 327 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 328 ierr = PetscViewerASCIIPrintf(monitor," Line search: Cubically determined step, current gnorm %14.12e lambda=%18.16e\n",(double)gnorm,(double)lambda);CHKERRQ(ierr); 329 } else { 330 ierr = PetscViewerASCIIPrintf(monitor," Line search: Quadratically determined step, current gnorm %14.12e lambda=%18.16e\n",(double)gnorm,(double)lambda);CHKERRQ(ierr); 331 } 332 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 333 } else { 334 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 335 ierr = PetscViewerASCIIPrintf(monitor," Line search: Cubically determined step, obj %14.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr); 336 } else { 337 ierr = PetscViewerASCIIPrintf(monitor," Line search: Quadratically determined step, obj %14.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr); 338 } 339 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 340 } 341 } 342 break; 343 } else { 344 if (monitor) { 345 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 346 if (!obj) { 347 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 348 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); 349 } else { 350 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); 351 } 352 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 353 } else { 354 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 355 ierr = PetscViewerASCIIPrintf(monitor," Line search: Cubic step no good, shrinking lambda, obj %12.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr); 356 } else { 357 ierr = PetscViewerASCIIPrintf(monitor," Line search: Quadratic step no good, shrinking lambda, obj %12.12e lambda=%18.16e\n",(double)g,(double)lambda);CHKERRQ(ierr); 358 } 359 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 360 } 361 } 362 } 363 } 364 } 365 } 366 367 /* postcheck */ 368 ierr = SNESLineSearchPostCheck(linesearch,X,Y,W,&changed_y,&changed_w);CHKERRQ(ierr); 369 if (changed_y) { 370 ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr); 371 if (linesearch->ops->viproject) { 372 ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); 373 } 374 } 375 if (changed_y || changed_w || obj) { /* recompute the function norm if the step has changed or the objective isn't the norm */ 376 ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr); 377 ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); 378 if (domainerror) { 379 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 380 PetscFunctionReturn(0); 381 } 382 if (linesearch->ops->vinorm) { 383 gnorm = fnorm; 384 ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr); 385 } else { 386 ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr); 387 } 388 ierr = VecNorm(Y,NORM_2,&ynorm);CHKERRQ(ierr); 389 if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 390 391 } 392 393 /* copy the solution over */ 394 ierr = VecCopy(W, X);CHKERRQ(ierr); 395 ierr = VecCopy(G, F);CHKERRQ(ierr); 396 ierr = VecNorm(X, NORM_2, &xnorm);CHKERRQ(ierr); 397 ierr = SNESLineSearchSetLambda(linesearch, lambda);CHKERRQ(ierr); 398 ierr = SNESLineSearchSetNorms(linesearch, xnorm, gnorm, ynorm);CHKERRQ(ierr); 399 PetscFunctionReturn(0); 400 } 401 402 #undef __FUNCT__ 403 #define __FUNCT__ "SNESLineSearchView_BT" 404 PetscErrorCode SNESLineSearchView_BT(SNESLineSearch linesearch, PetscViewer viewer) 405 { 406 PetscErrorCode ierr; 407 PetscBool iascii; 408 SNESLineSearch_BT *bt; 409 PetscFunctionBegin; 410 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 411 bt = (SNESLineSearch_BT*)linesearch->data; 412 if (iascii) { 413 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 414 ierr = PetscViewerASCIIPrintf(viewer, " interpolation: cubic\n");CHKERRQ(ierr); 415 } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) { 416 ierr = PetscViewerASCIIPrintf(viewer, " interpolation: quadratic\n");CHKERRQ(ierr); 417 } 418 ierr = PetscViewerASCIIPrintf(viewer, " alpha=%e\n", bt->alpha);CHKERRQ(ierr); 419 } 420 PetscFunctionReturn(0); 421 } 422 423 424 #undef __FUNCT__ 425 #define __FUNCT__ "SNESLineSearchDestroy_BT" 426 static PetscErrorCode SNESLineSearchDestroy_BT(SNESLineSearch linesearch) 427 { 428 PetscErrorCode ierr; 429 430 PetscFunctionBegin; 431 ierr = PetscFree(linesearch->data);CHKERRQ(ierr); 432 PetscFunctionReturn(0); 433 } 434 435 436 #undef __FUNCT__ 437 #define __FUNCT__ "SNESLineSearchSetFromOptions_BT" 438 static PetscErrorCode SNESLineSearchSetFromOptions_BT(SNESLineSearch linesearch) 439 { 440 441 PetscErrorCode ierr; 442 SNESLineSearch_BT *bt; 443 PetscFunctionBegin; 444 445 bt = (SNESLineSearch_BT*)linesearch->data; 446 447 ierr = PetscOptionsHead("SNESLineSearch BT options");CHKERRQ(ierr); 448 ierr = PetscOptionsReal("-snes_linesearch_alpha", "Descent tolerance", "SNESLineSearchBT", bt->alpha, &bt->alpha, PETSC_NULL);CHKERRQ(ierr); 449 450 ierr = PetscOptionsTail();CHKERRQ(ierr); 451 PetscFunctionReturn(0); 452 } 453 454 455 #undef __FUNCT__ 456 #define __FUNCT__ "SNESLineSearchCreate_BT" 457 /*MC 458 SNESLINESEARCHBT - Backtracking line search. 459 460 This line search finds the minimum of a polynomial fitting of the L2 norm of the 461 function. If this fit does not satisfy the conditions for progress, the interval shrinks 462 and the fit is reattempted at most max_it times or until lambda is below minlambda. 463 464 Options Database Keys: 465 + -snes_linesearch_alpha<1e-4> - slope descent parameter 466 . -snes_linesearch_damping<1.0> - initial step length 467 . -snes_linesearch_max_it<40> - maximum number of shrinking step 468 . -snes_linesearch_minlambda<1e-12> - minimum step length allowed 469 - -snes_linesearch_order<cubic,quadratic> - order of the approximation 470 471 Level: advanced 472 473 Notes: 474 This line search is taken from "Numerical Methods for Unconstrained 475 Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 476 477 .keywords: SNES, SNESLineSearch, damping 478 479 .seealso: SNESLineSearchCreate(), SNESLineSearchSetType() 480 M*/ 481 PETSC_EXTERN_C PetscErrorCode SNESLineSearchCreate_BT(SNESLineSearch linesearch) 482 { 483 484 SNESLineSearch_BT *bt; 485 PetscErrorCode ierr; 486 487 PetscFunctionBegin; 488 linesearch->ops->apply = SNESLineSearchApply_BT; 489 linesearch->ops->destroy = SNESLineSearchDestroy_BT; 490 linesearch->ops->setfromoptions = SNESLineSearchSetFromOptions_BT; 491 linesearch->ops->reset = PETSC_NULL; 492 linesearch->ops->view = SNESLineSearchView_BT; 493 linesearch->ops->setup = PETSC_NULL; 494 495 ierr = PetscNewLog(linesearch, SNESLineSearch_BT, &bt);CHKERRQ(ierr); 496 linesearch->data = (void *)bt; 497 linesearch->max_its = 40; 498 linesearch->order = SNES_LINESEARCH_ORDER_CUBIC; 499 bt->alpha = 1e-4; 500 501 PetscFunctionReturn(0); 502 } 503