xref: /petsc/src/ksp/ksp/impls/fcg/fcg.c (revision cd545bacbb74b28ee04a97aa2a6bca79b7d5aa2e)
1 /*
2     This file implements the FCG (Flexible Conjugate Gradient) method
3 
4 */
5 
6 #include <../src/ksp/ksp/impls/fcg/fcgimpl.h>       /*I  "petscksp.h"  I*/
7 extern PetscErrorCode KSPComputeExtremeSingularValues_CG(KSP,PetscReal*,PetscReal*);
8 extern PetscErrorCode KSPComputeEigenvalues_CG(KSP,PetscInt,PetscReal*,PetscReal*,PetscInt*);
9 
10 const char *const KSPFCGTruncationTypes[]     = {"STANDARD","NOTAY","KSPFCGTrunctionTypes","KSP_FCG_TRUNC_TYPE_",0};
11 
12 #define KSPFCG_DEFAULT_MMAX 30          /* maximum number of search directions to keep */
13 #define KSPFCG_DEFAULT_NPREALLOC 10     /* number of search directions to preallocate */
14 #define KSPFCG_DEFAULT_VECB 5           /* number of search directions to allocate each time new direction vectors are needed */
15 #define KSPFCG_DEFAULT_TRUNCSTRAT KSP_FCG_TRUNC_TYPE_NOTAY
16 
17 #undef __FUNCT__
18 #define __FUNCT__ "KSPAllocateVectors_FCG"
19 static PetscErrorCode KSPAllocateVectors_FCG(KSP ksp, PetscInt nvecsneeded, PetscInt chunksize)
20 {
21   PetscErrorCode  ierr;
22   PetscInt        i;
23   KSP_FCG         *fcg = (KSP_FCG*)ksp->data;
24   PetscInt        nnewvecs, nvecsprev;
25 
26   PetscFunctionBegin;
27   /* Allocate enough new vectors to add chunksize new vectors, reach nvecsneedtotal, or to reach mmax+1, whichever is smallest */
28   if (fcg->nvecs < PetscMin(fcg->mmax+1,nvecsneeded)){
29     nvecsprev = fcg->nvecs;
30     nnewvecs = PetscMin(PetscMax(nvecsneeded-fcg->nvecs,chunksize),fcg->mmax+1-fcg->nvecs);
31     ierr = KSPCreateVecs(ksp,nnewvecs,&fcg->pCvecs[fcg->nchunks],0,NULL);CHKERRQ(ierr);
32     ierr = PetscLogObjectParents((PetscObject)ksp,nnewvecs,fcg->pCvecs[fcg->nchunks]);CHKERRQ(ierr);
33     ierr = KSPCreateVecs(ksp,nnewvecs,&fcg->pPvecs[fcg->nchunks],0,NULL);CHKERRQ(ierr);
34     ierr = PetscLogObjectParents((PetscObject)ksp,nnewvecs,fcg->pPvecs[fcg->nchunks]);CHKERRQ(ierr);
35     fcg->nvecs += nnewvecs;
36     for (i=0;i<nnewvecs;++i){
37       fcg->Cvecs[nvecsprev + i] = fcg->pCvecs[fcg->nchunks][i];
38       fcg->Pvecs[nvecsprev + i] = fcg->pPvecs[fcg->nchunks][i];
39     }
40     fcg->chunksizes[fcg->nchunks] = nnewvecs;
41     ++fcg->nchunks;
42   }
43   PetscFunctionReturn(0);
44 }
45 
46 #undef __FUNCT__
47 #define __FUNCT__ "KSPSetUp_FCG"
48 PetscErrorCode    KSPSetUp_FCG(KSP ksp)
49 {
50   PetscErrorCode ierr;
51   KSP_FCG        *fcg = (KSP_FCG*)ksp->data;
52   PetscInt       maxit = ksp->max_it;
53   const PetscInt nworkstd = 2;
54 
55   PetscFunctionBegin;
56 
57   /* Allocate "standard" work vectors (not including the basis and transformed basis vectors) */
58   ierr = KSPSetWorkVecs(ksp,nworkstd);CHKERRQ(ierr);
59 
60   /* Allocated space for pointers to additional work vectors
61    note that mmax is the number of previous directions, so we add 1 for the current direction,
62    and an extra 1 for the prealloc (which might be empty) */
63   ierr = PetscMalloc5(fcg->mmax+1,&fcg->Pvecs,fcg->mmax+1,&fcg->Cvecs,fcg->mmax+1,&fcg->pPvecs,fcg->mmax+1,&fcg->pCvecs,fcg->mmax+2,&fcg->chunksizes);CHKERRQ(ierr);
64   ierr = PetscLogObjectMemory((PetscObject)ksp,2*(fcg->mmax+1)*sizeof(Vec*) + 2*(fcg->mmax + 1)*sizeof(Vec**) + (fcg->mmax + 2)*sizeof(PetscInt));CHKERRQ(ierr);
65 
66   /* Preallocate additional work vectors */
67   ierr = KSPAllocateVectors_FCG(ksp,fcg->nprealloc,fcg->nprealloc);CHKERRQ(ierr);
68   /*
69   If user requested computations of eigenvalues then allocate work
70   work space needed
71   */
72   if (ksp->calc_sings) {
73     /* get space to store tridiagonal matrix for Lanczos */
74     ierr = PetscMalloc4(maxit,&fcg->e,maxit,&fcg->d,maxit,&fcg->ee,maxit,&fcg->dd);CHKERRQ(ierr);
75     ierr = PetscLogObjectMemory((PetscObject)ksp,2*(maxit+1)*(sizeof(PetscScalar)+sizeof(PetscReal)));CHKERRQ(ierr);
76 
77     ksp->ops->computeextremesingularvalues = KSPComputeExtremeSingularValues_CG;
78     ksp->ops->computeeigenvalues           = KSPComputeEigenvalues_CG;
79   }
80   PetscFunctionReturn(0);
81 }
82 
83 #undef __FUNCT__
84 #define __FUNCT__ "KSPSolve_FCG"
85 PetscErrorCode KSPSolve_FCG(KSP ksp)
86 {
87   PetscErrorCode ierr;
88   PetscInt       i,k,idx,mi;
89   KSP_FCG        *fcg = (KSP_FCG*)ksp->data;
90   PetscScalar    alpha=0.0,beta = 0.0,dpi,s;
91   PetscReal      dp=0.0;
92   Vec            B,R,Z,X,Pcurr,Ccurr;
93   Mat            Amat,Pmat;
94   PetscInt       eigs = ksp->calc_sings; /* Variables for eigen estimation - START*/
95   PetscInt       stored_max_it = ksp->max_it;
96   PetscScalar    alphaold = 0,betaold = 1.0,*e = 0,*d = 0;/* Variables for eigen estimation  - FINISH */
97 
98   PetscFunctionBegin;
99 
100 #define VecXDot(x,y,a) (((fcg->type) == (KSP_CG_HERMITIAN)) ? VecDot(x,y,a) : VecTDot(x,y,a))
101 #define VecXMDot(a,b,c,d) (((fcg->type) == (KSP_CG_HERMITIAN)) ? VecMDot(a,b,c,d) : VecMTDot(a,b,c,d))
102 
103   X             = ksp->vec_sol;
104   B             = ksp->vec_rhs;
105   R             = ksp->work[0];
106   Z             = ksp->work[1];
107 
108   ierr = PCGetOperators(ksp->pc,&Amat,&Pmat);CHKERRQ(ierr);
109   if (eigs) {e = fcg->e; d = fcg->d; e[0] = 0.0; }
110   /* Compute initial residual needed for convergence check*/
111   ksp->its = 0;
112   if (!ksp->guess_zero) {
113     ierr = KSP_MatMult(ksp,Amat,X,R);CHKERRQ(ierr);
114     ierr = VecAYPX(R,-1.0,B);CHKERRQ(ierr);                    /*   r <- b - Ax     */
115   } else {
116     ierr = VecCopy(B,R);CHKERRQ(ierr);                         /*   r <- b (x is 0) */
117   }
118   switch (ksp->normtype) {
119     case KSP_NORM_PRECONDITIONED:
120       ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr);               /*   z <- Br         */
121       ierr = VecNorm(Z,NORM_2,&dp);CHKERRQ(ierr);              /*   dp <- dqrt(z'*z) = sqrt(e'*A'*B'*B*A*e)     */
122       break;
123     case KSP_NORM_UNPRECONDITIONED:
124       ierr = VecNorm(R,NORM_2,&dp);CHKERRQ(ierr);              /*   dp <- sqrt(r'*r) = sqrt(e'*A'*A*e)     */
125       break;
126     case KSP_NORM_NATURAL:
127       ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr);               /*   z <- Br         */
128       ierr = VecXDot(R,Z,&s);CHKERRQ(ierr);
129       dp = PetscSqrtReal(PetscAbsScalar(s));                   /*   dp <- sqrt(r'*z) = sqrt(e'*A'*B*A*e)  */
130       break;
131     case KSP_NORM_NONE:
132       dp = 0.0;
133       break;
134     default: SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"%s",KSPNormTypes[ksp->normtype]);
135   }
136 
137   /* Initial Convergence Check */
138   ierr       = KSPLogResidualHistory(ksp,dp);CHKERRQ(ierr);
139   ierr       = KSPMonitor(ksp,0,dp);CHKERRQ(ierr);
140   ksp->rnorm = dp;
141   if (ksp->normtype == KSP_NORM_NONE) {
142     ierr = KSPConvergedSkip(ksp,0,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr);
143   } else {
144     ierr = (*ksp->converged)(ksp,0,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr);
145   }
146   if (ksp->reason) PetscFunctionReturn(0);
147 
148   /* Apply PC if not already done for convergence check */
149   if(ksp->normtype == KSP_NORM_UNPRECONDITIONED || ksp->normtype == KSP_NORM_NONE){
150     ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr);               /*   z <- Br         */
151   }
152 
153   i = 0;
154   do {
155     ksp->its = i+1;
156 
157     /*  If needbe, allocate a new chunk of vectors in P and C */
158     ierr = KSPAllocateVectors_FCG(ksp,i+1,fcg->vecb);CHKERRQ(ierr);
159 
160     /* Note that we wrap around and start clobbering old vectors */
161     idx = i % (fcg->mmax+1);
162     Pcurr = fcg->Pvecs[idx];
163     Ccurr = fcg->Cvecs[idx];
164 
165     /* Compute a new column of P (Currently does not support modified G-S or iterative refinement)*/
166     switch(fcg->truncstrat){
167       case KSP_FCG_TRUNC_TYPE_NOTAY :
168         mi = PetscMax(1,i%(fcg->mmax+1));
169         break;
170       case KSP_FCG_TRUNC_TYPE_STANDARD :
171         mi = fcg->mmax;
172         break;
173       default:
174         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Unrecognized FCG Truncation Strategy");CHKERRQ(ierr);
175     }
176     ierr = VecCopy(Z,Pcurr);CHKERRQ(ierr);
177 
178     {
179       PetscInt l,ndots;
180 
181       l = PetscMax(0,i-mi);
182       ndots = i-l;
183       if (ndots){
184         PetscInt    j;
185         Vec         *Pold,  *Cold;
186         PetscScalar *dots;
187 
188         ierr = PetscMalloc3(ndots,&dots,ndots,&Cold,ndots,&Pold);CHKERRQ(ierr);
189         for(k=l,j=0;j<ndots;++k,++j){
190           idx = k % (fcg->mmax+1);
191           Cold[j] = fcg->Cvecs[idx];
192           Pold[j] = fcg->Pvecs[idx];
193         }
194         ierr = VecXMDot(Z,ndots,Cold,dots);CHKERRQ(ierr);
195         for(k=0;k<ndots;++k){
196           dots[k] = -dots[k];
197         }
198         ierr = VecMAXPY(Pcurr,ndots,dots,Pold);CHKERRQ(ierr);
199         ierr = PetscFree3(dots,Cold,Pold);CHKERRQ(ierr);
200       }
201     }
202 
203     /* Update X and R */
204     betaold = beta;
205     ierr = VecXDot(Pcurr,R,&beta);CHKERRQ(ierr);                 /*  beta <- pi'*r       */
206     ierr = KSP_MatMult(ksp,Amat,Pcurr,Ccurr);CHKERRQ(ierr);      /*  w <- A*pi (stored in ci)   */
207     ierr = VecXDot(Pcurr,Ccurr,&dpi);CHKERRQ(ierr);              /*  dpi <- pi'*w        */
208     alphaold = alpha;
209     alpha = beta / dpi;                                          /*  alpha <- beta/dpi    */
210     ierr = VecAXPY(X,alpha,Pcurr);CHKERRQ(ierr);                 /*  x <- x + alpha * pi  */
211     ierr = VecAXPY(R,-alpha,Ccurr);CHKERRQ(ierr);                /*  r <- r - alpha * wi  */
212 
213     /* Compute norm for convergence check */
214     switch (ksp->normtype) {
215       case KSP_NORM_PRECONDITIONED:
216         ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr);               /*   z <- Br             */
217         ierr = VecNorm(Z,NORM_2,&dp);CHKERRQ(ierr);              /*   dp <- sqrt(z'*z) = sqrt(e'*A'*B'*B*A*e)  */
218         break;
219       case KSP_NORM_UNPRECONDITIONED:
220         ierr = VecNorm(R,NORM_2,&dp);CHKERRQ(ierr);              /*   dp <- sqrt(r'*r) = sqrt(e'*A'*A*e)   */
221         break;
222       case KSP_NORM_NATURAL:
223         ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr);               /*   z <- Br             */
224         ierr = VecXDot(R,Z,&s);CHKERRQ(ierr);
225         dp = PetscSqrtReal(PetscAbsScalar(s));                   /*   dp <- sqrt(r'*z) = sqrt(e'*A'*B*A*e)  */
226         break;
227       case KSP_NORM_NONE:
228         dp = 0.0;
229         break;
230       default: SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"%s",KSPNormTypes[ksp->normtype]);
231     }
232 
233     /* Check for convergence */
234     ksp->rnorm = dp;
235     KSPLogResidualHistory(ksp,dp);CHKERRQ(ierr);
236     ierr = KSPMonitor(ksp,i+1,dp);CHKERRQ(ierr);
237     ierr = (*ksp->converged)(ksp,i+1,dp,&ksp->reason,ksp->cnvP);CHKERRQ(ierr);
238     if (ksp->reason) break;
239 
240     /* Apply PC if not already done for convergence check */
241     if(ksp->normtype == KSP_NORM_UNPRECONDITIONED || ksp->normtype == KSP_NORM_NONE){
242       ierr = KSP_PCApply(ksp,R,Z);CHKERRQ(ierr);               /*   z <- Br         */
243     }
244 
245     /* Compute current C (which is W/dpi) */
246     ierr = VecScale(Ccurr,1.0/dpi);CHKERRQ(ierr);              /*   w <- ci/dpi   */
247 
248     if (eigs) {
249       if (i > 0) {
250         if (ksp->max_it != stored_max_it) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"Can not change maxit AND calculate eigenvalues");
251         e[i] = PetscSqrtReal(PetscAbsScalar(beta/betaold))/alphaold;
252         d[i] = PetscSqrtReal(PetscAbsScalar(beta/betaold))*e[i] + 1.0/alpha;
253       } else {
254         d[i] = PetscSqrtReal(PetscAbsScalar(beta))*e[i] + 1.0/alpha;
255       }
256       fcg->ned = ksp->its-1;
257     }
258     ++i;
259   } while (i<ksp->max_it);
260   if (i >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
261   PetscFunctionReturn(0);
262 }
263 
264 #undef __FUNCT__
265 #define __FUNCT__ "KSPDestroy_FCG"
266 PetscErrorCode KSPDestroy_FCG(KSP ksp)
267 {
268   PetscErrorCode ierr;
269   PetscInt       i;
270   KSP_FCG        *fcg = (KSP_FCG*)ksp->data;
271 
272   PetscFunctionBegin;
273 
274   /* Destroy "standard" work vecs */
275   VecDestroyVecs(ksp->nwork,&ksp->work);
276 
277   /* Destroy P and C vectors and the arrays that manage pointers to them */
278   if (fcg->nvecs){
279     for (i=0;i<fcg->nchunks;++i){
280       ierr = VecDestroyVecs(fcg->chunksizes[i],&fcg->pPvecs[i]);CHKERRQ(ierr);
281       ierr = VecDestroyVecs(fcg->chunksizes[i],&fcg->pCvecs[i]);CHKERRQ(ierr);
282     }
283   }
284   ierr = PetscFree5(fcg->Pvecs,fcg->Cvecs,fcg->pPvecs,fcg->pCvecs,fcg->chunksizes);CHKERRQ(ierr);
285   /* free space used for singular value calculations */
286   if (ksp->calc_sings) {
287     ierr = PetscFree4(fcg->e,fcg->d,fcg->ee,fcg->dd);CHKERRQ(ierr);
288   }
289   ierr = KSPDestroyDefault(ksp);CHKERRQ(ierr);
290   PetscFunctionReturn(0);
291 }
292 
293 #undef __FUNCT__
294 #define __FUNCT__ "KSPView_FCG"
295 PetscErrorCode KSPView_FCG(KSP ksp,PetscViewer viewer)
296 {
297   KSP_FCG        *fcg = (KSP_FCG*)ksp->data;
298   PetscErrorCode ierr;
299   PetscBool      iascii,isstring;
300   const char     *truncstr;
301 
302   PetscFunctionBegin;
303   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
304   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring);CHKERRQ(ierr);
305 
306   if (fcg->truncstrat == KSP_FCG_TRUNC_TYPE_STANDARD) truncstr = "Using standard truncation strategy";
307   else if (fcg->truncstrat == KSP_FCG_TRUNC_TYPE_NOTAY) truncstr = "Using Notay's truncation strategy";
308   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Undefined FCG truncation strategy");
309 
310   if (iascii) {
311     ierr = PetscViewerASCIIPrintf(viewer,"  FCG: m_max=%D\n",fcg->mmax);CHKERRQ(ierr);
312     ierr = PetscViewerASCIIPrintf(viewer,"  FCG: preallocated %D directions\n",PetscMin(fcg->nprealloc,fcg->mmax+1));CHKERRQ(ierr);
313     ierr = PetscViewerASCIIPrintf(viewer,"  FCG: %s\n",truncstr);CHKERRQ(ierr);
314   } else if (isstring) {
315     ierr = PetscViewerStringSPrintf(viewer,"m_max %D nprealloc %D %s",fcg->mmax,fcg->nprealloc,truncstr);CHKERRQ(ierr);
316   }
317   PetscFunctionReturn(0);
318 }
319 
320 #undef __FUNCT__
321 #define __FUNCT__ "KSPFCGSetMmax"
322 /*@
323   KSPFCGSetMmax - set the maximum number of previous directions FCG will store for orthogonalization
324 
325   Note: mmax + 1 directions are stored (mmax previous ones along with a current one)
326   and whether all are used in each iteration also depends on the truncation strategy
327   (see KSPFCGSetTruncationType())
328 
329   Logically Collective on KSP
330 
331   Input Parameters:
332 +  ksp - the Krylov space context
333 -  mmax - the maximum number of previous directions to orthogonalize againt
334 
335   Level: intermediate
336 
337   Options Database:
338 . -ksp_fcg_mmax <N>
339 
340 .seealso: KSPFCG, KSPFCGGetTruncationType(), KSPFCGGetNprealloc()
341 @*/
342 PetscErrorCode KSPFCGSetMmax(KSP ksp,PetscInt mmax)
343 {
344   KSP_FCG *fcg = (KSP_FCG*)ksp->data;
345 
346   PetscFunctionBegin;
347   PetscValidHeaderSpecific(ksp,KSP_CLASSID,1);
348   PetscValidLogicalCollectiveEnum(ksp,mmax,2);
349   fcg->mmax = mmax;
350   PetscFunctionReturn(0);
351 }
352 
353 #undef __FUNCT__
354 #define __FUNCT__ "KSPFCGGetMmax"
355 /*@
356   KSPFCGGetMmax - get the maximum number of previous directions FCG will store
357 
358   Note: FCG stores mmax+1 directions at most (mmax previous ones, and one current one)
359 
360    Not Collective
361 
362    Input Parameter:
363 .  ksp - the Krylov space context
364 
365    Output Parameter:
366 .  mmax - the maximum number of previous directons allowed for orthogonalization
367 
368   Options Database:
369 . -ksp_fcg_mmax <N>
370 
371    Level: intermediate
372 
373 .keywords: KSP, FCG, truncation
374 
375 .seealso: KSPFCG, KSPFCGGetTruncationType(), KSPFCGGetNprealloc(), KSPFCGSetMmax()
376 @*/
377 
378 PetscErrorCode KSPFCGGetMmax(KSP ksp,PetscInt *mmax)
379 {
380   KSP_FCG *fcg=(KSP_FCG*)ksp->data;
381 
382   PetscFunctionBegin;
383   PetscValidHeaderSpecific(ksp,KSP_CLASSID,1);
384   *mmax = fcg->mmax;
385   PetscFunctionReturn(0);
386 }
387 
388 #undef __FUNCT__
389 #define __FUNCT__ "KSPFCGSetNprealloc"
390 /*@
391   KSPFCGSetNprealloc - set the number of directions to preallocate with FCG
392 
393   Logically Collective on KSP
394 
395   Input Parameters:
396 +  ksp - the Krylov space context
397 -  nprealloc - the number of vectors to preallocate
398 
399   Level: advanced
400 
401   Options Database:
402 . -ksp_fcg_nprealloc <N>
403 
404 .seealso: KSPFCG, KSPFCGGetTruncationType(), KSPFCGGetNprealloc()
405 @*/
406 PetscErrorCode KSPFCGSetNprealloc(KSP ksp,PetscInt nprealloc)
407 {
408   KSP_FCG *fcg=(KSP_FCG*)ksp->data;
409 
410   PetscFunctionBegin;
411   PetscValidHeaderSpecific(ksp,KSP_CLASSID,1);
412   PetscValidLogicalCollectiveEnum(ksp,nprealloc,2);
413   if(nprealloc > fcg->mmax+1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Cannot preallocate more than m_max+1 vectors");
414   fcg->nprealloc = nprealloc;
415   PetscFunctionReturn(0);
416 }
417 
418 #undef __FUNCT__
419 #define __FUNCT__ "KSPFCGGetNprealloc"
420 /*@
421   KSPFCGGetNprealloc - get the number of directions preallocate by FCG
422 
423    Not Collective
424 
425    Input Parameter:
426 .  ksp - the Krylov space context
427 
428    Output Parameter:
429 .  nprealloc - the number of directions preallocated
430 
431   Options Database:
432 . -ksp_fcg_nprealloc <N>
433 
434    Level: advanced
435 
436 .keywords: KSP, FCG, truncation
437 
438 .seealso: KSPFCG, KSPFCGGetTruncationType(), KSPFCGSetNprealloc()
439 @*/
440 PetscErrorCode KSPFCGGetNprealloc(KSP ksp,PetscInt *nprealloc)
441 {
442   KSP_FCG *fcg=(KSP_FCG*)ksp->data;
443 
444   PetscFunctionBegin;
445   PetscValidHeaderSpecific(ksp,KSP_CLASSID,1);
446   *nprealloc = fcg->nprealloc;
447   PetscFunctionReturn(0);
448 }
449 
450 #undef __FUNCT__
451 #define __FUNCT__ "KSPFCGSetTruncationType"
452 /*@
453   KSPFCGSetTruncationType - specify how many of its stored previous directions FCG uses during orthoganalization
454 
455   Logically Collective on KSP
456 
457   KSP_FCG_TRUNC_TYPE_STANDARD uses all (up to mmax) stored directions
458   KSP_FCG_TRUNC_TYPE_NOTAY uses the last max(1,mod(i,mmax)) stored directions at iteration i=0,1..
459 
460   Input Parameters:
461 +  ksp - the Krylov space context
462 -  truncstrat - the choice of strategy
463 
464   Level: intermediate
465 
466   Options Database:
467 . -ksp_fcg_truncation_type <standard, notay>
468 
469   .seealso: KSPFCGTruncationType, KSPFCGGetTruncationType
470 @*/
471 PetscErrorCode KSPFCGSetTruncationType(KSP ksp,KSPFCGTruncationType truncstrat)
472 {
473   KSP_FCG *fcg=(KSP_FCG*)ksp->data;
474 
475   PetscFunctionBegin;
476   PetscValidHeaderSpecific(ksp,KSP_CLASSID,1);
477   PetscValidLogicalCollectiveEnum(ksp,truncstrat,2);
478   fcg->truncstrat=truncstrat;
479   PetscFunctionReturn(0);
480 }
481 
482 #undef __FUNCT__
483 #define __FUNCT__ "KSPFCGGetTruncationType"
484 /*@
485   KSPFCGGetTruncationType - get the truncation strategy employed by FCG
486 
487    Not Collective
488 
489    Input Parameter:
490 .  ksp - the Krylov space context
491 
492    Output Parameter:
493 .  truncstrat - the strategy type
494 
495   Options Database:
496 . -ksp_fcg_truncation_type <standard, notay>
497 
498    Level: intermediate
499 
500 .keywords: KSP, FCG, truncation
501 
502 .seealso: KSPFCG, KSPFCGSetTruncationType, KSPFCGTruncationType
503 @*/
504 PetscErrorCode KSPFCGGetTruncationType(KSP ksp,KSPFCGTruncationType *truncstrat)
505 {
506   KSP_FCG *fcg=(KSP_FCG*)ksp->data;
507 
508   PetscFunctionBegin;
509   PetscValidHeaderSpecific(ksp,KSP_CLASSID,1);
510   *truncstrat=fcg->truncstrat;
511   PetscFunctionReturn(0);
512 }
513 
514 #undef __FUNCT__
515 #define __FUNCT__ "KSPSetFromOptions_FCG"
516 PetscErrorCode KSPSetFromOptions_FCG(PetscOptionItems *PetscOptionsObject,KSP ksp)
517 {
518   PetscErrorCode ierr;
519   KSP_FCG        *fcg=(KSP_FCG*)ksp->data;
520   PetscInt       mmax,nprealloc;
521   PetscBool      flg;
522 
523   PetscFunctionBegin;
524   ierr = PetscOptionsHead(PetscOptionsObject,"KSP FCG Options");CHKERRQ(ierr);
525   ierr = PetscOptionsInt("-ksp_fcg_mmax","Maximum number of search directions to store","KSPFCGSetMmax",fcg->mmax,&mmax,&flg);CHKERRQ(ierr);
526   if (flg) {
527     ierr = KSPFCGSetMmax(ksp,mmax);CHKERRQ(ierr);
528   }
529   ierr = PetscOptionsInt("-ksp_fcg_nprealloc","Number of directions to preallocate","KSPFCGSetNprealloc",fcg->nprealloc,&nprealloc,&flg);CHKERRQ(ierr);
530   if (flg) {
531     ierr = KSPFCGSetNprealloc(ksp,nprealloc);CHKERRQ(ierr);
532   }
533   ierr = PetscOptionsEnum("-ksp_fcg_truncation_type","Truncation approach for directions","KSPFCGSetTruncationType",KSPFCGTruncationTypes,(PetscEnum)fcg->truncstrat,(PetscEnum*)&fcg->truncstrat,NULL);CHKERRQ(ierr);
534   ierr = PetscOptionsTail();CHKERRQ(ierr);
535   PetscFunctionReturn(0);
536 }
537 
538 /*MC
539       KSPFCG - Implements the Flexible Conjugate Gradient method (FCG)
540 
541   Options Database Keys:
542 +   -ksp_fcg_mmax <N>
543 .   -ksp_fcg_nprealloc <N>
544 -   -ksp_fcg_truncation_type <standard,notay>
545 
546     Contributed by Patrick Sanan
547 
548    Notes:
549    Supports left preconditioning only.
550 
551    Level: beginner
552 
553   References:
554     1) Notay, Y."Flexible Conjugate Gradients", SIAM J. Sci. Comput. 22:4, pp 1444-1460, 2000
555 
556     2) Axelsson, O. and Vassilevski, P. S. "A Black Box Generalized Conjugate Gradient Solver with Inner Iterations and Variable-Step Preconditioning",
557     SIAM J. Matrix Anal. Appl. 12:4, pp 625-44, 1991
558 
559  .seealso : KSPGCR, KSPFGMRES, KSPCG, KSPFCGSetMmax(), KSPFCGGetMmax(), KSPFCGSetNprealloc(), KSPFCGGetNprealloc(), KSPFCGSetTruncationType(), KSPFCGGetTruncationType()
560 
561 M*/
562 #undef __FUNCT__
563 #define __FUNCT__ "KSPCreate_FCG"
564 PETSC_EXTERN PetscErrorCode KSPCreate_FCG(KSP ksp)
565 {
566   PetscErrorCode ierr;
567   KSP_FCG        *fcg;
568 
569   PetscFunctionBegin;
570   ierr = PetscNewLog(ksp,&fcg);CHKERRQ(ierr);
571 #if !defined(PETSC_USE_COMPLEX)
572   fcg->type       = KSP_CG_SYMMETRIC;
573 #else
574   fcg->type       = KSP_CG_HERMITIAN;
575 #endif
576   fcg->mmax       = KSPFCG_DEFAULT_MMAX;
577   fcg->nprealloc  = KSPFCG_DEFAULT_NPREALLOC;
578   fcg->nvecs      = 0;
579   fcg->vecb       = KSPFCG_DEFAULT_VECB;
580   fcg->nchunks    = 0;
581   fcg->truncstrat = KSPFCG_DEFAULT_TRUNCSTRAT;
582 
583   ksp->data = (void*)fcg;
584 
585   ierr = KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,2);CHKERRQ(ierr);
586   ierr = KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_LEFT,1);CHKERRQ(ierr);
587   ierr = KSPSetSupportedNorm(ksp,KSP_NORM_NATURAL,PC_LEFT,1);CHKERRQ(ierr);
588   ierr = KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_LEFT,1);CHKERRQ(ierr);
589 
590   ksp->ops->setup          = KSPSetUp_FCG;
591   ksp->ops->solve          = KSPSolve_FCG;
592   ksp->ops->destroy        = KSPDestroy_FCG;
593   ksp->ops->view           = KSPView_FCG;
594   ksp->ops->setfromoptions = KSPSetFromOptions_FCG;
595   ksp->ops->buildsolution  = KSPBuildSolutionDefault;
596   ksp->ops->buildresidual  = KSPBuildResidualDefault;
597   PetscFunctionReturn(0);
598 }
599 
600