xref: /petsc/src/snes/impls/ncg/snesncg.c (revision bbd98b0ddc3b728de2842e56499debb5c79c81f3)
1 #include <../src/snes/impls/ncg/snesncgimpl.h> /*I "petscsnes.h" I*/
2 const char *const SNESNCGTypes[] = {"FR","PRP","HS","DY","CD","SNESNCGType","SNES_NCG_",0};
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "SNESReset_NCG"
6 PetscErrorCode SNESReset_NCG(SNES snes)
7 {
8   PetscFunctionBegin;
9   PetscFunctionReturn(0);
10 }
11 
12 #define SNESLINESEARCHNCGLINEAR "ncglinear"
13 
14 /*
15   SNESDestroy_NCG - Destroys the private SNES_NCG context that was created with SNESCreate_NCG().
16 
17   Input Parameter:
18 . snes - the SNES context
19 
20   Application Interface Routine: SNESDestroy()
21 */
22 #undef __FUNCT__
23 #define __FUNCT__ "SNESDestroy_NCG"
24 PetscErrorCode SNESDestroy_NCG(SNES snes)
25 {
26   PetscErrorCode ierr;
27 
28   PetscFunctionBegin;
29   ierr = PetscFree(snes->data);CHKERRQ(ierr);
30   PetscFunctionReturn(0);
31 }
32 
33 /*
34    SNESSetUp_NCG - Sets up the internal data structures for the later use
35    of the SNESNCG nonlinear solver.
36 
37    Input Parameters:
38 +  snes - the SNES context
39 -  x - the solution vector
40 
41    Application Interface Routine: SNESSetUp()
42  */
43 
44 PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_NCGLinear(SNESLineSearch);
45 
46 #undef __FUNCT__
47 #define __FUNCT__ "SNESSetUp_NCG"
48 PetscErrorCode SNESSetUp_NCG(SNES snes)
49 {
50   PetscErrorCode ierr;
51 
52   PetscFunctionBegin;
53   ierr = SNESSetWorkVecs(snes,2);CHKERRQ(ierr);
54   if (snes->pcside == PC_RIGHT) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNESNCG only supports left preconditioning");
55   if (snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_UNPRECONDITIONED;
56   PetscFunctionReturn(0);
57 }
58 /*
59   SNESSetFromOptions_NCG - Sets various parameters for the SNESNCG method.
60 
61   Input Parameter:
62 . snes - the SNES context
63 
64   Application Interface Routine: SNESSetFromOptions()
65 */
66 #undef __FUNCT__
67 #define __FUNCT__ "SNESSetFromOptions_NCG"
68 static PetscErrorCode SNESSetFromOptions_NCG(PetscOptions *PetscOptionsObject,SNES snes)
69 {
70   SNES_NCG       *ncg = (SNES_NCG*)snes->data;
71   PetscErrorCode ierr;
72   PetscBool      debug = PETSC_FALSE;
73   SNESLineSearch linesearch;
74   SNESNCGType    ncgtype=ncg->type;
75 
76   PetscFunctionBegin;
77   ierr = PetscOptionsHead(PetscOptionsObject,"SNES NCG options");CHKERRQ(ierr);
78   ierr = PetscOptionsBool("-snes_ncg_monitor","Monitor NCG iterations","SNES",ncg->monitor ? PETSC_TRUE : PETSC_FALSE, &debug, NULL);CHKERRQ(ierr);
79   if (debug) {
80     ncg->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
81   }
82   ierr = PetscOptionsEnum("-snes_ncg_type","NCG Beta type used","SNESNCGSetType",SNESNCGTypes,(PetscEnum)ncg->type,(PetscEnum*)&ncgtype,NULL);CHKERRQ(ierr);
83   ierr = SNESNCGSetType(snes, ncgtype);CHKERRQ(ierr);
84   ierr = PetscOptionsTail();CHKERRQ(ierr);
85   if (!snes->linesearch) {
86     ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
87     if (!snes->pc) {
88       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr);
89     } else {
90       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHL2);CHKERRQ(ierr);
91     }
92   }
93   ierr = SNESLineSearchRegister(SNESLINESEARCHNCGLINEAR, SNESLineSearchCreate_NCGLinear);CHKERRQ(ierr);
94   PetscFunctionReturn(0);
95 }
96 
97 /*
98   SNESView_NCG - Prints info from the SNESNCG data structure.
99 
100   Input Parameters:
101 + SNES - the SNES context
102 - viewer - visualization context
103 
104   Application Interface Routine: SNESView()
105 */
106 #undef __FUNCT__
107 #define __FUNCT__ "SNESView_NCG"
108 static PetscErrorCode SNESView_NCG(SNES snes, PetscViewer viewer)
109 {
110   SNES_NCG      *ncg = (SNES_NCG *) snes->data;
111   PetscBool      iascii;
112   PetscErrorCode ierr;
113 
114   PetscFunctionBegin;
115   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
116   if (iascii) {
117     ierr = PetscViewerASCIIPrintf(viewer, "ncg type: %s\n", SNESNCGTypes[ncg->type]);CHKERRQ(ierr);
118   }
119   PetscFunctionReturn(0);
120 }
121 
122 #undef __FUNCT__
123 #define __FUNCT__ "SNESLineSearchApply_NCGLinear"
124 PetscErrorCode SNESLineSearchApply_NCGLinear(SNESLineSearch linesearch)
125 {
126   PetscScalar    alpha, ptAp;
127   Vec            X, Y, F, W;
128   SNES           snes;
129   PetscErrorCode ierr;
130   PetscReal      *fnorm, *xnorm, *ynorm;
131 
132   PetscFunctionBegin;
133   ierr  = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr);
134   X     = linesearch->vec_sol;
135   W     = linesearch->vec_sol_new;
136   F     = linesearch->vec_func;
137   Y     = linesearch->vec_update;
138   fnorm = &linesearch->fnorm;
139   xnorm = &linesearch->xnorm;
140   ynorm = &linesearch->ynorm;
141 
142   if (!snes->jacobian) {
143     ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
144   }
145 
146   /*
147 
148    The exact step size for unpreconditioned linear CG is just:
149    alpha = (r, r) / (p, Ap) = (f, f) / (y, Jy)
150    */
151   ierr  = SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre);CHKERRQ(ierr);
152   ierr  = VecDot(F, F, &alpha);CHKERRQ(ierr);
153   ierr  = MatMult(snes->jacobian, Y, W);CHKERRQ(ierr);
154   ierr  = VecDot(Y, W, &ptAp);CHKERRQ(ierr);
155   alpha = alpha / ptAp;
156   ierr  = VecAXPY(X,-alpha,Y);CHKERRQ(ierr);
157   ierr  = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
158 
159   ierr = VecNorm(F,NORM_2,fnorm);CHKERRQ(ierr);
160   ierr = VecNorm(X,NORM_2,xnorm);CHKERRQ(ierr);
161   ierr = VecNorm(Y,NORM_2,ynorm);CHKERRQ(ierr);
162   PetscFunctionReturn(0);
163 }
164 
165 #undef __FUNCT__
166 #define __FUNCT__ "SNESLineSearchCreate_NCGLinear"
167 PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_NCGLinear(SNESLineSearch linesearch)
168 {
169   PetscFunctionBegin;
170   linesearch->ops->apply          = SNESLineSearchApply_NCGLinear;
171   linesearch->ops->destroy        = NULL;
172   linesearch->ops->setfromoptions = NULL;
173   linesearch->ops->reset          = NULL;
174   linesearch->ops->view           = NULL;
175   linesearch->ops->setup          = NULL;
176   PetscFunctionReturn(0);
177 }
178 
179 #undef __FUNCT__
180 #define __FUNCT__ "SNESNCGComputeYtJtF_Private"
181 /*
182 
183  Assuming F = SNESComputeFunction(X) compute Y^tJ^tF using a simple secant approximation of the jacobian.
184 
185  */
186 PetscErrorCode SNESNCGComputeYtJtF_Private(SNES snes, Vec X, Vec F, Vec Y, Vec W, Vec G, PetscScalar * ytJtf)
187 {
188   PetscErrorCode ierr;
189   PetscScalar    ftf, ftg, fty, h;
190 
191   PetscFunctionBegin;
192   ierr   = VecDot(F, F, &ftf);CHKERRQ(ierr);
193   ierr   = VecDot(F, Y, &fty);CHKERRQ(ierr);
194   h      = 1e-5*fty / fty;
195   ierr   = VecCopy(X, W);CHKERRQ(ierr);
196   ierr   = VecAXPY(W, -h, Y);CHKERRQ(ierr);          /* this is arbitrary */
197   ierr   = SNESComputeFunction(snes, W, G);CHKERRQ(ierr);
198   ierr   = VecDot(G, F, &ftg);CHKERRQ(ierr);
199   *ytJtf = (ftg - ftf) / h;
200   PetscFunctionReturn(0);
201 }
202 
203 #undef __FUNCT__
204 #define __FUNCT__ "SNESNCGSetType"
205 /*@
206     SNESNCGSetType - Sets the conjugate update type for SNESNCG.
207 
208     Logically Collective on SNES
209 
210     Input Parameters:
211 +   snes - the iterative context
212 -   btype - update type
213 
214     Options Database:
215 .   -snes_ncg_type<prp,fr,hs,dy,cd>
216 
217     Level: intermediate
218 
219     SNESNCGSelectTypes:
220 +   SNES_NCG_FR - Fletcher-Reeves update
221 .   SNES_NCG_PRP - Polak-Ribiere-Polyak update
222 .   SNES_NCG_HS - Hestenes-Steifel update
223 .   SNES_NCG_DY - Dai-Yuan update
224 -   SNES_NCG_CD - Conjugate Descent update
225 
226    Notes:
227    PRP is the default, and the only one that tolerates generalized search directions.
228 
229 .keywords: SNES, SNESNCG, selection, type, set
230 @*/
231 PetscErrorCode SNESNCGSetType(SNES snes, SNESNCGType btype)
232 {
233   PetscErrorCode ierr;
234 
235   PetscFunctionBegin;
236   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
237   ierr = PetscTryMethod(snes,"SNESNCGSetType_C",(SNES,SNESNCGType),(snes,btype));CHKERRQ(ierr);
238   PetscFunctionReturn(0);
239 }
240 
241 #undef __FUNCT__
242 #define __FUNCT__ "SNESNCGSetType_NCG"
243 PetscErrorCode SNESNCGSetType_NCG(SNES snes, SNESNCGType btype)
244 {
245   SNES_NCG *ncg = (SNES_NCG*)snes->data;
246 
247   PetscFunctionBegin;
248   ncg->type = btype;
249   PetscFunctionReturn(0);
250 }
251 
252 /*
253   SNESSolve_NCG - Solves a nonlinear system with the Nonlinear Conjugate Gradient method.
254 
255   Input Parameters:
256 . snes - the SNES context
257 
258   Output Parameter:
259 . outits - number of iterations until termination
260 
261   Application Interface Routine: SNESSolve()
262 */
263 #undef __FUNCT__
264 #define __FUNCT__ "SNESSolve_NCG"
265 PetscErrorCode SNESSolve_NCG(SNES snes)
266 {
267   SNES_NCG             *ncg = (SNES_NCG*)snes->data;
268   Vec                  X,dX,lX,F,dXold;
269   PetscReal            fnorm, ynorm, xnorm, beta = 0.0;
270   PetscScalar          dXdotdX, dXolddotdXold, dXdotdXold, lXdotdX, lXdotdXold;
271   PetscInt             maxits, i;
272   PetscErrorCode       ierr;
273   SNESLineSearchReason lsresult = SNES_LINESEARCH_SUCCEEDED;
274   SNESLineSearch       linesearch;
275   SNESConvergedReason  reason;
276 
277   PetscFunctionBegin;
278   if (snes->xl || snes->xu || snes->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
279 
280   ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr);
281   snes->reason = SNES_CONVERGED_ITERATING;
282 
283   maxits = snes->max_its;            /* maximum number of iterations */
284   X      = snes->vec_sol;            /* X^n */
285   dXold  = snes->work[0];            /* The previous iterate of X */
286   dX     = snes->work[1];            /* the preconditioned direction */
287   lX     = snes->vec_sol_update;     /* the conjugate direction */
288   F      = snes->vec_func;           /* residual vector */
289 
290   ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
291 
292   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
293   snes->iter = 0;
294   snes->norm = 0.;
295   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
296 
297   /* compute the initial function and preconditioned update dX */
298 
299   if (snes->pc && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
300     ierr = SNESApplyNPC(snes,X,NULL,dX);CHKERRQ(ierr);
301     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
302     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
303       snes->reason = SNES_DIVERGED_INNER;
304       PetscFunctionReturn(0);
305     }
306     ierr = VecCopy(dX,F);CHKERRQ(ierr);
307     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
308   } else {
309     if (!snes->vec_func_init_set) {
310       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
311     } else snes->vec_func_init_set = PETSC_FALSE;
312 
313     /* convergence test */
314     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
315     SNESCheckFunctionNorm(snes,fnorm);
316     ierr = VecCopy(F,dX);CHKERRQ(ierr);
317   }
318   if (snes->pc) {
319     if (snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
320       ierr = SNESApplyNPC(snes,X,F,dX);CHKERRQ(ierr);
321       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
322       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
323         snes->reason = SNES_DIVERGED_INNER;
324         PetscFunctionReturn(0);
325       }
326     }
327   }
328   ierr = VecCopy(dX,lX);CHKERRQ(ierr);
329   ierr = VecDot(dX, dX, &dXdotdX);CHKERRQ(ierr);
330 
331 
332   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
333   snes->norm = fnorm;
334   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
335   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
336   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
337 
338   /* test convergence */
339   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
340   if (snes->reason) PetscFunctionReturn(0);
341 
342   /* Call general purpose update function */
343   if (snes->ops->update) {
344     ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
345   }
346 
347   /* first update -- just use the (preconditioned) residual direction for the initial conjugate direction */
348 
349   for (i = 1; i < maxits + 1; i++) {
350     /* some update types require the old update direction or conjugate direction */
351     if (ncg->type != SNES_NCG_FR) {
352       ierr = VecCopy(dX, dXold);CHKERRQ(ierr);
353     }
354     ierr = SNESLineSearchApply(linesearch,X,F,&fnorm,lX);CHKERRQ(ierr);
355     ierr = SNESLineSearchGetReason(linesearch, &lsresult);CHKERRQ(ierr);
356     ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
357     if (lsresult) {
358       if (++snes->numFailures >= snes->maxFailures) {
359         snes->reason = SNES_DIVERGED_LINE_SEARCH;
360         PetscFunctionReturn(0);
361       }
362     }
363     if (snes->nfuncs >= snes->max_funcs) {
364       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
365       PetscFunctionReturn(0);
366     }
367     /* Monitor convergence */
368     ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
369     snes->iter = i;
370     snes->norm = fnorm;
371     ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
372     ierr       = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr);
373     ierr       = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
374 
375     /* Test for convergence */
376     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
377     if (snes->reason) PetscFunctionReturn(0);
378 
379     /* Call general purpose update function */
380     if (snes->ops->update) {
381       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
382     }
383     if (snes->pc) {
384       if (snes->functype == SNES_FUNCTION_PRECONDITIONED) {
385         ierr = SNESApplyNPC(snes,X,NULL,dX);CHKERRQ(ierr);
386         ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
387         if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
388           snes->reason = SNES_DIVERGED_INNER;
389           PetscFunctionReturn(0);
390         }
391         ierr = VecCopy(dX,F);CHKERRQ(ierr);
392       } else {
393         ierr = SNESApplyNPC(snes,X,F,dX);CHKERRQ(ierr);
394         ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
395         if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
396           snes->reason = SNES_DIVERGED_INNER;
397           PetscFunctionReturn(0);
398         }
399       }
400     } else {
401       ierr = VecCopy(F,dX);CHKERRQ(ierr);
402     }
403 
404     /* compute the conjugate direction lX = dX + beta*lX with beta = ((dX, dX) / (dX_old, dX_old) (Fletcher-Reeves update)*/
405     switch (ncg->type) {
406     case SNES_NCG_FR: /* Fletcher-Reeves */
407       dXolddotdXold= dXdotdX;
408       ierr         = VecDot(dX, dX, &dXdotdX);CHKERRQ(ierr);
409       beta         = PetscRealPart(dXdotdX / dXolddotdXold);
410       break;
411     case SNES_NCG_PRP: /* Polak-Ribiere-Poylak */
412       dXolddotdXold= dXdotdX;
413       ierr         = VecDotBegin(dX, dX, &dXdotdXold);CHKERRQ(ierr);
414       ierr         = VecDotBegin(dXold, dX, &dXdotdXold);CHKERRQ(ierr);
415       ierr         = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr);
416       ierr         = VecDotEnd(dXold, dX, &dXdotdXold);CHKERRQ(ierr);
417       beta         = PetscRealPart(((dXdotdX - dXdotdXold) / dXolddotdXold));
418       if (beta < 0.0) beta = 0.0; /* restart */
419       break;
420     case SNES_NCG_HS: /* Hestenes-Stiefel */
421       ierr = VecDotBegin(dX, dX, &dXdotdX);CHKERRQ(ierr);
422       ierr = VecDotBegin(dX, dXold, &dXdotdXold);CHKERRQ(ierr);
423       ierr = VecDotBegin(lX, dX, &lXdotdX);CHKERRQ(ierr);
424       ierr = VecDotBegin(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
425       ierr = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr);
426       ierr = VecDotEnd(dX, dXold, &dXdotdXold);CHKERRQ(ierr);
427       ierr = VecDotEnd(lX, dX, &lXdotdX);CHKERRQ(ierr);
428       ierr = VecDotEnd(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
429       beta = PetscRealPart((dXdotdX - dXdotdXold) / (lXdotdX - lXdotdXold));
430       break;
431     case SNES_NCG_DY: /* Dai-Yuan */
432       ierr = VecDotBegin(dX, dX, &dXdotdX);CHKERRQ(ierr);
433       ierr = VecDotBegin(lX, dX, &lXdotdX);CHKERRQ(ierr);
434       ierr = VecDotBegin(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
435       ierr = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr);
436       ierr = VecDotEnd(lX, dX, &lXdotdX);CHKERRQ(ierr);
437       ierr = VecDotEnd(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
438       beta = PetscRealPart(dXdotdX / (lXdotdXold - lXdotdX));CHKERRQ(ierr);
439       break;
440     case SNES_NCG_CD: /* Conjugate Descent */
441       ierr = VecDotBegin(dX, dX, &dXdotdX);CHKERRQ(ierr);
442       ierr = VecDotBegin(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
443       ierr = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr);
444       ierr = VecDotEnd(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
445       beta = PetscRealPart(dXdotdX / lXdotdXold);CHKERRQ(ierr);
446       break;
447     }
448     if (ncg->monitor) {
449       ierr = PetscViewerASCIIPrintf(ncg->monitor, "beta = %e\n", (double)beta);CHKERRQ(ierr);
450     }
451     ierr = VecAYPX(lX, beta, dX);CHKERRQ(ierr);
452   }
453   ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
454   if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
455   PetscFunctionReturn(0);
456 }
457 
458 
459 
460 /*MC
461   SNESNCG - Nonlinear Conjugate-Gradient method for the solution of general nonlinear systems.
462 
463   Level: beginner
464 
465   Options Database:
466 +   -snes_ncg_type <fr, prp, dy, hs, cd> - Choice of conjugate-gradient update parameter.
467 .   -snes_linesearch_type <cp,l2,basic> - Line search type.
468 -   -snes_ncg_monitor - Print relevant information about the ncg iteration.
469 
470 Notes: This solves the nonlinear system of equations F(x) = 0 using the nonlinear generalization of the conjugate
471 gradient method.  This may be used with a nonlinear preconditioner used to pick the new search directions, but otherwise
472 chooses the initial search direction as F(x) for the initial guess x.
473 
474 The default type is PRP.
475 
476 
477 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR, SNESNGMRES, SNESNQN
478 M*/
479 #undef __FUNCT__
480 #define __FUNCT__ "SNESCreate_NCG"
481 PETSC_EXTERN PetscErrorCode SNESCreate_NCG(SNES snes)
482 {
483   PetscErrorCode ierr;
484   SNES_NCG       * neP;
485 
486   PetscFunctionBegin;
487   snes->ops->destroy        = SNESDestroy_NCG;
488   snes->ops->setup          = SNESSetUp_NCG;
489   snes->ops->setfromoptions = SNESSetFromOptions_NCG;
490   snes->ops->view           = SNESView_NCG;
491   snes->ops->solve          = SNESSolve_NCG;
492   snes->ops->reset          = SNESReset_NCG;
493 
494   snes->usesksp = PETSC_FALSE;
495   snes->usespc  = PETSC_TRUE;
496   snes->pcside  = PC_LEFT;
497 
498   if (!snes->tolerancesset) {
499     snes->max_funcs = 30000;
500     snes->max_its   = 10000;
501     snes->stol      = 1e-20;
502   }
503 
504   ierr         = PetscNewLog(snes,&neP);CHKERRQ(ierr);
505   snes->data   = (void*) neP;
506   neP->monitor = NULL;
507   neP->type    = SNES_NCG_PRP;
508   ierr         = PetscObjectComposeFunction((PetscObject)snes,"SNESNCGSetType_C", SNESNCGSetType_NCG);CHKERRQ(ierr);
509   PetscFunctionReturn(0);
510 }
511