Actual source code: lcd.c

  1: #define PETSCKSP_DLL
  2: /*
  3:     This file implements the LCD (left conjugate direction) method in PETSc.
  4:     References: 
  5:    - J.Y. Yuan, G.H.Golub, R.J. Plemmons, and W.A.G. Cecilio. Semiconjugate
  6:      direction methods for real positive definite system. BIT Numerical
  7:      Mathematics, 44(1):189-207,2004.
  8:    - Y. Dai and J.Y. Yuan. Study on semi-conjugate direction methods for
  9:      non-symmetric systems. International Journal for Numerical Methods in
 10:      Engineering, 60:1383-1399,2004.
 11:    - L. Catabriga, A.L.G.A. Coutinho, and L.P.Franca. Evaluating the LCD
 12:      algorithm for solving linear systems of equations arising from implicit
 13:      SUPG formulation of compressible flows. International Journal for
 14:      Numerical Methods in Engineering, 60:1513-1534,2004 
 15:    - L. Catabriga, A. M. P. Valli, B. Z. Melotti, L. M. Pessoa,
 16:      A. L. G. A. Coutinho, Performance of LCD iterative method in the finite
 17:      element and finite difference solution of convection-diffusion
 18:      equations,  Communications in Numerical Methods in Engineering, (Early
 19:      View).

 21:   Contributed by: Lucia Catabriga <luciac@ices.utexas.edu>
 22: */

 24:  #include src/ksp/ksp/impls/lcd/lcdctx.h

 28: PetscErrorCode KSPSetUp_LCD(KSP ksp)
 29: {
 30:   KSP_LCD         *lcd = (KSP_LCD*)ksp->data;
 32:   PetscInt        restart = lcd->restart;

 35:   /* 
 36:        This implementation of LCD only handles left preconditioning
 37:      so generate an error otherwise.
 38:   */
 39:   if (ksp->pc_side == PC_RIGHT) {
 40:     SETERRQ(2,"No right preconditioning for KSPCG");
 41:   } else if (ksp->pc_side == PC_SYMMETRIC) {
 42:     SETERRQ(2,"No symmetric preconditioning for KSPCG");
 43:   }

 45:   /* get work vectors needed by LCD */
 46:   KSPDefaultGetWork(ksp,2);
 47: 
 48:   VecDuplicateVecs(ksp->vec_rhs,restart+1,&lcd->P);
 49:   VecDuplicateVecs(ksp->vec_rhs, restart + 1, &lcd->Q);
 50:   PetscLogObjectMemory(ksp,2*(restart+2)*sizeof(Vec));
 51:   return(0);
 52: }

 54: /*     KSPSolve_LCD - This routine actually applies the left conjugate
 55:     direction method

 57:    Input Parameter:
 58: .     ksp - the Krylov space object that was set to use LCD, by, for 
 59:             example, KSPCreate(MPI_Comm,KSP *ksp); KSPSetType(ksp,KSPLCD);

 61:    Output Parameter:
 62: .     its - number of iterations used

 64: */
 67: PetscErrorCode  KSPSolve_LCD(KSP ksp)
 68: {
 70:   PetscInt       it,j,max_k;
 71:   PetscScalar    alfa, beta, num, den, mone, pone;
 72:   PetscReal      rnorm;
 73:   Vec            X,B,R,Z;
 74:   KSP_LCD        *lcd;
 75:   Mat            Amat,Pmat;
 76:   MatStructure   pflag;
 77:   PetscTruth     diagonalscale;

 80: 
 81:   PCDiagonalScale(ksp->pc,&diagonalscale);
 82:   if (diagonalscale) SETERRQ1(PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",ksp->type_name);

 84:   lcd            = (KSP_LCD*)ksp->data;
 85:   X              = ksp->vec_sol;
 86:   B              = ksp->vec_rhs;
 87:   R              = ksp->work[0];
 88:   Z              = ksp->work[1];
 89:   max_k          = lcd->restart;
 90:   mone = -1;
 91:   pone = 1;

 93:   PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);

 95:   ksp->its = 0;
 96:   if (!ksp->guess_zero) {
 97:     KSP_MatMult(ksp,Amat,X,Z);             /*   z <- b - Ax       */
 98:     VecAYPX(Z,mone,B);
 99:   } else {
100:     VecCopy(B,Z);                         /*     z <- b (x is 0) */
101:   }
102: 
103:   KSP_PCApply(ksp,Z,R);                   /*     r <- M^-1z         */
104:   VecNorm(R,NORM_2,&rnorm);
105:   KSPLogResidualHistory(ksp,rnorm);
106:   KSPMonitor(ksp,0,rnorm);                    /* call any registered monitor routines */
107:   ksp->rnorm = rnorm;
108: 
109:    /* test for convergence */
110:   (*ksp->converged)(ksp,0,rnorm,&ksp->reason,ksp->cnvP);
111:   if (ksp->reason) return(0);

113:   it = 0;
114:   VecCopy(R,lcd->P[0]);
115: 
116:   while (!ksp->reason && ksp->its < ksp->max_it) {
117:     it = 0;
118:     KSP_MatMult(ksp,Amat,lcd->P[it],Z);
119:     KSP_PCApply(ksp,Z,lcd->Q[it]);
120: 
121:     while(!ksp->reason && it < max_k && ksp->its < ksp->max_it) {
122:       ksp->its++;
123:       VecDot(lcd->P[it],R,&num);
124:       VecDot(lcd->P[it],lcd->Q[it], &den);
125:       alfa = num/den;
126:       VecAXPY(X,alfa,lcd->P[it]);
127:       VecAXPY(R,-alfa,lcd->Q[it]);
128:       VecNorm(R,NORM_2,&rnorm);

130:       ksp->rnorm = rnorm;
131:       KSPLogResidualHistory(ksp,rnorm);
132:       KSPMonitor(ksp,ksp->its,rnorm);
133:       (*ksp->converged)(ksp,ksp->its,rnorm,&ksp->reason,ksp->cnvP);
134: 
135:       if (ksp->reason) break;
136: 
137:       VecCopy(R,lcd->P[it+1]);
138:       KSP_MatMult(ksp,Amat,lcd->P[it+1],Z);
139:       KSP_PCApply(ksp,Z,lcd->Q[it+1]);
140: 
141:       for( j = 0; j <= it; j++)        {
142:         VecDot(lcd->P[j],lcd->Q[it+1],&num);
143:         VecDot(lcd->P[j],lcd->Q[j],&den);
144:         beta = - num/den;
145:         VecAXPY(lcd->P[it+1],beta,lcd->P[j]);
146:         VecAXPY(lcd->Q[it+1],beta,lcd->Q[j]);
147:       }
148:       it++;
149:     }
150:     VecCopy(lcd->P[it],lcd->P[0]);
151:   }
152:   if (ksp->its >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
153:   VecCopy(X,ksp->vec_sol);
154: 
155:   return(0);
156: }
157: /*
158:        KSPDestroy_LCD - Frees all memory space used by the Krylov method

160: */
163: PetscErrorCode KSPDestroy_LCD(KSP ksp)
164: {
165:   KSP_LCD         *lcd = (KSP_LCD*)ksp->data;

169:   KSPDefaultFreeWork(ksp);

171:   VecDestroyVecs(lcd->P, lcd->restart+1);
172:   VecDestroyVecs(lcd->Q, lcd->restart+1);
173: 
174:   PetscFree(lcd);
175:   return(0);
176: }

178: /*
179:      KSPView_LCD - Prints information about the current Krylov method being used

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

185: */
188: PetscErrorCode KSPView_LCD(KSP ksp,PetscViewer viewer)
189: {

191:   KSP_LCD         *lcd = (KSP_LCD *)ksp->data;
193:   PetscTruth     iascii;

196:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
197:   if (iascii) {
198:       PetscViewerASCIIPrintf(viewer,"  LCD: restart=%d\n",lcd->restart);
199:       PetscViewerASCIIPrintf(viewer,"  LCD: happy breakdown tolerance %g\n",lcd->haptol);
200:   } else {
201:     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for KSP LCD",((PetscObject)viewer)->type_name);
202:   }
203:   return(0);
204: }

206: /*
207:     KSPSetFromOptions_LCD - Checks the options database for options related to the 
208:                             LCD method.
209: */
212: PetscErrorCode KSPSetFromOptions_LCD(KSP ksp)
213: {
215:   PetscTruth     flg;
216:   KSP_LCD        *lcd = (KSP_LCD *)ksp->data;
217: 
219:   PetscOptionsHead("KSP LCD options");
220:   PetscOptionsInt("-ksp_lcd_restart","Number of vectors conjugate","KSPLCDSetRestart",lcd->restart,&lcd->restart,&flg);
221:   if(flg && lcd->restart < 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Restart must be positive");
222:   PetscOptionsReal("-ksp_lcd_haptol","Tolerance for exact convergence (happy ending)","KSPLCDSetHapTol",lcd->haptol,&lcd->haptol,&flg);
223:   if (flg && lcd->haptol < 0.0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Tolerance must be non-negative");
224:   return(0);
225: }

230: PetscErrorCode KSPCreate_LCD(KSP ksp)
231: {
233:   KSP_LCD         *lcd;

236:   PetscNew(KSP_LCD,&lcd);
237:   PetscMemzero(lcd,sizeof(KSP_LCD));
238:   PetscLogObjectMemory(ksp,sizeof(KSP_LCD));
239:   ksp->data                      = (void*)lcd;
240:   ksp->pc_side                   = PC_LEFT;
241:   lcd->restart                   = 30;
242:   lcd->haptol                    = 1.0e-30;

244:   /*
245:        Sets the functions that are associated with this data structure 
246:        (in C++ this is the same as defining virtual functions)
247:   */
248:   ksp->ops->setup                = KSPSetUp_LCD;
249:   ksp->ops->solve                = KSPSolve_LCD;
250:   ksp->ops->destroy              = KSPDestroy_LCD;
251:   ksp->ops->view                 = KSPView_LCD;
252:   ksp->ops->setfromoptions       = KSPSetFromOptions_LCD;
253:   ksp->ops->buildsolution        = KSPDefaultBuildSolution;
254:   ksp->ops->buildresidual        = KSPDefaultBuildResidual;

256:   return(0);
257: }