Actual source code: cg.c
1: /*$Id: cg.c,v 1.117 2001/08/07 03:03:50 balay Exp $*/
3: /*
4: This file implements the conjugate gradient method in PETSc as part of
5: KSP. You can use this as a starting point for implementing your own
6: Krylov method that is not provided with PETSc.
8: The following basic routines are required for each Krylov method.
9: KSPCreate_XXX() - Creates the Krylov context
10: KSPSetFromOptions_XXX() - Sets runtime options
11: KSPSolve_XXX() - Runs the Krylov method
12: KSPDestroy_XXX() - Destroys the Krylov context, freeing all
13: memory it needed
14: Here the "_XXX" denotes a particular implementation, in this case
15: we use _CG (e.g. KSPCreate_CG, KSPDestroy_CG). These routines are
16: are actually called vai the common user interface routines
17: KSPSetType(), KSPSetFromOptions(), KSPSolve(), and KSPDestroy() so the
18: application code interface remains identical for all preconditioners.
20: Other basic routines for the KSP objects include
21: KSPSetUp_XXX()
22: KSPView_XXX() - Prints details of solver being used.
24: Detailed notes:
25: By default, this code implements the CG (Conjugate Gradient) method,
26: which is valid for real symmetric (and complex Hermitian) positive
27: definite matrices. Note that for the complex Hermitian case, the
28: VecDot() arguments within the code MUST remain in the order given
29: for correct computation of inner products.
31: Reference: Hestenes and Steifel, 1952.
33: By switching to the indefinite vector inner product, VecTDot(), the
34: same code is used for the complex symmetric case as well. The user
35: must call KSPCGSetType(ksp,KSP_CG_SYMMETRIC) or use the option
36: -ksp_cg_symmetric to invoke this variant for the complex case.
37: Note, however, that the complex symmetric code is NOT valid for
38: all such matrices ... and thus we don't recommend using this method.
39: */
40: /*
41: cgctx.h defines the simple data structured used to store information
42: related to the type of matrix (e.g. complex symmetric) being solved and
43: data used during the optional Lanczo process used to compute eigenvalues
44: */
45: #include src/sles/ksp/impls/cg/cgctx.h
46: EXTERN int KSPComputeExtremeSingularValues_CG(KSP,PetscReal *,PetscReal *);
47: EXTERN int KSPComputeEigenvalues_CG(KSP,int,PetscReal *,PetscReal *,int *);
49: /*
50: KSPSetUp_CG - Sets up the workspace needed by the CG method.
52: This is called once, usually automatically by SLESSolve() or SLESSetUp()
53: but can be called directly by KSPSetUp()
54: */
55: #undef __FUNCT__
57: int KSPSetUp_CG(KSP ksp)
58: {
59: KSP_CG *cgP = (KSP_CG*)ksp->data;
60: int maxit = ksp->max_it,ierr;
63: /*
64: This implementation of CG only handles left preconditioning
65: so generate an error otherwise.
66: */
67: if (ksp->pc_side == PC_RIGHT) {
68: SETERRQ(2,"No right preconditioning for KSPCG");
69: } else if (ksp->pc_side == PC_SYMMETRIC) {
70: SETERRQ(2,"No symmetric preconditioning for KSPCG");
71: }
73: /* get work vectors needed by CG */
74: KSPDefaultGetWork(ksp,3);
76: /*
77: If user requested computations of eigenvalues then allocate work
78: work space needed
79: */
80: if (ksp->calc_sings) {
81: /* get space to store tridiagonal matrix for Lanczos */
82: PetscMalloc(2*(maxit+1)*sizeof(PetscScalar),&cgP->e);
83: PetscLogObjectMemory(ksp,2*(maxit+1)*sizeof(PetscScalar));
84: cgP->d = cgP->e + maxit + 1;
85: PetscMalloc(2*(maxit+1)*sizeof(PetscReal),&cgP->ee);
86: PetscLogObjectMemory(ksp,2*(maxit+1)*sizeof(PetscScalar));
87: cgP->dd = cgP->ee + maxit + 1;
88: ksp->ops->computeextremesingularvalues = KSPComputeExtremeSingularValues_CG;
89: ksp->ops->computeeigenvalues = KSPComputeEigenvalues_CG;
90: }
91: return(0);
92: }
94: /*
95: KSPSolve_CG - This routine actually applies the conjugate gradient
96: method
98: Input Parameter:
99: . ksp - the Krylov space object that was set to use conjugate gradient, by, for
100: example, KSPCreate(MPI_Comm,KSP *ksp); KSPSetType(ksp,KSPCG);
102: Output Parameter:
103: . its - number of iterations used
105: */
106: #undef __FUNCT__
108: int KSPSolve_CG(KSP ksp,int *its)
109: {
110: int ierr,i,maxit,eigs;
111: PetscScalar dpi,a = 1.0,beta,betaold = 1.0,b,*e = 0,*d = 0,mone = -1.0,ma;
112: PetscReal dp = 0.0;
113: Vec X,B,Z,R,P;
114: KSP_CG *cg;
115: Mat Amat,Pmat;
116: MatStructure pflag;
117: PetscTruth diagonalscale;
120: ierr = PCDiagonalScale(ksp->B,&diagonalscale);
121: if (diagonalscale) SETERRQ1(1,"Krylov method %s does not support diagonal scaling",ksp->type_name);
123: cg = (KSP_CG*)ksp->data;
124: eigs = ksp->calc_sings;
125: maxit = ksp->max_it;
126: X = ksp->vec_sol;
127: B = ksp->vec_rhs;
128: R = ksp->work[0];
129: Z = ksp->work[1];
130: P = ksp->work[2];
132: #if !defined(PETSC_USE_COMPLEX)
133: #define VecXDot(x,y,a) VecDot(x,y,a)
134: #else
135: #define VecXDot(x,y,a) (((cg->type) == (KSP_CG_HERMITIAN)) ? VecDot(x,y,a) : VecTDot(x,y,a))
136: #endif
138: if (eigs) {e = cg->e; d = cg->d; e[0] = 0.0; b = 0.0; }
139: PCGetOperators(ksp->B,&Amat,&Pmat,&pflag);
141: ksp->its = 0;
142: if (!ksp->guess_zero) {
143: KSP_MatMult(ksp,Amat,X,R); /* r <- b - Ax */
144: VecAYPX(&mone,B,R);
145: } else {
146: VecCopy(B,R); /* r <- b (x is 0) */
147: }
148: KSP_PCApply(ksp,ksp->B,R,Z); /* z <- Br */
149: VecXDot(Z,R,&beta);
150: if (ksp->normtype == KSP_PRECONDITIONED_NORM) {
151: VecNorm(Z,NORM_2,&dp); /* dp <- z'*z */
152: } else if (ksp->normtype == KSP_UNPRECONDITIONED_NORM) {
153: VecNorm(R,NORM_2,&dp); /* dp <- r'*r */
154: } else if (ksp->normtype == KSP_NATURAL_NORM) {
155: dp = sqrt(PetscAbsScalar(beta));
156: } else dp = 0.0;
157: (*ksp->converged)(ksp,0,dp,&ksp->reason,ksp->cnvP); /* test for convergence */
158: if (ksp->reason) {*its = 0; return(0);}
159: KSPLogResidualHistory(ksp,dp);
160: KSPMonitor(ksp,0,dp); /* call any registered monitor routines */
161: ksp->rnorm = dp;
163: for (i=0; i<maxit; i++) {
164: ksp->its = i+1;
165: VecXDot(Z,R,&beta); /* beta <- r'z */
166: if (beta == 0.0) {
167: ksp->reason = KSP_CONVERGED_ATOL;
168: break;
169: }
170: if (!i) {
171: VecCopy(Z,P); /* p <- z */
172: } else {
173: b = beta/betaold;
174: #if !defined(PETSC_USE_COMPLEX)
175: if (b < 0.0) {
176: ksp->reason = KSP_DIVERGED_INDEFINITE_PC;
177: break;
178: }
179: #endif
180: if (eigs) {
181: e[i] = sqrt(PetscAbsScalar(b))/a;
182: }
183: VecAYPX(&b,Z,P); /* p <- z + b* p */
184: }
185: betaold = beta;
186: KSP_MatMult(ksp,Amat,P,Z); /* z <- Kp */
187: VecXDot(P,Z,&dpi); /* dpi <- z'p */
188: a = beta/dpi; /* a = beta/p'z */
189: if (eigs) {
190: d[i] = sqrt(PetscAbsScalar(b))*e[i] + 1.0/a;
191: }
192: VecAXPY(&a,P,X); /* x <- x + ap */
193: ma = -a; VecAXPY(&ma,Z,R); /* r <- r - az */
194: if (ksp->normtype == KSP_PRECONDITIONED_NORM) {
195: KSP_PCApply(ksp,ksp->B,R,Z); /* z <- Br */
196: VecNorm(Z,NORM_2,&dp); /* dp <- z'*z */
197: } else if (ksp->normtype == KSP_UNPRECONDITIONED_NORM) {
198: VecNorm(R,NORM_2,&dp); /* dp <- r'*r */
199: } else if (ksp->normtype == KSP_NATURAL_NORM) {
200: dp = sqrt(PetscAbsScalar(beta));
201: } else {
202: dp = 0.0;
203: }
204: ksp->rnorm = dp;
205: KSPLogResidualHistory(ksp,dp);
206: KSPMonitor(ksp,i+1,dp);
207: (*ksp->converged)(ksp,i+1,dp,&ksp->reason,ksp->cnvP);
208: if (ksp->reason) break;
209: if (ksp->normtype != KSP_PRECONDITIONED_NORM) {
210: KSP_PCApply(ksp,ksp->B,R,Z); /* z <- Br */
211: }
212: }
213: if (i == maxit) {
214: ksp->reason = KSP_DIVERGED_ITS;
215: }
216: *its = ksp->its;
217: return(0);
218: }
219: /*
220: KSPDestroy_CG - Frees all memory space used by the Krylov method
222: */
223: #undef __FUNCT__
225: int KSPDestroy_CG(KSP ksp)
226: {
227: KSP_CG *cg = (KSP_CG*)ksp->data;
228: int ierr;
231: /* free space used for singular value calculations */
232: if (ksp->calc_sings) {
233: PetscFree(cg->e);
234: PetscFree(cg->ee);
235: }
237: KSPDefaultFreeWork(ksp);
238:
239: /* free the context variable */
240: PetscFree(cg);
241: return(0);
242: }
244: /*
245: KSPView_CG - Prints information about the current Krylov method being used
247: Currently this only prints information to a file (or stdout) about the
248: symmetry of the problem. If your Krylov method has special options or
249: flags that information should be printed here.
251: */
252: #undef __FUNCT__
254: int KSPView_CG(KSP ksp,PetscViewer viewer)
255: {
256: #if defined(PETSC_USE_COMPLEX)
257: KSP_CG *cg = (KSP_CG *)ksp->data;
258: int ierr;
259: PetscTruth isascii;
262: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
263: if (isascii) {
264: if (cg->type == KSP_CG_HERMITIAN) {
265: PetscViewerASCIIPrintf(viewer," CG: variant for complex, Hermitian systemn");
266: } else if (cg->type == KSP_CG_SYMMETRIC) {
267: PetscViewerASCIIPrintf(viewer," CG: variant for complex, symmetric systemn");
268: } else {
269: PetscViewerASCIIPrintf(viewer," CG: unknown variantn");
270: }
271: } else {
272: SETERRQ1(1,"Viewer type %s not supported for KSP cg",((PetscObject)viewer)->type_name);
273: }
274: #endif
275: return(0);
276: }
278: /*
279: KSPSetFromOptions_CG - Checks the options database for options related to the
280: conjugate gradient method.
281: */
282: #undef __FUNCT__
284: int KSPSetFromOptions_CG(KSP ksp)
285: {
286: #if defined(PETSC_USE_COMPLEX)
287: int ierr;
288: PetscTruth flg;
289: #endif
292: #if defined(PETSC_USE_COMPLEX)
293: PetscOptionsHead("KSP CG options");
294: PetscOptionsLogicalGroupBegin("-ksp_cg_Hermitian","Matrix is Hermitian","KSPCGSetType",&flg);
295: if (flg) { KSPCGSetType(ksp,KSP_CG_HERMITIAN); }
296: PetscOptionsLogicalGroupEnd("-ksp_cg_symmetric","Matrix is complex symmetric, not Hermitian","KSPCGSetType",&flg);
297: if (flg) { KSPCGSetType(ksp,KSP_CG_SYMMETRIC); }
298: PetscOptionsTail();
299: #endif
300: return(0);
301: }
303: /*
304: KSPCGSetType_CG - This is an option that is SPECIFIC to this particular Krylov method.
305: This routine is registered below in KSPCreate_CG() and called from the
306: routine KSPCGSetType() (see the file cgtype.c).
308: This must be wrapped in an EXTERN_C_BEGIN to be dynamically linkable in C++
309: */
310: EXTERN_C_BEGIN
311: #undef __FUNCT__
313: int KSPCGSetType_CG(KSP ksp,KSPCGType type)
314: {
315: KSP_CG *cg;
318: cg = (KSP_CG *)ksp->data;
319: cg->type = type;
320: return(0);
321: }
322: EXTERN_C_END
324: /*
325: KSPCreate_CG - Creates the data structure for the Krylov method CG and sets the
326: function pointers for all the routines it needs to call (KSPSolve_CG() etc)
328: It must be wrapped in EXTERN_C_BEGIN to be dynamically linkable in C++
329: */
330: EXTERN_C_BEGIN
331: #undef __FUNCT__
333: int KSPCreate_CG(KSP ksp)
334: {
335: int ierr;
336: KSP_CG *cg;
339: PetscNew(KSP_CG,&cg);
340: PetscMemzero(cg,sizeof(KSP_CG));
341: PetscLogObjectMemory(ksp,sizeof(KSP_CG));
342: #if !defined(PETSC_USE_COMPLEX)
343: cg->type = KSP_CG_SYMMETRIC;
344: #else
345: cg->type = KSP_CG_HERMITIAN;
346: #endif
347: ksp->data = (void*)cg;
348: ksp->pc_side = PC_LEFT;
350: /*
351: Sets the functions that are associated with this data structure
352: (in C++ this is the same as defining virtual functions)
353: */
354: ksp->ops->setup = KSPSetUp_CG;
355: ksp->ops->solve = KSPSolve_CG;
356: ksp->ops->destroy = KSPDestroy_CG;
357: ksp->ops->view = KSPView_CG;
358: ksp->ops->setfromoptions = KSPSetFromOptions_CG;
359: ksp->ops->buildsolution = KSPDefaultBuildSolution;
360: ksp->ops->buildresidual = KSPDefaultBuildResidual;
362: /*
363: Attach the function KSPCGSetType_CG() to this object. The routine
364: KSPCGSetType() checks for this attached function and calls it if it finds
365: it. (Sort of like a dynamic member function that can be added at run time
366: */
367: PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPCGSetType_C","KSPCGSetType_CG",
368: KSPCGSetType_CG);
369: return(0);
370: }
371: EXTERN_C_END