Actual source code: umls.c

  1: /*$Id: umls.c,v 1.109 2001/04/10 19:36:57 bsmith Exp $*/

 3:  #include src/snes/impls/umls/umls.h

  5: EXTERN int SNESStep(SNES,double*,double*,double*,double*,
  6:                     double*,double*,double*,double*,double*);

  8: /*
  9:    Implements Newton's Method with a line search approach
 10:    for solving unconstrained minimization problems.

 12:    Note:
 13:    The line search algorithm is taken from More and Thuente,
 14:    "Line search algorithms with guaranteed sufficient decrease",
 15:    Argonne National Laboratory, Technical Report MCS-P330-1092.
 16: */

 18: static int SNESSolve_UM_LS(SNES snes,int *outits)
 19: {
 20:   SNES_UM_LS          *neP = (SNES_UM_LS*)snes->data;
 21:   int                 maxits,success,iters,i,global_dim,ierr,kspmaxit;
 22:   double              snorm,*f,*gnorm,two = 2.0,tnorm;
 23:   Scalar              neg_one = -1.0;
 24:   Vec                 G,X,RHS,S,W;
 25:   SLES                sles;
 26:   KSP                 ksp;
 27:   MatStructure        flg = DIFFERENT_NONZERO_PATTERN;
 28:   SNESConvergedReason reason;
 29:   KSPConvergedReason  kreason;

 32:   snes->reason  = SNES_CONVERGED_ITERATING;

 34:   maxits        = snes->max_its;        /* maximum number of iterations */
 35:   X                = snes->vec_sol;         /* solution vector */
 36:   G                = snes->vec_func;        /* gradient vector */
 37:   RHS                = snes->work[0];         /* work vectors */
 38:   S                = snes->work[1];        /* step vector */
 39:   W                = snes->work[2];        /* work vector */
 40:   f                = &(snes->fc);                /* function to minimize */
 41:   gnorm                = &(snes->norm);        /* gradient norm */

 43:   PetscObjectTakeAccess(snes);
 44:   snes->iter = 0;
 45:   PetscObjectGrantAccess(snes);
 46:   SNESComputeMinimizationFunction(snes,X,f); /* f(X) */
 47:   SNESComputeGradient(snes,X,G);     /* G(X) <- gradient */

 49:   PetscObjectTakeAccess(snes);
 50:   VecNorm(G,NORM_2,gnorm);         /* gnorm = || G || */
 51:   PetscObjectGrantAccess(snes);
 52:   SNESLogConvHistory(snes,*gnorm,0);
 53:   SNESMonitor(snes,0,*gnorm);

 55:   SNESGetSLES(snes,&sles);
 56:   SLESGetKSP(sles,&ksp);
 57:   VecGetSize(X,&global_dim);
 58:   kspmaxit = neP->max_kspiter_factor * ((int)sqrt((double)global_dim));
 59:   KSPSetTolerances(ksp,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,kspmaxit);

 61:   for (i=0; i<maxits; i++) {
 62:     PetscObjectTakeAccess(snes);
 63:     snes->iter = i+1;
 64:     PetscObjectGrantAccess(snes);
 65:     neP->gamma = neP->gamma_factor*(*gnorm);
 66:     success = 0;
 67:     VecCopy(G,RHS);
 68:     VecScale(&neg_one,RHS);
 69:     SNESComputeHessian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);
 70:     SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg);
 71:     while (!success) {
 72:       SLESSolve(snes->sles,RHS,S,&iters);
 73:       snes->linear_its += iters;
 74:       KSPGetConvergedReason(ksp,&kreason);
 75:       if ((int)kreason < 0 || (iters >= kspmaxit)) { /* Modify diagonal of Hessian */
 76:         neP->gamma_factor *= two;
 77:         neP->gamma = neP->gamma_factor*(*gnorm);
 78: #if !defined(PETSC_USE_COMPLEX)
 79:         PetscLogInfo(snes,"SNESSolve_UM_LS:  modify diagonal (assume same nonzero structure), gamma_factor=%g, gamma=%gn",
 80:                  neP->gamma_factor,neP->gamma);
 81: #else
 82:         PetscLogInfo(snes,"SNESSolve_UM_LS:  modify diagonal (asuume same nonzero structure), gamma_factor=%g, gamma=%gn",
 83:                  neP->gamma_factor,PetscRealPart(neP->gamma));
 84: #endif
 85:         MatShift(&neP->gamma,snes->jacobian);
 86:         if ((snes->jacobian_pre != snes->jacobian) && (flg != SAME_PRECONDITIONER)){
 87:           MatShift(&neP->gamma,snes->jacobian_pre);
 88:         }
 89:         /* We currently assume that all diagonal elements were allocated in
 90:          original matrix, so that nonzero pattern is same ... should fix this */
 91:         SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,
 92:                SAME_NONZERO_PATTERN);
 93:       } else {
 94:         success = 1;
 95:       }
 96:     }
 97:     VecNorm(S,NORM_2,&snorm);

 99:     /* Line search */
