Actual source code: ls.c

petsc-3.3-p1 2012-06-15
  2: #include <../src/snes/impls/ls/lsimpl.h>

  4: /*
  5:      Checks if J^T F = 0 which implies we've found a local minimum of the norm of the function,
  6:     || F(u) ||_2 but not a zero, F(u) = 0. In the case when one cannot compute J^T F we use the fact that
  7:     0 = (J^T F)^T W = F^T J W iff W not in the null space of J. Thanks for Jorge More 
  8:     for this trick. One assumes that the probability that W is in the null space of J is very, very small.
  9: */
 12: PetscErrorCode SNESLSCheckLocalMin_Private(SNES snes,Mat A,Vec F,Vec W,PetscReal fnorm,PetscBool  *ismin)
 13: {
 14:   PetscReal      a1;
 16:   PetscBool      hastranspose;

 19:   *ismin = PETSC_FALSE;
 20:   MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);
 21:   if (hastranspose) {
 22:     /* Compute || J^T F|| */
 23:     MatMultTranspose(A,F,W);
 24:     VecNorm(W,NORM_2,&a1);
 25:     PetscInfo1(snes,"|| J^T F|| %14.12e near zero implies found a local minimum\n",(double)(a1/fnorm));
 26:     if (a1/fnorm < 1.e-4) *ismin = PETSC_TRUE;
 27:   } else {
 28:     Vec         work;
 29:     PetscScalar result;
 30:     PetscReal   wnorm;

 32:     VecSetRandom(W,PETSC_NULL);
 33:     VecNorm(W,NORM_2,&wnorm);
 34:     VecDuplicate(W,&work);
 35:     MatMult(A,W,work);
 36:     VecDot(F,work,&result);
 37:     VecDestroy(&work);
 38:     a1   = PetscAbsScalar(result)/(fnorm*wnorm);
 39:     PetscInfo1(snes,"(F^T J random)/(|| F ||*||random|| %14.12e near zero implies found a local minimum\n",(double)a1);
 40:     if (a1 < 1.e-4) *ismin = PETSC_TRUE;
 41:   }
 42:   return(0);
 43: }

 45: /*
 46:      Checks if J^T(F - J*X) = 0 
 47: */
 50: PetscErrorCode SNESLSCheckResidual_Private(SNES snes,Mat A,Vec F,Vec X,Vec W1,Vec W2)
 51: {
 52:   PetscReal      a1,a2;
 54:   PetscBool      hastranspose;

 57:   MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);
 58:   if (hastranspose) {
 59:     MatMult(A,X,W1);
 60:     VecAXPY(W1,-1.0,F);

 62:     /* Compute || J^T W|| */
 63:     MatMultTranspose(A,W1,W2);
 64:     VecNorm(W1,NORM_2,&a1);
 65:     VecNorm(W2,NORM_2,&a2);
 66:     if (a1 != 0.0) {
 67:       PetscInfo1(snes,"||J^T(F-Ax)||/||F-AX|| %14.12e near zero implies inconsistent rhs\n",(double)(a2/a1));
 68:     }
 69:   }
 70:   return(0);
 71: }

 73: /*  -------------------------------------------------------------------- 

 75:      This file implements a truncated Newton method with a line search,
 76:      for solving a system of nonlinear equations, using the KSP, Vec, 
 77:      and Mat interfaces for linear solvers, vectors, and matrices, 
 78:      respectively.

 80:      The following basic routines are required for each nonlinear solver:
 81:           SNESCreate_XXX()          - Creates a nonlinear solver context
 82:           SNESSetFromOptions_XXX()  - Sets runtime options
 83:           SNESSolve_XXX()           - Solves the nonlinear system
 84:           SNESDestroy_XXX()         - Destroys the nonlinear solver context
 85:      The suffix "_XXX" denotes a particular implementation, in this case
 86:      we use _LS (e.g., SNESCreate_LS, SNESSolve_LS) for solving
 87:      systems of nonlinear equations with a line search (LS) method.
 88:      These routines are actually called via the common user interface
 89:      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and 
 90:      SNESDestroy(), so the application code interface remains identical 
 91:      for all nonlinear solvers.

 93:      Another key routine is:
 94:           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
 95:      by setting data structures and options.   The interface routine SNESSetUp()
 96:      is not usually called directly by the user, but instead is called by
 97:      SNESSolve() if necessary.

 99:      Additional basic routines are:
100:           SNESView_XXX()            - Prints details of runtime options that
101:                                       have actually been used.
102:      These are called by application codes via the interface routines
103:      SNESView().

105:      The various types of solvers (preconditioners, Krylov subspace methods,
106:      nonlinear solvers, timesteppers) are all organized similarly, so the
107:      above description applies to these categories also.  

109:     -------------------------------------------------------------------- */
110: /*
111:    SNESSolve_LS - Solves a nonlinear system with a truncated Newton
112:    method with a line search.

114:    Input Parameters:
115: .  snes - the SNES context

117:    Output Parameter:
118: .  outits - number of iterations until termination

120:    Application Interface Routine: SNESSolve()

122:    Notes:
123:    This implements essentially a truncated Newton method with a
124:    line search.  By default a cubic backtracking line search
125:    is employed, as described in the text "Numerical Methods for
126:    Unconstrained Optimization and Nonlinear Equations" by Dennis
127:    and Schnabel.
128: */
131: PetscErrorCode SNESSolve_LS(SNES snes)
132: {
133:   PetscErrorCode     ierr;
134:   PetscInt           maxits,i,lits;
135:   PetscBool          lssucceed;
136:   MatStructure       flg = DIFFERENT_NONZERO_PATTERN;
137:   PetscReal          fnorm,gnorm,xnorm,ynorm;
138:   Vec                Y,X,F,G,W;
139:   KSPConvergedReason kspreason;
140:   PetscBool          domainerror;
141:   SNESLineSearch    linesearch;

144:   snes->numFailures            = 0;
145:   snes->numLinearSolveFailures = 0;
146:   snes->reason                 = SNES_CONVERGED_ITERATING;

148:   maxits        = snes->max_its;        /* maximum number of iterations */
149:   X                = snes->vec_sol;        /* solution vector */
150:   F                = snes->vec_func;        /* residual vector */
151:   Y                = snes->vec_sol_update; /* newton step */
152:   G                = snes->work[0];
153:   W                = snes->work[1];

155:   PetscObjectTakeAccess(snes);
156:   snes->iter = 0;
157:   snes->norm = 0.0;
158:   PetscObjectGrantAccess(snes);
159:   SNESGetSNESLineSearch(snes, &linesearch);
160:   if (!snes->vec_func_init_set) {
161:     SNESComputeFunction(snes,X,F);
162:     SNESGetFunctionDomainError(snes, &domainerror);
163:     if (domainerror) {
164:       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
165:       return(0);
166:     }
167:   } else {
168:     snes->vec_func_init_set = PETSC_FALSE;
169:   }
170:   if (!snes->norm_init_set) {
171:     VecNormBegin(F,NORM_2,&fnorm);        /* fnorm <- ||F||  */
172:     VecNormEnd(F,NORM_2,&fnorm);
173:     if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided compute function generated a Not-a-Number");
174:   } else {
175:     fnorm = snes->norm_init;
176:     snes->norm_init_set = PETSC_FALSE;
177:   }
178:   PetscObjectTakeAccess(snes);
179:   snes->norm = fnorm;
180:   PetscObjectGrantAccess(snes);
181:   SNESLogConvHistory(snes,fnorm,0);
182:   SNESMonitor(snes,0,fnorm);

184:   /* set parameter for default relative tolerance convergence test */
185:   snes->ttol = fnorm*snes->rtol;
186:   /* test convergence */
187:   (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
188:   if (snes->reason) return(0);

190:   for (i=0; i<maxits; i++) {

192:     /* Call general purpose update function */
193:     if (snes->ops->update) {
194:       (*snes->ops->update)(snes, snes->iter);
195:     }

197:     /* Solve J Y = F, where J is Jacobian matrix */
198:     SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);
199:     KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);
200:     SNES_KSPSolve(snes,snes->ksp,F,Y);
201:     KSPGetConvergedReason(snes->ksp,&kspreason);
202:     if (kspreason < 0) {
203:       if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
204:         PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);
205:         snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
206:         break;
207:       }
208:     }
209:     KSPGetIterationNumber(snes->ksp,&lits);
210:     snes->linear_its += lits;
211:     PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);

