Actual source code: cg.c

  1: /*$Id: cg.c,v 1.115 2001/03/23 23:23:34 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: int KSPSetUp_CG(KSP ksp)
 56: {
 57:   KSP_CG *cgP = (KSP_CG*)ksp->data;
 58:   int    maxit = ksp->max_it,ierr;

 61:   /* 
 62:        This implementation of CG only handles left preconditioning
 63:      so generate an error otherwise.
 64:   */
 65:   if (ksp->pc_side == PC_RIGHT) {
 66:     SETERRQ(2,"No right preconditioning for KSPCG");
 67:   } else if (ksp->pc_side == PC_SYMMETRIC) {
 68:     SETERRQ(2,"No symmetric preconditioning for KSPCG");
 69:   }

 71:   /* get work vectors needed by CG */
 72:   KSPDefaultGetWork(ksp,3);

 74:   /*
 75:      If user requested computations of eigenvalues then allocate work
 76:      work space needed
 77:   */
 78:   if (ksp->calc_sings) {
 79:     /* get space to store tridiagonal matrix for Lanczos */
 80:     PetscMalloc(2*(maxit+1)*sizeof(Scalar),&cgP->e);
 81:     PetscLogObjectMemory(ksp,2*(maxit+1)*sizeof(Scalar));
 82:     cgP->d                         = cgP->e + maxit + 1;
 83:     PetscMalloc(2*(maxit+1)*sizeof(PetscReal),&cgP->ee);
 84:     PetscLogObjectMemory(ksp,2*(maxit+1)*sizeof(Scalar));
 85:     cgP->dd                        = cgP->ee + maxit + 1;
 86:     ksp->ops->computeextremesingularvalues = KSPComputeExtremeSingularValues_CG;
 87:     ksp->ops->computeeigenvalues           = KSPComputeEigenvalues_CG;
 88:   }
 89:   return(0);
 90: }

 92: /*
 93:        KSPSolve_CG - This routine actually applies the conjugate gradient 
 94:     method

 96:    Input Parameter:
 97: .     ksp - the Krylov space object that was set to use conjugate gradient, by, for 
 98:             example, KSPCreate(MPI_Comm,KSP *ksp); KSPSetType(ksp,KSPCG);

100:    Output Parameter:
101: .     its - number of iterations used

103: */
104: int  KSPSolve_CG(KSP ksp,int *its)
105: {
106:   int          ierr,i,maxit,eigs,pres;
107:   Scalar       dpi,a = 1.0,beta,betaold = 1.0,b,*e = 0,*d = 0,mone = -1.0,ma;
108:   PetscReal    dp = 0.0;
109:   Vec          X,B,Z,R,P;
110:   KSP_CG       *cg;
111:   Mat          Amat,Pmat;
112:   MatStructure pflag;
113:   PetscTruth   diagonalscale;

116:   ierr    = PCDiagonalScale(ksp->B,&diagonalscale);
117:   if (diagonalscale) SETERRQ1(1,"Krylov method %s does not support diagonal scaling",ksp->type_name);

119:   cg      = (KSP_CG*)ksp->data;
120:   eigs    = ksp->calc_sings;
121:   pres    = ksp->use_pres;
122:   maxit   = ksp->max_it;
123:   X       = ksp->vec_sol;
124:   B       = ksp->vec_rhs;
125:   R       = ksp->work[0];
126:   Z       = ksp->work[1];
127:   P       = ksp->work[2];

129: #if !defined(PETSC_USE_COMPLEX)
130: #define VecXDot(x,y,a) VecDot(x,y,a)
131: #else
132: #define VecXDot(x,y,a) (((cg->type) == (KSP_CG_HERMITIAN)) ? VecDot(x,y,a) : VecTDot(x,y,a))
133: #endif

135:   if (eigs) {e = cg->e; d = cg->d; e[0] = 0.0; b = 0.0; }
136:   PCGetOperators(ksp->B,&Amat,&Pmat,&pflag);

138:   ksp->its = 0;
139:   if (!ksp->guess_zero) {
140:     KSP_MatMult(ksp,Amat,X,R);         /*   r <- b - Ax       */
141:     VecAYPX(&mone,B,R);
142:   } else {
143:     VecCopy(B,R);              /*     r <- b (x is 0) */
144:   }
145:   KSP_PCApply(ksp,ksp->B,R,Z);         /*     z <- Br         */
146:   if (!ksp->avoidnorms) {
147:     if (pres) {
148:       VecNorm(Z,NORM_2,&dp); /*    dp <- z'*z       */
149:     } else {
150:       VecNorm(R,NORM_2,&dp); /*    dp <- r'*r       */
151:     }
152:   }
153:   (*ksp->converged)(ksp,0,dp,&ksp->reason,ksp->cnvP);      /* test for convergence */
154:   if (ksp->reason) {*its =  0; return(0);}
155:   KSPLogResidualHistory(ksp,dp);
156:   KSPMonitor(ksp,0,dp);                              /* call any registered monitor routines */
157:   ksp->rnorm = dp;

159:   for (i=0; i<maxit; i++) {
160:      ksp->its = i+1;
161:      VecXDot(Z,R,&beta);     /*     beta <- r'z     */
162:      if (beta == 0.0) {
163:        ksp->reason = KSP_CONVERGED_ATOL;
164:        break;
165:      }
166:      if (!i) {
167:        VecCopy(Z,P);         /*     p <- z          */
168:      } else {
169:          b = beta/betaold;
170: #if !defined(PETSC_USE_COMPLEX)
171:          if (b < 0.0) SETERRQ(PETSC_ERR_KSP_BRKDWN,"Nonsymmetric/bad preconditioner");
172: #endif
173:          if (eigs) {
174:            e[i] = sqrt(PetscAbsScalar(b))/a;
175:          }
176:          VecAYPX(&b,Z,P);    /*     p <- z + b* p   */
177:      }
178:      betaold = beta;
179:      KSP_MatMult(ksp,Amat,P,Z);      /*     z <- Kp         */
180:      VecXDot(P,Z,&dpi);      /*     dpi <- z'p      */
181:      a = beta/dpi;                                 /*     a = beta/p'z    */
182:      if (eigs) {
183:        d[i] = sqrt(PetscAbsScalar(b))*e[i] + 1.0/a;
184:      }
185:      VecAXPY(&a,P,X);          /*     x <- x + ap     */
186:      ma = -a; VecAXPY(&ma,Z,R);                      /*     r <- r - az     */
187:      if (pres) {
188:        KSP_PCApply(ksp,ksp->B,R,Z);    /*     z <- Br         */
189:        if (!ksp->avoidnorms) {
190:          VecNorm(Z,NORM_2,&dp);/*    dp <- z'*z       */
191:        }
192:      } else if (!ksp->avoidnorms) {
193:        VecNorm(R,NORM_2,&dp);  /*    dp <- r'*r       */
194:      }
195:      ksp->rnorm = dp;
196:      KSPLogResidualHistory(ksp,dp);
197:      KSPMonitor(ksp,i+1,dp);
198:      (*ksp->converged)(ksp,i+1,dp,&ksp->reason,ksp->cnvP);
199:      if (ksp->reason) break;
200:      if (!pres) {KSP_PCApply(ksp,ksp->B,R,Z);} /* z <- Br  */
201:   }
202:   if (i == maxit) {
203:     ksp->reason = KSP_DIVERGED_ITS;
204:   }
205:   *its = ksp->its;
206:   return(0);
207: }
208: /*
209:        KSPDestroy_CG - Frees all memory space used by the Krylov method

211: */
212: int KSPDestroy_CG(KSP ksp)
213: {
214:   KSP_CG *cg = (KSP_CG*)ksp->data;
215:   int    ierr;

218:   /* free space used for singular value calculations */
219:   if (ksp->calc_sings) {
220:     PetscFree(cg->e);
221:     PetscFree(cg->ee);
222:   }

224:   KSPDefaultFreeWork(ksp);
225: 
226:   /* free the context variable */
227:   PetscFree(cg);
228:   return(0);
229: }