100:     neP->step = 1.0;
101:     (*neP->LineSearch)(snes,X,G,S,W,f,&(neP->step),&tnorm,&(neP->line));
102:     PetscObjectTakeAccess(snes);
103:     snes->norm = tnorm;
104:     PetscObjectGrantAccess(snes);
105:     if (neP->line != 1) snes->nfailures++;

107:     SNESLogConvHistory(snes,*gnorm,iters);
108:     SNESMonitor(snes,i+1,*gnorm);
109:     PetscLogInfo(snes,"SNESSolve_UM_LS: %d:  f=%g, gnorm=%g, snorm=%g, step=%g, KSP iters=%dn",
110:              snes->iter,*f,*gnorm,snorm,neP->step,iters);

112:     /* Test for convergence */
113:     (*snes->converged)(snes,snorm,*gnorm,*f,&reason,snes->cnvP);
114:     if (reason) break;
115:     neP->gamma_factor /= two;
116:   }
117:   /* Verify solution is in correct location */
118:   if (X != snes->vec_sol) {
119:     VecCopy(X,snes->vec_sol);
120:     snes->vec_sol_always = snes->vec_sol;
121:     snes->vec_func_always = snes->vec_func;
122:   }
123:   if (i == maxits) {
124:     PetscLogInfo(snes,"SNESSolve_UM_LS: Maximum number of iterations reached: %dn",maxits);
125:     i--;
126:     reason = SNES_DIVERGED_MAX_IT;
127:   }
128:   PetscObjectTakeAccess(snes);
129:   snes->reason = reason;
130:   PetscObjectGrantAccess(snes);
131:   *outits = i+1;
132:   return(0);
133: }
134: /* ---------------------------------------------------------- */
135: static int SNESSetUp_UM_LS(SNES snes)
136: {
137:   int        ierr;
138:   PetscTruth ilu,bjacobi;
139:   SLES       sles;
140:   PC         pc;

143:   snes->nwork = 4;
144:   VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);
145:   PetscLogObjectParents(snes,snes->nwork,snes->work);
146:   snes->vec_sol_update_always = snes->work[3];

148:   /* 
149:        If PC was set by default to ILU then change it to Jacobi
150:   */
151:   SNESGetSLES(snes,&sles);
152:   SLESGetPC(sles,&pc);
153:   PetscTypeCompare((PetscObject)pc,PCILU,&ilu);
154:   if (ilu) {
155:     PCSetType(pc,PCJACOBI);
156:   } else {
157:     PetscTypeCompare((PetscObject)pc,PCBJACOBI,&bjacobi);
158:     if (bjacobi) {
159:        /* cannot do this; since PC may not have been setup yet */
160:        /* PCBJacobiGetSubSLES(pc,0,0,&subsles);
161:        SLESGetPC(*subsles,&subpc);
162:        PetscTypeCompare((PetscObject)subpc,PCILU,&ilu);
163:        if (ilu) {
164:          PCSetType(pc,PCJACOBI);
165:        } */
166:        /* don't really want to do this, since user may have selected BJacobi plus something
167:          that is symmetric on each processor; really only want to catch the default ILU */
168:       PCSetType(pc,PCJACOBI);
169:     }
170:   }