213:     if (PetscLogPrintInfo){
214:       SNESLSCheckResidual_Private(snes,snes->jacobian,F,Y,G,W);
215:     }

217:     /* Compute a (scaled) negative update in the line search routine:
218:          X <- X - lambda*Y
219:        and evaluate F = function(X) (depends on the line search).
220:     */
221:     gnorm = fnorm;
222:     SNESLineSearchApply(linesearch, X, F, &fnorm, Y);
223:     SNESLineSearchGetSuccess(linesearch, &lssucceed);
224:     SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm);
225:     PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)gnorm,(double)fnorm,(double)ynorm,(int)lssucceed);
226:     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
227:     SNESGetFunctionDomainError(snes, &domainerror);
228:     if (domainerror) {
229:       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
230:       return(0);
231:     }
232:     if (!lssucceed) {
233:       if (++snes->numFailures >= snes->maxFailures) {
234:         PetscBool  ismin;
235:         snes->reason = SNES_DIVERGED_LINE_SEARCH;
236:         SNESLSCheckLocalMin_Private(snes,snes->jacobian,F,X,fnorm,&ismin);
237:         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
238:         break;
239:       }
240:     }
241:     /* Monitor convergence */
242:     PetscObjectTakeAccess(snes);
243:     snes->iter = i+1;
244:     snes->norm = fnorm;
245:     PetscObjectGrantAccess(snes);
246:     SNESLogConvHistory(snes,snes->norm,lits);
247:     SNESMonitor(snes,snes->iter,snes->norm);
248:     /* Test for convergence, xnorm = || X || */
249:     if (snes->ops->converged != SNESSkipConverged) { VecNorm(X,NORM_2,&xnorm); }
250:     (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);
251:     if (snes->reason) break;
252:   }
253:   if (i == maxits) {
254:     PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
255:     if(!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
256:   }
257:   return(0);
258: }
259: /* -------------------------------------------------------------------------- */
260: /*
261:    SNESSetUp_LS - Sets up the internal data structures for the later use
262:    of the SNESLS nonlinear solver.

264:    Input Parameter:
265: .  snes - the SNES context
266: .  x - the solution vector

268:    Application Interface Routine: SNESSetUp()

270:    Notes:
271:    For basic use of the SNES solvers, the user need not explicitly call
272:    SNESSetUp(), since these actions will automatically occur during
273:    the call to SNESSolve().
274:  */
277: PetscErrorCode SNESSetUp_LS(SNES snes)
278: {

282:   SNESDefaultGetWork(snes,2);
283:   SNESSetUpMatrices(snes);

285:   return(0);
286: }
287: /* -------------------------------------------------------------------------- */

