Actual source code: lcd.c

  1: #include <../src/ksp/ksp/impls/lcd/lcdimpl.h>

  3: static PetscErrorCode KSPSetUp_LCD(KSP ksp)
  4: {
  5:   KSP_LCD *lcd     = (KSP_LCD *)ksp->data;
  6:   PetscInt restart = lcd->restart;

  8:   PetscFunctionBegin;
  9:   /* get work vectors needed by LCD */
 10:   PetscCall(KSPSetWorkVecs(ksp, 2));

 12:   PetscCall(VecDuplicateVecs(ksp->work[0], restart + 1, &lcd->P));
 13:   PetscCall(VecDuplicateVecs(ksp->work[0], restart + 1, &lcd->Q));
 14:   PetscFunctionReturn(PETSC_SUCCESS);
 15: }

 17: /*     KSPSolve_LCD - This routine actually applies the left conjugate
 18:     direction method

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

 24:    Output Parameter:
 25: .     its - number of iterations used

 27: */
 28: static PetscErrorCode KSPSolve_LCD(KSP ksp)
 29: {
 30:   PetscInt    it, j, max_k;
 31:   PetscScalar alfa, beta, num, den, mone;
 32:   PetscReal   rnorm = 0.0;
 33:   Vec         X, B, R, Z;
 34:   KSP_LCD    *lcd;
 35:   Mat         Amat, Pmat;

 37:   PetscFunctionBegin;
 38:   lcd   = (KSP_LCD *)ksp->data;
 39:   X     = ksp->vec_sol;
 40:   B     = ksp->vec_rhs;
 41:   R     = ksp->work[0];
 42:   Z     = ksp->work[1];
 43:   max_k = lcd->restart;
 44:   mone  = -1;

 46:   PetscCall(PCGetOperators(ksp->pc, &Amat, &Pmat));

 48:   ksp->its = 0;
 49:   if (!ksp->guess_zero) {
 50:     PetscCall(KSP_MatMult(ksp, Amat, X, Z)); /*   z <- b - Ax       */
 51:     PetscCall(VecAYPX(Z, mone, B));
 52:   } else {
 53:     PetscCall(VecCopy(B, Z)); /*     z <- b (x is 0) */
 54:   }

 56:   PetscCall(KSP_PCApply(ksp, Z, R)); /*     r <- M^-1z         */
 57:   if (ksp->normtype != KSP_NORM_NONE) {
 58:     PetscCall(VecNorm(R, NORM_2, &rnorm));
 59:     KSPCheckNorm(ksp, rnorm);
 60:   }
 61:   PetscCall(KSPLogResidualHistory(ksp, rnorm));
 62:   PetscCall(KSPMonitor(ksp, 0, rnorm));
 63:   ksp->rnorm = rnorm;

 65:   /* test for convergence */
 66:   PetscCall((*ksp->converged)(ksp, 0, rnorm, &ksp->reason, ksp->cnvP));
 67:   if (ksp->reason) PetscFunctionReturn(PETSC_SUCCESS);

 69:   PetscCall(VecCopy(R, lcd->P[0]));

 71:   while (!ksp->reason && ksp->its < ksp->max_it) {
 72:     it = 0;
 73:     PetscCall(KSP_MatMult(ksp, Amat, lcd->P[it], Z));
 74:     PetscCall(KSP_PCApply(ksp, Z, lcd->Q[it]));

 76:     while (!ksp->reason && it < max_k && ksp->its < ksp->max_it) {
 77:       ksp->its++;
 78:       PetscCall(VecDot(lcd->P[it], R, &num));
 79:       PetscCall(VecDot(lcd->P[it], lcd->Q[it], &den));
 80:       KSPCheckDot(ksp, den);
 81:       alfa = num / den;
 82:       PetscCall(VecAXPY(X, alfa, lcd->P[it]));
 83:       PetscCall(VecAXPY(R, -alfa, lcd->Q[it]));
 84:       if (ksp->normtype != KSP_NORM_NONE) {
 85:         PetscCall(VecNorm(R, NORM_2, &rnorm));
 86:         KSPCheckNorm(ksp, rnorm);
 87:       }

 89:       ksp->rnorm = rnorm;
 90:       PetscCall(KSPLogResidualHistory(ksp, rnorm));
 91:       PetscCall(KSPMonitor(ksp, ksp->its, rnorm));
 92:       PetscCall((*ksp->converged)(ksp, ksp->its, rnorm, &ksp->reason, ksp->cnvP));

 94:       if (ksp->reason) break;

 96:       PetscCall(VecCopy(R, lcd->P[it + 1]));
 97:       PetscCall(KSP_MatMult(ksp, Amat, lcd->P[it + 1], Z));
 98:       PetscCall(KSP_PCApply(ksp, Z, lcd->Q[it + 1]));

100:       for (j = 0; j <= it; j++) {
101:         PetscCall(VecDot(lcd->P[j], lcd->Q[it + 1], &num));
102:         KSPCheckDot(ksp, num);
103:         PetscCall(VecDot(lcd->P[j], lcd->Q[j], &den));
104:         beta = -num / den;
105:         PetscCall(VecAXPY(lcd->P[it + 1], beta, lcd->P[j]));
106:         PetscCall(VecAXPY(lcd->Q[it + 1], beta, lcd->Q[j]));
107:       }
108:       it++;
109:     }
110:     PetscCall(VecCopy(lcd->P[it], lcd->P[0]));
111:   }
112:   if (ksp->its >= ksp->max_it && !ksp->reason) ksp->reason = KSP_DIVERGED_ITS;
113:   PetscCall(VecCopy(X, ksp->vec_sol));
114:   PetscFunctionReturn(PETSC_SUCCESS);
115: }
116: /*
117:        KSPDestroy_LCD - Frees all memory space used by the Krylov method

119: */
120: static PetscErrorCode KSPReset_LCD(KSP ksp)
121: {
122:   KSP_LCD *lcd = (KSP_LCD *)ksp->data;

124:   PetscFunctionBegin;
125:   if (lcd->P) PetscCall(VecDestroyVecs(lcd->restart + 1, &lcd->P));
126:   if (lcd->Q) PetscCall(VecDestroyVecs(lcd->restart + 1, &lcd->Q));
127:   PetscFunctionReturn(PETSC_SUCCESS);
128: }