172:   return(0);
173: }
174: /*------------------------------------------------------------*/
175: static int SNESDestroy_UM_LS(SNES snes)
176: {
177:   int  ierr;

180:   if (snes->nwork) {
181:      VecDestroyVecs(snes->work,snes->nwork);
182:   }
183:   PetscFree(snes->data);
184:   return(0);
185: }
186: /*------------------------------------------------------------*/
187: static int SNESSetFromOptions_UM_LS(SNES snes)
188: {
189:   SNES_UM_LS *ctx = (SNES_UM_LS *)snes->data;
190:   int        ierr;
191:   SLES       sles;
192:   PC         pc;
193:   PetscTruth ismatshell,nopcset;
194:   Mat        pmat;

197:   PetscOptionsHead("SNES trust region options for minimization");
198:     PetscOptionsDouble("-snes_um_ls_gamma_factor","Damping parameter","None",ctx->gamma_factor,&ctx->gamma_factor,0);
199:     PetscOptionsInt("-snes_um_ls_maxfev","Max function evaluation in line search","None",ctx->maxfev,&ctx->maxfev,0);
200:     PetscOptionsDouble("-snes_um_ls_ftol","Tolerance for sufficient decrease","None",ctx->ftol,&ctx->ftol,0);
201:     PetscOptionsDouble("-snes_um_ls_gtol","Tolerance for curvature condition","None",ctx->gtol,&ctx->gtol,0);
202:     PetscOptionsDouble("-snes_um_ls_rtol","Relative tolerance for acceptable step","None",ctx->rtol,&ctx->rtol,0);
203:     PetscOptionsDouble("-snes_um_ls_stepmin","Lower bound for step","None",ctx->stepmin,&ctx->stepmin,0);
204:     PetscOptionsDouble("-snes_um_ls_stepmax","upper bound for step","None",ctx->stepmax,&ctx->stepmax,0);
205:   PetscOptionsTail();
206:   /* if preconditioner has not been set yet, and not using a matrix shell then
207:      set preconditioner to Jacobi. This is to prevent PCSetFromOptions() from 
208:      setting a default of ILU or block Jacobi-ILU which won't work since TR 
209:      requires a symmetric preconditioner
210:   */
211:   SNESGetSLES(snes,&sles);
212:   SLESGetPC(sles,&pc);
213:   PetscTypeCompare((PetscObject)pc,0,&nopcset);
214:   if (nopcset) {
215:     PCGetOperators(pc,PETSC_NULL,&pmat,PETSC_NULL);
216:     if (pmat) {
217:       PetscTypeCompare((PetscObject)pmat,MATSHELL,&ismatshell);
218:       if (!ismatshell) {
219:         PCSetType(pc,PCJACOBI);
220:       }
221:     }
222:   }
223:   return(0);
224: }