231: /*
232:      KSPView_CG - Prints information about the current Krylov method being used

234:       Currently this only prints information to a file (or stdout) about the 
235:       symmetry of the problem. If your Krylov method has special options or 
236:       flags that information should be printed here.

238: */
239: int KSPView_CG(KSP ksp,PetscViewer viewer)
240: {
241: #if defined(PETSC_USE_COMPLEX)
242:   KSP_CG     *cg = (KSP_CG *)ksp->data;
243:   int        ierr;
244:   PetscTruth isascii;

247:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
248:   if (isascii) {
249:     if (cg->type == KSP_CG_HERMITIAN) {
250:       PetscViewerASCIIPrintf(viewer,"  CG: variant for complex, Hermitian systemn");
251:     } else if (cg->type == KSP_CG_SYMMETRIC) {
252:       PetscViewerASCIIPrintf(viewer,"  CG: variant for complex, symmetric systemn");
253:     } else {
254:       PetscViewerASCIIPrintf(viewer,"  CG: unknown variantn");
255:     }
256:   } else {
257:     SETERRQ1(1,"Viewer type %s not supported for KSP cg",((PetscObject)viewer)->type_name);
258:   }
259: #endif
260:   return(0);
261: }

263: /*
264:     KSPSetFromOptions_CG - Checks the options database for options related to the 
265:                            conjugate gradient method.
266: */
267: int KSPSetFromOptions_CG(KSP ksp)
268: {
269: #if defined(PETSC_USE_COMPLEX)
270:   int        ierr;
271:   PetscTruth flg;
272: #endif

275: #if defined(PETSC_USE_COMPLEX)
276:   PetscOptionsHead("KSP CG options");
277:     PetscOptionsLogicalGroupBegin("-ksp_cg_Hermitian","Matrix is Hermitian","KSPCGSetType",&flg);
278:     if (flg) { KSPCGSetType(ksp,KSP_CG_HERMITIAN); }
279:     PetscOptionsLogicalGroupEnd("-ksp_cg_symmetric","Matrix is complex symmetric, not Hermitian","KSPCGSetType",&flg);
280:     if (flg) { KSPCGSetType(ksp,KSP_CG_SYMMETRIC); }
281:   PetscOptionsTail();
282: #endif
283:   return(0);
284: }

