Actual source code: ls.c

petsc-3.6.4 2016-04-12
Report Typos and Errors
  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: static PetscErrorCode SNESNEWTONLSCheckLocalMin_Private(SNES snes,Mat A,Vec F,PetscReal fnorm,PetscBool  *ismin)
 13: {
 14:   PetscReal      a1;
 16:   PetscBool      hastranspose;
 17:   Vec            W;

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

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

 48: /*
 49:      Checks if J^T(F - J*X) = 0
 50: */
 53: static PetscErrorCode SNESNEWTONLSCheckResidual_Private(SNES snes,Mat A,Vec F,Vec X)
 54: {
 55:   PetscReal      a1,a2;
 57:   PetscBool      hastranspose;

 60:   MatHasOperation(A,MATOP_MULT_TRANSPOSE,&hastranspose);
 61:   if (hastranspose) {
 62:     Vec   W1,W2;

 64:     VecDuplicate(F,&W1);
 65:     VecDuplicate(F,&W2);
 66:     MatMult(A,X,W1);
 67:     VecAXPY(W1,-1.0,F);

 69:     /* Compute || J^T W|| */
 70:     MatMultTranspose(A,W1,W2);
 71:     VecNorm(W1,NORM_2,&a1);
 72:     VecNorm(W2,NORM_2,&a2);
 73:     if (a1 != 0.0) {
 74:       PetscInfo1(snes,"||J^T(F-Ax)||/||F-AX|| %14.12e near zero implies inconsistent rhs\n",(double)(a2/a1));
 75:     }
 76:     VecDestroy(&W1);
 77:     VecDestroy(&W2);
 78:   }
 79:   return(0);
 80: }

 82: /*  --------------------------------------------------------------------

 84:      This file implements a truncated Newton method with a line search,
 85:      for solving a system of nonlinear equations, using the KSP, Vec,
 86:      and Mat interfaces for linear solvers, vectors, and matrices,
 87:      respectively.

 89:      The following basic routines are required for each nonlinear solver:
 90:           SNESCreate_XXX()          - Creates a nonlinear solver context
 91:           SNESSetFromOptions_XXX()  - Sets runtime options
 92:           SNESSolve_XXX()           - Solves the nonlinear system
 93:           SNESDestroy_XXX()         - Destroys the nonlinear solver context
 94:      The suffix "_XXX" denotes a particular implementation, in this case
 95:      we use _NEWTONLS (e.g., SNESCreate_NEWTONLS, SNESSolve_NEWTONLS) for solving
 96:      systems of nonlinear equations with a line search (LS) method.
 97:      These routines are actually called via the common user interface
 98:      routines SNESCreate(), SNESSetFromOptions(), SNESSolve(), and
 99:      SNESDestroy(), so the application code interface remains identical
100:      for all nonlinear solvers.

102:      Another key routine is:
103:           SNESSetUp_XXX()           - Prepares for the use of a nonlinear solver
104:      by setting data structures and options.   The interface routine SNESSetUp()
105:      is not usually called directly by the user, but instead is called by
106:      SNESSolve() if necessary.

108:      Additional basic routines are:
109:           SNESView_XXX()            - Prints details of runtime options that
110:                                       have actually been used.
111:      These are called by application codes via the interface routines
112:      SNESView().

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

118:     -------------------------------------------------------------------- */
119: /*
120:    SNESSolve_NEWTONLS - Solves a nonlinear system with a truncated Newton
121:    method with a line search.

123:    Input Parameters:
124: .  snes - the SNES context

126:    Output Parameter:
127: .  outits - number of iterations until termination

129:    Application Interface Routine: SNESSolve()

131:    Notes:
132:    This implements essentially a truncated Newton method with a
133:    line search.  By default a cubic backtracking line search
134:    is employed, as described in the text "Numerical Methods for
135:    Unconstrained Optimization and Nonlinear Equations" by Dennis
136:    and Schnabel.
137: */
140: PetscErrorCode SNESSolve_NEWTONLS(SNES snes)
141: {
142:   PetscErrorCode       ierr;
143:   PetscInt             maxits,i,lits;
144:   SNESLineSearchReason lssucceed;
145:   PetscReal            fnorm,gnorm,xnorm,ynorm;
146:   Vec                  Y,X,F;
147:   SNESLineSearch       linesearch;
148:   SNESConvergedReason  reason;


152:   if (snes->xl || snes->xu || snes->ops->computevariablebounds) {
153:     SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
154:   }

156:   snes->numFailures            = 0;
157:   snes->numLinearSolveFailures = 0;
158:   snes->reason                 = SNES_CONVERGED_ITERATING;

160:   maxits = snes->max_its;               /* maximum number of iterations */
161:   X      = snes->vec_sol;               /* solution vector */
162:   F      = snes->vec_func;              /* residual vector */
163:   Y      = snes->vec_sol_update;        /* newton step */

165:   PetscObjectSAWsTakeAccess((PetscObject)snes);
166:   snes->iter = 0;
167:   snes->norm = 0.0;
168:   PetscObjectSAWsGrantAccess((PetscObject)snes);
169:   SNESGetLineSearch(snes, &linesearch);

171:   /* compute the preconditioned function first in the case of left preconditioning with preconditioned function */
172:   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
173:     SNESApplyNPC(snes,X,NULL,F);
174:     SNESGetConvergedReason(snes->pc,&reason);
175:     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
176:       snes->reason = SNES_DIVERGED_INNER;
177:       return(0);
178:     }

180:     VecNormBegin(F,NORM_2,&fnorm);
181:     VecNormEnd(F,NORM_2,&fnorm);
182:   } else {
183:     if (!snes->vec_func_init_set) {
184:       SNESComputeFunction(snes,X,F);
185:     } else snes->vec_func_init_set = PETSC_FALSE;
186:   }

