xref: /petsc/src/snes/impls/ncg/snesncg.c (revision 6c4ed00291fe44f94936dd2f04c02ab3c442e77c)
10a844d1aSPeter Brune #include <../src/snes/impls/ncg/snesncgimpl.h> /*I "petscsnes.h" I*/
26a6fc655SJed Brown const char *const SNESNCGTypes[] = {"FR","PRP","HS","DY","CD","SNESNCGType","SNES_NCG_",0};
3fef7b6d8SPeter Brune 
4fef7b6d8SPeter Brune #undef __FUNCT__
5fef7b6d8SPeter Brune #define __FUNCT__ "SNESReset_NCG"
6fef7b6d8SPeter Brune PetscErrorCode SNESReset_NCG(SNES snes)
7fef7b6d8SPeter Brune {
8fef7b6d8SPeter Brune   PetscFunctionBegin;
9fef7b6d8SPeter Brune   PetscFunctionReturn(0);
10fef7b6d8SPeter Brune }
11fef7b6d8SPeter Brune 
129105210eSPeter Brune #define SNESLINESEARCHNCGLINEAR "ncglinear"
13bbd5d0b3SPeter 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 = PetscFree(snes->data);CHKERRQ(ierr);
30fef7b6d8SPeter Brune   PetscFunctionReturn(0);
31fef7b6d8SPeter Brune }
32fef7b6d8SPeter Brune 
33fef7b6d8SPeter Brune /*
34fef7b6d8SPeter Brune    SNESSetUp_NCG - Sets up the internal data structures for the later use
35fef7b6d8SPeter Brune    of the SNESNCG nonlinear solver.
36fef7b6d8SPeter Brune 
37fef7b6d8SPeter Brune    Input Parameters:
38fef7b6d8SPeter Brune +  snes - the SNES context
39fef7b6d8SPeter Brune -  x - the solution vector
40fef7b6d8SPeter Brune 
41fef7b6d8SPeter Brune    Application Interface Routine: SNESSetUp()
42fef7b6d8SPeter Brune  */
43bbd5d0b3SPeter Brune 
448cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_NCGLinear(SNESLineSearch);
45bbd5d0b3SPeter Brune 
46fef7b6d8SPeter Brune #undef __FUNCT__
47fef7b6d8SPeter Brune #define __FUNCT__ "SNESSetUp_NCG"
48fef7b6d8SPeter Brune PetscErrorCode SNESSetUp_NCG(SNES snes)
49fef7b6d8SPeter Brune {
50fef7b6d8SPeter Brune   PetscErrorCode ierr;
51fef7b6d8SPeter Brune 
52fef7b6d8SPeter Brune   PetscFunctionBegin;
53fa0ddf94SBarry Smith   ierr = SNESSetWorkVecs(snes,2);CHKERRQ(ierr);
54a71552e2SPeter Brune   if (snes->pcside == PC_RIGHT) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNESNCG only supports left preconditioning");
556c67d002SPeter Brune   if (snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_UNPRECONDITIONED;
56fef7b6d8SPeter Brune   PetscFunctionReturn(0);
57fef7b6d8SPeter Brune }
58fef7b6d8SPeter Brune /*
5905b53524SPeter Brune   SNESSetFromOptions_NCG - Sets various parameters for the SNESNCG method.
60fef7b6d8SPeter Brune 
61fef7b6d8SPeter Brune   Input Parameter:
62fef7b6d8SPeter Brune . snes - the SNES context
63fef7b6d8SPeter Brune 
64fef7b6d8SPeter Brune   Application Interface Routine: SNESSetFromOptions()
65fef7b6d8SPeter Brune */
66fef7b6d8SPeter Brune #undef __FUNCT__
67fef7b6d8SPeter Brune #define __FUNCT__ "SNESSetFromOptions_NCG"
688c34d3f5SBarry Smith static PetscErrorCode SNESSetFromOptions_NCG(PetscOptions *PetscOptionsObject,SNES snes)
69fef7b6d8SPeter Brune {
70dfb256c7SPeter Brune   SNES_NCG       *ncg = (SNES_NCG*)snes->data;
71fef7b6d8SPeter Brune   PetscErrorCode ierr;
7294ae4db5SBarry Smith   PetscBool      debug = PETSC_FALSE;
73f1c6b773SPeter Brune   SNESLineSearch linesearch;
74a11d90f7SPeter Brune   SNESNCGType    ncgtype=ncg->type;
75fef7b6d8SPeter Brune 
76fef7b6d8SPeter Brune   PetscFunctionBegin;
77e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"SNES NCG options");CHKERRQ(ierr);
780298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ncg_monitor","Monitor NCG iterations","SNES",ncg->monitor ? PETSC_TRUE : PETSC_FALSE, &debug, NULL);CHKERRQ(ierr);
79dfb256c7SPeter Brune   if (debug) {
80ce94432eSBarry Smith     ncg->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
81dfb256c7SPeter Brune   }
8294ae4db5SBarry Smith   ierr = PetscOptionsEnum("-snes_ncg_type","NCG Beta type used","SNESNCGSetType",SNESNCGTypes,(PetscEnum)ncg->type,(PetscEnum*)&ncgtype,NULL);CHKERRQ(ierr);
8394ae4db5SBarry Smith   ierr = SNESNCGSetType(snes, ncgtype);CHKERRQ(ierr);
84fef7b6d8SPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
859e764e56SPeter Brune   if (!snes->linesearch) {
867601faf0SJed Brown     ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
879e764e56SPeter Brune     if (!snes->pc) {
881a4f838cSPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr);
899e764e56SPeter Brune     } else {
901a4f838cSPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHL2);CHKERRQ(ierr);
919e764e56SPeter Brune     }
929e764e56SPeter Brune   }
939105210eSPeter Brune   ierr = SNESLineSearchRegister(SNESLINESEARCHNCGLINEAR, SNESLineSearchCreate_NCGLinear);CHKERRQ(ierr);
94fef7b6d8SPeter Brune   PetscFunctionReturn(0);
95fef7b6d8SPeter Brune }
96fef7b6d8SPeter Brune 
97fef7b6d8SPeter Brune /*
98fef7b6d8SPeter Brune   SNESView_NCG - Prints info from the SNESNCG data structure.
99fef7b6d8SPeter Brune 
100fef7b6d8SPeter Brune   Input Parameters:
101fef7b6d8SPeter Brune + SNES - the SNES context
102fef7b6d8SPeter Brune - viewer - visualization context
103fef7b6d8SPeter Brune 
104fef7b6d8SPeter Brune   Application Interface Routine: SNESView()
105fef7b6d8SPeter Brune */
106fef7b6d8SPeter Brune #undef __FUNCT__
107fef7b6d8SPeter Brune #define __FUNCT__ "SNESView_NCG"
108fef7b6d8SPeter Brune static PetscErrorCode SNESView_NCG(SNES snes, PetscViewer viewer)
109fef7b6d8SPeter Brune {
110cc3c3c0fSMatthew G. Knepley   SNES_NCG      *ncg = (SNES_NCG *) snes->data;
111fef7b6d8SPeter Brune   PetscBool      iascii;
112fef7b6d8SPeter Brune   PetscErrorCode ierr;
113fef7b6d8SPeter Brune 
114fef7b6d8SPeter Brune   PetscFunctionBegin;
115251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
116fef7b6d8SPeter Brune   if (iascii) {
117cc3c3c0fSMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(viewer, "ncg type: %s\n", SNESNCGTypes[ncg->type]);CHKERRQ(ierr);
118fef7b6d8SPeter Brune   }
119fef7b6d8SPeter Brune   PetscFunctionReturn(0);
120fef7b6d8SPeter Brune }
121fef7b6d8SPeter Brune 
122fef7b6d8SPeter Brune #undef __FUNCT__
123f1c6b773SPeter Brune #define __FUNCT__ "SNESLineSearchApply_NCGLinear"
124f1c6b773SPeter Brune PetscErrorCode SNESLineSearchApply_NCGLinear(SNESLineSearch linesearch)
125ea630c6eSPeter Brune {
126ea630c6eSPeter Brune   PetscScalar    alpha, ptAp;
127bbd5d0b3SPeter Brune   Vec            X, Y, F, W;
128bbd5d0b3SPeter Brune   SNES           snes;
129ea630c6eSPeter Brune   PetscErrorCode ierr;
130bbd5d0b3SPeter Brune   PetscReal      *fnorm, *xnorm, *ynorm;
131ea630c6eSPeter Brune 
132ea630c6eSPeter Brune   PetscFunctionBegin;
133f1c6b773SPeter Brune   ierr  = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr);
134bbd5d0b3SPeter Brune   X     = linesearch->vec_sol;
135bbd5d0b3SPeter Brune   W     = linesearch->vec_sol_new;
136bbd5d0b3SPeter Brune   F     = linesearch->vec_func;
137bbd5d0b3SPeter Brune   Y     = linesearch->vec_update;
138bbd5d0b3SPeter Brune   fnorm = &linesearch->fnorm;
139bbd5d0b3SPeter Brune   xnorm = &linesearch->xnorm;
140bbd5d0b3SPeter Brune   ynorm = &linesearch->ynorm;
141bbd5d0b3SPeter Brune 
1429105210eSPeter Brune   if (!snes->jacobian) {
1439105210eSPeter Brune     ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
1449105210eSPeter Brune   }
1459105210eSPeter Brune 
146ea630c6eSPeter Brune   /*
147ea630c6eSPeter Brune 
148d2140ca3SPeter Brune    The exact step size for unpreconditioned linear CG is just:
149ea630c6eSPeter Brune    alpha = (r, r) / (p, Ap) = (f, f) / (y, Jy)
150ea630c6eSPeter Brune    */
151d1e9a80fSBarry Smith   ierr  = SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre);CHKERRQ(ierr);
152ea630c6eSPeter Brune   ierr  = VecDot(F, F, &alpha);CHKERRQ(ierr);
153ea630c6eSPeter Brune   ierr  = MatMult(snes->jacobian, Y, W);CHKERRQ(ierr);
154ea630c6eSPeter Brune   ierr  = VecDot(Y, W, &ptAp);CHKERRQ(ierr);
155ea630c6eSPeter Brune   alpha = alpha / ptAp;
1569105210eSPeter Brune   ierr  = VecAXPY(X,-alpha,Y);CHKERRQ(ierr);
157bbd5d0b3SPeter Brune   ierr  = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
158bbd5d0b3SPeter Brune 
159bbd5d0b3SPeter Brune   ierr = VecNorm(F,NORM_2,fnorm);CHKERRQ(ierr);
160bbd5d0b3SPeter Brune   ierr = VecNorm(X,NORM_2,xnorm);CHKERRQ(ierr);
161bbd5d0b3SPeter Brune   ierr = VecNorm(Y,NORM_2,ynorm);CHKERRQ(ierr);
162ea630c6eSPeter Brune   PetscFunctionReturn(0);
163ea630c6eSPeter Brune }
164ea630c6eSPeter Brune 
165bbd5d0b3SPeter Brune #undef __FUNCT__
166f1c6b773SPeter Brune #define __FUNCT__ "SNESLineSearchCreate_NCGLinear"
1678cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_NCGLinear(SNESLineSearch linesearch)
168bbd5d0b3SPeter Brune {
169bbd5d0b3SPeter Brune   PetscFunctionBegin;
170f1c6b773SPeter Brune   linesearch->ops->apply          = SNESLineSearchApply_NCGLinear;
1710298fd71SBarry Smith   linesearch->ops->destroy        = NULL;
1720298fd71SBarry Smith   linesearch->ops->setfromoptions = NULL;
1730298fd71SBarry Smith   linesearch->ops->reset          = NULL;
1740298fd71SBarry Smith   linesearch->ops->view           = NULL;
1750298fd71SBarry Smith   linesearch->ops->setup          = NULL;
176bbd5d0b3SPeter Brune   PetscFunctionReturn(0);
177bbd5d0b3SPeter Brune }
178bbd5d0b3SPeter Brune 
17988d374b2SPeter Brune #undef __FUNCT__
1808c40d5fbSBarry Smith #define __FUNCT__ "SNESNCGComputeYtJtF_Private"
18188d374b2SPeter Brune /*
18288d374b2SPeter Brune 
18388d374b2SPeter Brune  Assuming F = SNESComputeFunction(X) compute Y^tJ^tF using a simple secant approximation of the jacobian.
18488d374b2SPeter Brune 
18588d374b2SPeter Brune  */
18667392de3SBarry Smith PetscErrorCode SNESNCGComputeYtJtF_Private(SNES snes, Vec X, Vec F, Vec Y, Vec W, Vec G, PetscScalar * ytJtf)
18767392de3SBarry Smith {
18888d374b2SPeter Brune   PetscErrorCode ierr;
18988d374b2SPeter Brune   PetscScalar    ftf, ftg, fty, h;
19067392de3SBarry Smith 
19188d374b2SPeter Brune   PetscFunctionBegin;
19288d374b2SPeter Brune   ierr   = VecDot(F, F, &ftf);CHKERRQ(ierr);
19388d374b2SPeter Brune   ierr   = VecDot(F, Y, &fty);CHKERRQ(ierr);
19488d374b2SPeter Brune   h      = 1e-5*fty / fty;
19588d374b2SPeter Brune   ierr   = VecCopy(X, W);CHKERRQ(ierr);
19688d374b2SPeter Brune   ierr   = VecAXPY(W, -h, Y);CHKERRQ(ierr);          /* this is arbitrary */
19788d374b2SPeter Brune   ierr   = SNESComputeFunction(snes, W, G);CHKERRQ(ierr);
19888d374b2SPeter Brune   ierr   = VecDot(G, F, &ftg);CHKERRQ(ierr);
19988d374b2SPeter Brune   *ytJtf = (ftg - ftf) / h;
20088d374b2SPeter Brune   PetscFunctionReturn(0);
20188d374b2SPeter Brune }
20288d374b2SPeter Brune 
2030a844d1aSPeter Brune #undef __FUNCT__
2040a844d1aSPeter Brune #define __FUNCT__ "SNESNCGSetType"
2050a844d1aSPeter Brune /*@
2060a844d1aSPeter Brune     SNESNCGSetType - Sets the conjugate update type for SNESNCG.
2070a844d1aSPeter Brune 
2080a844d1aSPeter Brune     Logically Collective on SNES
2090a844d1aSPeter Brune 
2100a844d1aSPeter Brune     Input Parameters:
2110a844d1aSPeter Brune +   snes - the iterative context
2120a844d1aSPeter Brune -   btype - update type
2130a844d1aSPeter Brune 
2140a844d1aSPeter Brune     Options Database:
2150a844d1aSPeter Brune .   -snes_ncg_type<prp,fr,hs,dy,cd>
2160a844d1aSPeter Brune 
2170a844d1aSPeter Brune     Level: intermediate
2180a844d1aSPeter Brune 
2190a844d1aSPeter Brune     SNESNCGSelectTypes:
2200a844d1aSPeter Brune +   SNES_NCG_FR - Fletcher-Reeves update
2210a844d1aSPeter Brune .   SNES_NCG_PRP - Polak-Ribiere-Polyak update
2220a844d1aSPeter Brune .   SNES_NCG_HS - Hestenes-Steifel update
2230a844d1aSPeter Brune .   SNES_NCG_DY - Dai-Yuan update
2240a844d1aSPeter Brune -   SNES_NCG_CD - Conjugate Descent update
2250a844d1aSPeter Brune 
2260a844d1aSPeter Brune    Notes:
2270a844d1aSPeter Brune    PRP is the default, and the only one that tolerates generalized search directions.
2280a844d1aSPeter Brune 
2290a844d1aSPeter Brune .keywords: SNES, SNESNCG, selection, type, set
2300a844d1aSPeter Brune @*/
2310adebc6cSBarry Smith PetscErrorCode SNESNCGSetType(SNES snes, SNESNCGType btype)
2320adebc6cSBarry Smith {
2330a844d1aSPeter Brune   PetscErrorCode ierr;
2346e111a19SKarl Rupp 
2350a844d1aSPeter Brune   PetscFunctionBegin;
2360a844d1aSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
2370a844d1aSPeter Brune   ierr = PetscTryMethod(snes,"SNESNCGSetType_C",(SNES,SNESNCGType),(snes,btype));CHKERRQ(ierr);
2380a844d1aSPeter Brune   PetscFunctionReturn(0);
2390a844d1aSPeter Brune }
2400a844d1aSPeter Brune 
2410a844d1aSPeter Brune #undef __FUNCT__
2420a844d1aSPeter Brune #define __FUNCT__ "SNESNCGSetType_NCG"
2430adebc6cSBarry Smith PetscErrorCode SNESNCGSetType_NCG(SNES snes, SNESNCGType btype)
2440adebc6cSBarry Smith {
2450a844d1aSPeter Brune   SNES_NCG *ncg = (SNES_NCG*)snes->data;
2466e111a19SKarl Rupp 
2470a844d1aSPeter Brune   PetscFunctionBegin;
2480a844d1aSPeter Brune   ncg->type = btype;
2490a844d1aSPeter Brune   PetscFunctionReturn(0);
2500a844d1aSPeter Brune }
2510a844d1aSPeter Brune 
252fef7b6d8SPeter Brune /*
253fef7b6d8SPeter Brune   SNESSolve_NCG - Solves a nonlinear system with the Nonlinear Conjugate Gradient method.
254fef7b6d8SPeter Brune 
255fef7b6d8SPeter Brune   Input Parameters:
256fef7b6d8SPeter Brune . snes - the SNES context
257fef7b6d8SPeter Brune 
258fef7b6d8SPeter Brune   Output Parameter:
259fef7b6d8SPeter Brune . outits - number of iterations until termination
260fef7b6d8SPeter Brune 
261fef7b6d8SPeter Brune   Application Interface Routine: SNESSolve()
262fef7b6d8SPeter Brune */
263fef7b6d8SPeter Brune #undef __FUNCT__
264fef7b6d8SPeter Brune #define __FUNCT__ "SNESSolve_NCG"
265fef7b6d8SPeter Brune PetscErrorCode SNESSolve_NCG(SNES snes)
266fef7b6d8SPeter Brune {
267dfb256c7SPeter Brune   SNES_NCG             *ncg = (SNES_NCG*)snes->data;
26832cc618eSPeter Brune   Vec                  X,dX,lX,F,dXold;
269bbd5d0b3SPeter Brune   PetscReal            fnorm, ynorm, xnorm, beta = 0.0;
27032cc618eSPeter Brune   PetscScalar          dXdotdX, dXolddotdXold, dXdotdXold, lXdotdX, lXdotdXold;
271fef7b6d8SPeter Brune   PetscInt             maxits, i;
272fef7b6d8SPeter Brune   PetscErrorCode       ierr;
273422a814eSBarry Smith   SNESLineSearchReason lsresult = SNES_LINESEARCH_SUCCEEDED;
274f1c6b773SPeter Brune   SNESLineSearch       linesearch;
275b7281c8aSPeter Brune   SNESConvergedReason  reason;
27688d374b2SPeter Brune 
277fef7b6d8SPeter Brune   PetscFunctionBegin;
278*6c4ed002SBarry Smith   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);
279c579b300SPatrick Farrell 
280fffbeea8SBarry Smith   ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr);
281fef7b6d8SPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
282fef7b6d8SPeter Brune 
283fef7b6d8SPeter Brune   maxits = snes->max_its;            /* maximum number of iterations */
284fef7b6d8SPeter Brune   X      = snes->vec_sol;            /* X^n */
28532cc618eSPeter Brune   dXold  = snes->work[0];            /* The previous iterate of X */
28688d374b2SPeter Brune   dX     = snes->work[1];            /* the preconditioned direction */
287169e2be8SPeter Brune   lX     = snes->vec_sol_update;     /* the conjugate direction */
288fef7b6d8SPeter Brune   F      = snes->vec_func;           /* residual vector */
289fef7b6d8SPeter Brune 
2907601faf0SJed Brown   ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
2919e764e56SPeter Brune 
292e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
293fef7b6d8SPeter Brune   snes->iter = 0;
294fef7b6d8SPeter Brune   snes->norm = 0.;
295e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
296fef7b6d8SPeter Brune 
297bbd5d0b3SPeter Brune   /* compute the initial function and preconditioned update dX */
298a71552e2SPeter Brune 
299a71552e2SPeter Brune   if (snes->pc && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
300be95d8f1SBarry Smith     ierr = SNESApplyNPC(snes,X,NULL,dX);CHKERRQ(ierr);
301b7281c8aSPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
302b7281c8aSPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
303b7281c8aSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
304b7281c8aSPeter Brune       PetscFunctionReturn(0);
305b7281c8aSPeter Brune     }
306a71552e2SPeter Brune     ierr = VecCopy(dX,F);CHKERRQ(ierr);
307a71552e2SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
308a71552e2SPeter Brune   } else {
309e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
310fef7b6d8SPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
3111aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
312c1c75074SPeter Brune 
313fef7b6d8SPeter Brune     /* convergence test */
314a71552e2SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
315422a814eSBarry Smith     SNESCheckFunctionNorm(snes,fnorm);
316a71552e2SPeter Brune     ierr = VecCopy(F,dX);CHKERRQ(ierr);
317a71552e2SPeter Brune   }
318a71552e2SPeter Brune   if (snes->pc) {
319a71552e2SPeter Brune     if (snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
320be95d8f1SBarry Smith       ierr = SNESApplyNPC(snes,X,F,dX);CHKERRQ(ierr);
321b7281c8aSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
322b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
323b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
324b7281c8aSPeter Brune         PetscFunctionReturn(0);
325b7281c8aSPeter Brune       }
326a71552e2SPeter Brune     }
327a71552e2SPeter Brune   }
328a71552e2SPeter Brune   ierr = VecCopy(dX,lX);CHKERRQ(ierr);
32932cc618eSPeter Brune   ierr = VecDot(dX, dX, &dXdotdX);CHKERRQ(ierr);
330a71552e2SPeter Brune 
331a71552e2SPeter Brune 
332e04113cfSBarry Smith   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
333fef7b6d8SPeter Brune   snes->norm = fnorm;
334e04113cfSBarry Smith   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
335a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
336fef7b6d8SPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
337fef7b6d8SPeter Brune 
338fef7b6d8SPeter Brune   /* test convergence */
339fef7b6d8SPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
340fef7b6d8SPeter Brune   if (snes->reason) PetscFunctionReturn(0);
341fef7b6d8SPeter Brune 
342fef7b6d8SPeter Brune   /* Call general purpose update function */
343fef7b6d8SPeter Brune   if (snes->ops->update) {
344fef7b6d8SPeter Brune     ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
345fef7b6d8SPeter Brune   }
346fef7b6d8SPeter Brune 
347fef7b6d8SPeter Brune   /* first update -- just use the (preconditioned) residual direction for the initial conjugate direction */
348bbd5d0b3SPeter Brune 
34909c08436SPeter Brune   for (i = 1; i < maxits + 1; i++) {
35029c94e34SPeter Brune     /* some update types require the old update direction or conjugate direction */
3510a844d1aSPeter Brune     if (ncg->type != SNES_NCG_FR) {
35232cc618eSPeter Brune       ierr = VecCopy(dX, dXold);CHKERRQ(ierr);
35388d374b2SPeter Brune     }
354f1c6b773SPeter Brune     ierr = SNESLineSearchApply(linesearch,X,F,&fnorm,lX);CHKERRQ(ierr);
355422a814eSBarry Smith     ierr = SNESLineSearchGetReason(linesearch, &lsresult);CHKERRQ(ierr);
356422a814eSBarry Smith     ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
357422a814eSBarry Smith     if (lsresult) {
358fef7b6d8SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
359fef7b6d8SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
3605d10c001SPeter Brune         PetscFunctionReturn(0);
361fef7b6d8SPeter Brune       }
362fef7b6d8SPeter Brune     }
363fef7b6d8SPeter Brune     if (snes->nfuncs >= snes->max_funcs) {
364fef7b6d8SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
3655d10c001SPeter Brune       PetscFunctionReturn(0);
366fef7b6d8SPeter Brune     }
367fef7b6d8SPeter Brune     /* Monitor convergence */
368e04113cfSBarry Smith     ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
369169e2be8SPeter Brune     snes->iter = i;
370fef7b6d8SPeter Brune     snes->norm = fnorm;
371e04113cfSBarry Smith     ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
372a71f0d7dSBarry Smith     ierr       = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr);
373fef7b6d8SPeter Brune     ierr       = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
374302dbbaeSPeter Brune 
375fef7b6d8SPeter Brune     /* Test for convergence */
376d484d688SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
3775d10c001SPeter Brune     if (snes->reason) PetscFunctionReturn(0);
378302dbbaeSPeter Brune 
379302dbbaeSPeter Brune     /* Call general purpose update function */
380302dbbaeSPeter Brune     if (snes->ops->update) {
381302dbbaeSPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
382302dbbaeSPeter Brune     }
383a71552e2SPeter Brune     if (snes->pc) {
384a71552e2SPeter Brune       if (snes->functype == SNES_FUNCTION_PRECONDITIONED) {
385be95d8f1SBarry Smith         ierr = SNESApplyNPC(snes,X,NULL,dX);CHKERRQ(ierr);
386b7281c8aSPeter Brune         ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
387b7281c8aSPeter Brune         if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
388b7281c8aSPeter Brune           snes->reason = SNES_DIVERGED_INNER;
389b7281c8aSPeter Brune           PetscFunctionReturn(0);
390b7281c8aSPeter Brune         }
391a71552e2SPeter Brune         ierr = VecCopy(dX,F);CHKERRQ(ierr);
392a71552e2SPeter Brune       } else {
393be95d8f1SBarry Smith         ierr = SNESApplyNPC(snes,X,F,dX);CHKERRQ(ierr);
394b7281c8aSPeter Brune         ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
395b7281c8aSPeter Brune         if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
396b7281c8aSPeter Brune           snes->reason = SNES_DIVERGED_INNER;
397b7281c8aSPeter Brune           PetscFunctionReturn(0);
398b7281c8aSPeter Brune         }
399302dbbaeSPeter Brune       }
400a3685310SPeter Brune     } else {
401a3685310SPeter Brune       ierr = VecCopy(F,dX);CHKERRQ(ierr);
402302dbbaeSPeter Brune     }
403302dbbaeSPeter Brune 
40429c94e34SPeter Brune     /* compute the conjugate direction lX = dX + beta*lX with beta = ((dX, dX) / (dX_old, dX_old) (Fletcher-Reeves update)*/
4050a844d1aSPeter Brune     switch (ncg->type) {
4060a844d1aSPeter Brune     case SNES_NCG_FR: /* Fletcher-Reeves */
40732cc618eSPeter Brune       dXolddotdXold= dXdotdX;
40832cc618eSPeter Brune       ierr         = VecDot(dX, dX, &dXdotdX);CHKERRQ(ierr);
40932cc618eSPeter Brune       beta         = PetscRealPart(dXdotdX / dXolddotdXold);
410dfb256c7SPeter Brune       break;
4110a844d1aSPeter Brune     case SNES_NCG_PRP: /* Polak-Ribiere-Poylak */
41232cc618eSPeter Brune       dXolddotdXold= dXdotdX;
41332cc618eSPeter Brune       ierr         = VecDotBegin(dX, dX, &dXdotdXold);CHKERRQ(ierr);
41432cc618eSPeter Brune       ierr         = VecDotBegin(dXold, dX, &dXdotdXold);CHKERRQ(ierr);
41532cc618eSPeter Brune       ierr         = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr);
41632cc618eSPeter Brune       ierr         = VecDotEnd(dXold, dX, &dXdotdXold);CHKERRQ(ierr);
41732cc618eSPeter Brune       beta         = PetscRealPart(((dXdotdX - dXdotdXold) / dXolddotdXold));
418dfb256c7SPeter Brune       if (beta < 0.0) beta = 0.0; /* restart */
419dfb256c7SPeter Brune       break;
4200a844d1aSPeter Brune     case SNES_NCG_HS: /* Hestenes-Stiefel */
42132cc618eSPeter Brune       ierr = VecDotBegin(dX, dX, &dXdotdX);CHKERRQ(ierr);
42232cc618eSPeter Brune       ierr = VecDotBegin(dX, dXold, &dXdotdXold);CHKERRQ(ierr);
42332cc618eSPeter Brune       ierr = VecDotBegin(lX, dX, &lXdotdX);CHKERRQ(ierr);
42432cc618eSPeter Brune       ierr = VecDotBegin(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
42532cc618eSPeter Brune       ierr = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr);
42632cc618eSPeter Brune       ierr = VecDotEnd(dX, dXold, &dXdotdXold);CHKERRQ(ierr);
42732cc618eSPeter Brune       ierr = VecDotEnd(lX, dX, &lXdotdX);CHKERRQ(ierr);
42832cc618eSPeter Brune       ierr = VecDotEnd(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
42932cc618eSPeter Brune       beta = PetscRealPart((dXdotdX - dXdotdXold) / (lXdotdX - lXdotdXold));
430dfb256c7SPeter Brune       break;
4310a844d1aSPeter Brune     case SNES_NCG_DY: /* Dai-Yuan */
43232cc618eSPeter Brune       ierr = VecDotBegin(dX, dX, &dXdotdX);CHKERRQ(ierr);
43332cc618eSPeter Brune       ierr = VecDotBegin(lX, dX, &lXdotdX);CHKERRQ(ierr);
43432cc618eSPeter Brune       ierr = VecDotBegin(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
43532cc618eSPeter Brune       ierr = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr);
43632cc618eSPeter Brune       ierr = VecDotEnd(lX, dX, &lXdotdX);CHKERRQ(ierr);
43732cc618eSPeter Brune       ierr = VecDotEnd(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
43832cc618eSPeter Brune       beta = PetscRealPart(dXdotdX / (lXdotdXold - lXdotdX));CHKERRQ(ierr);
439dfb256c7SPeter Brune       break;
4400a844d1aSPeter Brune     case SNES_NCG_CD: /* Conjugate Descent */
44132cc618eSPeter Brune       ierr = VecDotBegin(dX, dX, &dXdotdX);CHKERRQ(ierr);
44232cc618eSPeter Brune       ierr = VecDotBegin(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
44332cc618eSPeter Brune       ierr = VecDotEnd(dX, dX, &dXdotdX);CHKERRQ(ierr);
44432cc618eSPeter Brune       ierr = VecDotEnd(lX, dXold, &lXdotdXold);CHKERRQ(ierr);
44532cc618eSPeter Brune       beta = PetscRealPart(dXdotdX / lXdotdXold);CHKERRQ(ierr);
446dfb256c7SPeter Brune       break;
447dfb256c7SPeter Brune     }
448dfb256c7SPeter Brune     if (ncg->monitor) {
4497904a332SBarry Smith       ierr = PetscViewerASCIIPrintf(ncg->monitor, "beta = %e\n", (double)beta);CHKERRQ(ierr);
450dfb256c7SPeter Brune     }
451dfb256c7SPeter Brune     ierr = VecAYPX(lX, beta, dX);CHKERRQ(ierr);
452fef7b6d8SPeter Brune   }
453fef7b6d8SPeter Brune   ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
454fef7b6d8SPeter Brune   if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
455fef7b6d8SPeter Brune   PetscFunctionReturn(0);
456fef7b6d8SPeter Brune }
457fef7b6d8SPeter Brune 
4580a844d1aSPeter Brune 
4590a844d1aSPeter Brune 
460fef7b6d8SPeter Brune /*MC
461fef7b6d8SPeter Brune   SNESNCG - Nonlinear Conjugate-Gradient method for the solution of general nonlinear systems.
462fef7b6d8SPeter Brune 
463fef7b6d8SPeter Brune   Level: beginner
464fef7b6d8SPeter Brune 
465fef7b6d8SPeter Brune   Options Database:
4661867fe5bSPeter Brune +   -snes_ncg_type <fr, prp, dy, hs, cd> - Choice of conjugate-gradient update parameter.
46741a8cb50SPeter Brune .   -snes_linesearch_type <cp,l2,basic> - Line search type.
4681867fe5bSPeter Brune -   -snes_ncg_monitor - Print relevant information about the ncg iteration.
469fef7b6d8SPeter Brune 
470fef7b6d8SPeter Brune Notes: This solves the nonlinear system of equations F(x) = 0 using the nonlinear generalization of the conjugate
471fef7b6d8SPeter Brune gradient method.  This may be used with a nonlinear preconditioner used to pick the new search directions, but otherwise
472fef7b6d8SPeter Brune chooses the initial search direction as F(x) for the initial guess x.
473fef7b6d8SPeter Brune 
474cc3c3c0fSMatthew G. Knepley The default type is PRP.
475cc3c3c0fSMatthew G. Knepley 
476fef7b6d8SPeter Brune 
47704d7464bSBarry Smith .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR, SNESNGMRES, SNESNQN
478fef7b6d8SPeter Brune M*/
479fef7b6d8SPeter Brune #undef __FUNCT__
480fef7b6d8SPeter Brune #define __FUNCT__ "SNESCreate_NCG"
4818cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_NCG(SNES snes)
482fef7b6d8SPeter Brune {
483fef7b6d8SPeter Brune   PetscErrorCode ierr;
484ea630c6eSPeter Brune   SNES_NCG       * neP;
485fef7b6d8SPeter Brune 
486fef7b6d8SPeter Brune   PetscFunctionBegin;
487fef7b6d8SPeter Brune   snes->ops->destroy        = SNESDestroy_NCG;
488fef7b6d8SPeter Brune   snes->ops->setup          = SNESSetUp_NCG;
489fef7b6d8SPeter Brune   snes->ops->setfromoptions = SNESSetFromOptions_NCG;
490fef7b6d8SPeter Brune   snes->ops->view           = SNESView_NCG;
491fef7b6d8SPeter Brune   snes->ops->solve          = SNESSolve_NCG;
492fef7b6d8SPeter Brune   snes->ops->reset          = SNESReset_NCG;
493fef7b6d8SPeter Brune 
494fef7b6d8SPeter Brune   snes->usesksp = PETSC_FALSE;
495fef7b6d8SPeter Brune   snes->usespc  = PETSC_TRUE;
496a71552e2SPeter Brune   snes->pcside  = PC_LEFT;
497fef7b6d8SPeter Brune 
49888976e71SPeter Brune   if (!snes->tolerancesset) {
4990e444f03SPeter Brune     snes->max_funcs = 30000;
5000e444f03SPeter Brune     snes->max_its   = 10000;
501c522fa08SPeter Brune     snes->stol      = 1e-20;
50288976e71SPeter Brune   }
5030e444f03SPeter Brune 
504b00a9115SJed Brown   ierr         = PetscNewLog(snes,&neP);CHKERRQ(ierr);
505fef7b6d8SPeter Brune   snes->data   = (void*) neP;
5060298fd71SBarry Smith   neP->monitor = NULL;
5070a844d1aSPeter Brune   neP->type    = SNES_NCG_PRP;
508bdf89e91SBarry Smith   ierr         = PetscObjectComposeFunction((PetscObject)snes,"SNESNCGSetType_C", SNESNCGSetType_NCG);CHKERRQ(ierr);
509fef7b6d8SPeter Brune   PetscFunctionReturn(0);
510fef7b6d8SPeter Brune }
511