1 #include <../src/ksp/pc/impls/deflation/deflation.h> /*I "petscksp.h" I*/ /* header file for Fortran wrappers */ 2 3 const char *const PCDeflationSpaceTypes[] = {"haar", "db2", "db4", "db8", "db16", "biorth22", "meyer", "aggregation", "user", "PCDeflationSpaceType", "PC_DEFLATION_SPACE_", NULL}; 4 5 static PetscErrorCode PCDeflationSetInitOnly_Deflation(PC pc, PetscBool flg) 6 { 7 PC_Deflation *def = (PC_Deflation *)pc->data; 8 9 PetscFunctionBegin; 10 def->init = flg; 11 PetscFunctionReturn(PETSC_SUCCESS); 12 } 13 14 /*@ 15 PCDeflationSetInitOnly - Do only initialization step. 16 Sets initial guess to the solution on the deflation space but does not apply 17 the deflation preconditioner. The additional preconditioner is still applied. 18 19 Logically Collective 20 21 Input Parameters: 22 + pc - the preconditioner context 23 - flg - default `PETSC_FALSE` 24 25 Options Database Key: 26 . -pc_deflation_init_only <false> - if true computes only the special guess 27 28 Level: intermediate 29 30 .seealso: [](ch_ksp), `PCDEFLATION` 31 @*/ 32 PetscErrorCode PCDeflationSetInitOnly(PC pc, PetscBool flg) 33 { 34 PetscFunctionBegin; 35 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 36 PetscValidLogicalCollectiveBool(pc, flg, 2); 37 PetscTryMethod(pc, "PCDeflationSetInitOnly_C", (PC, PetscBool), (pc, flg)); 38 PetscFunctionReturn(PETSC_SUCCESS); 39 } 40 41 static PetscErrorCode PCDeflationSetLevels_Deflation(PC pc, PetscInt current, PetscInt max) 42 { 43 PC_Deflation *def = (PC_Deflation *)pc->data; 44 45 PetscFunctionBegin; 46 if (current) def->lvl = current; 47 def->maxlvl = max; 48 PetscFunctionReturn(PETSC_SUCCESS); 49 } 50 51 /*@ 52 PCDeflationSetLevels - Set the maximum level of deflation nesting. 53 54 Logically Collective 55 56 Input Parameters: 57 + pc - the preconditioner context 58 - max - maximum deflation level 59 60 Options Database Key: 61 . -pc_deflation_max_lvl <0> - maximum number of levels for multilevel deflation 62 63 Level: intermediate 64 65 .seealso: [](ch_ksp), `PCDeflationSetSpaceToCompute()`, `PCDeflationSetSpace()`, `PCDEFLATION` 66 @*/ 67 PetscErrorCode PCDeflationSetLevels(PC pc, PetscInt max) 68 { 69 PetscFunctionBegin; 70 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 71 PetscValidLogicalCollectiveInt(pc, max, 2); 72 PetscTryMethod(pc, "PCDeflationSetLevels_C", (PC, PetscInt, PetscInt), (pc, 0, max)); 73 PetscFunctionReturn(PETSC_SUCCESS); 74 } 75 76 static PetscErrorCode PCDeflationSetReductionFactor_Deflation(PC pc, PetscInt red) 77 { 78 PC_Deflation *def = (PC_Deflation *)pc->data; 79 80 PetscFunctionBegin; 81 def->reductionfact = red; 82 PetscFunctionReturn(PETSC_SUCCESS); 83 } 84 85 /*@ 86 PCDeflationSetReductionFactor - Set reduction factor for the `PCDEFLATION` 87 88 Logically Collective 89 90 Input Parameters: 91 + pc - the preconditioner context 92 - red - reduction factor (or `PETSC_DETERMINE`) 93 94 Options Database Key: 95 . -pc_deflation_reduction_factor <\-1> - reduction factor on bottom level coarse problem for `PCDEFLATION` 96 97 Note: 98 Default is computed based on the size of the coarse problem. 99 100 Level: intermediate 101 102 .seealso: [](ch_ksp), `PCTELESCOPE`, `PCDEFLATION`, `PCDeflationSetLevels()` 103 @*/ 104 PetscErrorCode PCDeflationSetReductionFactor(PC pc, PetscInt red) 105 { 106 PetscFunctionBegin; 107 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 108 PetscValidLogicalCollectiveInt(pc, red, 2); 109 PetscTryMethod(pc, "PCDeflationSetReductionFactor_C", (PC, PetscInt), (pc, red)); 110 PetscFunctionReturn(PETSC_SUCCESS); 111 } 112 113 static PetscErrorCode PCDeflationSetCorrectionFactor_Deflation(PC pc, PetscScalar fact) 114 { 115 PC_Deflation *def = (PC_Deflation *)pc->data; 116 117 PetscFunctionBegin; 118 /* TODO PETSC_DETERMINE -> compute max eigenvalue with power method */ 119 def->correct = PETSC_TRUE; 120 def->correctfact = fact; 121 if (def->correctfact == 0.0) def->correct = PETSC_FALSE; 122 PetscFunctionReturn(PETSC_SUCCESS); 123 } 124 125 /*@ 126 PCDeflationSetCorrectionFactor - Set coarse problem correction factor. 127 The preconditioner becomes P*M^{-1} + fact*Q. 128 129 Logically Collective 130 131 Input Parameters: 132 + pc - the preconditioner context 133 - fact - correction factor 134 135 Options Database Keys: 136 + -pc_deflation_correction <false> - if true apply coarse problem correction 137 - -pc_deflation_correction_factor <1.0> - sets coarse problem correction factor 138 139 Note: 140 Any non-zero fact enables the coarse problem correction. 141 142 Level: intermediate 143 144 .seealso: [](ch_ksp), `PCDEFLATION`, `PCDeflationSetLevels()`, `PCDeflationSetReductionFactor()` 145 @*/ 146 PetscErrorCode PCDeflationSetCorrectionFactor(PC pc, PetscScalar fact) 147 { 148 PetscFunctionBegin; 149 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 150 PetscValidLogicalCollectiveScalar(pc, fact, 2); 151 PetscTryMethod(pc, "PCDeflationSetCorrectionFactor_C", (PC, PetscScalar), (pc, fact)); 152 PetscFunctionReturn(PETSC_SUCCESS); 153 } 154 155 static PetscErrorCode PCDeflationSetSpaceToCompute_Deflation(PC pc, PCDeflationSpaceType type, PetscInt size) 156 { 157 PC_Deflation *def = (PC_Deflation *)pc->data; 158 159 PetscFunctionBegin; 160 if (type) def->spacetype = type; 161 if (size > 0) def->spacesize = size; 162 PetscFunctionReturn(PETSC_SUCCESS); 163 } 164 165 /*@ 166 PCDeflationSetSpaceToCompute - Set deflation space type and size to compute. 167 168 Logically Collective 169 170 Input Parameters: 171 + pc - the preconditioner context 172 . type - deflation space type to compute (or `PETSC_IGNORE`) 173 - size - size of the space to compute (or `PETSC_DEFAULT`) 174 175 Options Database Keys: 176 + -pc_deflation_compute_space <haar> - compute `PCDeflationSpaceType` deflation space 177 - -pc_deflation_compute_space_size <1> - size of the deflation space 178 179 Notes: 180 For wavelet-based deflation, size represents number of levels. 181 182 The deflation space is computed in `PCSetUp()`. 183 184 Level: intermediate 185 186 .seealso: [](ch_ksp), `PCDeflationSetLevels()`, `PCDEFLATION` 187 @*/ 188 PetscErrorCode PCDeflationSetSpaceToCompute(PC pc, PCDeflationSpaceType type, PetscInt size) 189 { 190 PetscFunctionBegin; 191 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 192 if (type) PetscValidLogicalCollectiveEnum(pc, type, 2); 193 if (size > 0) PetscValidLogicalCollectiveInt(pc, size, 3); 194 PetscTryMethod(pc, "PCDeflationSetSpaceToCompute_C", (PC, PCDeflationSpaceType, PetscInt), (pc, type, size)); 195 PetscFunctionReturn(PETSC_SUCCESS); 196 } 197 198 static PetscErrorCode PCDeflationSetSpace_Deflation(PC pc, Mat W, PetscBool transpose) 199 { 200 PC_Deflation *def = (PC_Deflation *)pc->data; 201 202 PetscFunctionBegin; 203 /* possibly allows W' = Wt (which is valid but not tested) */ 204 PetscCall(PetscObjectReference((PetscObject)W)); 205 if (transpose) { 206 PetscCall(MatDestroy(&def->Wt)); 207 def->Wt = W; 208 } else { 209 PetscCall(MatDestroy(&def->W)); 210 def->W = W; 211 } 212 PetscFunctionReturn(PETSC_SUCCESS); 213 } 214 215 /*@ 216 PCDeflationSetSpace - Set the deflation space matrix (or its (Hermitian) transpose). 217 218 Logically Collective 219 220 Input Parameters: 221 + pc - the preconditioner context 222 . W - deflation matrix 223 - transpose - indicates that W is an explicit transpose of the deflation matrix 224 225 Level: intermediate 226 227 Notes: 228 Setting W as a multipliplicative `MATCOMPOSITE` enables use of the multilevel 229 deflation. If W = W0*W1*W2*...*Wn, W0 is taken as the first deflation space and 230 the coarse problem (W0'*A*W0)^{-1} is again preconditioned by deflation with 231 W1 as the deflation matrix. This repeats until the maximum level set by 232 PCDeflationSetLevels() is reached or there are no more matrices available. 233 If there are matrices left after reaching the maximum level, 234 they are merged into a deflation matrix ...*W{n-1}*Wn. 235 236 .seealso: [](ch_ksp), `PCDeflationSetLevels()`, `PCDEFLATION`, `PCDeflationSetProjectionNullSpaceMat()` 237 @*/ 238 PetscErrorCode PCDeflationSetSpace(PC pc, Mat W, PetscBool transpose) 239 { 240 PetscFunctionBegin; 241 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 242 PetscValidHeaderSpecific(W, MAT_CLASSID, 2); 243 PetscValidLogicalCollectiveBool(pc, transpose, 3); 244 PetscTryMethod(pc, "PCDeflationSetSpace_C", (PC, Mat, PetscBool), (pc, W, transpose)); 245 PetscFunctionReturn(PETSC_SUCCESS); 246 } 247 248 static PetscErrorCode PCDeflationSetProjectionNullSpaceMat_Deflation(PC pc, Mat mat) 249 { 250 PC_Deflation *def = (PC_Deflation *)pc->data; 251 252 PetscFunctionBegin; 253 PetscCall(PetscObjectReference((PetscObject)mat)); 254 PetscCall(MatDestroy(&def->WtA)); 255 def->WtA = mat; 256 PetscFunctionReturn(PETSC_SUCCESS); 257 } 258 259 /*@ 260 PCDeflationSetProjectionNullSpaceMat - Set the projection null space matrix (W'*A). 261 262 Collective 263 264 Input Parameters: 265 + pc - preconditioner context 266 - mat - projection null space matrix 267 268 Level: developer 269 270 .seealso: [](ch_ksp), `PCDEFLATION`, `PCDeflationSetSpace()` 271 @*/ 272 PetscErrorCode PCDeflationSetProjectionNullSpaceMat(PC pc, Mat mat) 273 { 274 PetscFunctionBegin; 275 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 276 PetscValidHeaderSpecific(mat, MAT_CLASSID, 2); 277 PetscTryMethod(pc, "PCDeflationSetProjectionNullSpaceMat_C", (PC, Mat), (pc, mat)); 278 PetscFunctionReturn(PETSC_SUCCESS); 279 } 280 281 static PetscErrorCode PCDeflationSetCoarseMat_Deflation(PC pc, Mat mat) 282 { 283 PC_Deflation *def = (PC_Deflation *)pc->data; 284 285 PetscFunctionBegin; 286 PetscCall(PetscObjectReference((PetscObject)mat)); 287 PetscCall(MatDestroy(&def->WtAW)); 288 def->WtAW = mat; 289 PetscFunctionReturn(PETSC_SUCCESS); 290 } 291 292 /*@ 293 PCDeflationSetCoarseMat - Set the coarse problem `Mat`. 294 295 Collective 296 297 Input Parameters: 298 + pc - preconditioner context 299 - mat - coarse problem mat 300 301 Level: developer 302 303 .seealso: [](ch_ksp), `PCDEFLATION`, `PCDeflationGetCoarseKSP()` 304 @*/ 305 PetscErrorCode PCDeflationSetCoarseMat(PC pc, Mat mat) 306 { 307 PetscFunctionBegin; 308 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 309 PetscValidHeaderSpecific(mat, MAT_CLASSID, 2); 310 PetscTryMethod(pc, "PCDeflationSetCoarseMat_C", (PC, Mat), (pc, mat)); 311 PetscFunctionReturn(PETSC_SUCCESS); 312 } 313 314 static PetscErrorCode PCDeflationGetCoarseKSP_Deflation(PC pc, KSP *ksp) 315 { 316 PC_Deflation *def = (PC_Deflation *)pc->data; 317 318 PetscFunctionBegin; 319 *ksp = def->WtAWinv; 320 PetscFunctionReturn(PETSC_SUCCESS); 321 } 322 323 /*@ 324 PCDeflationGetCoarseKSP - Returns the coarse problem `KSP`. 325 326 Not Collective 327 328 Input Parameter: 329 . pc - preconditioner context 330 331 Output Parameter: 332 . ksp - coarse problem `KSP` context 333 334 Level: advanced 335 336 .seealso: [](ch_ksp), `PCDEFLATION`, `PCDeflationSetCoarseMat()` 337 @*/ 338 PetscErrorCode PCDeflationGetCoarseKSP(PC pc, KSP *ksp) 339 { 340 PetscFunctionBegin; 341 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 342 PetscAssertPointer(ksp, 2); 343 PetscTryMethod(pc, "PCDeflationGetCoarseKSP_C", (PC, KSP *), (pc, ksp)); 344 PetscFunctionReturn(PETSC_SUCCESS); 345 } 346 347 static PetscErrorCode PCDeflationGetPC_Deflation(PC pc, PC *apc) 348 { 349 PC_Deflation *def = (PC_Deflation *)pc->data; 350 351 PetscFunctionBegin; 352 *apc = def->pc; 353 PetscFunctionReturn(PETSC_SUCCESS); 354 } 355 356 /*@ 357 PCDeflationGetPC - Returns the additional preconditioner M^{-1}. 358 359 Not Collective 360 361 Input Parameter: 362 . pc - the preconditioner context 363 364 Output Parameter: 365 . apc - additional preconditioner 366 367 Level: advanced 368 369 .seealso: [](ch_ksp), `PCDEFLATION`, `PCDeflationGetCoarseKSP()` 370 @*/ 371 PetscErrorCode PCDeflationGetPC(PC pc, PC *apc) 372 { 373 PetscFunctionBegin; 374 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 375 PetscAssertPointer(pc, 1); 376 PetscTryMethod(pc, "PCDeflationGetPC_C", (PC, PC *), (pc, apc)); 377 PetscFunctionReturn(PETSC_SUCCESS); 378 } 379 380 /* 381 x <- x + W*(W'*A*W)^{-1}*W'*r = x + Q*r 382 */ 383 static PetscErrorCode PCPreSolve_Deflation(PC pc, KSP ksp, Vec b, Vec x) 384 { 385 PC_Deflation *def = (PC_Deflation *)pc->data; 386 Mat A; 387 Vec r, w1, w2; 388 PetscBool nonzero; 389 390 PetscFunctionBegin; 391 w1 = def->workcoarse[0]; 392 w2 = def->workcoarse[1]; 393 r = def->work; 394 PetscCall(PCGetOperators(pc, NULL, &A)); 395 396 PetscCall(KSPGetInitialGuessNonzero(ksp, &nonzero)); 397 PetscCall(KSPSetInitialGuessNonzero(ksp, PETSC_TRUE)); 398 if (nonzero) { 399 PetscCall(MatMult(A, x, r)); /* r <- b - Ax */ 400 PetscCall(VecAYPX(r, -1.0, b)); 401 } else { 402 PetscCall(VecCopy(b, r)); /* r <- b (x is 0) */ 403 } 404 405 if (def->Wt) { 406 PetscCall(MatMult(def->Wt, r, w1)); /* w1 <- W'*r */ 407 } else { 408 PetscCall(MatMultHermitianTranspose(def->W, r, w1)); /* w1 <- W'*r */ 409 } 410 PetscCall(KSPSolve(def->WtAWinv, w1, w2)); /* w2 <- (W'*A*W)^{-1}*w1 */ 411 PetscCall(MatMult(def->W, w2, r)); /* r <- W*w2 */ 412 PetscCall(VecAYPX(x, 1.0, r)); 413 PetscFunctionReturn(PETSC_SUCCESS); 414 } 415 416 /* 417 if (def->correct) { 418 z <- M^{-1}r - W*(W'*A*W)^{-1}*(W'*A*M^{-1}r - l*W'*r) = (P*M^{-1} + l*Q)*r 419 } else { 420 z <- M^{-1}*r - W*(W'*A*W)^{-1}*W'*A*M{-1}*r = P*M^{-1}*r 421 } 422 */ 423 static PetscErrorCode PCApply_Deflation(PC pc, Vec r, Vec z) 424 { 425 PC_Deflation *def = (PC_Deflation *)pc->data; 426 Mat A; 427 Vec u, w1, w2; 428 429 PetscFunctionBegin; 430 w1 = def->workcoarse[0]; 431 w2 = def->workcoarse[1]; 432 u = def->work; 433 PetscCall(PCGetOperators(pc, NULL, &A)); 434 435 PetscCall(PCApply(def->pc, r, z)); /* z <- M^{-1}*r */ 436 if (!def->init) { 437 PetscCall(MatMult(def->WtA, z, w1)); /* w1 <- W'*A*z */ 438 if (def->correct) { 439 if (def->Wt) { 440 PetscCall(MatMult(def->Wt, r, w2)); /* w2 <- W'*r */ 441 } else { 442 PetscCall(MatMultHermitianTranspose(def->W, r, w2)); /* w2 <- W'*r */ 443 } 444 PetscCall(VecAXPY(w1, -1.0 * def->correctfact, w2)); /* w1 <- w1 - l*w2 */ 445 } 446 PetscCall(KSPSolve(def->WtAWinv, w1, w2)); /* w2 <- (W'*A*W)^{-1}*w1 */ 447 PetscCall(MatMult(def->W, w2, u)); /* u <- W*w2 */ 448 PetscCall(VecAXPY(z, -1.0, u)); /* z <- z - u */ 449 } 450 PetscFunctionReturn(PETSC_SUCCESS); 451 } 452 453 static PetscErrorCode PCSetUp_Deflation(PC pc) 454 { 455 PC_Deflation *def = (PC_Deflation *)pc->data; 456 DM dm; 457 KSP innerksp; 458 PC pcinner; 459 Mat Amat, nextDef = NULL, *mats; 460 PetscInt i, m, red, size; 461 PetscMPIInt commsize; 462 PetscBool match, flgspd, isset, transp = PETSC_FALSE; 463 MatCompositeType ctype; 464 MPI_Comm comm; 465 char prefix[128] = ""; 466 467 PetscFunctionBegin; 468 if (pc->setupcalled) PetscFunctionReturn(PETSC_SUCCESS); 469 PetscCall(PetscObjectGetComm((PetscObject)pc, &comm)); 470 PetscCall(PCGetOperators(pc, NULL, &Amat)); 471 if (!def->lvl && !def->prefix) PetscCall(PCGetOptionsPrefix(pc, &def->prefix)); 472 if (def->lvl) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%" PetscInt_FMT "_", def->lvl)); 473 474 /* compute a deflation space */ 475 if (def->W || def->Wt) { 476 def->spacetype = PC_DEFLATION_SPACE_USER; 477 } else { 478 PetscCall(PCDeflationComputeSpace(pc)); 479 } 480 481 /* nested deflation */ 482 if (def->W) { 483 PetscCall(PetscObjectTypeCompare((PetscObject)def->W, MATCOMPOSITE, &match)); 484 if (match) { 485 PetscCall(MatCompositeGetType(def->W, &ctype)); 486 PetscCall(MatCompositeGetNumberMat(def->W, &size)); 487 } 488 } else { 489 PetscCall(MatCreateHermitianTranspose(def->Wt, &def->W)); 490 PetscCall(PetscObjectTypeCompare((PetscObject)def->Wt, MATCOMPOSITE, &match)); 491 if (match) { 492 PetscCall(MatCompositeGetType(def->Wt, &ctype)); 493 PetscCall(MatCompositeGetNumberMat(def->Wt, &size)); 494 } 495 transp = PETSC_TRUE; 496 } 497 if (match && ctype == MAT_COMPOSITE_MULTIPLICATIVE) { 498 if (!transp) { 499 if (def->lvl < def->maxlvl) { 500 PetscCall(PetscMalloc1(size, &mats)); 501 for (i = 0; i < size; i++) PetscCall(MatCompositeGetMat(def->W, i, &mats[i])); 502 size -= 1; 503 PetscCall(MatDestroy(&def->W)); 504 def->W = mats[size]; 505 PetscCall(PetscObjectReference((PetscObject)mats[size])); 506 if (size > 1) { 507 PetscCall(MatCreateComposite(comm, size, mats, &nextDef)); 508 PetscCall(MatCompositeSetType(nextDef, MAT_COMPOSITE_MULTIPLICATIVE)); 509 } else { 510 nextDef = mats[0]; 511 PetscCall(PetscObjectReference((PetscObject)mats[0])); 512 } 513 PetscCall(PetscFree(mats)); 514 } else { 515 /* TODO test merge side performance */ 516 /* PetscCall(MatCompositeSetMergeType(def->W,MAT_COMPOSITE_MERGE_LEFT)); */ 517 PetscCall(MatCompositeMerge(def->W)); 518 } 519 } else { 520 if (def->lvl < def->maxlvl) { 521 PetscCall(PetscMalloc1(size, &mats)); 522 for (i = 0; i < size; i++) PetscCall(MatCompositeGetMat(def->Wt, i, &mats[i])); 523 size -= 1; 524 PetscCall(MatDestroy(&def->Wt)); 525 def->Wt = mats[0]; 526 PetscCall(PetscObjectReference((PetscObject)mats[0])); 527 if (size > 1) { 528 PetscCall(MatCreateComposite(comm, size, &mats[1], &nextDef)); 529 PetscCall(MatCompositeSetType(nextDef, MAT_COMPOSITE_MULTIPLICATIVE)); 530 } else { 531 nextDef = mats[1]; 532 PetscCall(PetscObjectReference((PetscObject)mats[1])); 533 } 534 PetscCall(PetscFree(mats)); 535 } else { 536 /* PetscCall(MatCompositeSetMergeType(def->W,MAT_COMPOSITE_MERGE_LEFT)); */ 537 PetscCall(MatCompositeMerge(def->Wt)); 538 } 539 } 540 } 541 542 if (transp) { 543 PetscCall(MatDestroy(&def->W)); 544 PetscCall(MatHermitianTranspose(def->Wt, MAT_INITIAL_MATRIX, &def->W)); 545 } 546 547 /* assemble WtA */ 548 if (!def->WtA) { 549 if (def->Wt) { 550 PetscCall(MatMatMult(def->Wt, Amat, MAT_INITIAL_MATRIX, PETSC_CURRENT, &def->WtA)); 551 } else { 552 #if defined(PETSC_USE_COMPLEX) 553 PetscCall(MatHermitianTranspose(def->W, MAT_INITIAL_MATRIX, &def->Wt)); 554 PetscCall(MatMatMult(def->Wt, Amat, MAT_INITIAL_MATRIX, PETSC_CURRENT, &def->WtA)); 555 #else 556 PetscCall(MatTransposeMatMult(def->W, Amat, MAT_INITIAL_MATRIX, PETSC_CURRENT, &def->WtA)); 557 #endif 558 } 559 } 560 /* setup coarse problem */ 561 if (!def->WtAWinv) { 562 PetscCall(MatGetSize(def->W, NULL, &m)); 563 if (!def->WtAW) { 564 PetscCall(MatMatMult(def->WtA, def->W, MAT_INITIAL_MATRIX, PETSC_CURRENT, &def->WtAW)); 565 /* TODO create MatInheritOption(Mat,MatOption) */ 566 PetscCall(MatIsSPDKnown(Amat, &isset, &flgspd)); 567 if (isset) PetscCall(MatSetOption(def->WtAW, MAT_SPD, flgspd)); 568 if (PetscDefined(USE_DEBUG)) { 569 /* Check columns of W are not in kernel of A */ 570 PetscReal *norms; 571 572 PetscCall(PetscMalloc1(m, &norms)); 573 PetscCall(MatGetColumnNorms(def->WtAW, NORM_INFINITY, norms)); 574 for (i = 0; i < m; i++) PetscCheck(norms[i] > 100 * PETSC_MACHINE_EPSILON, PetscObjectComm((PetscObject)def->WtAW), PETSC_ERR_SUP, "Column %" PetscInt_FMT " of W is in kernel of A.", i); 575 PetscCall(PetscFree(norms)); 576 } 577 } else PetscCall(MatIsSPDKnown(def->WtAW, &isset, &flgspd)); 578 579 /* TODO use MATINV ? */ 580 PetscCall(KSPCreate(comm, &def->WtAWinv)); 581 PetscCall(KSPSetNestLevel(def->WtAWinv, pc->kspnestlevel)); 582 PetscCall(KSPSetOperators(def->WtAWinv, def->WtAW, def->WtAW)); 583 PetscCall(KSPGetPC(def->WtAWinv, &pcinner)); 584 /* Setup KSP and PC */ 585 if (nextDef) { /* next level for multilevel deflation */ 586 innerksp = def->WtAWinv; 587 /* set default KSPtype */ 588 if (!def->ksptype) { 589 def->ksptype = KSPFGMRES; 590 if (isset && flgspd) { /* SPD system */ 591 def->ksptype = KSPFCG; 592 } 593 } 594 PetscCall(KSPSetType(innerksp, def->ksptype)); /* TODO iherit from KSP + tolerances */ 595 PetscCall(PCSetType(pcinner, PCDEFLATION)); /* TODO create coarse preconditinoner M_c = WtMW ? */ 596 PetscCall(PCDeflationSetSpace(pcinner, nextDef, transp)); 597 PetscCall(PCDeflationSetLevels_Deflation(pcinner, def->lvl + 1, def->maxlvl)); 598 /* inherit options */ 599 if (def->prefix) ((PC_Deflation *)pcinner->data)->prefix = def->prefix; 600 ((PC_Deflation *)pcinner->data)->init = def->init; 601 ((PC_Deflation *)pcinner->data)->ksptype = def->ksptype; 602 ((PC_Deflation *)pcinner->data)->correct = def->correct; 603 ((PC_Deflation *)pcinner->data)->correctfact = def->correctfact; 604 ((PC_Deflation *)pcinner->data)->reductionfact = def->reductionfact; 605 PetscCall(MatDestroy(&nextDef)); 606 } else { /* the last level */ 607 PetscCall(KSPSetType(def->WtAWinv, KSPPREONLY)); 608 PetscCall(PCSetType(pcinner, PCTELESCOPE)); 609 /* do not overwrite PCTELESCOPE */ 610 if (def->prefix) PetscCall(KSPSetOptionsPrefix(def->WtAWinv, def->prefix)); 611 PetscCall(KSPAppendOptionsPrefix(def->WtAWinv, "deflation_tel_")); 612 PetscCall(PCSetFromOptions(pcinner)); 613 PetscCall(PetscObjectTypeCompare((PetscObject)pcinner, PCTELESCOPE, &match)); 614 PetscCheck(match, comm, PETSC_ERR_SUP, "User can not overwrite PCTELESCOPE on bottom level, use reduction factor = 1 instead."); 615 /* Reduction factor choice */ 616 red = def->reductionfact; 617 if (red < 0) { 618 PetscCallMPI(MPI_Comm_size(comm, &commsize)); 619 red = PetscCeilInt(commsize, PetscCeilInt(m, commsize)); 620 PetscCall(PetscObjectTypeCompareAny((PetscObject)def->WtAW, &match, MATSEQDENSE, MATMPIDENSE, MATDENSE, "")); 621 if (match) red = commsize; 622 PetscCall(PetscInfo(pc, "Auto choosing reduction factor %" PetscInt_FMT "\n", red)); 623 } 624 PetscCall(PCTelescopeSetReductionFactor(pcinner, red)); 625 PetscCall(PCSetUp(pcinner)); 626 PetscCall(PCTelescopeGetKSP(pcinner, &innerksp)); 627 if (innerksp) { 628 PetscCall(KSPGetPC(innerksp, &pcinner)); 629 PetscCall(PCSetType(pcinner, PCLU)); 630 #if defined(PETSC_HAVE_SUPERLU) 631 PetscCall(MatGetFactorAvailable(def->WtAW, MATSOLVERSUPERLU, MAT_FACTOR_LU, &match)); 632 if (match) PetscCall(PCFactorSetMatSolverType(pcinner, MATSOLVERSUPERLU)); 633 #endif 634 #if defined(PETSC_HAVE_SUPERLU_DIST) 635 PetscCall(MatGetFactorAvailable(def->WtAW, MATSOLVERSUPERLU_DIST, MAT_FACTOR_LU, &match)); 636 if (match) PetscCall(PCFactorSetMatSolverType(pcinner, MATSOLVERSUPERLU_DIST)); 637 #endif 638 } 639 } 640 641 if (innerksp) { 642 if (def->prefix) { 643 PetscCall(KSPSetOptionsPrefix(innerksp, def->prefix)); 644 PetscCall(KSPAppendOptionsPrefix(innerksp, "deflation_")); 645 } else { 646 PetscCall(KSPSetOptionsPrefix(innerksp, "deflation_")); 647 } 648 PetscCall(KSPAppendOptionsPrefix(innerksp, prefix)); 649 PetscCall(KSPSetFromOptions(innerksp)); 650 PetscCall(KSPSetUp(innerksp)); 651 } 652 } 653 PetscCall(KSPSetFromOptions(def->WtAWinv)); 654 PetscCall(KSPSetUp(def->WtAWinv)); 655 656 /* create preconditioner */ 657 if (!def->pc) { 658 PetscCall(PCCreate(comm, &def->pc)); 659 PetscCall(PCSetOperators(def->pc, Amat, Amat)); 660 PetscCall(PCSetType(def->pc, PCNONE)); 661 if (def->prefix) PetscCall(PCSetOptionsPrefix(def->pc, def->prefix)); 662 PetscCall(PCAppendOptionsPrefix(def->pc, "deflation_")); 663 PetscCall(PCAppendOptionsPrefix(def->pc, prefix)); 664 PetscCall(PCAppendOptionsPrefix(def->pc, "pc_")); 665 PetscCall(PCGetDM(pc, &dm)); 666 PetscCall(PCSetDM(def->pc, dm)); 667 PetscCall(PCSetFromOptions(def->pc)); 668 PetscCall(PCSetUp(def->pc)); 669 } 670 671 /* create work vecs */ 672 PetscCall(MatCreateVecs(Amat, NULL, &def->work)); 673 PetscCall(KSPCreateVecs(def->WtAWinv, 2, &def->workcoarse, 0, NULL)); 674 PetscFunctionReturn(PETSC_SUCCESS); 675 } 676 677 static PetscErrorCode PCReset_Deflation(PC pc) 678 { 679 PC_Deflation *def = (PC_Deflation *)pc->data; 680 681 PetscFunctionBegin; 682 PetscCall(VecDestroy(&def->work)); 683 PetscCall(VecDestroyVecs(2, &def->workcoarse)); 684 PetscCall(MatDestroy(&def->W)); 685 PetscCall(MatDestroy(&def->Wt)); 686 PetscCall(MatDestroy(&def->WtA)); 687 PetscCall(MatDestroy(&def->WtAW)); 688 PetscCall(KSPDestroy(&def->WtAWinv)); 689 PetscCall(PCDestroy(&def->pc)); 690 PetscFunctionReturn(PETSC_SUCCESS); 691 } 692 693 static PetscErrorCode PCDestroy_Deflation(PC pc) 694 { 695 PetscFunctionBegin; 696 PetscCall(PCReset_Deflation(pc)); 697 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetInitOnly_C", NULL)); 698 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetLevels_C", NULL)); 699 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetReductionFactor_C", NULL)); 700 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetCorrectionFactor_C", NULL)); 701 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetSpaceToCompute_C", NULL)); 702 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetSpace_C", NULL)); 703 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetProjectionNullSpaceMat_C", NULL)); 704 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetCoarseMat_C", NULL)); 705 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationGetCoarseKSP_C", NULL)); 706 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationGetPC_C", NULL)); 707 PetscCall(PetscFree(pc->data)); 708 PetscFunctionReturn(PETSC_SUCCESS); 709 } 710 711 static PetscErrorCode PCView_Deflation(PC pc, PetscViewer viewer) 712 { 713 PC_Deflation *def = (PC_Deflation *)pc->data; 714 PetscInt its; 715 PetscBool isascii; 716 717 PetscFunctionBegin; 718 if (!pc->setupcalled) PetscFunctionReturn(PETSC_SUCCESS); 719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 720 if (isascii) { 721 if (def->correct) PetscCall(PetscViewerASCIIPrintf(viewer, "using CP correction, factor = %g+%gi\n", (double)PetscRealPart(def->correctfact), (double)PetscImaginaryPart(def->correctfact))); 722 if (!def->lvl) PetscCall(PetscViewerASCIIPrintf(viewer, "deflation space type: %s\n", PCDeflationSpaceTypes[def->spacetype])); 723 724 PetscCall(PetscViewerASCIIPrintf(viewer, "--- Additional PC:\n")); 725 PetscCall(PetscViewerASCIIPushTab(viewer)); 726 PetscCall(PCView(def->pc, viewer)); 727 PetscCall(PetscViewerASCIIPopTab(viewer)); 728 729 PetscCall(PetscViewerASCIIPrintf(viewer, "--- Coarse problem solver:\n")); 730 PetscCall(PetscViewerASCIIPushTab(viewer)); 731 PetscCall(KSPGetTotalIterations(def->WtAWinv, &its)); 732 PetscCall(PetscViewerASCIIPrintf(viewer, "total number of iterations: %" PetscInt_FMT "\n", its)); 733 PetscCall(KSPView(def->WtAWinv, viewer)); 734 PetscCall(PetscViewerASCIIPopTab(viewer)); 735 } 736 PetscFunctionReturn(PETSC_SUCCESS); 737 } 738 739 static PetscErrorCode PCSetFromOptions_Deflation(PC pc, PetscOptionItems PetscOptionsObject) 740 { 741 PC_Deflation *def = (PC_Deflation *)pc->data; 742 743 PetscFunctionBegin; 744 PetscOptionsHeadBegin(PetscOptionsObject, "Deflation options"); 745 PetscCall(PetscOptionsBool("-pc_deflation_init_only", "Use only initialization step - Initdef", "PCDeflationSetInitOnly", def->init, &def->init, NULL)); 746 PetscCall(PetscOptionsInt("-pc_deflation_levels", "Maximum of deflation levels", "PCDeflationSetLevels", def->maxlvl, &def->maxlvl, NULL)); 747 PetscCall(PetscOptionsInt("-pc_deflation_reduction_factor", "Reduction factor for coarse problem solution using PCTELESCOPE", "PCDeflationSetReductionFactor", def->reductionfact, &def->reductionfact, NULL)); 748 PetscCall(PetscOptionsBool("-pc_deflation_correction", "Add coarse problem correction Q to P", "PCDeflationSetCorrectionFactor", def->correct, &def->correct, NULL)); 749 PetscCall(PetscOptionsScalar("-pc_deflation_correction_factor", "Set multiple of Q to use as coarse problem correction", "PCDeflationSetCorrectionFactor", def->correctfact, &def->correctfact, NULL)); 750 PetscCall(PetscOptionsEnum("-pc_deflation_compute_space", "Compute deflation space", "PCDeflationSetSpace", PCDeflationSpaceTypes, (PetscEnum)def->spacetype, (PetscEnum *)&def->spacetype, NULL)); 751 PetscCall(PetscOptionsInt("-pc_deflation_compute_space_size", "Set size of the deflation space to compute", "PCDeflationSetSpace", def->spacesize, &def->spacesize, NULL)); 752 PetscCall(PetscOptionsBool("-pc_deflation_space_extend", "Extend deflation space instead of truncating (wavelets)", "PCDeflation", def->extendsp, &def->extendsp, NULL)); 753 PetscOptionsHeadEnd(); 754 PetscFunctionReturn(PETSC_SUCCESS); 755 } 756 757 /*MC 758 PCDEFLATION - Deflation preconditioner shifts (deflates) part of the spectrum to zero or to a predefined value. 759 760 Options Database Keys: 761 + -pc_deflation_init_only <false> - if true computes only the special guess 762 . -pc_deflation_max_lvl <0> - maximum number of levels for multilevel deflation 763 . -pc_deflation_reduction_factor <\-1> - reduction factor on bottom level coarse problem for PCTELESCOPE (default based on the size of the coarse problem) 764 . -pc_deflation_correction <false> - if true apply coarse problem correction 765 . -pc_deflation_correction_factor <1.0> - sets coarse problem correction factor 766 . -pc_deflation_compute_space <haar> - compute PCDeflationSpaceType deflation space 767 - -pc_deflation_compute_space_size <1> - size of the deflation space (corresponds to number of levels for wavelet-based deflation) 768 769 Notes: 770 Given a (complex - transpose is always Hermitian) full rank deflation matrix W, the deflation (introduced in [1,2]) 771 preconditioner uses projections Q = W*(W'*A*W)^{-1}*W' and P = I - Q*A, where A is pmat. 772 773 The deflation computes initial guess x0 = x_{-1} - Q*r_{-1}, which is the solution on the deflation space. 774 If `PCDeflationSetInitOnly()` or -pc_deflation_init_only is set to `PETSC_TRUE` (InitDef scheme), the application of the 775 preconditioner consists only of application of the additional preconditioner M^{-1}. Otherwise, the preconditioner 776 application consists of P*M^{-1} + factor*Q. The first part of the preconditioner (PM^{-1}) shifts some eigenvalues 777 to zero while the addition of the coarse problem correction (factor*Q) makes the preconditioner to shift some 778 eigenvalues to the given factor. The InitDef scheme is recommended for deflation using high accuracy estimates 779 of eigenvectors of A when it exhibits similar convergence to the full deflation but is cheaper. 780 781 The deflation matrix is by default automatically computed. The type of deflation matrix and its size to compute can 782 be controlled by `PCDeflationSetSpaceToCompute()` or -pc_deflation_compute_space and -pc_deflation_compute_space_size. 783 User can set an arbitrary deflation space matrix with `PCDeflationSetSpace()`. If the deflation matrix 784 is a multiplicative `MATCOMPOSITE`, a multilevel deflation [3] is used. The first matrix in the composite is used as the 785 deflation matrix, and the coarse problem (W'*A*W)^{-1} is solved by `KSPFCG` (if A is `MAT_SPD`) or `KSPFGMRES` preconditioned 786 by deflation with deflation matrix being the next matrix in the `MATCOMPOSITE`. This scheme repeats until the maximum 787 level is reached or there are no more matrices. If the maximum level is reached, the remaining matrices are merged 788 (multiplied) to create the last deflation matrix. The maximum level defaults to 0 and can be set by 789 `PCDeflationSetLevels()` or by -pc_deflation_levels. 790 791 The coarse problem `KSP` can be controlled from the command line with prefix -deflation_ for the first level and -deflation_[lvl-1] 792 from the second level onward. You can also use 793 `PCDeflationGetCoarseKSP()` to control it from code. The bottom level KSP defaults to 794 `KSPPREONLY` with `PCLU` direct solver (`MATSOLVERSUPERLU`/`MATSOLVERSUPERLU_DIST` if available) wrapped into `PCTELESCOPE`. 795 For convenience, the reduction factor can be set by `PCDeflationSetReductionFactor()` 796 or -pc_deflation_recduction_factor. The default is chosen heuristically based on the coarse problem size. 797 798 The additional preconditioner can be controlled from command line with prefix -deflation_[lvl]_pc (same rules used for 799 coarse problem `KSP` apply for [lvl]_ part of prefix), e.g., -deflation_1_pc_pc_type bjacobi. You can also use 800 `PCDeflationGetPC()` to control the additional preconditioner from code. It defaults to `PCNONE`. 801 802 The coarse problem correction term (factor*Q) can be turned on by -pc_deflation_correction and the factor value can 803 be set by pc_deflation_correction_factor or by `PCDeflationSetCorrectionFactor()`. The coarse problem can 804 significantly improve convergence when the deflation coarse problem is not solved with high enough accuracy. We 805 recommend setting factor to some eigenvalue, e.g., the largest eigenvalue so that the preconditioner does not create 806 an isolated eigenvalue. 807 808 The options are automatically inherited from the previous deflation level. 809 810 The preconditioner supports `KSPMonitorDynamicTolerance()`. This is useful for the multilevel scheme for which we also 811 recommend limiting the number of iterations for the coarse problems. 812 813 See section 3 of [4] for additional references and description of the algorithm when used for conjugate gradients. 814 Section 4 describes some possible choices for the deflation space. 815 816 Contributed by Jakub Kruzik (PERMON), Institute of Geonics of the Czech 817 Academy of Sciences and VSB - TU Ostrava. 818 819 Developed from PERMON code used in [4] while on a research stay with 820 Prof. Reinhard Nabben at the Institute of Mathematics, TU Berlin. 821 822 References: 823 + * - A. Nicolaides. "Deflation of conjugate gradients with applications to boundary value problems", SIAM J. Numer. Anal. 24.2, 1987. 824 . * - Z. Dostal. "Conjugate gradient method with preconditioning by projector", Int J. Comput. Math. 23.3-4, 1988. 825 . * - Y. A. Erlangga and R. Nabben. "Multilevel Projection-Based Nested Krylov Iteration for Boundary Value Problems", SIAM J. Sci. Comput. 30.3, 2008. 826 - * - J. Kruzik "Implementation of the Deflated Variants of the Conjugate Gradient Method", Master's thesis, VSB-TUO, 2018 - http://dspace5.vsb.cz/bitstream/handle/10084/130303/KRU0097_USP_N2658_2612T078_2018.pdf 827 828 Level: intermediate 829 830 .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`, 831 `PCDeflationSetInitOnly()`, `PCDeflationSetLevels()`, `PCDeflationSetReductionFactor()`, 832 `PCDeflationSetCorrectionFactor()`, `PCDeflationSetSpaceToCompute()`, 833 `PCDeflationSetSpace()`, `PCDeflationSpaceType`, `PCDeflationSetProjectionNullSpaceMat()`, 834 `PCDeflationSetCoarseMat()`, `PCDeflationGetCoarseKSP()`, `PCDeflationGetPC()` 835 M*/ 836 837 PETSC_EXTERN PetscErrorCode PCCreate_Deflation(PC pc) 838 { 839 PC_Deflation *def; 840 841 PetscFunctionBegin; 842 PetscCall(PetscNew(&def)); 843 pc->data = (void *)def; 844 845 def->init = PETSC_FALSE; 846 def->correct = PETSC_FALSE; 847 def->correctfact = 1.0; 848 def->reductionfact = -1; 849 def->spacetype = PC_DEFLATION_SPACE_HAAR; 850 def->spacesize = 1; 851 def->extendsp = PETSC_FALSE; 852 def->lvl = 0; 853 def->maxlvl = 0; 854 def->W = NULL; 855 def->Wt = NULL; 856 857 pc->ops->apply = PCApply_Deflation; 858 pc->ops->presolve = PCPreSolve_Deflation; 859 pc->ops->setup = PCSetUp_Deflation; 860 pc->ops->reset = PCReset_Deflation; 861 pc->ops->destroy = PCDestroy_Deflation; 862 pc->ops->setfromoptions = PCSetFromOptions_Deflation; 863 pc->ops->view = PCView_Deflation; 864 865 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetInitOnly_C", PCDeflationSetInitOnly_Deflation)); 866 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetLevels_C", PCDeflationSetLevels_Deflation)); 867 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetReductionFactor_C", PCDeflationSetReductionFactor_Deflation)); 868 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetCorrectionFactor_C", PCDeflationSetCorrectionFactor_Deflation)); 869 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetSpaceToCompute_C", PCDeflationSetSpaceToCompute_Deflation)); 870 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetSpace_C", PCDeflationSetSpace_Deflation)); 871 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetProjectionNullSpaceMat_C", PCDeflationSetProjectionNullSpaceMat_Deflation)); 872 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetCoarseMat_C", PCDeflationSetCoarseMat_Deflation)); 873 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationGetCoarseKSP_C", PCDeflationGetCoarseKSP_Deflation)); 874 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationGetPC_C", PCDeflationGetPC_Deflation)); 875 PetscFunctionReturn(PETSC_SUCCESS); 876 } 877