188:   VecNorm(F,NORM_2,&fnorm);        /* fnorm <- ||F||  */
189:   SNESCheckFunctionNorm(snes,fnorm);
190:   PetscObjectSAWsTakeAccess((PetscObject)snes);
191:   snes->norm = fnorm;
192:   PetscObjectSAWsGrantAccess((PetscObject)snes);
193:   SNESLogConvergenceHistory(snes,fnorm,0);
194:   SNESMonitor(snes,0,fnorm);

196:   /* test convergence */
197:   (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
198:   if (snes->reason) return(0);

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

202:     /* Call general purpose update function */
203:     if (snes->ops->update) {
204:       (*snes->ops->update)(snes, snes->iter);
205:     }

207:     /* apply the nonlinear preconditioner */
208:     if (snes->pc) {
209:       if (snes->pcside == PC_RIGHT) {
210:         SNESSetInitialFunction(snes->pc, F);
211:         PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,snes->vec_rhs,0);
212:         SNESSolve(snes->pc, snes->vec_rhs, X);
213:         PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,snes->vec_rhs,0);
214:         SNESGetConvergedReason(snes->pc,&reason);
215:         if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
216:           snes->reason = SNES_DIVERGED_INNER;
217:           return(0);
218:         }
219:         SNESGetNPCFunction(snes,F,&fnorm);
220:       } else if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
221:         SNESApplyNPC(snes,X,F,F);
222:         SNESGetConvergedReason(snes->pc,&reason);
223:         if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
224:           snes->reason = SNES_DIVERGED_INNER;
225:           return(0);
226:         }
227:       }
228:     }

230:     /* Solve J Y = F, where J is Jacobian matrix */
231:     SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);
232:     KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre);
233:     KSPSolve(snes->ksp,F,Y);
234:     SNESCheckKSPSolve(snes);
235:     KSPGetIterationNumber(snes->ksp,&lits);
236:     snes->linear_its += lits;
237:     PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);

239:     if (PetscLogPrintInfo) {
240:       SNESNEWTONLSCheckResidual_Private(snes,snes->jacobian,F,Y);
241:     }

243:     /* Compute a (scaled) negative update in the line search routine:
244:          X <- X - lambda*Y
245:        and evaluate F = function(X) (depends on the line search).
246:     */
247:     gnorm = fnorm;
248:     SNESLineSearchApply(linesearch, X, F, &fnorm, Y);
249:     SNESLineSearchGetReason(linesearch, &lssucceed);
250:     SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm);
251:     PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)gnorm,(double)fnorm,(double)ynorm,(int)lssucceed);
252:     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
253:     SNESCheckFunctionNorm(snes,fnorm);
254:     if (lssucceed) {
255:       if (snes->stol*xnorm > ynorm) {
256:         snes->reason = SNES_CONVERGED_SNORM_RELATIVE;
257:         return(0);
258:       }
259:       if (++snes->numFailures >= snes->maxFailures) {
260:         PetscBool ismin;
261:         snes->reason = SNES_DIVERGED_LINE_SEARCH;
262:         SNESNEWTONLSCheckLocalMin_Private(snes,snes->jacobian,F,fnorm,&ismin);
263:         if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
264:         break;
265:       }
266:     }
267:     /* Monitor convergence */
268:     PetscObjectSAWsTakeAccess((PetscObject)snes);
269:     snes->iter = i+1;
270:     snes->norm = fnorm;
271:     PetscObjectSAWsGrantAccess((PetscObject)snes);
272:     SNESLogConvergenceHistory(snes,snes->norm,lits);
273:     SNESMonitor(snes,snes->iter,snes->norm);
274:     /* Test for convergence */
275:     (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);
276:     if (snes->reason) break;
277:   }
278:   if (i == maxits) {
279:     PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
280:     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
281:   }
282:   return(0);
283: }
284: /* -------------------------------------------------------------------------- */
285: /*
286:    SNESSetUp_NEWTONLS - Sets up the internal data structures for the later use
287:    of the SNESNEWTONLS nonlinear solver.

289:    Input Parameter:
290: .  snes - the SNES context
291: .  x - the solution vector

293:    Application Interface Routine: SNESSetUp()

295:    Notes:
296:    For basic use of the SNES solvers, the user need not explicitly call
297:    SNESSetUp(), since these actions will automatically occur during
298:    the call to SNESSolve().
299:  */
302: PetscErrorCode SNESSetUp_NEWTONLS(SNES snes)
303: {

307:   SNESSetUpMatrices(snes);
308:   if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED;
309:   return(0);
310: }
311: /* -------------------------------------------------------------------------- */