130: static PetscErrorCode KSPDestroy_LCD(KSP ksp)
131: {
132:   PetscFunctionBegin;
133:   PetscCall(KSPReset_LCD(ksp));
134:   PetscCall(PetscFree(ksp->data));
135:   PetscFunctionReturn(PETSC_SUCCESS);
136: }

138: /*
139:      KSPView_LCD - Prints information about the current Krylov method being used

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

145: */
146: static PetscErrorCode KSPView_LCD(KSP ksp, PetscViewer viewer)
147: {
148:   KSP_LCD  *lcd = (KSP_LCD *)ksp->data;
149:   PetscBool isascii;

151:   PetscFunctionBegin;
152:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
153:   if (isascii) {
154:     PetscCall(PetscViewerASCIIPrintf(viewer, "  restart=%" PetscInt_FMT "\n", lcd->restart));
155:     PetscCall(PetscViewerASCIIPrintf(viewer, "  happy breakdown tolerance=%g\n", (double)lcd->haptol));
156:   }
157:   PetscFunctionReturn(PETSC_SUCCESS);
158: }

160: /*
161:     KSPSetFromOptions_LCD - Checks the options database for options related to the
162:                             LCD method.
163: */
164: static PetscErrorCode KSPSetFromOptions_LCD(KSP ksp, PetscOptionItems PetscOptionsObject)
165: {
166:   PetscBool flg;
167:   KSP_LCD  *lcd = (KSP_LCD *)ksp->data;

169:   PetscFunctionBegin;
170:   PetscOptionsHeadBegin(PetscOptionsObject, "KSP LCD options");
171:   PetscCall(PetscOptionsBoundedInt("-ksp_lcd_restart", "Number of vectors conjugate", "KSPLCDSetRestart", lcd->restart, &lcd->restart, &flg, 1));
172:   PetscCall(PetscOptionsBoundedReal("-ksp_lcd_haptol", "Tolerance for exact convergence (happy breakdown)", "KSPLCDSetHapTol", lcd->haptol, &lcd->haptol, &flg, 0.0));
173:   PetscFunctionReturn(PETSC_SUCCESS);
174: }

176: /*MC
177:    KSPLCD -  Implements the LCD (left conjugate direction) method

179:    Options Database Keys:
180: +  -ksp_lcd_restart - number of vectors conjugate
181: -  -ksp_lcd_haptol  - tolerance for exact convergence (happy breakdown)

183:    Level: beginner

185:    Notes:
186:    Support only for left preconditioning

188:    See {cite}`yuan2004semi`, {cite}`dai2004study`, {cite}`catabriga2004evaluating`, and {cite}`catabriga2006performance`

190:    Contributed by:
191:    Lucia Catabriga <luciac@ices.utexas.edu>

193: .seealso: [](ch_ksp), `KSPCreate()`, `KSPSetType()`, `KSPType`, `KSP`, `KSPCG`,
194:           `KSPCGSetType()`, `KSPLCDSetRestart()`, `KSPLCDSetHapTol()`
195: M*/

197: PETSC_EXTERN PetscErrorCode KSPCreate_LCD(KSP ksp)
198: {
199:   KSP_LCD *lcd;

201:   PetscFunctionBegin;
202:   PetscCall(PetscNew(&lcd));
203:   ksp->data = (void *)lcd;
204:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NONE, PC_LEFT, 1));
205:   PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_PRECONDITIONED, PC_LEFT, 3));
206:   lcd->restart = 30;
207:   lcd->haptol  = 1.0e-30;

209:   /*
210:        Sets the functions that are associated with this data structure
211:        (in C++ this is the same as defining virtual functions)
212:   */
213:   ksp->ops->setup          = KSPSetUp_LCD;
214:   ksp->ops->solve          = KSPSolve_LCD;
215:   ksp->ops->reset          = KSPReset_LCD;
216:   ksp->ops->destroy        = KSPDestroy_LCD;
217:   ksp->ops->view           = KSPView_LCD;
218:   ksp->ops->setfromoptions = KSPSetFromOptions_LCD;
219:   ksp->ops->buildsolution  = KSPBuildSolutionDefault;
220:   ksp->ops->buildresidual  = KSPBuildResidualDefault;
221:   PetscFunctionReturn(PETSC_SUCCESS);
222: }