286: /*
287:     KSPCGSetType_CG - This is an option that is SPECIFIC to this particular Krylov method.
288:                       This routine is registered below in KSPCreate_CG() and called from the 
289:                       routine KSPCGSetType() (see the file cgtype.c).

291:         This must be wrapped in an EXTERN_C_BEGIN to be dynamically linkable in C++
292: */
293: EXTERN_C_BEGIN
294: int KSPCGSetType_CG(KSP ksp,KSPCGType type)
295: {
296:   KSP_CG *cg;

299:   cg = (KSP_CG *)ksp->data;
300:   cg->type = type;
301:   return(0);
302: }
303: EXTERN_C_END

305: /*
306:     KSPCreate_CG - Creates the data structure for the Krylov method CG and sets the 
307:        function pointers for all the routines it needs to call (KSPSolve_CG() etc)

309:     It must be wrapped in EXTERN_C_BEGIN to be dynamically linkable in C++
310: */
311: EXTERN_C_BEGIN
312: int KSPCreate_CG(KSP ksp)
313: {
314:   int    ierr;
315:   KSP_CG *cg;

318:   PetscNew(KSP_CG,&cg);
319:   PetscMemzero(cg,sizeof(KSP_CG));
320:   PetscLogObjectMemory(ksp,sizeof(KSP_CG));
321: #if !defined(PETSC_USE_COMPLEX)
322:   cg->type                       = KSP_CG_SYMMETRIC;
323: #else
324:   cg->type                       = KSP_CG_HERMITIAN;
325: #endif
326:   ksp->data                      = (void*)cg;
327:   ksp->pc_side                   = PC_LEFT;
328:   ksp->calc_res                  = PETSC_TRUE;

330:   /*
331:        Sets the functions that are associated with this data structure 
332:        (in C++ this is the same as defining virtual functions)
333:   */
334:   ksp->ops->setup                = KSPSetUp_CG;
335:   ksp->ops->solve                = KSPSolve_CG;
336:   ksp->ops->destroy              = KSPDestroy_CG;
337:   ksp->ops->view                 = KSPView_CG;
338:   ksp->ops->setfromoptions       = KSPSetFromOptions_CG;
339:   ksp->ops->buildsolution        = KSPDefaultBuildSolution;
340:   ksp->ops->buildresidual        = KSPDefaultBuildResidual;

342:   /*
343:       Attach the function KSPCGSetType_CG() to this object. The routine 
344:       KSPCGSetType() checks for this attached function and calls it if it finds
345:       it. (Sort of like a dynamic member function that can be added at run time
346:   */
347:   PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPCGSetType_C","KSPCGSetType_CG",
348:                                      KSPCGSetType_CG);
349:   return(0);
350: }
351: EXTERN_C_END