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