226: /*------------------------------------------------------------*/
227: static int SNESView_UM_LS(SNES snes,PetscViewer viewer)
228: {
229:   SNES_UM_LS *ls = (SNES_UM_LS *)snes->data;
230:   int        ierr;
231:   PetscTruth isascii;

234:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
235:   if (isascii) {
236:     PetscViewerASCIIPrintf(viewer,"  gamma_f=%g, maxf=%d, maxkspf=%d, ftol=%g, rtol=%g, gtol=%gn",
237:                       ls->gamma_factor,ls->maxfev,ls->max_kspiter_factor,ls->ftol,ls->rtol,ls->gtol);
238:   } else {
239:     SETERRQ1(1,"Viewer type %s not supported for SNES UM LS",((PetscObject)viewer)->type_name);
240:   }
241:   return(0);
242: }
243: /* ---------------------------------------------------------- */
244: /*@C
245:    SNESConverged_UM_LS - Monitors the convergence of the SNESSolve_UM_LS()
246:    routine (default). 

248:    Collective on SNES

250:    Input Parameters:
251: +  snes - the SNES context
252: .  xnorm - 2-norm of current iterate
253: .  gnorm - 2-norm of current gradient
254: .  f - objective function value
255: -  dummy - unused dummy context

257:    Output Parameter:
258: .   reason - one of
259: $   SNES_CONVERGED_FNORM_ABS         (F < F_minabs),
260: $   SNES_CONVERGED_GNORM_ABS         (grad F < grad),
261: $   SNES_DIVERGED_FUNCTION_COUNT     (nfunc > max_func),
262: $   SNES_DIVERGED_LS_FAILURE         (line search attempt failed)
263: $   SNES_DIVERGED_FNORM_NAN          (f = NaN),
264: $   SNES_CONVERGED_ITERATING         otherwise

266:    where
267: +  atol     - absolute gradient norm tolerance, set with SNESSetTolerances()
268: .  fmin     - lower bound on function value, set with SNESSetMinimizationFunctionTolerance()
269: .  max_func - maximum number of function evaluations, set with SNESSetTolerances()
270: -  nfunc    - number of function evaluations

272:    Level: intermediate

274: @*/
275: int SNESConverged_UM_LS(SNES snes,double xnorm,double gnorm,double f,SNESConvergedReason *reason,void *dummy)
276: {
277:   SNES_UM_LS *neP = (SNES_UM_LS*)snes->data;


281:   if (f != f) {
282:     PetscLogInfo(snes,"SNESConverged_UM_LS:Failed to converged, function is NaNn");
283:     *reason = SNES_DIVERGED_FNORM_NAN;
284:   } else if (f < snes->fmin) {
285:     PetscLogInfo(snes,"SNESConverged_UM_LS: Converged due to function value %g < minimum function value %gn",
286:              f,snes->fmin);
287:     *reason = SNES_CONVERGED_FNORM_ABS ;
288:   } else if (gnorm < snes->atol) {
289:     PetscLogInfo(snes,"SNESConverged_UM_LS: Converged due to gradient norm %g < %gn",gnorm,snes->atol);
290:     *reason = SNES_CONVERGED_GNORM_ABS;
291:   } else if (snes->nfuncs > snes->max_funcs) {
292:     PetscLogInfo(snes,"SNESConverged_UM_LS: Exceeded maximum number of function evaluations: %d > %dn",
293:              snes->nfuncs,snes->max_funcs);
294:     *reason = SNES_DIVERGED_FUNCTION_COUNT;
295:   } else if (neP->line != 1) {
296:     PetscLogInfo(snes,"SNESConverged_UM_LS: Line search failed for above reasonn");
297:     *reason = SNES_DIVERGED_LS_FAILURE;
298:   } else {
299:     *reason = SNES_CONVERGED_ITERATING;
300:   }
301:   return(0);
302: }
303: /* ---------------------------------------------------------- */
304: /* @ SNESMoreLineSearch - This routine performs a line search algorithm,
305:      taken from More and Thuente, "Line search algorithms with 
306:      guaranteed sufficient decrease", Argonne National Laboratory", 
307:      Technical Report MCS-P330-1092.

309:    Input Parameters:
310: +  snes - SNES context
311: .  X - current iterate (on output X contains new iterate, X + step*S)
312: .  S - search direction
313: .  f - objective function evaluated at X
314: .  G - gradient evaluated at X
315: .  W - work vector
316: -  step - initial estimate of step length

318:    Output parameters:
319: +  f - objective function evaluated at new iterate, X + step*S
320: .  G - gradient evaluated at new iterate, X + step*S
321: .  X - new iterate
322: .  gnorm - 2-norm of G
323: -  step - final step length

325:    Info is set to one of:
326: .   1 - the line search succeeds; the sufficient decrease
327:    condition and the directional derivative condition hold

329:    negative number if an input parameter is invalid
330: .   -1 -  step < 0 
331: .   -2 -  ftol < 0 
332: .   -3 -  rtol < 0 
333: .   -4 -  gtol < 0 
334: .   -5 -  stepmin < 0 
335: .   -6 -  stepmax < stepmin
336: -   -7 -  maxfev < 0

338:    positive number > 1 if the line search otherwise terminates
339: +    2 -  Relative width of the interval of uncertainty is 
340:          at most rtol.
341: .    3 -  Maximum number of function evaluations (maxfev) has 
342:          been reached.
343: .    4 -  Step is at the lower bound, stepmin.
344: .    5 -  Step is at the upper bound, stepmax.
345: .    6 -  Rounding errors may prevent further progress. 
346:          There may not be a step that satisfies the 
347:          sufficient decrease and curvature conditions.  
348:          Tolerances may be too small.
349: +    7 -  Search direction is not a descent direction.

351:    Notes:
352:    This routine is used within the SNESUMLS method.
353: @ */
354: int SNESMoreLineSearch(SNES snes,Vec X,Vec G,Vec S,Vec W,double *f,
355:                   double *step,double *gnorm,int *info)
356: {
357:   SNES_UM_LS *neP = (SNES_UM_LS*)snes->data;
358:   double     zero = 0.0,two = 2.0,p5 = 0.5,p66 = 0.66,xtrapf = 4.0;
359:   double     finit,width,width1,dginit,fm,fxm,fym,dgm,dgxm,dgym;
360:   double     dgx,dgy,dg,fx,fy,stx,sty,dgtest,ftest1;
361:   int        ierr,i,stage1;
362: #if defined(PETSC_USE_COMPLEX)
363:   Scalar    cdginit,cdg,cstep = 0.0;
364: #endif

367:   /* neP->stepmin - lower bound for step */
368:   /* neP->stepmax - upper bound for step */
369:   /* neP->rtol           - relative tolerance for an acceptable step */
370:   /* neP->ftol           - tolerance for sufficient decrease condition */
371:   /* neP->gtol           - tolerance for curvature condition */
372:   /* neP->nfev           - number of function evaluations */
373:   /* neP->maxfev  - maximum number of function evaluations */

375:   /* Check input parameters for errors */
376:   if (*step < zero) {
377:     PetscLogInfo(snes,"SNESMoreLineSearch:Line search error: step (%g) < 0n",*step);
378:     *info = -1; return(0);
379:   } else if (neP->ftol < zero) {
380:     PetscLogInfo(snes,"SNESMoreLineSearch:Line search error: ftol (%g) < 0n,neP->ftol");
381:     *info = -2; return(0);
382:   } else if (neP->rtol < zero) {
383:     PetscLogInfo(snes,"SNESMoreLineSearch:Line search error: rtol (%g) < 0n",neP->rtol);
384:     *info = -3; return(0);
385:   } else if (neP->gtol < zero) {
386:     PetscLogInfo(snes,"SNESMoreLineSearch:Line search error: gtol (%g) < 0n",neP->gtol);
387:     *info = -4; return(0);
388:   } else if (neP->stepmin < zero) {
389:     PetscLogInfo(snes,"SNESMoreLineSearch:Line search error: stepmin (%g) < 0n,neP->stepmin");
390:     *info = -5; return(0);
391:   } else if (neP->stepmax < neP->stepmin) {
392:     PetscLogInfo(snes,"SNESMoreLineSearch:Line search error: stepmax (%g) < stepmin (%g)n",
393:        neP->stepmax,neP->stepmin);
394:     *info = -6; return(0);
395:   } else if (neP->maxfev < zero) {
396:     PetscLogInfo(snes,"SNESMoreLineSearch:Line search error: maxfev (%d) < 0n",neP->maxfev);
397:     *info = -7; return(0);
398:   }

400:   /* Check that search direction is a descent direction */
401: #if defined(PETSC_USE_COMPLEX)
402:   VecDot(G,S,&cdginit); dginit = PetscRealPart(cdginit);
403: #else
404:   VecDot(G,S,&dginit);  /* dginit = G^T S */
405: #endif
406:   if (dginit >= zero) {
407:     PetscLogInfo(snes,"SNESMoreLineSearch:Search direction not a descent directionn");
408:     *info = 7; return(0);
409:   }

411:   /* Initialization */
412:   neP->bracket = 0;
413:   *info          = 0;
414:   stage1  = 1;
415:   finit   = *f;
416:   dgtest  = neP->ftol * dginit;
417:   width   = neP->stepmax - neP->stepmin;
418:   width1  = width * two;
419:   VecCopy(X,W);
420:   /* Variable dictionary:  
421:      stx, fx, dgx - the step, function, and derivative at the best step
422:      sty, fy, dgy - the step, function, and derivative at the other endpoint 
423:                    of the interval of uncertainty
424:      step, f, dg - the step, function, and derivative at the current step */

426:   stx = zero;
427:   fx  = finit;
428:   dgx = dginit;
429:   sty = zero;
430:   fy  = finit;
431:   dgy = dginit;
432: 
433:   neP->nfev = 0;
434:   for (i=0; i< neP->maxfev; i++) {
435:     /* Set min and max steps to correspond to the interval of uncertainty */
436:     if (neP->bracket) {
437:       neP->stepmin = PetscMin(stx,sty);
438:       neP->stepmax = PetscMax(stx,sty);
439:     } else {
440:       neP->stepmin = stx;
441:       neP->stepmax = *step + xtrapf * (*step - stx);
442:     }

444:     /* Force the step to be within the bounds */
445:     *step = PetscMax(*step,neP->stepmin);
446:     *step = PetscMin(*step,neP->stepmax);

448:     /* If an unusual termination is to occur, then let step be the lowest
449:        point obtained thus far */
450:     if (((neP->bracket) && (*step <= neP->stepmin || *step >= neP->stepmax)) ||
451:         ((neP->bracket) && (neP->stepmax - neP->stepmin <= neP->rtol * neP->stepmax)) ||
452:         (neP->nfev >= neP->maxfev - 1) || (neP->infoc == 0))
453:       *step = stx;

455: #if defined(PETSC_USE_COMPLEX)
456:     cstep = *step;
457:     VecWAXPY(&cstep,S,W,X);
458: #else
459:     VecWAXPY(step,S,W,X);         /* X = W + step*S */
460: #endif
461:     SNESComputeMinimizationFunction(snes,X,f);
462:     neP->nfev++;
463:     SNESComputeGradient(snes,X,G);
464: #if defined(PETSC_USE_COMPLEX)
465:     VecDot(G,S,&cdg); dg = PetscRealPart(cdg);
466: #else
467:     VecDot(G,S,&dg);                /* dg = G^T S */
468: #endif
469:     ftest1 = finit + *step * dgtest;
470: 
471:     /* Convergence testing */
472:     if (((neP->bracket) && (*step <= neP->stepmin||*step >= neP->stepmax)) || (!neP->infoc)) {
473:       *info = 6;
474:       PetscLogInfo(snes,"SNESMoreLineSearch:Rounding errors may prevent further progress.  May not be a step satisfyingn");
475:       PetscLogInfo(snes,"SNESMoreLineSearch:sufficient decrease and curvature conditions. Tolerances may be too small.n");
476:     }
477:     if ((*step == neP->stepmax) && (*f <= ftest1) && (dg <= dgtest)) {
478:       PetscLogInfo(snes,"SNESMoreLineSearch:Step is at the upper bound, stepmax (%g)n",neP->stepmax);
479:       *info = 5;
480:     }
481:     if ((*step == neP->stepmin) && (*f >= ftest1) && (dg >= dgtest)) {
482:       PetscLogInfo(snes,"SNESMoreLineSearch:Step is at the lower bound, stepmin (%g)n",neP->stepmin);
483:       *info = 4;
484:     }
485:     if (neP->nfev >= neP->maxfev) {
486:       PetscLogInfo(snes,"SNESMoreLineSearch:Number of line search function evals (%d) > maximum (%d)n",neP->nfev,neP->maxfev);
487:       *info = 3;
488:     }
489:     if ((neP->bracket) && (neP->stepmax - neP->stepmin <= neP->rtol*neP->stepmax)){
490:       PetscLogInfo(snes,"SNESMoreLineSearch:Relative width of interval of uncertainty is at most rtol (%g)n",neP->rtol);
491:       *info = 2;
492:     }
493:     if ((*f <= ftest1) && (PetscAbsDouble(dg) <= neP->gtol*(-dginit))) {
494:       PetscLogInfo(snes,"SNESMoreLineSearch:Line search success: Sufficient decrease and directional deriv conditions holdn");
495:       *info = 1;
496:     }
497:     if (*info) break;

499:     /* In the first stage, we seek a step for which the modified function
500:         has a nonpositive value and nonnegative derivative */
501:     if ((stage1) && (*f <= ftest1) && (dg >= dginit * PetscMin(neP->ftol,neP->gtol)))
502:       stage1 = 0;

504:     /* A modified function is used to predict the step only if we
505:        have not obtained a step for which the modified function has a 
506:        nonpositive function value and nonnegative derivative, and if a
507:        lower function value has been obtained but the decrease is not
508:        sufficient */

510:     if ((stage1) && (*f <= fx) && (*f > ftest1)) {
511:       fm   = *f - *step * dgtest;        /* Define modified function */
512:       fxm  = fx - stx * dgtest;                /* and derivatives */
513:       fym  = fy - sty * dgtest;
514:       dgm  = dg - dgtest;
515:       dgxm = dgx - dgtest;
516:       dgym = dgy - dgtest;

518:       /* Update the interval of uncertainty and compute the new step */
519:       SNESStep(snes,&stx,&fxm,&dgxm,&sty,&fym,&dgym,step,&fm,&dgm);

521:       fx  = fxm + stx * dgtest;        /* Reset the function and */
522:       fy  = fym + sty * dgtest;        /* gradient values */
523:       dgx = dgxm + dgtest;
524:       dgy = dgym + dgtest;
525:     } else {
526:       /* Update the interval of uncertainty and compute the new step */
527:       SNESStep(snes,&stx,&fx,&dgx,&sty,&fy,&dgy,step,f,&dg);
528:     }

530:    /* Force a sufficient decrease in the interval of uncertainty */
531:    if (neP->bracket) {
532:      if (PetscAbsDouble(sty - stx) >= p66 * width1) *step = stx + p5*(sty - stx);
533:        width1 = width;
534:        width = PetscAbsDouble(sty - stx);
535:      }
536:    }

538:   /* Finish computations */
539:   PetscLogInfo(snes,"SNESMoreLineSearch:%d function evals in line search, step = %10.4fn",neP->nfev,neP->step);
540:   VecNorm(G,NORM_2,gnorm);
541:   return(0);
542: }

