1 #ifndef lint 2 static char vcid[] = "$Id: ls.c,v 1.46 1995/10/12 04:20:05 bsmith Exp curfman $"; 3 #endif 4 5 #include <math.h> 6 #include "ls.h" 7 #include "pinclude/pviewer.h" 8 9 /* 10 Implements a line search variant of Newton's Method 11 for solving systems of nonlinear equations. 12 13 Input parameters: 14 . snes - nonlinear context obtained from SNESCreate() 15 16 Output Parameters: 17 . outits - Number of global iterations until termination. 18 19 Notes: 20 This implements essentially a truncated Newton method with a 21 line search. By default a cubic backtracking line search 22 is employed, as described in the text "Numerical Methods for 23 Unconstrained Optimization and Nonlinear Equations" by Dennis 24 and Schnabel. 25 */ 26 27 int SNESSolve_LS(SNES snes,int *outits) 28 { 29 SNES_LS *neP = (SNES_LS *) snes->data; 30 int maxits, i, history_len, ierr, lits, lsfail; 31 MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN; 32 double fnorm, gnorm, xnorm, ynorm, *history; 33 Vec Y, X, F, G, W, TMP; 34 35 history = snes->conv_hist; /* convergence history */ 36 history_len = snes->conv_hist_len; /* convergence history length */ 37 maxits = snes->max_its; /* maximum number of iterations */ 38 X = snes->vec_sol; /* solution vector */ 39 F = snes->vec_func; /* residual vector */ 40 Y = snes->work[0]; /* work vectors */ 41 G = snes->work[1]; 42 W = snes->work[2]; 43 44 ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr); /* X <- X_0 */ 45 ierr = VecNorm(X,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 46 ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* (+/-) F(X) */ 47 ierr = VecNorm(F,&fnorm); CHKERRQ(ierr); /* fnorm <- ||F|| */ 48 snes->norm = fnorm; 49 if (history && history_len > 0) history[0] = fnorm; 50 if (snes->monitor) {ierr = (*snes->monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);} 51 52 for ( i=0; i<maxits; i++ ) { 53 snes->iter = i+1; 54 55 /* Solve J Y = -F, where J is Jacobian matrix */ 56 ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg); 57 CHKERRQ(ierr); 58 ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); 59 CHKERRQ(ierr); 60 ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr); 61 ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr); 62 ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);CHKERRQ(ierr); 63 if (lsfail) snes->nfailures++; 64 65 TMP = F; F = G; snes->vec_func_always = F; G = TMP; 66 TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 67 fnorm = gnorm; 68 69 snes->norm = fnorm; 70 if (history && history_len > i+1) history[i+1] = fnorm; 71 ierr = VecNorm(X,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 72 if (snes->monitor) {ierr = (*snes->monitor)(snes,i+1,fnorm,snes->monP);CHKERRQ(ierr);} 73 74 /* Test for convergence */ 75 if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) { 76 if (X != snes->vec_sol) { 77 ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr); 78 snes->vec_sol_always = snes->vec_sol; 79 snes->vec_func_always = snes->vec_func; 80 } 81 break; 82 } 83 } 84 if (i == maxits) { 85 PLogInfo((PetscObject)snes, 86 "SNESSolve_LS: Maximum number of iterations has been reached: %d\n",maxits); 87 i--; 88 } 89 *outits = i+1; 90 return 0; 91 } 92 /* ------------------------------------------------------------ */ 93 int SNESSetUp_LS(SNES snes ) 94 { 95 int ierr; 96 snes->nwork = 4; 97 ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work); CHKERRQ(ierr); 98 PLogObjectParents(snes,snes->nwork,snes->work); 99 snes->vec_sol_update_always = snes->work[3]; 100 return 0; 101 } 102 /* ------------------------------------------------------------ */ 103 int SNESDestroy_LS(PetscObject obj) 104 { 105 SNES snes = (SNES) obj; 106 int ierr; 107 ierr = VecFreeVecs(snes->work,snes->nwork); CHKERRQ(ierr); 108 PETSCFREE(snes->data); 109 return 0; 110 } 111 /* ------------------------------------------------------------ */ 112 /*ARGSUSED*/ 113 /*@C 114 SNESNoLineSearch - This routine is not a line search at all; 115 it simply uses the full Newton step. Thus, this routine is intended 116 to serve as a template and is not recommended for general use. 117 118 Input Parameters: 119 . snes - nonlinear context 120 . x - current iterate 121 . f - residual evaluated at x 122 . y - search direction (contains new iterate on output) 123 . w - work vector 124 . fnorm - 2-norm of f 125 126 Output Parameters: 127 . g - residual evaluated at new iterate y 128 . y - new iterate (contains search direction on input) 129 . gnorm - 2-norm of g 130 . ynorm - 2-norm of search length 131 . flag - set to 0, indicating a successful line search 132 133 Options Database Key: 134 $ -snes_line_search basic 135 136 .keywords: SNES, nonlinear, line search, cubic 137 138 .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 139 SNESSetLineSearchRoutine() 140 @*/ 141 int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 142 double fnorm, double *ynorm, double *gnorm,int *flag ) 143 { 144 int ierr; 145 Scalar one = 1.0; 146 *flag = 0; 147 PLogEventBegin(SNES_LineSearch,snes,x,f,g); 148 ierr = VecNorm(y,ynorm); CHKERRQ(ierr); /* ynorm = || y || */ 149 ierr = VecAXPY(&one,x,y); CHKERRQ(ierr); /* y <- x + y */ 150 ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* (+/-) F(y) */ 151 ierr = VecNorm(g,gnorm); CHKERRQ(ierr); /* gnorm = || g || */ 152 PLogEventEnd(SNES_LineSearch,snes,x,f,g); 153 return 0; 154 } 155 /* ------------------------------------------------------------------ */ 156 /*@C 157 SNESCubicLineSearch - This routine performs a cubic line search and 158 is the default line search method. 159 160 Input Parameters: 161 . snes - nonlinear context 162 . x - current iterate 163 . f - residual evaluated at x 164 . y - search direction (contains new iterate on output) 165 . w - work vector 166 . fnorm - 2-norm of f 167 168 Output Parameters: 169 . g - residual evaluated at new iterate y 170 . y - new iterate (contains search direction on input) 171 . gnorm - 2-norm of g 172 . ynorm - 2-norm of search length 173 . flag - 0 if line search succeeds; -1 on failure. 174 175 Options Database Key: 176 $ -snes_line_search cubic 177 178 Notes: 179 This line search is taken from "Numerical Methods for Unconstrained 180 Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 181 182 .keywords: SNES, nonlinear, line search, cubic 183 184 .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine() 185 @*/ 186 int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 187 double fnorm, double *ynorm, double *gnorm,int *flag) 188 { 189 double steptol, initslope,lambdaprev, gnormprev,a, b, d, t1, t2; 190 double maxstep,minlambda,alpha,lambda,lambdatemp; 191 #if defined(PETSC_COMPLEX) 192 Scalar cinitslope,clambda; 193 #endif 194 int ierr, count; 195 SNES_LS *neP = (SNES_LS *) snes->data; 196 Scalar one = 1.0,scale; 197 198 PLogEventBegin(SNES_LineSearch,snes,x,f,g); 199 *flag = 0; 200 alpha = neP->alpha; 201 maxstep = neP->maxstep; 202 steptol = neP->steptol; 203 204 ierr = VecNorm(y,ynorm); CHKERRQ(ierr); 205 if (*ynorm > maxstep) { /* Step too big, so scale back */ 206 scale = maxstep/(*ynorm); 207 #if defined(PETSC_COMPLEX) 208 PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale)); 209 #else 210 PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Scaling step by %g\n",scale); 211 #endif 212 ierr = VecScale(&scale,y); CHKERRQ(ierr); 213 *ynorm = maxstep; 214 } 215 minlambda = steptol/(*ynorm); 216 ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 217 #if defined(PETSC_COMPLEX) 218 ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 219 initslope = real(cinitslope); 220 #else 221 ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 222 #endif 223 if (initslope > 0.0) initslope = -initslope; 224 if (initslope == 0.0) initslope = -1.0; 225 226 ierr = VecCopy(y,w); CHKERRQ(ierr); 227 ierr = VecAXPY(&one,x,w); CHKERRQ(ierr); 228 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 229 ierr = VecNorm(g,gnorm); 230 if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 231 ierr = VecCopy(w,y); CHKERRQ(ierr); 232 PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Using full step\n"); 233 goto theend; 234 } 235 236 /* Fit points with quadratic */ 237 lambda = 1.0; count = 0; 238 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 239 lambdaprev = lambda; 240 gnormprev = *gnorm; 241 if (lambdatemp <= .1*lambda) lambda = .1*lambda; 242 else lambda = lambdatemp; 243 ierr = VecCopy(x,w); CHKERRQ(ierr); 244 #if defined(PETSC_COMPLEX) 245 clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 246 #else 247 ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 248 #endif 249 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 250 ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 251 if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 252 ierr = VecCopy(w,y); CHKERRQ(ierr); 253 PLogInfo((PetscObject)snes, 254 "SNESCubicLineSearch: Quadratically determined step, lambda %g\n",lambda); 255 goto theend; 256 } 257 258 /* Fit points with cubic */ 259 count = 1; 260 while (1) { 261 if (lambda <= minlambda) { /* bad luck; use full step */ 262 PLogInfo((PetscObject)snes, 263 "SNESCubicLineSearch:Unable to find good step length! %d \n",count); 264 PLogInfo((PetscObject)snes, 265 "SNESCubicLineSearch:f %g fnew %g ynorm %g lambda %g\n",fnorm,*gnorm,*ynorm,lambda); 266 ierr = VecCopy(w,y); CHKERRQ(ierr); 267 *flag = -1; break; 268 } 269 t1 = *gnorm - fnorm - lambda*initslope; 270 t2 = gnormprev - fnorm - lambdaprev*initslope; 271 a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 272 b = (-lambdaprev*t1/(lambda*lambda) + 273 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 + sqrt(d))/(3.0*a); 280 } 281 if (lambdatemp > .5*lambda) { 282 lambdatemp = .5*lambda; 283 } 284 lambdaprev = lambda; 285 gnormprev = *gnorm; 286 if (lambdatemp <= .1*lambda) { 287 lambda = .1*lambda; 288 } 289 else lambda = lambdatemp; 290 ierr = VecCopy( x, w ); CHKERRQ(ierr); 291 #if defined(PETSC_COMPLEX) 292 ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 293 #else 294 ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 295 #endif 296 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 297 ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 298 if (*gnorm <= fnorm + alpha*initslope) { /* is reduction enough */ 299 ierr = VecCopy(w,y); CHKERRQ(ierr); 300 PLogInfo((PetscObject)snes, 301 "SNESCubicLineSearch: Cubically determined step, lambda %g\n",lambda); 302 *flag = -1; break; 303 } 304 count++; 305 } 306 theend: 307 PLogEventEnd(SNES_LineSearch,snes,x,f,g); 308 return 0; 309 } 310 /* ------------------------------------------------------------------ */ 311 /*@C 312 SNESQuadraticLineSearch - This routine performs a cubic line search. 313 314 Input Parameters: 315 . snes - the SNES context 316 . x - current iterate 317 . f - residual evaluated at x 318 . y - search direction (contains new iterate on output) 319 . w - work vector 320 . fnorm - 2-norm of f 321 322 Output Parameters: 323 . g - residual evaluated at new iterate y 324 . y - new iterate (contains search direction on input) 325 . gnorm - 2-norm of g 326 . ynorm - 2-norm of search length 327 . flag - 0 if line search succeeds; -1 on failure. 328 329 Options Database Key: 330 $ -snes_line_search quadratic 331 332 Notes: 333 Use SNESSetLineSearchRoutine() 334 to set this routine within the SNES_EQ_NLS method. 335 336 .keywords: SNES, nonlinear, quadratic, line search 337 338 .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine() 339 @*/ 340 int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 341 double fnorm, double *ynorm, double *gnorm,int *flag) 342 { 343 double steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp; 344 #if defined(PETSC_COMPLEX) 345 Scalar cinitslope,clambda; 346 #endif 347 int ierr,count; 348 SNES_LS *neP = (SNES_LS *) snes->data; 349 Scalar one = 1.0,scale; 350 351 PLogEventBegin(SNES_LineSearch,snes,x,f,g); 352 *flag = 0; 353 alpha = neP->alpha; 354 maxstep = neP->maxstep; 355 steptol = neP->steptol; 356 357 VecNorm(y, ynorm ); 358 if (*ynorm > maxstep) { /* Step too big, so scale back */ 359 scale = maxstep/(*ynorm); 360 ierr = VecScale(&scale,y); CHKERRQ(ierr); 361 *ynorm = maxstep; 362 } 363 minlambda = steptol/(*ynorm); 364 ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 365 #if defined(PETSC_COMPLEX) 366 ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 367 initslope = real(cinitslope); 368 #else 369 ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 370 #endif 371 if (initslope > 0.0) initslope = -initslope; 372 if (initslope == 0.0) initslope = -1.0; 373 374 ierr = VecCopy(y,w); CHKERRQ(ierr); 375 ierr = VecAXPY(&one,x,w); CHKERRQ(ierr); 376 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 377 ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 378 if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 379 ierr = VecCopy(w,y); CHKERRQ(ierr); 380 PLogInfo((PetscObject)snes,"SNESQuadraticLineSearch: Using full step\n"); 381 goto theend; 382 } 383 384 /* Fit points with quadratic */ 385 lambda = 1.0; count = 0; 386 count = 1; 387 while (1) { 388 if (lambda <= minlambda) { /* bad luck; use full step */ 389 PLogInfo((PetscObject)snes, 390 "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 391 PLogInfo((PetscObject)snes, 392 "SNESQuadraticLineSearch:f %g fnew %g ynorm %g lambda %g\n",fnorm,*gnorm,*ynorm,lambda); 393 ierr = VecCopy(w,y); CHKERRQ(ierr); 394 *flag = -1; break; 395 } 396 lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 397 lambdaprev = lambda; 398 gnormprev = *gnorm; 399 if (lambdatemp <= .1*lambda) { 400 lambda = .1*lambda; 401 } else lambda = lambdatemp; 402 ierr = VecCopy(x,w); CHKERRQ(ierr); 403 #if defined(PETSC_COMPLEX) 404 clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 405 #else 406 ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 407 #endif 408 ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 409 ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 410 if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 411 ierr = VecCopy(w,y); CHKERRQ(ierr); 412 PLogInfo((PetscObject)snes, 413 "SNESQuadraticLineSearch:Quadratically determined step, lambda %g\n",lambda); 414 break; 415 } 416 count++; 417 } 418 theend: 419 PLogEventEnd(SNES_LineSearch,snes,x,f,g); 420 return 0; 421 } 422 /* ------------------------------------------------------------ */ 423 /*@ 424 SNESSetLineSearchRoutine - Sets the line search routine to be used 425 by the method SNES_LS. 426 427 Input Parameters: 428 . snes - nonlinear context obtained from SNESCreate() 429 . func - pointer to int function 430 431 Available Routines: 432 . SNESCubicLineSearch() - default line search 433 . SNESQuadraticLineSearch() - quadratic line search 434 . SNESNoLineSearch() - the full Newton step (actually not a line search) 435 436 Options Database Keys: 437 $ -snes_line_search [basic,quadratic,cubic] 438 439 Calling sequence of func: 440 func (SNES snes, Vec x, Vec f, Vec g, Vec y, 441 Vec w, double fnorm, double *ynorm, 442 double *gnorm, *flag) 443 444 Input parameters for func: 445 . snes - nonlinear context 446 . x - current iterate 447 . f - residual evaluated at x 448 . y - search direction (contains new iterate on output) 449 . w - work vector 450 . fnorm - 2-norm of f 451 452 Output parameters for func: 453 . g - residual evaluated at new iterate y 454 . y - new iterate (contains search direction on input) 455 . gnorm - 2-norm of g 456 . ynorm - 2-norm of search length 457 . flag - set to 0 if the line search succeeds; a nonzero integer 458 on failure. 459 460 .keywords: SNES, nonlinear, set, line search, routine 461 462 .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch() 463 @*/ 464 int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 465 double,double *,double*,int*) ) 466 { 467 if ((snes)->type == SNES_EQ_NLS) 468 ((SNES_LS *)(snes->data))->LineSearch = func; 469 return 0; 470 } 471 /* ------------------------------------------------------------------ */ 472 static int SNESPrintHelp_LS(SNES snes) 473 { 474 SNES_LS *ls = (SNES_LS *)snes->data; 475 char *p; 476 if (snes->prefix) p = snes->prefix; else p = "-"; 477 MPIU_printf(snes->comm," method ls (system of nonlinear equations):\n"); 478 MPIU_printf(snes->comm," %ssnes_line_search [basic,quadratic,cubic]\n",p); 479 MPIU_printf(snes->comm," %ssnes_line_search_alpha alpha (default %g)\n",p,ls->alpha); 480 MPIU_printf(snes->comm," %ssnes_line_search_maxstep max (default %g)\n",p,ls->maxstep); 481 MPIU_printf(snes->comm," %ssnes_line_search_steptol tol (default %g)\n",p,ls->steptol); 482 return 0; 483 } 484 /* ------------------------------------------------------------------ */ 485 static int SNESView_LS(PetscObject obj,Viewer viewer) 486 { 487 SNES snes = (SNES)obj; 488 SNES_LS *ls = (SNES_LS *)snes->data; 489 FILE *fd; 490 char *cstring; 491 int ierr; 492 493 ierr = ViewerFileGetPointer_Private(viewer,&fd); CHKERRQ(ierr); 494 if (ls->LineSearch == SNESNoLineSearch) cstring = "SNESNoLineSearch"; 495 else if (ls->LineSearch == SNESQuadraticLineSearch) cstring = "SNESQuadraticLineSearch"; 496 else if (ls->LineSearch == SNESCubicLineSearch) cstring = "SNESCubicLineSearch"; 497 else cstring = "unknown"; 498 MPIU_fprintf(snes->comm,fd," line search variant: %s\n",cstring); 499 MPIU_fprintf(snes->comm,fd," alpha=%g, maxstep=%g, steptol=%g\n", 500 ls->alpha,ls->maxstep,ls->steptol); 501 return 0; 502 } 503 /* ------------------------------------------------------------------ */ 504 static int SNESSetFromOptions_LS(SNES snes) 505 { 506 SNES_LS *ls = (SNES_LS *)snes->data; 507 char ver[16]; 508 double tmp; 509 510 if (OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp)) { 511 ls->alpha = tmp; 512 } 513 if (OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp)) { 514 ls->maxstep = tmp; 515 } 516 if (OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp)) { 517 ls->steptol = tmp; 518 } 519 if (OptionsGetString(snes->prefix,"-snes_line_search",ver,16)) { 520 if (!PetscStrcmp(ver,"basic")) { 521 SNESSetLineSearchRoutine(snes,SNESNoLineSearch); 522 } 523 else if (!PetscStrcmp(ver,"quadratic")) { 524 SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch); 525 } 526 else if (!PetscStrcmp(ver,"cubic")) { 527 SNESSetLineSearchRoutine(snes,SNESCubicLineSearch); 528 } 529 else {SETERRQ(1,"SNESSetFromOptions_LS:Unknown line search");} 530 } 531 return 0; 532 } 533 /* ------------------------------------------------------------ */ 534 int SNESCreate_LS(SNES snes ) 535 { 536 SNES_LS *neP; 537 538 if (snes->method_class != SNES_NONLINEAR_EQUATIONS) 539 SETERRQ(1,"SNESCreate_LS:For SNES_NONLINEAR_EQUATIONS only"); 540 snes->type = SNES_EQ_NLS; 541 snes->setup = SNESSetUp_LS; 542 snes->solve = SNESSolve_LS; 543 snes->destroy = SNESDestroy_LS; 544 snes->converged = SNESDefaultConverged; 545 snes->printhelp = SNESPrintHelp_LS; 546 snes->setfromoptions = SNESSetFromOptions_LS; 547 snes->view = SNESView_LS; 548 549 neP = PETSCNEW(SNES_LS); CHKPTRQ(neP); 550 PLogObjectMemory(snes,sizeof(SNES_LS)); 551 snes->data = (void *) neP; 552 neP->alpha = 1.e-4; 553 neP->maxstep = 1.e8; 554 neP->steptol = 1.e-12; 555 neP->LineSearch = SNESCubicLineSearch; 556 return 0; 557 } 558 559 560 561 562