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, gnormprev; 66 PetscReal lambda, lambdatemp, lambdaprev, minlambda, maxstep, rellength, initslope, alpha; 67 PetscReal t1, t2, a, b, d, steptol; 68 #if defined(PETSC_USE_COMPLEX) 69 PetscScalar cinitslope; 70 #endif 71 PetscBool domainerror; 72 PetscViewer monitor; 73 PetscInt max_its, count; 74 SNESLineSearch_BT *bt; 75 Mat jac; 76 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, &steptol, &maxstep, PETSC_NULL, PETSC_NULL, PETSC_NULL, &max_its); 86 bt = (SNESLineSearch_BT *)linesearch->data; 87 88 alpha = bt->alpha; 89 90 ierr = SNESGetJacobian(snes, &jac, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr); 91 if (!jac) { 92 SETERRQ(((PetscObject)linesearch)->comm, PETSC_ERR_USER, "SNESLineSearchBT requires a Jacobian matrix"); 93 } 94 /* precheck */ 95 ierr = SNESLineSearchPreCheck(linesearch, &changed_y);CHKERRQ(ierr); 96 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_TRUE);CHKERRQ(ierr); 97 98 ierr = VecNorm(Y, NORM_2, &ynorm);CHKERRQ(ierr); 99 if (ynorm == 0.0) { 100 if (monitor) { 101 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 102 ierr = PetscViewerASCIIPrintf(monitor," Line search: Initial direction and size is 0\n");CHKERRQ(ierr); 103 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 104 } 105 ierr = VecCopy(X,W);CHKERRQ(ierr); 106 ierr = VecCopy(F,G);CHKERRQ(ierr); 107 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 108 PetscFunctionReturn(0); 109 } 110 if (ynorm > maxstep) { /* Step too big, so scale back */ 111 if (monitor) { 112 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 113 ierr = PetscViewerASCIIPrintf(monitor," Line search: Scaling step by %14.12e old ynorm %14.12e\n", (maxstep/ynorm),ynorm);CHKERRQ(ierr); 114 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 115 } 116 ierr = VecScale(Y,maxstep/(ynorm));CHKERRQ(ierr); 117 ynorm = maxstep; 118 } 119 ierr = VecMaxPointwiseDivide(Y,X,&rellength);CHKERRQ(ierr); 120 minlambda = steptol/rellength; 121 ierr = MatMult(jac,Y,W);CHKERRQ(ierr); 122 #if defined(PETSC_USE_COMPLEX) 123 ierr = VecDot(F,W,&cinitslope);CHKERRQ(ierr); 124 initslope = PetscRealPart(cinitslope); 125 #else 126 ierr = VecDot(F,W,&initslope);CHKERRQ(ierr); 127 #endif 128 if (initslope > 0.0) initslope = -initslope; 129 if (initslope == 0.0) initslope = -1.0; 130 131 ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr); 132 if (linesearch->ops->viproject) { 133 ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); 134 } 135 if (snes->nfuncs >= snes->max_funcs) { 136 ierr = PetscInfo(snes,"Exceeded maximum function evaluations, while checking full step length!\n");CHKERRQ(ierr); 137 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 138 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 139 PetscFunctionReturn(0); 140 } 141 ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr); 142 ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); 143 if (domainerror) { 144 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 145 PetscFunctionReturn(0); 146 } 147 if (linesearch->ops->vinorm) { 148 gnorm = fnorm; 149 ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr); 150 } else { 151 ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr); 152 } 153 154 if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 155 ierr = PetscInfo2(snes,"Initial fnorm %14.12e gnorm %14.12e\n", fnorm, gnorm);CHKERRQ(ierr); 156 if (.5*gnorm*gnorm <= .5*fnorm*fnorm + lambda*alpha*initslope) { /* Sufficient reduction */ 157 if (monitor) { 158 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 159 ierr = PetscViewerASCIIPrintf(monitor," Line search: Using full step: fnorm %14.12e gnorm %14.12e\n", fnorm, gnorm);CHKERRQ(ierr); 160 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 161 } 162 } else { 163 /* Fit points with quadratic */ 164 lambdatemp = -initslope/(gnorm*gnorm - fnorm*fnorm - 2.0*lambda*initslope); 165 lambdaprev = lambda; 166 gnormprev = gnorm; 167 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 168 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 169 else lambda = lambdatemp; 170 171 ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr); 172 if (linesearch->ops->viproject) { 173 ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); 174 } 175 if (snes->nfuncs >= snes->max_funcs) { 176 ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while attempting quadratic backtracking! %D \n",snes->nfuncs);CHKERRQ(ierr); 177 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 178 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 179 PetscFunctionReturn(0); 180 } 181 ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr); 182 ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); 183 if (domainerror) { 184 PetscFunctionReturn(0); 185 } 186 if (linesearch->ops->vinorm) { 187 gnorm = fnorm; 188 ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr); 189 } else { 190 ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr); 191 } 192 if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 193 if (monitor) { 194 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 195 ierr = PetscViewerASCIIPrintf(monitor," Line search: gnorm after quadratic fit %14.12e\n",gnorm);CHKERRQ(ierr); 196 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 197 } 198 if (.5*gnorm*gnorm < .5*fnorm*fnorm + lambda*alpha*initslope) { /* sufficient reduction */ 199 if (monitor) { 200 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 201 ierr = PetscViewerASCIIPrintf(monitor," Line search: Quadratically determined step, lambda=%18.16e\n",(double)lambda);CHKERRQ(ierr); 202 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 203 } 204 } else { 205 /* Fit points with cubic */ 206 for (count = 0; count < max_its; count++) { 207 if (lambda <= minlambda) { 208 if (monitor) { 209 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 210 ierr = PetscViewerASCIIPrintf(monitor," Line search: unable to find good step length! After %D tries \n",count);CHKERRQ(ierr); 211 ierr = PetscViewerASCIIPrintf(monitor, 212 " Line search: fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, minlambda=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", 213 fnorm, gnorm, ynorm, minlambda, lambda, initslope);CHKERRQ(ierr); 214 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 215 } 216 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 217 PetscFunctionReturn(0); 218 } 219 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 220 t1 = .5*(gnorm*gnorm - fnorm*fnorm) - lambda*initslope; 221 t2 = .5*(gnormprev*gnormprev - fnorm*fnorm) - lambdaprev*initslope; 222 a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 223 b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 224 d = b*b - 3*a*initslope; 225 if (d < 0.0) d = 0.0; 226 if (a == 0.0) { 227 lambdatemp = -initslope/(2.0*b); 228 } else { 229 lambdatemp = (-b + PetscSqrtReal(d))/(3.0*a); 230 } 231 } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) { 232 lambdatemp = -initslope/(gnorm*gnorm - fnorm*fnorm - 2.0*initslope); 233 } else { 234 SETERRQ(((PetscObject)linesearch)->comm, PETSC_ERR_SUP, "unsupported line search order for type bt"); 235 } 236 lambdaprev = lambda; 237 gnormprev = gnorm; 238 if (lambdatemp > .5*lambda) lambdatemp = .5*lambda; 239 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 240 else lambda = lambdatemp; 241 ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr); 242 if (snes->nfuncs >= snes->max_funcs) { 243 ierr = PetscInfo1(snes,"Exceeded maximum function evaluations, while looking for good step length! %D \n",count);CHKERRQ(ierr); 244 ierr = PetscInfo5(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lambda=%18.16e, initial slope=%18.16e\n", 245 fnorm,gnorm,ynorm,lambda,initslope);CHKERRQ(ierr); 246 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 247 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 248 PetscFunctionReturn(0); 249 } 250 ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr); 251 ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); 252 if (domainerror) { 253 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 254 PetscFunctionReturn(0); 255 } 256 if (linesearch->ops->vinorm) { 257 gnorm = fnorm; 258 ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr); 259 } else { 260 ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr); 261 } 262 if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 263 if (.5*gnorm*gnorm < .5*fnorm*fnorm + lambda*alpha*initslope) { /* is reduction enough? */ 264 if (monitor) { 265 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 266 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 267 ierr = PetscViewerASCIIPrintf(monitor," Line search: Cubically determined step, current gnorm %14.12e lambda=%18.16e\n",gnorm,lambda);CHKERRQ(ierr); 268 } else { 269 ierr = PetscViewerASCIIPrintf(monitor," Line search: Quadratically determined step, current gnorm %14.12e lambda=%18.16e\n",gnorm,lambda);CHKERRQ(ierr); 270 } 271 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 272 } 273 break; 274 } else { 275 if (monitor) { 276 ierr = PetscViewerASCIIAddTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 277 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 278 ierr = PetscViewerASCIIPrintf(monitor," Line search: Cubic step no good, shrinking lambda, current gnorm %12.12e lambda=%18.16e\n",gnorm,lambda);CHKERRQ(ierr); 279 } else { 280 ierr = PetscViewerASCIIPrintf(monitor," Line search: Quadratic step no good, shrinking lambda, current gnorm %12.12e lambda=%18.16e\n",gnorm,lambda);CHKERRQ(ierr); 281 } 282 ierr = PetscViewerASCIISubtractTab(monitor,((PetscObject)linesearch)->tablevel);CHKERRQ(ierr); 283 } 284 } 285 } 286 } 287 } 288 289 /* postcheck */ 290 ierr = SNESLineSearchPostCheck(linesearch, &changed_y, &changed_w);CHKERRQ(ierr); 291 if (changed_y) { 292 ierr = VecWAXPY(W,-lambda,Y,X);CHKERRQ(ierr); 293 if (linesearch->ops->viproject) { 294 ierr = (*linesearch->ops->viproject)(snes, W);CHKERRQ(ierr); 295 } 296 } 297 if (changed_y || changed_w) { /* recompute the function if the step has changed */ 298 ierr = SNESComputeFunction(snes,W,G);CHKERRQ(ierr); 299 ierr = SNESGetFunctionDomainError(snes, &domainerror);CHKERRQ(ierr); 300 if (domainerror) { 301 ierr = SNESLineSearchSetSuccess(linesearch, PETSC_FALSE);CHKERRQ(ierr); 302 PetscFunctionReturn(0); 303 } 304 if (linesearch->ops->vinorm) { 305 gnorm = fnorm; 306 ierr = (*linesearch->ops->vinorm)(snes, G, W, &gnorm);CHKERRQ(ierr); 307 } else { 308 ierr = VecNorm(G,NORM_2,&gnorm);CHKERRQ(ierr); 309 } 310 ierr = VecNorm(Y,NORM_2,&ynorm);CHKERRQ(ierr); 311 if (PetscIsInfOrNanReal(gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number"); 312 313 } 314 315 /* copy the solution over */ 316 ierr = VecCopy(W, X);CHKERRQ(ierr); 317 ierr = VecCopy(G, F);CHKERRQ(ierr); 318 ierr = VecNorm(X, NORM_2, &xnorm);CHKERRQ(ierr); 319 ierr = SNESLineSearchSetLambda(linesearch, lambda);CHKERRQ(ierr); 320 ierr = SNESLineSearchSetNorms(linesearch, xnorm, gnorm, ynorm);CHKERRQ(ierr); 321 PetscFunctionReturn(0); 322 } 323 324 #undef __FUNCT__ 325 #define __FUNCT__ "SNESLineSearchView_BT" 326 PetscErrorCode SNESLineSearchView_BT(SNESLineSearch linesearch, PetscViewer viewer) 327 { 328 PetscErrorCode ierr; 329 PetscBool iascii; 330 SNESLineSearch_BT *bt; 331 PetscFunctionBegin; 332 ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 333 bt = (SNESLineSearch_BT*)linesearch->data; 334 if (iascii) { 335 if (linesearch->order == SNES_LINESEARCH_ORDER_CUBIC) { 336 ierr = PetscViewerASCIIPrintf(viewer, " interpolation: cubic\n");CHKERRQ(ierr); 337 } else if (linesearch->order == SNES_LINESEARCH_ORDER_QUADRATIC) { 338 ierr = PetscViewerASCIIPrintf(viewer, " interpolation: quadratic\n");CHKERRQ(ierr); 339 } 340 ierr = PetscViewerASCIIPrintf(viewer, " alpha=%G\n", bt->alpha);CHKERRQ(ierr); 341 } 342 PetscFunctionReturn(0); 343 } 344 345 346 #undef __FUNCT__ 347 #define __FUNCT__ "SNESLineSearchDestroy_BT" 348 static PetscErrorCode SNESLineSearchDestroy_BT(SNESLineSearch linesearch) 349 { 350 PetscErrorCode ierr; 351 352 PetscFunctionBegin; 353 ierr = PetscFree(linesearch->data);CHKERRQ(ierr); 354 PetscFunctionReturn(0); 355 } 356 357 358 #undef __FUNCT__ 359 #define __FUNCT__ "SNESLineSearchSetFromOptions_BT" 360 static PetscErrorCode SNESLineSearchSetFromOptions_BT(SNESLineSearch linesearch) 361 { 362 363 PetscErrorCode ierr; 364 SNESLineSearch_BT *bt; 365 PetscFunctionBegin; 366 367 bt = (SNESLineSearch_BT*)linesearch->data; 368 369 ierr = PetscOptionsHead("SNESLineSearch BT options");CHKERRQ(ierr); 370 ierr = PetscOptionsReal("-snes_linesearch_alpha", "Descent tolerance", "SNESLineSearchBT", bt->alpha, &bt->alpha, PETSC_NULL);CHKERRQ(ierr); 371 372 ierr = PetscOptionsTail();CHKERRQ(ierr); 373 PetscFunctionReturn(0); 374 } 375 376 377 #undef __FUNCT__ 378 #define __FUNCT__ "SNESLineSearchCreate_BT" 379 /*MC 380 SNESLINESEARCHBT - Backtracking line search. 381 382 This line search finds the minimum of a polynomial fitting of the L2 norm of the 383 function. If this fit does not satisfy the conditions for progress, the interval shrinks 384 and the fit is reattempted at most max_it times or until lambda is below minlambda. 385 386 Options Database Keys: 387 + -snes_linesearch_alpha<1e-4> - slope descent parameter 388 . -snes_linesearch_damping<1.0> - initial step length 389 . -snes_linesearch_max_it<40> - maximum number of shrinking step 390 . -snes_linesearch_minlambda<1e-12> - minimum step length allowed 391 - -snes_linesearch_order<cubic,quadratic> - order of the approximation 392 393 Level: advanced 394 395 Notes: 396 This line search is taken from "Numerical Methods for Unconstrained 397 Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 398 399 .keywords: SNES, SNESLineSearch, damping 400 401 .seealso: SNESLineSearchCreate(), SNESLineSearchSetType() 402 M*/ 403 PETSC_EXTERN_C PetscErrorCode SNESLineSearchCreate_BT(SNESLineSearch linesearch) 404 { 405 406 SNESLineSearch_BT *bt; 407 PetscErrorCode ierr; 408 409 PetscFunctionBegin; 410 linesearch->ops->apply = SNESLineSearchApply_BT; 411 linesearch->ops->destroy = SNESLineSearchDestroy_BT; 412 linesearch->ops->setfromoptions = SNESLineSearchSetFromOptions_BT; 413 linesearch->ops->reset = PETSC_NULL; 414 linesearch->ops->view = SNESLineSearchView_BT; 415 linesearch->ops->setup = PETSC_NULL; 416 417 ierr = PetscNewLog(linesearch, SNESLineSearch_BT, &bt);CHKERRQ(ierr); 418 linesearch->data = (void *)bt; 419 linesearch->max_its = 40; 420 linesearch->order = SNES_LINESEARCH_ORDER_CUBIC; 421 bt->alpha = 1e-4; 422 423 PetscFunctionReturn(0); 424 } 425