544: EXTERN_C_BEGIN
545: int SNESLineSearchGetDampingParameter_UM_LS(SNES snes,Scalar *damp)
546: {
547:   SNES_UM_LS *neP;

550:   neP = (SNES_UM_LS*)snes->data;
551:   *damp = neP->gamma;
552:   return(0);
553: }
554: EXTERN_C_END

556: /* ---------------------------------------------------------- */
557: EXTERN_C_BEGIN
558: int SNESCreate_UM_LS(SNES snes)
559: {
560:   SNES_UM_LS *neP;
561:   int       ierr;

564:   if (snes->method_class != SNES_UNCONSTRAINED_MINIMIZATION) {
565:     SETERRQ(PETSC_ERR_ARG_WRONG,"For SNES_UNCONSTRAINED_MINIMIZATION only");
566:   }
567:   snes->setup                  = SNESSetUp_UM_LS;
568:   snes->solve                  = SNESSolve_UM_LS;
569:   snes->destroy                  = SNESDestroy_UM_LS;
570:   snes->converged          = SNESConverged_UM_LS;
571:   snes->view              = SNESView_UM_LS;
572:   snes->setfromoptions    = SNESSetFromOptions_UM_LS;
573:   snes->nwork             = 0;

575:   ierr                          = PetscNew(SNES_UM_LS,&neP);
576:   PetscLogObjectMemory(snes,sizeof(SNES_UM_LS));
577:   snes->data                  = (void*)neP;
578:   neP->LineSearch          = SNESMoreLineSearch;
579:   neP->gamma                  = 0.0;
580:   neP->gamma_factor          = 0.005;
581:   neP->max_kspiter_factor = 5;
582:   neP->step                  = 1.0;
583:   neP->ftol                  = 0.001;
584:   neP->rtol                  = 1.0e-10;
585:   neP->gtol                  = 0.90;
586:   neP->stepmin                  = 1.0e-20;
587:   neP->stepmax                  = 1.0e+20;
588:   neP->nfev                  = 0;
589:   neP->bracket                  = 0;
590:   neP->infoc              = 1;
591:   neP->maxfev                  = 30;

593:   PetscObjectComposeFunctionDynamic((PetscObject)snes,"SNESLineSearchGetDampingParameter_C",
594:                                     "SNESLineSearchGetDampingParameter_UM_LS",
595:                                      SNESLineSearchGetDampingParameter_UM_LS);

597:   return(0);
598: }
599: EXTERN_C_END


602: /* @
603:    SNESLineSearchGetDampingParameter - Gets the damping parameter used within
604:    the line search method SNESUMLS for unconstrained minimization.

606:    Input Parameter:
607: .  type - SNES method

609:    Output Parameter:
610: .  damp - the damping parameter

612: .keywords: SNES, nonlinear, get, line search, damping parameter
613: @ */
614: int SNESLineSearchGetDampingParameter(SNES snes,Scalar *damp)
615: {
616:   int ierr,(*f)(SNES,Scalar *);


621:   PetscObjectQueryFunction((PetscObject)snes,"SNESLineSearchGetDampingParameter_C",(void (**)())&f);
622:   if (f) {
623:     (*f)(snes,damp);
624:   } else {
625:     SETERRQ(1,"Can only get line search damping when line search algorithm used");
626:   }
627:   return(0);
628: }