291: PetscErrorCode SNESReset_LS(SNES snes)
292: {
294:   return(0);
295: }

297: /*
298:    SNESDestroy_LS - Destroys the private SNES_LS context that was created
299:    with SNESCreate_LS().

301:    Input Parameter:
302: .  snes - the SNES context

304:    Application Interface Routine: SNESDestroy()
305:  */
308: PetscErrorCode SNESDestroy_LS(SNES snes)
309: {

313:   SNESReset_LS(snes);
314:   PetscFree(snes->data);
315:   return(0);
316: }
317: /* -------------------------------------------------------------------------- */

319: /*
320:    SNESView_LS - Prints info from the SNESLS data structure.

322:    Input Parameters:
323: .  SNES - the SNES context
324: .  viewer - visualization context

326:    Application Interface Routine: SNESView()
327: */
330: static PetscErrorCode SNESView_LS(SNES snes,PetscViewer viewer)
331: {
333:   PetscBool      iascii;

336:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
337:   if (iascii) {
338:   }
339:   return(0);
340: }

342: /* -------------------------------------------------------------------------- */
343: /*
344:    SNESSetFromOptions_LS - Sets various parameters for the SNESLS method.

346:    Input Parameter:
347: .  snes - the SNES context

349:    Application Interface Routine: SNESSetFromOptions()
350: */
353: static PetscErrorCode SNESSetFromOptions_LS(SNES snes)
354: {
356:   SNESLineSearch linesearch;

359:   PetscOptionsHead("SNESLS options");
360:   PetscOptionsTail();
361:   /* set the default line search type */
362:   if (!snes->linesearch) {
363:     SNESGetSNESLineSearch(snes, &linesearch);
364:     SNESLineSearchSetType(linesearch, SNESLINESEARCHBT);
365:   }
366:   return(0);
367: }

369: /* -------------------------------------------------------------------------- */
370: /*MC
371:       SNESLS - Newton based nonlinear solver that uses a line search

373:    Options Database:
374: +   -snes_linesearch [bt,basic] - Selects line search
375: .   -snes_linesearch_order[quadratic,cubic] - Selects the order of the line search for bt
376: .   -snes_linesearch_norms<true> - Turns on/off computation of the norms for basic
377: .   -snes_linesearch_alpha<alpha> - Sets alpha used in determining if reduction in function norm is sufficient
378: .   -snes_linesearch_maxstep<maxstep> - Sets the maximum stepsize the line search will use (if the 2-norm(y) > maxstep then scale y to be y = (maxstep/2-norm(y)) *y)
379: .   -snes_linesearch_minlambda<minlambda>  - Sets the minimum lambda the line search will use  minlambda / max_i ( y[i]/x[i] )
380: .   -snes_linesearch_monitor - print information about progress of line searches
381: -   -snes_linesearch_damping - damping factor used for basic line search


384:     Notes: This is the default nonlinear solver in SNES

386:    Level: beginner

388: .seealso:  SNESCreate(), SNES, SNESSetType(), SNESTR, SNESLineSearchSet(), 
389:            SNESLineSearchSetPostCheck(), SNESLineSearchNo(), SNESLineSearchCubic(), SNESLineSearchQuadratic(), 
390:           SNESLineSearchSet(), SNESLineSearchNoNorms(), SNESLineSearchSetPreCheck(), SNESLineSearchSetParams(), SNESLineSearchGetParams()

392: M*/
393: EXTERN_C_BEGIN
396: PetscErrorCode  SNESCreate_LS(SNES snes)
397: {
399:   SNES_LS        *neP;

402:   snes->ops->setup           = SNESSetUp_LS;
403:   snes->ops->solve           = SNESSolve_LS;
404:   snes->ops->destroy         = SNESDestroy_LS;
405:   snes->ops->setfromoptions  = SNESSetFromOptions_LS;
406:   snes->ops->view            = SNESView_LS;
407:   snes->ops->reset           = SNESReset_LS;

409:   snes->usesksp                      = PETSC_TRUE;
410:   snes->usespc                       = PETSC_FALSE;
411:   PetscNewLog(snes,SNES_LS,&neP);
412:   snes->data                         = (void*)neP;
413:   return(0);
414: }
415: EXTERN_C_END