xref: /petsc/src/snes/impls/ncg/snesncg.c (revision b7281c8a8dad9307a4edc7c93ebc34ff865e909f)
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 
121a4f838cSPeter Brune #define SNESLINESEARCHNCGLINEAR "linear"
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);
54bbd5d0b3SPeter Brune   ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
55a71552e2SPeter Brune   if (snes->pcside == PC_RIGHT) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNESNCG only supports left preconditioning");
56bdf89e91SBarry Smith   ierr = SNESLineSearchRegister(SNESLINESEARCHNCGLINEAR, SNESLineSearchCreate_NCGLinear);CHKERRQ(ierr);
57fef7b6d8SPeter Brune   PetscFunctionReturn(0);
58fef7b6d8SPeter Brune }
59fef7b6d8SPeter Brune /*
6005b53524SPeter Brune   SNESSetFromOptions_NCG - Sets various parameters for the SNESNCG method.
61fef7b6d8SPeter Brune 
62fef7b6d8SPeter Brune   Input Parameter:
63fef7b6d8SPeter Brune . snes - the SNES context
64fef7b6d8SPeter Brune 
65fef7b6d8SPeter Brune   Application Interface Routine: SNESSetFromOptions()
66fef7b6d8SPeter Brune */
67fef7b6d8SPeter Brune #undef __FUNCT__
68fef7b6d8SPeter Brune #define __FUNCT__ "SNESSetFromOptions_NCG"
69fef7b6d8SPeter Brune static PetscErrorCode SNESSetFromOptions_NCG(SNES snes)
70fef7b6d8SPeter Brune {
71dfb256c7SPeter Brune   SNES_NCG       *ncg = (SNES_NCG*)snes->data;
72fef7b6d8SPeter Brune   PetscErrorCode ierr;
730a844d1aSPeter Brune   PetscBool      debug;
74f1c6b773SPeter Brune   SNESLineSearch linesearch;
75a11d90f7SPeter Brune   SNESNCGType    ncgtype=ncg->type;
76fef7b6d8SPeter Brune 
77fef7b6d8SPeter Brune   PetscFunctionBegin;
78fef7b6d8SPeter Brune   ierr = PetscOptionsHead("SNES NCG options");CHKERRQ(ierr);
790298fd71SBarry Smith   ierr = PetscOptionsBool("-snes_ncg_monitor","Monitor NCG iterations","SNES",ncg->monitor ? PETSC_TRUE : PETSC_FALSE, &debug, NULL);CHKERRQ(ierr);
800298fd71SBarry Smith   ierr = PetscOptionsEnum("-snes_ncg_type","NCG Beta type used","SNESNCGSetType",SNESNCGTypes,(PetscEnum)ncg->type,(PetscEnum*)&ncgtype,NULL);CHKERRQ(ierr);
810a844d1aSPeter Brune   ierr = SNESNCGSetType(snes, ncgtype);CHKERRQ(ierr);
82dfb256c7SPeter Brune   if (debug) {
83ce94432eSBarry Smith     ncg->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
84dfb256c7SPeter Brune   }
85fef7b6d8SPeter Brune   ierr = PetscOptionsTail();CHKERRQ(ierr);
869e764e56SPeter Brune   if (!snes->linesearch) {
877601faf0SJed Brown     ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
889e764e56SPeter Brune     if (!snes->pc) {
891a4f838cSPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr);
909e764e56SPeter Brune     } else {
911a4f838cSPeter Brune       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHL2);CHKERRQ(ierr);
929e764e56SPeter Brune     }
939e764e56SPeter Brune   }
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 {
110fef7b6d8SPeter Brune   PetscBool      iascii;
111fef7b6d8SPeter Brune   PetscErrorCode ierr;
112fef7b6d8SPeter Brune 
113fef7b6d8SPeter Brune   PetscFunctionBegin;
114251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
115fef7b6d8SPeter Brune   if (iascii) {
116fef7b6d8SPeter Brune   }
117fef7b6d8SPeter Brune   PetscFunctionReturn(0);
118fef7b6d8SPeter Brune }
119fef7b6d8SPeter Brune 
120fef7b6d8SPeter Brune #undef __FUNCT__
121f1c6b773SPeter Brune #define __FUNCT__ "SNESLineSearchApply_NCGLinear"
122f1c6b773SPeter Brune PetscErrorCode SNESLineSearchApply_NCGLinear(SNESLineSearch linesearch)
123ea630c6eSPeter Brune {
124ea630c6eSPeter Brune   PetscScalar    alpha, ptAp;
125bbd5d0b3SPeter Brune   Vec            X, Y, F, W;
126bbd5d0b3SPeter Brune   SNES           snes;
127ea630c6eSPeter Brune   PetscErrorCode ierr;
128bbd5d0b3SPeter Brune   PetscReal      *fnorm, *xnorm, *ynorm;
129ea630c6eSPeter Brune   MatStructure   flg = DIFFERENT_NONZERO_PATTERN;
130ea630c6eSPeter Brune 
131ea630c6eSPeter Brune   PetscFunctionBegin;
132f1c6b773SPeter Brune   ierr  = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr);
133bbd5d0b3SPeter Brune   X     = linesearch->vec_sol;
134bbd5d0b3SPeter Brune   W     = linesearch->vec_sol_new;
135bbd5d0b3SPeter Brune   F     = linesearch->vec_func;
136bbd5d0b3SPeter Brune   Y     = linesearch->vec_update;
137bbd5d0b3SPeter Brune   fnorm = &linesearch->fnorm;
138bbd5d0b3SPeter Brune   xnorm = &linesearch->xnorm;
139bbd5d0b3SPeter Brune   ynorm = &linesearch->ynorm;
140bbd5d0b3SPeter Brune 
141ea630c6eSPeter Brune   /*
142ea630c6eSPeter Brune 
143d2140ca3SPeter Brune    The exact step size for unpreconditioned linear CG is just:
144ea630c6eSPeter Brune    alpha = (r, r) / (p, Ap) = (f, f) / (y, Jy)
145ea630c6eSPeter Brune    */
146a5892487SPeter Brune   ierr  = SNESComputeJacobian(snes, X, &snes->jacobian, &snes->jacobian_pre, &flg);CHKERRQ(ierr);
147ea630c6eSPeter Brune   ierr  = VecDot(F, F, &alpha);CHKERRQ(ierr);
148ea630c6eSPeter Brune   ierr  = MatMult(snes->jacobian, Y, W);CHKERRQ(ierr);
149ea630c6eSPeter Brune   ierr  = VecDot(Y, W, &ptAp);CHKERRQ(ierr);
150ea630c6eSPeter Brune   alpha = alpha / ptAp;
151ce94432eSBarry Smith   ierr  = PetscPrintf(PetscObjectComm((PetscObject)snes), "alpha: %G\n", PetscRealPart(alpha));CHKERRQ(ierr);
152bbd5d0b3SPeter Brune   ierr  = VecAXPY(X, alpha, Y);CHKERRQ(ierr);
153bbd5d0b3SPeter Brune   ierr  = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
154bbd5d0b3SPeter Brune 
155bbd5d0b3SPeter Brune   ierr = VecNorm(F, NORM_2, fnorm);CHKERRQ(ierr);
156bbd5d0b3SPeter Brune   ierr = VecNorm(X, NORM_2, xnorm);CHKERRQ(ierr);
157bbd5d0b3SPeter Brune   ierr = VecNorm(Y, NORM_2, ynorm);CHKERRQ(ierr);
158ea630c6eSPeter Brune   PetscFunctionReturn(0);
159ea630c6eSPeter Brune }
160ea630c6eSPeter Brune 
161bbd5d0b3SPeter Brune #undef __FUNCT__
162f1c6b773SPeter Brune #define __FUNCT__ "SNESLineSearchCreate_NCGLinear"
1638cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESLineSearchCreate_NCGLinear(SNESLineSearch linesearch)
164bbd5d0b3SPeter Brune {
165bbd5d0b3SPeter Brune   PetscFunctionBegin;
166f1c6b773SPeter Brune   linesearch->ops->apply          = SNESLineSearchApply_NCGLinear;
1670298fd71SBarry Smith   linesearch->ops->destroy        = NULL;
1680298fd71SBarry Smith   linesearch->ops->setfromoptions = NULL;
1690298fd71SBarry Smith   linesearch->ops->reset          = NULL;
1700298fd71SBarry Smith   linesearch->ops->view           = NULL;
1710298fd71SBarry Smith   linesearch->ops->setup          = NULL;
172bbd5d0b3SPeter Brune   PetscFunctionReturn(0);
173bbd5d0b3SPeter Brune }
174bbd5d0b3SPeter Brune 
17588d374b2SPeter Brune #undef __FUNCT__
1768c40d5fbSBarry Smith #define __FUNCT__ "SNESNCGComputeYtJtF_Private"
17788d374b2SPeter Brune /*
17888d374b2SPeter Brune 
17988d374b2SPeter Brune  Assuming F = SNESComputeFunction(X) compute Y^tJ^tF using a simple secant approximation of the jacobian.
18088d374b2SPeter Brune 
18188d374b2SPeter Brune  */
18267392de3SBarry Smith PetscErrorCode SNESNCGComputeYtJtF_Private(SNES snes, Vec X, Vec F, Vec Y, Vec W, Vec G, PetscScalar * ytJtf)
18367392de3SBarry Smith {
18488d374b2SPeter Brune   PetscErrorCode ierr;
18588d374b2SPeter Brune   PetscScalar    ftf, ftg, fty, h;
18667392de3SBarry Smith 
18788d374b2SPeter Brune   PetscFunctionBegin;
18888d374b2SPeter Brune   ierr   = VecDot(F, F, &ftf);CHKERRQ(ierr);
18988d374b2SPeter Brune   ierr   = VecDot(F, Y, &fty);CHKERRQ(ierr);
19088d374b2SPeter Brune   h      = 1e-5*fty / fty;
19188d374b2SPeter Brune   ierr   = VecCopy(X, W);CHKERRQ(ierr);
19288d374b2SPeter Brune   ierr   = VecAXPY(W, -h, Y);CHKERRQ(ierr);          /* this is arbitrary */
19388d374b2SPeter Brune   ierr   = SNESComputeFunction(snes, W, G);CHKERRQ(ierr);
19488d374b2SPeter Brune   ierr   = VecDot(G, F, &ftg);CHKERRQ(ierr);
19588d374b2SPeter Brune   *ytJtf = (ftg - ftf) / h;
19688d374b2SPeter Brune   PetscFunctionReturn(0);
19788d374b2SPeter Brune }
19888d374b2SPeter Brune 
1990a844d1aSPeter Brune #undef __FUNCT__
2000a844d1aSPeter Brune #define __FUNCT__ "SNESNCGSetType"
2010a844d1aSPeter Brune /*@
2020a844d1aSPeter Brune     SNESNCGSetType - Sets the conjugate update type for SNESNCG.
2030a844d1aSPeter Brune 
2040a844d1aSPeter Brune     Logically Collective on SNES
2050a844d1aSPeter Brune 
2060a844d1aSPeter Brune     Input Parameters:
2070a844d1aSPeter Brune +   snes - the iterative context
2080a844d1aSPeter Brune -   btype - update type
2090a844d1aSPeter Brune 
2100a844d1aSPeter Brune     Options Database:
2110a844d1aSPeter Brune .   -snes_ncg_type<prp,fr,hs,dy,cd>
2120a844d1aSPeter Brune 
2130a844d1aSPeter Brune     Level: intermediate
2140a844d1aSPeter Brune 
2150a844d1aSPeter Brune     SNESNCGSelectTypes:
2160a844d1aSPeter Brune +   SNES_NCG_FR - Fletcher-Reeves update
2170a844d1aSPeter Brune .   SNES_NCG_PRP - Polak-Ribiere-Polyak update
2180a844d1aSPeter Brune .   SNES_NCG_HS - Hestenes-Steifel update
2190a844d1aSPeter Brune .   SNES_NCG_DY - Dai-Yuan update
2200a844d1aSPeter Brune -   SNES_NCG_CD - Conjugate Descent update
2210a844d1aSPeter Brune 
2220a844d1aSPeter Brune    Notes:
2230a844d1aSPeter Brune    PRP is the default, and the only one that tolerates generalized search directions.
2240a844d1aSPeter Brune 
2250a844d1aSPeter Brune .keywords: SNES, SNESNCG, selection, type, set
2260a844d1aSPeter Brune @*/
2270adebc6cSBarry Smith PetscErrorCode SNESNCGSetType(SNES snes, SNESNCGType btype)
2280adebc6cSBarry Smith {
2290a844d1aSPeter Brune   PetscErrorCode ierr;
2306e111a19SKarl Rupp 
2310a844d1aSPeter Brune   PetscFunctionBegin;
2320a844d1aSPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
2330a844d1aSPeter Brune   ierr = PetscTryMethod(snes,"SNESNCGSetType_C",(SNES,SNESNCGType),(snes,btype));CHKERRQ(ierr);
2340a844d1aSPeter Brune   PetscFunctionReturn(0);
2350a844d1aSPeter Brune }
2360a844d1aSPeter Brune 
2370a844d1aSPeter Brune #undef __FUNCT__
2380a844d1aSPeter Brune #define __FUNCT__ "SNESNCGSetType_NCG"
2390adebc6cSBarry Smith PetscErrorCode SNESNCGSetType_NCG(SNES snes, SNESNCGType btype)
2400adebc6cSBarry Smith {
2410a844d1aSPeter Brune   SNES_NCG *ncg = (SNES_NCG*)snes->data;
2426e111a19SKarl Rupp 
2430a844d1aSPeter Brune   PetscFunctionBegin;
2440a844d1aSPeter Brune   ncg->type = btype;
2450a844d1aSPeter Brune   PetscFunctionReturn(0);
2460a844d1aSPeter Brune }
2470a844d1aSPeter Brune 
248fef7b6d8SPeter Brune /*
249fef7b6d8SPeter Brune   SNESSolve_NCG - Solves a nonlinear system with the Nonlinear Conjugate Gradient method.
250fef7b6d8SPeter Brune 
251fef7b6d8SPeter Brune   Input Parameters:
252fef7b6d8SPeter Brune . snes - the SNES context
253fef7b6d8SPeter Brune 
254fef7b6d8SPeter Brune   Output Parameter:
255fef7b6d8SPeter Brune . outits - number of iterations until termination
256fef7b6d8SPeter Brune 
257fef7b6d8SPeter Brune   Application Interface Routine: SNESSolve()
258fef7b6d8SPeter Brune */
259fef7b6d8SPeter Brune #undef __FUNCT__
260fef7b6d8SPeter Brune #define __FUNCT__ "SNESSolve_NCG"
261fef7b6d8SPeter Brune PetscErrorCode SNESSolve_NCG(SNES snes)
262fef7b6d8SPeter Brune {
263dfb256c7SPeter Brune   SNES_NCG            *ncg = (SNES_NCG*)snes->data;
264a71552e2SPeter Brune   Vec                 X,dX,lX,F,Fold;
265bbd5d0b3SPeter Brune   PetscReal           fnorm, ynorm, xnorm, beta = 0.0;
2665d115551SPeter Brune   PetscScalar         dXdotF, dXolddotFold, dXdotFold, lXdotF, lXdotFold;
267fef7b6d8SPeter Brune   PetscInt            maxits, i;
268fef7b6d8SPeter Brune   PetscErrorCode      ierr;
269fef7b6d8SPeter Brune   PetscBool           lsSuccess = PETSC_TRUE;
270f1c6b773SPeter Brune   SNESLineSearch      linesearch;
271*b7281c8aSPeter Brune   SNESConvergedReason reason;
27288d374b2SPeter Brune 
273fef7b6d8SPeter Brune   PetscFunctionBegin;
274fef7b6d8SPeter Brune   snes->reason = SNES_CONVERGED_ITERATING;
275fef7b6d8SPeter Brune 
276fef7b6d8SPeter Brune   maxits = snes->max_its;            /* maximum number of iterations */
277fef7b6d8SPeter Brune   X      = snes->vec_sol;            /* X^n */
2785d115551SPeter Brune   Fold   = snes->work[0];            /* The previous iterate of X */
27988d374b2SPeter Brune   dX     = snes->work[1];            /* the preconditioned direction */
280169e2be8SPeter Brune   lX     = snes->vec_sol_update;     /* the conjugate direction */
281fef7b6d8SPeter Brune   F      = snes->vec_func;           /* residual vector */
282fef7b6d8SPeter Brune 
2837601faf0SJed Brown   ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
2849e764e56SPeter Brune 
285ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
286fef7b6d8SPeter Brune   snes->iter = 0;
287fef7b6d8SPeter Brune   snes->norm = 0.;
288ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
289fef7b6d8SPeter Brune 
290bbd5d0b3SPeter Brune   /* compute the initial function and preconditioned update dX */
291a71552e2SPeter Brune 
292a71552e2SPeter Brune   if (snes->pc && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
293a71552e2SPeter Brune     ierr = SNESApplyPC(snes,X,NULL,NULL,dX);CHKERRQ(ierr);
294*b7281c8aSPeter Brune     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
295*b7281c8aSPeter Brune     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
296*b7281c8aSPeter Brune       snes->reason = SNES_DIVERGED_INNER;
297*b7281c8aSPeter Brune       PetscFunctionReturn(0);
298*b7281c8aSPeter Brune     }
299a71552e2SPeter Brune     ierr = VecCopy(dX,F);CHKERRQ(ierr);
300a71552e2SPeter Brune     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
301a71552e2SPeter Brune   } else {
302e4ed7901SPeter Brune     if (!snes->vec_func_init_set) {
303fef7b6d8SPeter Brune       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
304fef7b6d8SPeter Brune       if (snes->domainerror) {
305fef7b6d8SPeter Brune         snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
306fef7b6d8SPeter Brune         PetscFunctionReturn(0);
307fef7b6d8SPeter Brune       }
3081aa26658SKarl Rupp     } else snes->vec_func_init_set = PETSC_FALSE;
309e4ed7901SPeter Brune     if (!snes->norm_init_set) {
310fef7b6d8SPeter Brune       /* convergence test */
311a71552e2SPeter Brune       ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
312189a9710SBarry Smith       if (PetscIsInfOrNanReal(fnorm)) {
313189a9710SBarry Smith         snes->reason = SNES_DIVERGED_FNORM_NAN;
314189a9710SBarry Smith         PetscFunctionReturn(0);
315189a9710SBarry Smith       }
316e4ed7901SPeter Brune     } else {
317e4ed7901SPeter Brune       fnorm               = snes->norm_init;
318e4ed7901SPeter Brune       snes->norm_init_set = PETSC_FALSE;
319e4ed7901SPeter Brune     }
320a71552e2SPeter Brune     ierr = VecCopy(F,dX);CHKERRQ(ierr);
321a71552e2SPeter Brune   }
322a71552e2SPeter Brune   if (snes->pc) {
323a71552e2SPeter Brune     if (snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
324a71552e2SPeter Brune       ierr = SNESApplyPC(snes,X,F,&fnorm,dX);CHKERRQ(ierr);
325*b7281c8aSPeter Brune       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
326*b7281c8aSPeter Brune       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
327*b7281c8aSPeter Brune         snes->reason = SNES_DIVERGED_INNER;
328*b7281c8aSPeter Brune         PetscFunctionReturn(0);
329*b7281c8aSPeter Brune       }
330a71552e2SPeter Brune     }
331a71552e2SPeter Brune   }
332a71552e2SPeter Brune   ierr = VecCopy(dX,lX);CHKERRQ(ierr);
333a71552e2SPeter Brune   ierr = VecDot(dX, F, &dXdotF);CHKERRQ(ierr);
334a71552e2SPeter Brune 
335a71552e2SPeter Brune 
336ce8c27fbSBarry Smith   ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
337fef7b6d8SPeter Brune   snes->norm = fnorm;
338ce8c27fbSBarry Smith   ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
339a71f0d7dSBarry Smith   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
340fef7b6d8SPeter Brune   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
341fef7b6d8SPeter Brune 
342fef7b6d8SPeter Brune   /* set parameter for default relative tolerance convergence test */
343fef7b6d8SPeter Brune   snes->ttol = fnorm*snes->rtol;
344fef7b6d8SPeter Brune   /* test convergence */
345fef7b6d8SPeter Brune   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
346fef7b6d8SPeter Brune   if (snes->reason) PetscFunctionReturn(0);
347fef7b6d8SPeter Brune 
348fef7b6d8SPeter Brune   /* Call general purpose update function */
349fef7b6d8SPeter Brune   if (snes->ops->update) {
350fef7b6d8SPeter Brune     ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
351fef7b6d8SPeter Brune   }
352fef7b6d8SPeter Brune 
353fef7b6d8SPeter Brune   /* first update -- just use the (preconditioned) residual direction for the initial conjugate direction */
354bbd5d0b3SPeter Brune 
35509c08436SPeter Brune   for (i = 1; i < maxits + 1; i++) {
356fef7b6d8SPeter Brune     lsSuccess = PETSC_TRUE;
35729c94e34SPeter Brune     /* some update types require the old update direction or conjugate direction */
3580a844d1aSPeter Brune     if (ncg->type != SNES_NCG_FR) {
3595d115551SPeter Brune       ierr = VecCopy(F, Fold);CHKERRQ(ierr);
36088d374b2SPeter Brune     }
361f1c6b773SPeter Brune     ierr = SNESLineSearchApply(linesearch,X,F,&fnorm,lX);CHKERRQ(ierr);
362f1c6b773SPeter Brune     ierr = SNESLineSearchGetSuccess(linesearch, &lsSuccess);CHKERRQ(ierr);
363fef7b6d8SPeter Brune     if (!lsSuccess) {
364fef7b6d8SPeter Brune       if (++snes->numFailures >= snes->maxFailures) {
365fef7b6d8SPeter Brune         snes->reason = SNES_DIVERGED_LINE_SEARCH;
3665d10c001SPeter Brune         PetscFunctionReturn(0);
367fef7b6d8SPeter Brune       }
368fef7b6d8SPeter Brune     }
369fef7b6d8SPeter Brune     if (snes->nfuncs >= snes->max_funcs) {
370fef7b6d8SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
3715d10c001SPeter Brune       PetscFunctionReturn(0);
372fef7b6d8SPeter Brune     }
373fef7b6d8SPeter Brune     if (snes->domainerror) {
374fef7b6d8SPeter Brune       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
375fef7b6d8SPeter Brune       PetscFunctionReturn(0);
376fef7b6d8SPeter Brune     }
377f1c6b773SPeter Brune     ierr = SNESLineSearchGetNorms(linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
378fef7b6d8SPeter Brune     /* Monitor convergence */
379ce8c27fbSBarry Smith     ierr       = PetscObjectAMSTakeAccess((PetscObject)snes);CHKERRQ(ierr);
380169e2be8SPeter Brune     snes->iter = i;
381fef7b6d8SPeter Brune     snes->norm = fnorm;
382ce8c27fbSBarry Smith     ierr       = PetscObjectAMSGrantAccess((PetscObject)snes);CHKERRQ(ierr);
383a71f0d7dSBarry Smith     ierr       = SNESLogConvergenceHistory(snes,snes->norm,0);CHKERRQ(ierr);
384fef7b6d8SPeter Brune     ierr       = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
385302dbbaeSPeter Brune 
386fef7b6d8SPeter Brune     /* Test for convergence */
387d484d688SPeter Brune     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
3885d10c001SPeter Brune     if (snes->reason) PetscFunctionReturn(0);
389302dbbaeSPeter Brune 
390302dbbaeSPeter Brune     /* Call general purpose update function */
391302dbbaeSPeter Brune     if (snes->ops->update) {
392302dbbaeSPeter Brune       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
393302dbbaeSPeter Brune     }
394a71552e2SPeter Brune     if (snes->pc) {
395a71552e2SPeter Brune       if (snes->functype == SNES_FUNCTION_PRECONDITIONED) {
396a71552e2SPeter Brune         ierr = SNESApplyPC(snes,X,NULL,NULL,dX);CHKERRQ(ierr);
397*b7281c8aSPeter Brune         ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
398*b7281c8aSPeter Brune         if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
399*b7281c8aSPeter Brune           snes->reason = SNES_DIVERGED_INNER;
400*b7281c8aSPeter Brune           PetscFunctionReturn(0);
401*b7281c8aSPeter Brune         }
402a71552e2SPeter Brune         ierr = VecCopy(dX,F);CHKERRQ(ierr);
403a71552e2SPeter Brune       } else {
404a71552e2SPeter Brune         ierr = SNESApplyPC(snes,X,F,&fnorm,dX);CHKERRQ(ierr);
405*b7281c8aSPeter Brune         ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
406*b7281c8aSPeter Brune         if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
407*b7281c8aSPeter Brune           snes->reason = SNES_DIVERGED_INNER;
408*b7281c8aSPeter Brune           PetscFunctionReturn(0);
409*b7281c8aSPeter Brune         }
410302dbbaeSPeter Brune       }
411a3685310SPeter Brune     } else {
412a3685310SPeter Brune       ierr = VecCopy(F,dX);CHKERRQ(ierr);
413302dbbaeSPeter Brune     }
414302dbbaeSPeter Brune 
41529c94e34SPeter Brune     /* compute the conjugate direction lX = dX + beta*lX with beta = ((dX, dX) / (dX_old, dX_old) (Fletcher-Reeves update)*/
4160a844d1aSPeter Brune     switch (ncg->type) {
4170a844d1aSPeter Brune     case SNES_NCG_FR: /* Fletcher-Reeves */
4185d115551SPeter Brune       dXolddotFold = dXdotF;
419a71552e2SPeter Brune       ierr         = VecDot(dX, F, &dXdotF);CHKERRQ(ierr);
4205d115551SPeter Brune       beta         = PetscRealPart(dXdotF / dXolddotFold);
421dfb256c7SPeter Brune       break;
4220a844d1aSPeter Brune     case SNES_NCG_PRP: /* Polak-Ribiere-Poylak */
4235d115551SPeter Brune       dXolddotFold = dXdotF;
42415f0db4aSPeter Brune       ierr         = VecDotBegin(F, dX, &dXdotF);CHKERRQ(ierr);
42515f0db4aSPeter Brune       ierr         = VecDotBegin(Fold, dX, &dXdotFold);CHKERRQ(ierr);
42615f0db4aSPeter Brune       ierr         = VecDotEnd(F, dX, &dXdotF);CHKERRQ(ierr);
42715f0db4aSPeter Brune       ierr         = VecDotEnd(Fold, dX, &dXdotFold);CHKERRQ(ierr);
4285d115551SPeter Brune       beta         = PetscRealPart(((dXdotF - dXdotFold) / dXolddotFold));
429dfb256c7SPeter Brune       if (beta < 0.0) beta = 0.0; /* restart */
430dfb256c7SPeter Brune       break;
4310a844d1aSPeter Brune     case SNES_NCG_HS: /* Hestenes-Stiefel */
43215f0db4aSPeter Brune       ierr = VecDotBegin(dX, F, &dXdotF);CHKERRQ(ierr);
43315f0db4aSPeter Brune       ierr = VecDotBegin(dX, Fold, &dXdotFold);CHKERRQ(ierr);
43415f0db4aSPeter Brune       ierr = VecDotBegin(lX, F, &lXdotF);CHKERRQ(ierr);
43515f0db4aSPeter Brune       ierr = VecDotBegin(lX, Fold, &lXdotFold);CHKERRQ(ierr);
43615f0db4aSPeter Brune       ierr = VecDotEnd(dX, F, &dXdotF);CHKERRQ(ierr);
43715f0db4aSPeter Brune       ierr = VecDotEnd(dX, Fold, &dXdotFold);CHKERRQ(ierr);
43815f0db4aSPeter Brune       ierr = VecDotEnd(lX, F, &lXdotF);CHKERRQ(ierr);
43915f0db4aSPeter Brune       ierr = VecDotEnd(lX, Fold, &lXdotFold);CHKERRQ(ierr);
4405d115551SPeter Brune       beta = PetscRealPart((dXdotF - dXdotFold) / (lXdotF - lXdotFold));
441dfb256c7SPeter Brune       break;
4420a844d1aSPeter Brune     case SNES_NCG_DY: /* Dai-Yuan */
44315f0db4aSPeter Brune       ierr = VecDotBegin(dX, F, &dXdotF);CHKERRQ(ierr);
44415f0db4aSPeter Brune       ierr = VecDotBegin(lX, F, &lXdotF);CHKERRQ(ierr);
44515f0db4aSPeter Brune       ierr = VecDotBegin(lX, Fold, &lXdotFold);CHKERRQ(ierr);
44615f0db4aSPeter Brune       ierr = VecDotEnd(dX, F, &dXdotF);CHKERRQ(ierr);
44715f0db4aSPeter Brune       ierr = VecDotEnd(lX, F, &lXdotF);CHKERRQ(ierr);
44815f0db4aSPeter Brune       ierr = VecDotEnd(lX, Fold, &lXdotFold);CHKERRQ(ierr);
4495d115551SPeter Brune       beta = PetscRealPart(dXdotF / (lXdotFold - lXdotF));CHKERRQ(ierr);
450dfb256c7SPeter Brune       break;
4510a844d1aSPeter Brune     case SNES_NCG_CD: /* Conjugate Descent */
45215f0db4aSPeter Brune       ierr = VecDotBegin(dX, F, &dXdotF);CHKERRQ(ierr);
45315f0db4aSPeter Brune       ierr = VecDotBegin(lX, Fold, &lXdotFold);CHKERRQ(ierr);
45415f0db4aSPeter Brune       ierr = VecDotEnd(dX, F, &dXdotF);CHKERRQ(ierr);
45515f0db4aSPeter Brune       ierr = VecDotEnd(lX, Fold, &lXdotFold);CHKERRQ(ierr);
4565d115551SPeter Brune       beta = PetscRealPart(dXdotF / lXdotFold);CHKERRQ(ierr);
457dfb256c7SPeter Brune       break;
458dfb256c7SPeter Brune     }
459dfb256c7SPeter Brune     if (ncg->monitor) {
460646217ecSPeter Brune       ierr = PetscViewerASCIIPrintf(ncg->monitor, "beta = %e\n", beta);CHKERRQ(ierr);
461dfb256c7SPeter Brune     }
462dfb256c7SPeter Brune     ierr = VecAYPX(lX, beta, dX);CHKERRQ(ierr);
463fef7b6d8SPeter Brune   }
464fef7b6d8SPeter Brune   ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
465fef7b6d8SPeter Brune   if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
466fef7b6d8SPeter Brune   PetscFunctionReturn(0);
467fef7b6d8SPeter Brune }
468fef7b6d8SPeter Brune 
4690a844d1aSPeter Brune 
4700a844d1aSPeter Brune 
471fef7b6d8SPeter Brune /*MC
472fef7b6d8SPeter Brune   SNESNCG - Nonlinear Conjugate-Gradient method for the solution of general nonlinear systems.
473fef7b6d8SPeter Brune 
474fef7b6d8SPeter Brune   Level: beginner
475fef7b6d8SPeter Brune 
476fef7b6d8SPeter Brune   Options Database:
4771867fe5bSPeter Brune +   -snes_ncg_type <fr, prp, dy, hs, cd> - Choice of conjugate-gradient update parameter.
47841a8cb50SPeter Brune .   -snes_linesearch_type <cp,l2,basic> - Line search type.
4791867fe5bSPeter Brune -   -snes_ncg_monitor - Print relevant information about the ncg iteration.
480fef7b6d8SPeter Brune 
481fef7b6d8SPeter Brune Notes: This solves the nonlinear system of equations F(x) = 0 using the nonlinear generalization of the conjugate
482fef7b6d8SPeter Brune gradient method.  This may be used with a nonlinear preconditioner used to pick the new search directions, but otherwise
483fef7b6d8SPeter Brune chooses the initial search direction as F(x) for the initial guess x.
484fef7b6d8SPeter Brune 
485fef7b6d8SPeter Brune 
48604d7464bSBarry Smith .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR, SNESNGMRES, SNESNQN
487fef7b6d8SPeter Brune M*/
488fef7b6d8SPeter Brune #undef __FUNCT__
489fef7b6d8SPeter Brune #define __FUNCT__ "SNESCreate_NCG"
4908cc058d9SJed Brown PETSC_EXTERN PetscErrorCode SNESCreate_NCG(SNES snes)
491fef7b6d8SPeter Brune {
492fef7b6d8SPeter Brune   PetscErrorCode ierr;
493ea630c6eSPeter Brune   SNES_NCG       * neP;
494fef7b6d8SPeter Brune 
495fef7b6d8SPeter Brune   PetscFunctionBegin;
496fef7b6d8SPeter Brune   snes->ops->destroy        = SNESDestroy_NCG;
497fef7b6d8SPeter Brune   snes->ops->setup          = SNESSetUp_NCG;
498fef7b6d8SPeter Brune   snes->ops->setfromoptions = SNESSetFromOptions_NCG;
499fef7b6d8SPeter Brune   snes->ops->view           = SNESView_NCG;
500fef7b6d8SPeter Brune   snes->ops->solve          = SNESSolve_NCG;
501fef7b6d8SPeter Brune   snes->ops->reset          = SNESReset_NCG;
502fef7b6d8SPeter Brune 
503fef7b6d8SPeter Brune   snes->usesksp = PETSC_FALSE;
504fef7b6d8SPeter Brune   snes->usespc  = PETSC_TRUE;
505a71552e2SPeter Brune   snes->pcside  = PC_LEFT;
506a71552e2SPeter Brune   snes->functype = SNES_FUNCTION_PRECONDITIONED;
507fef7b6d8SPeter Brune 
50888976e71SPeter Brune   if (!snes->tolerancesset) {
5090e444f03SPeter Brune     snes->max_funcs = 30000;
5100e444f03SPeter Brune     snes->max_its   = 10000;
511c522fa08SPeter Brune     snes->stol      = 1e-20;
51288976e71SPeter Brune   }
5130e444f03SPeter Brune 
514fef7b6d8SPeter Brune   ierr         = PetscNewLog(snes, SNES_NCG, &neP);CHKERRQ(ierr);
515fef7b6d8SPeter Brune   snes->data   = (void*) neP;
5160298fd71SBarry Smith   neP->monitor = NULL;
5170a844d1aSPeter Brune   neP->type    = SNES_NCG_PRP;
518bdf89e91SBarry Smith   ierr         = PetscObjectComposeFunction((PetscObject)snes,"SNESNCGSetType_C", SNESNCGSetType_NCG);CHKERRQ(ierr);
519fef7b6d8SPeter Brune   PetscFunctionReturn(0);
520fef7b6d8SPeter Brune }
521