Actual source code: ls.c
petsc-dev 2014-02-02
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 SNESNEWTONLSCheckLocalMin_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,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 SNESNEWTONLSCheckResidual_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 _NEWTONLS (e.g., SNESCreate_NEWTONLS, SNESSolve_NEWTONLS) 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_NEWTONLS - 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_NEWTONLS(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;
142: SNESConvergedReason reason;
145: snes->numFailures = 0;
146: snes->numLinearSolveFailures = 0;
147: snes->reason = SNES_CONVERGED_ITERATING;
149: maxits = snes->max_its; /* maximum number of iterations */
150: X = snes->vec_sol; /* solution vector */
151: F = snes->vec_func; /* residual vector */
152: Y = snes->vec_sol_update; /* newton step */
153: G = snes->work[0];
154: W = snes->work[1];
156: PetscObjectSAWsTakeAccess((PetscObject)snes);
157: snes->iter = 0;
158: snes->norm = 0.0;
159: PetscObjectSAWsGrantAccess((PetscObject)snes);
160: SNESGetLineSearch(snes, &linesearch);
162: /* compute the preconditioned function first in the case of left preconditioning with preconditioned function */
163: if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
164: SNESApplyPC(snes,X,PETSC_NULL,PETSC_NULL,F);
165: SNESGetConvergedReason(snes->pc,&reason);
166: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
167: snes->reason = SNES_DIVERGED_INNER;
168: return(0);
169: }
171: VecNormBegin(F,NORM_2,&fnorm);
172: VecNormEnd(F,NORM_2,&fnorm);
173: } else {
174: if (!snes->vec_func_init_set) {
175: SNESComputeFunction(snes,X,F);
176: SNESGetFunctionDomainError(snes, &domainerror);
177: if (domainerror) {
178: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
179: return(0);
180: }
181: } else snes->vec_func_init_set = PETSC_FALSE;
182: }
184: VecNorm(F,NORM_2,&fnorm); /* fnorm <- ||F|| */
185: if (PetscIsInfOrNanReal(fnorm)) {
186: snes->reason = SNES_DIVERGED_FNORM_NAN;
187: return(0);
188: }
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: SNESGetPCFunction(snes,F,&fnorm);
220: } else if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
221: SNESApplyPC(snes,X,F,&fnorm,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,&flg);
232: KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);
233: KSPSolve(snes->ksp,F,Y);
234: KSPGetConvergedReason(snes->ksp,&kspreason);
235: if (kspreason < 0) {
236: if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) {
237: PetscInfo2(snes,"iter=%D, number linear solve failures %D greater than current SNES allowed, stopping solve\n",snes->iter,snes->numLinearSolveFailures);
238: snes->reason = SNES_DIVERGED_LINEAR_SOLVE;
239: break;
240: }
241: }
242: KSPGetIterationNumber(snes->ksp,&lits);
243: snes->linear_its += lits;
244: PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);
246: if (PetscLogPrintInfo) {
247: SNESNEWTONLSCheckResidual_Private(snes,snes->jacobian,F,Y,G,W);
248: }
250: /* Compute a (scaled) negative update in the line search routine:
251: X <- X - lambda*Y
252: and evaluate F = function(X) (depends on the line search).
253: */
254: gnorm = fnorm;
255: SNESLineSearchApply(linesearch, X, F, &fnorm, Y);
256: SNESLineSearchGetSuccess(linesearch, &lssucceed);
257: SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm);
258: PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)gnorm,(double)fnorm,(double)ynorm,(int)lssucceed);
259: if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
260: SNESGetFunctionDomainError(snes, &domainerror);
261: if (domainerror) {
262: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
263: return(0);
264: }
265: if (!lssucceed) {
266: if (snes->stol*xnorm > ynorm) {
267: snes->reason = SNES_CONVERGED_SNORM_RELATIVE;
268: return(0);
269: }
270: if (++snes->numFailures >= snes->maxFailures) {
271: PetscBool ismin;
272: snes->reason = SNES_DIVERGED_LINE_SEARCH;
273: SNESNEWTONLSCheckLocalMin_Private(snes,snes->jacobian,F,W,fnorm,&ismin);
274: if (ismin) snes->reason = SNES_DIVERGED_LOCAL_MIN;
275: break;
276: }
277: }
278: /* Monitor convergence */
279: PetscObjectSAWsTakeAccess((PetscObject)snes);
280: snes->iter = i+1;
281: snes->norm = fnorm;
282: PetscObjectSAWsGrantAccess((PetscObject)snes);
283: SNESLogConvergenceHistory(snes,snes->norm,lits);
284: SNESMonitor(snes,snes->iter,snes->norm);
285: /* Test for convergence */
286: (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);
287: if (snes->reason) break;
288: }
289: if (i == maxits) {
290: PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
291: if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
292: }
293: return(0);
294: }
295: /* -------------------------------------------------------------------------- */
296: /*
297: SNESSetUp_NEWTONLS - Sets up the internal data structures for the later use
298: of the SNESNEWTONLS nonlinear solver.
300: Input Parameter:
301: . snes - the SNES context
302: . x - the solution vector
304: Application Interface Routine: SNESSetUp()
306: Notes:
307: For basic use of the SNES solvers, the user need not explicitly call
308: SNESSetUp(), since these actions will automatically occur during
309: the call to SNESSolve().
310: */
313: PetscErrorCode SNESSetUp_NEWTONLS(SNES snes)
314: {
318: SNESSetWorkVecs(snes,2);
319: SNESSetUpMatrices(snes);
320: if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED;
321: return(0);
322: }
323: /* -------------------------------------------------------------------------- */
327: PetscErrorCode SNESReset_NEWTONLS(SNES snes)
328: {
330: return(0);
331: }
333: /*
334: SNESDestroy_NEWTONLS - Destroys the private SNES_NEWTONLS context that was created
335: with SNESCreate_NEWTONLS().
337: Input Parameter:
338: . snes - the SNES context
340: Application Interface Routine: SNESDestroy()
341: */
344: PetscErrorCode SNESDestroy_NEWTONLS(SNES snes)
345: {
349: SNESReset_NEWTONLS(snes);
350: PetscFree(snes->data);
351: return(0);
352: }
353: /* -------------------------------------------------------------------------- */
355: /*
356: SNESView_NEWTONLS - Prints info from the SNESNEWTONLS data structure.
358: Input Parameters:
359: . SNES - the SNES context
360: . viewer - visualization context
362: Application Interface Routine: SNESView()
363: */
366: static PetscErrorCode SNESView_NEWTONLS(SNES snes,PetscViewer viewer)
367: {
369: PetscBool iascii;
372: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
373: if (iascii) {
374: }
375: return(0);
376: }
378: /* -------------------------------------------------------------------------- */
379: /*
380: SNESSetFromOptions_NEWTONLS - Sets various parameters for the SNESNEWTONLS method.
382: Input Parameter:
383: . snes - the SNES context
385: Application Interface Routine: SNESSetFromOptions()
386: */
389: static PetscErrorCode SNESSetFromOptions_NEWTONLS(SNES snes)
390: {
392: SNESLineSearch linesearch;
395: PetscOptionsHead("SNESNEWTONLS options");
396: PetscOptionsTail();
397: /* set the default line search type */
398: if (!snes->linesearch) {
399: SNESGetLineSearch(snes, &linesearch);
400: SNESLineSearchSetType(linesearch, SNESLINESEARCHBT);
401: }
402: return(0);
403: }
405: /* -------------------------------------------------------------------------- */
406: /*MC
407: SNESNEWTONLS - Newton based nonlinear solver that uses a line search
409: Options Database:
410: + -snes_linesearch_type <bt> - bt,basic. Select line search type
411: . -snes_linesearch_order <3> - 2, 3. Selects the order of the line search for bt
412: . -snes_linesearch_norms <true> - Turns on/off computation of the norms for basic linesearch
413: . -snes_linesearch_alpha <alpha> - Sets alpha used in determining if reduction in function norm is sufficient
414: . -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)
415: . -snes_linesearch_minlambda <minlambda> - Sets the minimum lambda the line search will tolerate
416: . -snes_linesearch_monitor - print information about progress of line searches
417: - -snes_linesearch_damping - damping factor used for basic line search
419: Notes: This is the default nonlinear solver in SNES
421: Level: beginner
423: .seealso: SNESCreate(), SNES, SNESSetType(), SNESNEWTONTR, SNESQN, SNESLineSearchSetType(), SNESLineSearchSetOrder()
424: SNESLineSearchSetPostCheck(), SNESLineSearchSetPreCheck() SNESLineSearchSetComputeNorms()
426: M*/
429: PETSC_EXTERN PetscErrorCode SNESCreate_NEWTONLS(SNES snes)
430: {
432: SNES_NEWTONLS *neP;
435: snes->ops->setup = SNESSetUp_NEWTONLS;
436: snes->ops->solve = SNESSolve_NEWTONLS;
437: snes->ops->destroy = SNESDestroy_NEWTONLS;
438: snes->ops->setfromoptions = SNESSetFromOptions_NEWTONLS;
439: snes->ops->view = SNESView_NEWTONLS;
440: snes->ops->reset = SNESReset_NEWTONLS;
442: snes->pcside = PC_RIGHT;
443: snes->usesksp = PETSC_TRUE;
444: snes->usespc = PETSC_TRUE;
445: PetscNewLog(snes,&neP);
446: snes->data = (void*)neP;
447: return(0);
448: }