xref: /petsc/src/snes/impls/ncg/snesncg.c (revision ea630c6e93734680a55c9e053bce70cd1b499b87)
1fef7b6d8SPeter Brune #include <../src/snes/impls/ncg/snesncgimpl.h>
2fef7b6d8SPeter Brune 
3fef7b6d8SPeter Brune #undef __FUNCT__
4fef7b6d8SPeter Brune #define __FUNCT__ "SNESReset_NCG"
5fef7b6d8SPeter Brune PetscErrorCode SNESReset_NCG(SNES snes)
6fef7b6d8SPeter Brune {
7fef7b6d8SPeter Brune   PetscErrorCode ierr;
8fef7b6d8SPeter Brune 
9fef7b6d8SPeter Brune   PetscFunctionBegin;
10fef7b6d8SPeter Brune   if (snes->work) {ierr = VecDestroyVecs(snes->nwork,&snes->work);CHKERRQ(ierr);}
11fef7b6d8SPeter Brune   PetscFunctionReturn(0);
12fef7b6d8SPeter Brune }
13fef7b6d8SPeter Brune 
14fef7b6d8SPeter Brune /*
15fef7b6d8SPeter Brune   SNESDestroy_NCG - Destroys the private SNES_NCG context that was created with SNESCreate_NCG().
16fef7b6d8SPeter Brune 
17fef7b6d8SPeter Brune   Input Parameter:
18fef7b6d8SPeter Brune . snes - the SNES context
19fef7b6d8SPeter Brune 
20fef7b6d8SPeter Brune   Application Interface Routine: SNESDestroy()
21fef7b6d8SPeter Brune */
22fef7b6d8SPeter Brune #undef __FUNCT__
23fef7b6d8SPeter Brune #define __FUNCT__ "SNESDestroy_NCG"
24fef7b6d8SPeter Brune PetscErrorCode SNESDestroy_NCG(SNES snes)
25fef7b6d8SPeter Brune {
26fef7b6d8SPeter Brune   PetscErrorCode   ierr;
27fef7b6d8SPeter Brune 
28fef7b6d8SPeter Brune   PetscFunctionBegin;
29fef7b6d8SPeter Brune   ierr = SNESReset_NCG(snes);CHKERRQ(ierr);
30fef7b6d8SPeter Brune   ierr = PetscFree(snes->data);CHKERRQ(ierr);
31fef7b6d8SPeter Brune   PetscFunctionReturn(0);
32fef7b6d8SPeter Brune }
33fef7b6d8SPeter Brune 
34fef7b6d8SPeter Brune /*
35fef7b6d8SPeter Brune    SNESSetUp_NCG - Sets up the internal data structures for the later use
36fef7b6d8SPeter Brune    of the SNESNCG nonlinear solver.
37fef7b6d8SPeter Brune 
38fef7b6d8SPeter Brune    Input Parameters:
39fef7b6d8SPeter Brune +  snes - the SNES context
40fef7b6d8SPeter Brune -  x - the solution vector
41fef7b6d8SPeter Brune 
42fef7b6d8SPeter Brune    Application Interface Routine: SNESSetUp()
43fef7b6d8SPeter Brune  */
44fef7b6d8SPeter Brune #undef __FUNCT__
45fef7b6d8SPeter Brune #define __FUNCT__ "SNESSetUp_NCG"
46fef7b6d8SPeter Brune PetscErrorCode SNESSetUp_NCG(SNES snes)
47fef7b6d8SPeter Brune {
48fef7b6d8SPeter Brune   PetscErrorCode ierr;
49fef7b6d8SPeter Brune 
50fef7b6d8SPeter Brune   PetscFunctionBegin;
51fef7b6d8SPeter Brune   ierr = SNESDefaultGetWork(snes,2);CHKERRQ(ierr);
52fef7b6d8SPeter Brune   PetscFunctionReturn(0);
53fef7b6d8SPeter Brune }
54fef7b6d8SPeter Brune /*
55fef7b6d8SPeter Brune   SNESSetFromOptions_NCG - Sets various parameters for the SNESLS method.
56fef7b6d8SPeter Brune 
57fef7b6d8SPeter Brune   Input Parameter:
58fef7b6d8SPeter Brune . snes - the SNES context
59fef7b6d8SPeter Brune 
60fef7b6d8SPeter Brune   Application Interface Routine: SNESSetFromOptions()
61fef7b6d8SPeter Brune */
62fef7b6d8SPeter Brune #undef __FUNCT__
63fef7b6d8SPeter Brune #define __FUNCT__ "SNESSetFromOptions_NCG"
64fef7b6d8SPeter Brune static PetscErrorCode SNESSetFromOptions_NCG(SNES snes)
65fef7b6d8SPeter Brune {
66fef7b6d8SPeter Brune   PetscErrorCode     ierr;
67fef7b6d8SPeter Brune 
68fef7b6d8SPeter Brune   PetscFunctionBegin;
69fef7b6d8SPeter Brune   ierr = PetscOptionsHead("SNES NCG options");CHKERRQ(ierr);
70fef7b6d8SPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
71fef7b6d8SPeter Brune   PetscFunctionReturn(0);
72fef7b6d8SPeter Brune }
73fef7b6d8SPeter Brune 
74fef7b6d8SPeter Brune /*
75fef7b6d8SPeter Brune   SNESView_NCG - Prints info from the SNESNCG data structure.
76fef7b6d8SPeter Brune 
77fef7b6d8SPeter Brune   Input Parameters:
78fef7b6d8SPeter Brune + SNES - the SNES context
79fef7b6d8SPeter Brune - viewer - visualization context
80fef7b6d8SPeter Brune 
81fef7b6d8SPeter Brune   Application Interface Routine: SNESView()
82fef7b6d8SPeter Brune */
83fef7b6d8SPeter Brune #undef __FUNCT__
84fef7b6d8SPeter Brune #define __FUNCT__ "SNESView_NCG"
85fef7b6d8SPeter Brune static PetscErrorCode SNESView_NCG(SNES snes, PetscViewer viewer)
86fef7b6d8SPeter Brune {
87fef7b6d8SPeter Brune   PetscBool        iascii;
88fef7b6d8SPeter Brune   PetscErrorCode   ierr;
89fef7b6d8SPeter Brune 
90fef7b6d8SPeter Brune   PetscFunctionBegin;
91fef7b6d8SPeter Brune   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
92fef7b6d8SPeter Brune   if (iascii) {
93*ea630c6eSPeter Brune     ierr = PetscViewerASCIIPrintf(viewer,"  line search type variant: %s\n", SNESLineSearchTypeName(snes->ls_type));CHKERRQ(ierr);
94fef7b6d8SPeter Brune   }
95fef7b6d8SPeter Brune   PetscFunctionReturn(0);
96fef7b6d8SPeter Brune }
97fef7b6d8SPeter Brune 
98fef7b6d8SPeter Brune #undef __FUNCT__
99fef7b6d8SPeter Brune #define __FUNCT__ "SNESLineSearchNo_NCG"
100fef7b6d8SPeter Brune PetscErrorCode SNESLineSearchNo_NCG(SNES snes,void *lsctx,Vec X,Vec F,Vec Y,PetscReal fnorm,PetscReal dummyXnorm,Vec dummyG,Vec W,PetscReal *dummyYnorm,PetscReal *gnorm,PetscBool *flag)
101fef7b6d8SPeter Brune {
102fef7b6d8SPeter Brune   PetscErrorCode   ierr;
103fef7b6d8SPeter Brune 
104fef7b6d8SPeter Brune   PetscFunctionBegin;
105*ea630c6eSPeter Brune   ierr = VecAXPY(X, snes->damping, Y);CHKERRQ(ierr);
106fef7b6d8SPeter Brune   ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
107fef7b6d8SPeter Brune   ierr = VecNorm(F, NORM_2, gnorm);CHKERRQ(ierr);
108fef7b6d8SPeter Brune   if (PetscIsInfOrNanReal(*gnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated norm");
109fef7b6d8SPeter Brune   PetscFunctionReturn(0);
110fef7b6d8SPeter Brune }
111fef7b6d8SPeter Brune 
112fef7b6d8SPeter Brune #undef __FUNCT__
113fef7b6d8SPeter Brune #define __FUNCT__ "SNESLineSearchNoNorms_NCG"
114fef7b6d8SPeter Brune PetscErrorCode SNESLineSearchNoNorms_NCG(SNES snes,void *lsctx,Vec X,Vec F,Vec Y,PetscReal fnorm,PetscReal dummyXnorm,Vec dummyG,Vec W,PetscReal *dummyYnorm,PetscReal *gnorm,PetscBool *flag)
115fef7b6d8SPeter Brune {
116fef7b6d8SPeter Brune   PetscErrorCode   ierr;
117fef7b6d8SPeter Brune 
118fef7b6d8SPeter Brune   PetscFunctionBegin;
119*ea630c6eSPeter Brune   ierr = VecAXPY(X, snes->damping, Y);CHKERRQ(ierr);
120fef7b6d8SPeter Brune   ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
121fef7b6d8SPeter Brune   PetscFunctionReturn(0);
122fef7b6d8SPeter Brune }
123fef7b6d8SPeter Brune 
124fef7b6d8SPeter Brune #undef __FUNCT__
125fef7b6d8SPeter Brune #define __FUNCT__ "SNESLineSearchQuadratic_NCG"
126fef7b6d8SPeter Brune PetscErrorCode SNESLineSearchQuadratic_NCG(SNES snes,void *lsctx,Vec X,Vec F,Vec Y,PetscReal fnorm,PetscReal dummyXnorm,Vec G,Vec W,PetscReal *dummyYnorm,PetscReal *gnorm,PetscBool *flag)
127fef7b6d8SPeter Brune {
128fef7b6d8SPeter Brune   PetscInt         i;
129fef7b6d8SPeter Brune   PetscReal        alphas[3] = {0.0, 0.5, 1.0};
130fef7b6d8SPeter Brune   PetscReal        norms[3];
131fef7b6d8SPeter Brune   PetscReal        alpha,a,b;
132fef7b6d8SPeter Brune   PetscErrorCode   ierr;
133fef7b6d8SPeter Brune 
134fef7b6d8SPeter Brune   PetscFunctionBegin;
135fef7b6d8SPeter Brune   norms[0]  = fnorm;
136fef7b6d8SPeter Brune   for(i=1; i < 3; ++i) {
137fef7b6d8SPeter Brune     ierr = VecWAXPY(W, alphas[i], Y, X);CHKERRQ(ierr);     /* W =  X^n - \alpha Y */
138fef7b6d8SPeter Brune     ierr = SNESComputeFunction(snes, W, F);CHKERRQ(ierr);
139fef7b6d8SPeter Brune     ierr = VecNorm(F, NORM_2, &norms[i]);CHKERRQ(ierr);
140fef7b6d8SPeter Brune   }
141fef7b6d8SPeter Brune   for(i = 0; i < 3; ++i) {
142fef7b6d8SPeter Brune     norms[i] = PetscSqr(norms[i]);
143fef7b6d8SPeter Brune   }
144fef7b6d8SPeter Brune   /* Fit a quadratic:
145fef7b6d8SPeter Brune        If we have x_{0,1,2} = 0, x_1, x_2 which generate norms y_{0,1,2}
146fef7b6d8SPeter Brune        a = (x_1 y_2 - x_2 y_1 + (x_2 - x_1) y_0)/(x^2_2 x_1 - x_2 x^2_1)
147fef7b6d8SPeter Brune        b = (x^2_1 y_2 - x^2_2 y_1 + (x^2_2 - x^2_1) y_0)/(x_2 x^2_1 - x^2_2 x_1)
148fef7b6d8SPeter Brune        c = y_0
149fef7b6d8SPeter Brune        x_min = -b/2a
150fef7b6d8SPeter Brune 
151fef7b6d8SPeter Brune        If we let x_{0,1,2} = 0, 0.5, 1.0
152fef7b6d8SPeter Brune        a = 2 y_2 - 4 y_1 + 2 y_0
153fef7b6d8SPeter Brune        b =  -y_2 + 4 y_1 - 3 y_0
154fef7b6d8SPeter Brune        c =   y_0
155fef7b6d8SPeter Brune   */
156fef7b6d8SPeter Brune   a = (alphas[1]*norms[2] - alphas[2]*norms[1] + (alphas[2] - alphas[1])*norms[0])/(PetscSqr(alphas[2])*alphas[1] - alphas[2]*PetscSqr(alphas[1]));
157fef7b6d8SPeter Brune   b = (PetscSqr(alphas[1])*norms[2] - PetscSqr(alphas[2])*norms[1] + (PetscSqr(alphas[2]) - PetscSqr(alphas[1]))*norms[0])/(alphas[2]*PetscSqr(alphas[1]) - PetscSqr(alphas[2])*alphas[1]);
158fef7b6d8SPeter Brune   /* Check for positive a (concave up) */
159fef7b6d8SPeter Brune   if (a >= 0.0) {
160fef7b6d8SPeter Brune     alpha = -b/(2.0*a);
161fef7b6d8SPeter Brune     alpha = PetscMin(alpha, alphas[2]);
162fef7b6d8SPeter Brune     alpha = PetscMax(alpha, alphas[0]);
163fef7b6d8SPeter Brune   } else {
164fef7b6d8SPeter Brune     alpha = 1.0;
165fef7b6d8SPeter Brune   }
166*ea630c6eSPeter Brune   if (snes->ls_monitor) {
167*ea630c6eSPeter Brune     ierr = PetscViewerASCIIAddTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
168*ea630c6eSPeter Brune     ierr = PetscViewerASCIIPrintf(snes->ls_monitor,"    Line search: norms[0] = %g, norms[1] = %g, norms[2] = %g alpha %g\n", sqrt(norms[0]),sqrt(norms[1]),sqrt(norms[2]),alpha);CHKERRQ(ierr);
169*ea630c6eSPeter Brune     ierr = PetscViewerASCIISubtractTab(snes->ls_monitor,((PetscObject)snes)->tablevel);CHKERRQ(ierr);
170fef7b6d8SPeter Brune   }
171fef7b6d8SPeter Brune   ierr = VecAXPY(X, alpha, Y);CHKERRQ(ierr);
172fef7b6d8SPeter Brune   if (alpha != 1.0) {
173fef7b6d8SPeter Brune     ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
174fef7b6d8SPeter Brune     ierr = VecNorm(F, NORM_2, gnorm);CHKERRQ(ierr);
175fef7b6d8SPeter Brune   } else {
176fef7b6d8SPeter Brune     *gnorm = PetscSqrtReal(norms[2]);
177fef7b6d8SPeter Brune   }
178fef7b6d8SPeter Brune   if (alpha == 0.0) *flag = PETSC_FALSE;
179fef7b6d8SPeter Brune   else              *flag = PETSC_TRUE;
180fef7b6d8SPeter Brune   PetscFunctionReturn(0);
181fef7b6d8SPeter Brune }
182fef7b6d8SPeter Brune 
183*ea630c6eSPeter Brune 
184*ea630c6eSPeter Brune 
185*ea630c6eSPeter Brune #undef __FUNCT__
186*ea630c6eSPeter Brune #define __FUNCT__ "SNESLineSearchExactLinear_NCG"
187*ea630c6eSPeter Brune PetscErrorCode SNESLineSearchExactLinear_NCG(SNES snes,void *lsctx,Vec X,Vec F,Vec Y,PetscReal fnorm,PetscReal dummyXnorm,Vec G,Vec W,PetscReal *dummyYnorm,PetscReal *gnorm,PetscBool *flag)
188*ea630c6eSPeter Brune {
189*ea630c6eSPeter Brune   PetscScalar      alpha, ptAp;
190*ea630c6eSPeter Brune   PetscErrorCode   ierr;
191*ea630c6eSPeter Brune   /* SNES_NCG *ncg =  (SNES_NCG *) snes->data; */
192*ea630c6eSPeter Brune   MatStructure     flg = DIFFERENT_NONZERO_PATTERN;
193*ea630c6eSPeter Brune 
194*ea630c6eSPeter Brune   PetscFunctionBegin;
195*ea630c6eSPeter Brune   /*
196*ea630c6eSPeter Brune 
197*ea630c6eSPeter Brune    The exact step size for linear CG is just:
198*ea630c6eSPeter Brune 
199*ea630c6eSPeter Brune    alpha = (r, r) / (p, Ap) = (f, f) / (y, Jy)
200*ea630c6eSPeter Brune 
201*ea630c6eSPeter Brune    */
202*ea630c6eSPeter Brune 
203*ea630c6eSPeter Brune   ierr = SNESComputeJacobian(snes, X, &snes->jacobian, PETSC_NULL, &flg);CHKERRQ(ierr);
204*ea630c6eSPeter Brune   ierr = VecDot(F, F, &alpha);CHKERRQ(ierr);
205*ea630c6eSPeter Brune   ierr = MatMult(snes->jacobian, Y, W);CHKERRQ(ierr);
206*ea630c6eSPeter Brune   ierr = VecDot(Y, W, &ptAp);CHKERRQ(ierr);
207*ea630c6eSPeter Brune   alpha = alpha / ptAp;
208*ea630c6eSPeter Brune   ierr = PetscPrintf(((PetscObject)snes)->comm, "alpha: %g\n", alpha);CHKERRQ(ierr);
209*ea630c6eSPeter Brune   ierr = VecAXPY(X, alpha, Y);CHKERRQ(ierr);
210*ea630c6eSPeter Brune   ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
211*ea630c6eSPeter Brune   ierr = VecNorm(F, NORM_2, gnorm);CHKERRQ(ierr);
212*ea630c6eSPeter Brune   PetscFunctionReturn(0);
213*ea630c6eSPeter Brune }
214*ea630c6eSPeter Brune 
215fef7b6d8SPeter Brune /*
216fef7b6d8SPeter Brune   SNESSolve_NCG - Solves a nonlinear system with the Nonlinear Conjugate Gradient method.
217fef7b6d8SPeter Brune 
218fef7b6d8SPeter Brune   Input Parameters:
219fef7b6d8SPeter Brune . snes - the SNES context
220fef7b6d8SPeter Brune 
221fef7b6d8SPeter Brune   Output Parameter:
222fef7b6d8SPeter Brune . outits - number of iterations until termination
223fef7b6d8SPeter Brune 
224fef7b6d8SPeter Brune   Application Interface Routine: SNESSolve()
225fef7b6d8SPeter Brune */
226fef7b6d8SPeter Brune #undef __FUNCT__
227fef7b6d8SPeter Brune #define __FUNCT__ "SNESSolve_NCG"
228fef7b6d8SPeter Brune PetscErrorCode SNESSolve_NCG(SNES snes)
229fef7b6d8SPeter Brune {
230302dbbaeSPeter Brune   Vec                 X, dX, lX, F, W, B;
231fef7b6d8SPeter Brune   PetscReal           fnorm, dummyNorm;
232fef7b6d8SPeter Brune   PetscScalar         dXdot, dXdot_old;
233fef7b6d8SPeter Brune   PetscInt            maxits, i;
234fef7b6d8SPeter Brune   PetscErrorCode      ierr;
235fef7b6d8SPeter Brune   SNESConvergedReason reason;
236fef7b6d8SPeter Brune   PetscBool           lsSuccess = PETSC_TRUE;
237fef7b6d8SPeter Brune   PetscFunctionBegin;
238fef7b6d8SPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
239fef7b6d8SPeter Brune 
240fef7b6d8SPeter Brune   maxits = snes->max_its;            /* maximum number of iterations */
241fef7b6d8SPeter Brune   X      = snes->vec_sol;            /* X^n */
242169e2be8SPeter Brune   dX     = snes->work[1];            /* the steepest direction */
243169e2be8SPeter Brune   lX     = snes->vec_sol_update;     /* the conjugate direction */
244fef7b6d8SPeter Brune   F      = snes->vec_func;           /* residual vector */
245fef7b6d8SPeter Brune   W      = snes->work[0];            /* work vector for the line search */
246302dbbaeSPeter Brune   B      = snes->vec_rhs;            /* the right hand side */
247fef7b6d8SPeter Brune 
248fef7b6d8SPeter Brune   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
249fef7b6d8SPeter Brune   snes->iter = 0;
250fef7b6d8SPeter Brune   snes->norm = 0.;
251fef7b6d8SPeter Brune   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
252fef7b6d8SPeter Brune 
253fef7b6d8SPeter Brune   /* compute the initial function and preconditioned update delX */
254fef7b6d8SPeter Brune   ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
255fef7b6d8SPeter Brune   if (snes->domainerror) {
256fef7b6d8SPeter Brune     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
257fef7b6d8SPeter Brune     PetscFunctionReturn(0);
258fef7b6d8SPeter Brune   }
259fef7b6d8SPeter Brune   /* convergence test */
260fef7b6d8SPeter Brune   ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
261fef7b6d8SPeter Brune   if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated in norm");
262fef7b6d8SPeter Brune   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
263fef7b6d8SPeter Brune   snes->norm = fnorm;
264fef7b6d8SPeter Brune   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
265fef7b6d8SPeter Brune   SNESLogConvHistory(snes,fnorm,0);
266fef7b6d8SPeter Brune   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
267fef7b6d8SPeter Brune 
268fef7b6d8SPeter Brune   /* set parameter for default relative tolerance convergence test */
269fef7b6d8SPeter Brune   snes->ttol = fnorm*snes->rtol;
270fef7b6d8SPeter Brune   /* test convergence */
271fef7b6d8SPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
272fef7b6d8SPeter Brune   if (snes->reason) PetscFunctionReturn(0);
273fef7b6d8SPeter Brune 
274fef7b6d8SPeter Brune   /* Call general purpose update function */
275fef7b6d8SPeter Brune   if (snes->ops->update) {
276fef7b6d8SPeter Brune     ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
277fef7b6d8SPeter Brune   }
278fef7b6d8SPeter Brune 
279fef7b6d8SPeter Brune   /* first update -- just use the (preconditioned) residual direction for the initial conjugate direction */
280fef7b6d8SPeter Brune   if (!snes->pc) {
281fef7b6d8SPeter Brune     ierr = VecCopy(F, lX);CHKERRQ(ierr);
282fef7b6d8SPeter Brune     ierr = VecScale(lX, -1.0);CHKERRQ(ierr);
283fef7b6d8SPeter Brune   } else {
284fef7b6d8SPeter Brune     ierr = VecCopy(X, lX);CHKERRQ(ierr);
28551e86f29SPeter Brune     ierr = SNESSolve(snes->pc, snes->vec_rhs, lX);CHKERRQ(ierr);
286fef7b6d8SPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
287302dbbaeSPeter Brune     ierr = VecAXPY(lX, -1.0, X);CHKERRQ(ierr);
28851e86f29SPeter Brune     if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) {
289fef7b6d8SPeter Brune       snes->reason = SNES_DIVERGED_INNER;
290fef7b6d8SPeter Brune       PetscFunctionReturn(0);
291fef7b6d8SPeter Brune     }
292fef7b6d8SPeter Brune   }
293fef7b6d8SPeter Brune   ierr = VecDot(lX, lX, &dXdot);CHKERRQ(ierr);
294fef7b6d8SPeter Brune   for(i = 1; i < maxits; i++) {
295fef7b6d8SPeter Brune     lsSuccess = PETSC_TRUE;
296*ea630c6eSPeter Brune     ierr = (*snes->ops->linesearch)(snes, snes->lsP, X, F, lX, fnorm, 0.0, 0, W, &dummyNorm, &fnorm, &lsSuccess);CHKERRQ(ierr);
297fef7b6d8SPeter Brune     if (!lsSuccess) {
298fef7b6d8SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
299fef7b6d8SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
300fef7b6d8SPeter Brune         break;
301fef7b6d8SPeter Brune       }
302fef7b6d8SPeter Brune     }
303fef7b6d8SPeter Brune     if (snes->nfuncs >= snes->max_funcs) {
304fef7b6d8SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
305fef7b6d8SPeter Brune       break;
306fef7b6d8SPeter Brune     }
307fef7b6d8SPeter Brune     if (snes->domainerror) {
308fef7b6d8SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
309fef7b6d8SPeter Brune       PetscFunctionReturn(0);
310fef7b6d8SPeter Brune     }
311302dbbaeSPeter Brune 
312fef7b6d8SPeter Brune     /* Monitor convergence */
313fef7b6d8SPeter Brune     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
314169e2be8SPeter Brune     snes->iter = i;
315fef7b6d8SPeter Brune     snes->norm = fnorm;
316fef7b6d8SPeter Brune     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
317fef7b6d8SPeter Brune     SNESLogConvHistory(snes,snes->norm,0);
318fef7b6d8SPeter Brune     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
319302dbbaeSPeter Brune 
320fef7b6d8SPeter Brune     /* Test for convergence */
321fef7b6d8SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
322fef7b6d8SPeter Brune     if (snes->reason) break;
323302dbbaeSPeter Brune 
324302dbbaeSPeter Brune     /* Call general purpose update function */
325302dbbaeSPeter Brune     if (snes->ops->update) {
326302dbbaeSPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
327302dbbaeSPeter Brune     }
328ee78dd50SPeter Brune     if (!snes->pc) {
329302dbbaeSPeter Brune       ierr = VecCopy(F,dX);CHKERRQ(ierr);
330302dbbaeSPeter Brune       ierr = VecScale(dX,-1.0);CHKERRQ(ierr);
331302dbbaeSPeter Brune     } else {
332302dbbaeSPeter Brune       ierr = VecCopy(X,dX);CHKERRQ(ierr);
333ee78dd50SPeter Brune       ierr = SNESSolve(snes->pc, snes->vec_rhs, dX);CHKERRQ(ierr);
334302dbbaeSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
33551e86f29SPeter Brune       if (reason < 0 && (reason != SNES_DIVERGED_MAX_IT)) {
336302dbbaeSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
337302dbbaeSPeter Brune         PetscFunctionReturn(0);
338302dbbaeSPeter Brune       }
339302dbbaeSPeter Brune       ierr = VecAXPY(dX,-1.0,X);CHKERRQ(ierr);
340302dbbaeSPeter Brune     }
341302dbbaeSPeter Brune 
342169e2be8SPeter Brune     /* compute the conjugate direction lX = dX + beta*lX with beta = ((dX, dX) / (dX_old, dX_old) (Fletcher-Reeves update)*/
343302dbbaeSPeter Brune     dXdot_old = dXdot;
344302dbbaeSPeter Brune     ierr = VecDot(dX, dX, &dXdot);CHKERRQ(ierr);
345ee78dd50SPeter Brune #if 0
346421d9b32SPeter Brune     if (1)
347169e2be8SPeter Brune       ierr = PetscPrintf(PETSC_COMM_WORLD, "beta %e = %e / %e \n", dXdot / dXdot_old, dXdot, dXdot_old);CHKERRQ(ierr);
348ee78dd50SPeter Brune #endif
349302dbbaeSPeter Brune     ierr = VecAYPX(lX, dXdot / dXdot_old, dX);CHKERRQ(ierr);
350302dbbaeSPeter Brune     /* line search for the proper contribution of lX to the solution */
351fef7b6d8SPeter Brune   }
352fef7b6d8SPeter Brune   if (i == maxits) {
353fef7b6d8SPeter Brune     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
354fef7b6d8SPeter Brune     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
355fef7b6d8SPeter Brune   }
356fef7b6d8SPeter Brune   PetscFunctionReturn(0);
357fef7b6d8SPeter Brune }
358fef7b6d8SPeter Brune 
359fef7b6d8SPeter Brune /*MC
360fef7b6d8SPeter Brune   SNESNCG - Nonlinear Conjugate-Gradient method for the solution of general nonlinear systems.
361fef7b6d8SPeter Brune 
362fef7b6d8SPeter Brune   Level: beginner
363fef7b6d8SPeter Brune 
364fef7b6d8SPeter Brune   Options Database:
365fef7b6d8SPeter Brune +   -snes_ls_damping - damping factor to apply to F(x) (used only if -snes_ls is basic or basicnonorms)
366fef7b6d8SPeter Brune -   -snes_ls <basic,basicnormnorms,quadratic>
367fef7b6d8SPeter Brune 
368fef7b6d8SPeter Brune Notes: This solves the nonlinear system of equations F(x) = 0 using the nonlinear generalization of the conjugate
369fef7b6d8SPeter Brune gradient method.  This may be used with a nonlinear preconditioner used to pick the new search directions, but otherwise
370fef7b6d8SPeter Brune chooses the initial search direction as F(x) for the initial guess x.
371fef7b6d8SPeter Brune 
372fef7b6d8SPeter Brune 
373fef7b6d8SPeter Brune .seealso:  SNESCreate(), SNES, SNESSetType(), SNESLS, SNESTR, SNESNGMRES, SNESNQN
374fef7b6d8SPeter Brune M*/
375fef7b6d8SPeter Brune EXTERN_C_BEGIN
376fef7b6d8SPeter Brune #undef __FUNCT__
377fef7b6d8SPeter Brune #define __FUNCT__ "SNESCreate_NCG"
378fef7b6d8SPeter Brune PetscErrorCode  SNESCreate_NCG(SNES snes)
379fef7b6d8SPeter Brune {
380fef7b6d8SPeter Brune   PetscErrorCode   ierr;
381*ea630c6eSPeter Brune   SNES_NCG * neP;
382fef7b6d8SPeter Brune 
383fef7b6d8SPeter Brune   PetscFunctionBegin;
384fef7b6d8SPeter Brune   snes->ops->destroy         = SNESDestroy_NCG;
385fef7b6d8SPeter Brune   snes->ops->setup           = SNESSetUp_NCG;
386fef7b6d8SPeter Brune   snes->ops->setfromoptions  = SNESSetFromOptions_NCG;
387fef7b6d8SPeter Brune   snes->ops->view            = SNESView_NCG;
388fef7b6d8SPeter Brune   snes->ops->solve           = SNESSolve_NCG;
389fef7b6d8SPeter Brune   snes->ops->reset           = SNESReset_NCG;
390fef7b6d8SPeter Brune 
391fef7b6d8SPeter Brune   snes->usesksp              = PETSC_FALSE;
392fef7b6d8SPeter Brune   snes->usespc               = PETSC_TRUE;
393fef7b6d8SPeter Brune 
394fef7b6d8SPeter Brune   ierr = PetscNewLog(snes, SNES_NCG, &neP);CHKERRQ(ierr);
395fef7b6d8SPeter Brune   snes->data = (void*) neP;
396*ea630c6eSPeter Brune   snes->ops->linesearch             = SNESLineSearchQuadratic_NCG;
397*ea630c6eSPeter Brune   snes->ops->linesearchquadratic    = SNESLineSearchQuadratic_NCG;
398*ea630c6eSPeter Brune   snes->ops->linesearchno           = SNESLineSearchNo_NCG;
399*ea630c6eSPeter Brune   snes->ops->linesearchnonorms      = SNESLineSearchNoNorms_NCG;
400*ea630c6eSPeter Brune   snes->ops->linesearchtest         = SNESLineSearchExactLinear_NCG;
401*ea630c6eSPeter Brune   snes->lsP                = PETSC_NULL;
402*ea630c6eSPeter Brune   snes->ops->postcheckstep = PETSC_NULL;
403*ea630c6eSPeter Brune   snes->postcheck          = PETSC_NULL;
404*ea630c6eSPeter Brune   snes->ops->precheckstep  = PETSC_NULL;
405*ea630c6eSPeter Brune   snes->precheck           = PETSC_NULL;
406fef7b6d8SPeter Brune   PetscFunctionReturn(0);
407fef7b6d8SPeter Brune }
408fef7b6d8SPeter Brune EXTERN_C_END
409