315: PetscErrorCode SNESReset_NEWTONLS(SNES snes)
316: {
318:   return(0);
319: }

321: /*
322:    SNESDestroy_NEWTONLS - Destroys the private SNES_NEWTONLS context that was created
323:    with SNESCreate_NEWTONLS().

325:    Input Parameter:
326: .  snes - the SNES context

328:    Application Interface Routine: SNESDestroy()
329:  */
332: PetscErrorCode SNESDestroy_NEWTONLS(SNES snes)
333: {

337:   SNESReset_NEWTONLS(snes);
338:   PetscFree(snes->data);
339:   return(0);
340: }
341: /* -------------------------------------------------------------------------- */

343: /*
344:    SNESView_NEWTONLS - Prints info from the SNESNEWTONLS data structure.

346:    Input Parameters:
347: .  SNES - the SNES context
348: .  viewer - visualization context

350:    Application Interface Routine: SNESView()
351: */
354: static PetscErrorCode SNESView_NEWTONLS(SNES snes,PetscViewer viewer)
355: {
357:   PetscBool      iascii;

360:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
361:   if (iascii) {
362:   }
363:   return(0);
364: }

366: /* -------------------------------------------------------------------------- */
367: /*
368:    SNESSetFromOptions_NEWTONLS - Sets various parameters for the SNESNEWTONLS method.

370:    Input Parameter:
371: .  snes - the SNES context

373:    Application Interface Routine: SNESSetFromOptions()
374: */
377: static PetscErrorCode SNESSetFromOptions_NEWTONLS(PetscOptions *PetscOptionsObject,SNES snes)
378: {
380:   SNESLineSearch linesearch;

383:   if (!snes->linesearch) {
384:     SNESGetLineSearch(snes, &linesearch);
385:     SNESLineSearchSetType(linesearch, SNESLINESEARCHBT);
386:   }
387:   return(0);
388: }

390: /* -------------------------------------------------------------------------- */
391: /*MC
392:       SNESNEWTONLS - Newton based nonlinear solver that uses a line search

394:    Options Database:
395: +   -snes_linesearch_type <bt> - bt,basic.  Select line search type
396: .   -snes_linesearch_order <3> - 2, 3. Selects the order of the line search for bt
397: .   -snes_linesearch_norms <true> - Turns on/off computation of the norms for basic linesearch
398: .   -snes_linesearch_alpha <alpha> - Sets alpha used in determining if reduction in function norm is sufficient
399: .   -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)
400: .   -snes_linesearch_minlambda <minlambda>  - Sets the minimum lambda the line search will tolerate
401: .   -snes_linesearch_monitor - print information about progress of line searches
402: -   -snes_linesearch_damping - damping factor used for basic line search

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

406:    Level: beginner

408: .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONTR, SNESQN, SNESLineSearchSetType(), SNESLineSearchSetOrder()
409:            SNESLineSearchSetPostCheck(), SNESLineSearchSetPreCheck() SNESLineSearchSetComputeNorms()

411: M*/
414: PETSC_EXTERN PetscErrorCode SNESCreate_NEWTONLS(SNES snes)
415: {
417:   SNES_NEWTONLS  *neP;

420:   snes->ops->setup          = SNESSetUp_NEWTONLS;
421:   snes->ops->solve          = SNESSolve_NEWTONLS;
422:   snes->ops->destroy        = SNESDestroy_NEWTONLS;
423:   snes->ops->setfromoptions = SNESSetFromOptions_NEWTONLS;
424:   snes->ops->view           = SNESView_NEWTONLS;
425:   snes->ops->reset          = SNESReset_NEWTONLS;

427:   snes->pcside  = PC_RIGHT;
428:   snes->usesksp = PETSC_TRUE;
429:   snes->usespc  = PETSC_TRUE;
430:   PetscNewLog(snes,&neP);
431:   snes->data    = (void*)neP;
432:   return(0);
433: }