1 #include <../src/ksp/pc/impls/deflation/deflation.h> /*I "petscksp.h" I*/ /* includes 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: `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: `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: `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: `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: `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 Notes: 226 Setting W as a multipliplicative `MATCOMPOSITE` enables use of the multilevel 227 deflation. If W = W0*W1*W2*...*Wn, W0 is taken as the first deflation space and 228 the coarse problem (W0'*A*W0)^{-1} is again preconditioned by deflation with 229 W1 as the deflation matrix. This repeats until the maximum level set by 230 PCDeflationSetLevels() is reached or there are no more matrices available. 231 If there are matrices left after reaching the maximum level, 232 they are merged into a deflation matrix ...*W{n-1}*Wn. 233 234 Level: intermediate 235 236 .seealso: `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: `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: `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: `PCDEFLATION`, `PCDeflationSetCoarseMat()` 337 @*/ 338 PetscErrorCode PCDeflationGetCoarseKSP(PC pc, KSP *ksp) 339 { 340 PetscFunctionBegin; 341 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 342 PetscValidPointer(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: `PCDEFLATION`, `PCDeflationGetCoarseKSP()` 370 @*/ 371 PetscErrorCode PCDeflationGetPC(PC pc, PC *apc) 372 { 373 PetscFunctionBegin; 374 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 375 PetscValidPointer(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), "%d_", (int)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_DEFAULT, &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_DEFAULT, &def->WtA)); 555 #else 556 PetscCall(MatTransposeMatMult(def->W, Amat, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &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_DEFAULT, &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(KSPSetOperators(def->WtAWinv, def->WtAW, def->WtAW)); 582 PetscCall(KSPGetPC(def->WtAWinv, &pcinner)); 583 /* Setup KSP and PC */ 584 if (nextDef) { /* next level for multilevel deflation */ 585 innerksp = def->WtAWinv; 586 /* set default KSPtype */ 587 if (!def->ksptype) { 588 def->ksptype = KSPFGMRES; 589 if (isset && flgspd) { /* SPD system */ 590 def->ksptype = KSPFCG; 591 } 592 } 593 PetscCall(KSPSetType(innerksp, def->ksptype)); /* TODO iherit from KSP + tolerances */ 594 PetscCall(PCSetType(pcinner, PCDEFLATION)); /* TODO create coarse preconditinoner M_c = WtMW ? */ 595 PetscCall(PCDeflationSetSpace(pcinner, nextDef, transp)); 596 PetscCall(PCDeflationSetLevels_Deflation(pcinner, def->lvl + 1, def->maxlvl)); 597 /* inherit options */ 598 if (def->prefix) ((PC_Deflation *)(pcinner->data))->prefix = def->prefix; 599 ((PC_Deflation *)(pcinner->data))->init = def->init; 600 ((PC_Deflation *)(pcinner->data))->ksptype = def->ksptype; 601 ((PC_Deflation *)(pcinner->data))->correct = def->correct; 602 ((PC_Deflation *)(pcinner->data))->correctfact = def->correctfact; 603 ((PC_Deflation *)(pcinner->data))->reductionfact = def->reductionfact; 604 PetscCall(MatDestroy(&nextDef)); 605 } else { /* the last level */ 606 PetscCall(KSPSetType(def->WtAWinv, KSPPREONLY)); 607 PetscCall(PCSetType(pcinner, PCTELESCOPE)); 608 /* do not overwrite PCTELESCOPE */ 609 if (def->prefix) PetscCall(KSPSetOptionsPrefix(def->WtAWinv, def->prefix)); 610 PetscCall(KSPAppendOptionsPrefix(def->WtAWinv, "deflation_tel_")); 611 PetscCall(PCSetFromOptions(pcinner)); 612 PetscCall(PetscObjectTypeCompare((PetscObject)pcinner, PCTELESCOPE, &match)); 613 PetscCheck(match, comm, PETSC_ERR_SUP, "User can not overwrite PCTELESCOPE on bottom level, use reduction factor = 1 instead."); 614 /* Reduction factor choice */ 615 red = def->reductionfact; 616 if (red < 0) { 617 PetscCallMPI(MPI_Comm_size(comm, &commsize)); 618 red = PetscCeilInt(commsize, PetscCeilInt(m, commsize)); 619 PetscCall(PetscObjectTypeCompareAny((PetscObject)(def->WtAW), &match, MATSEQDENSE, MATMPIDENSE, MATDENSE, "")); 620 if (match) red = commsize; 621 PetscCall(PetscInfo(pc, "Auto choosing reduction factor %" PetscInt_FMT "\n", red)); 622 } 623 PetscCall(PCTelescopeSetReductionFactor(pcinner, red)); 624 PetscCall(PCSetUp(pcinner)); 625 PetscCall(PCTelescopeGetKSP(pcinner, &innerksp)); 626 if (innerksp) { 627 PetscCall(KSPGetPC(innerksp, &pcinner)); 628 PetscCall(PCSetType(pcinner, PCLU)); 629 #if defined(PETSC_HAVE_SUPERLU) 630 PetscCall(MatGetFactorAvailable(def->WtAW, MATSOLVERSUPERLU, MAT_FACTOR_LU, &match)); 631 if (match) PetscCall(PCFactorSetMatSolverType(pcinner, MATSOLVERSUPERLU)); 632 #endif 633 #if defined(PETSC_HAVE_SUPERLU_DIST) 634 PetscCall(MatGetFactorAvailable(def->WtAW, MATSOLVERSUPERLU_DIST, MAT_FACTOR_LU, &match)); 635 if (match) PetscCall(PCFactorSetMatSolverType(pcinner, MATSOLVERSUPERLU_DIST)); 636 #endif 637 } 638 } 639 640 if (innerksp) { 641 if (def->prefix) { 642 PetscCall(KSPSetOptionsPrefix(innerksp, def->prefix)); 643 PetscCall(KSPAppendOptionsPrefix(innerksp, "deflation_")); 644 } else { 645 PetscCall(KSPSetOptionsPrefix(innerksp, "deflation_")); 646 } 647 PetscCall(KSPAppendOptionsPrefix(innerksp, prefix)); 648 PetscCall(KSPSetFromOptions(innerksp)); 649 PetscCall(KSPSetUp(innerksp)); 650 } 651 } 652 PetscCall(KSPSetFromOptions(def->WtAWinv)); 653 PetscCall(KSPSetUp(def->WtAWinv)); 654 655 /* create preconditioner */ 656 if (!def->pc) { 657 PetscCall(PCCreate(comm, &def->pc)); 658 PetscCall(PCSetOperators(def->pc, Amat, Amat)); 659 PetscCall(PCSetType(def->pc, PCNONE)); 660 if (def->prefix) PetscCall(PCSetOptionsPrefix(def->pc, def->prefix)); 661 PetscCall(PCAppendOptionsPrefix(def->pc, "deflation_")); 662 PetscCall(PCAppendOptionsPrefix(def->pc, prefix)); 663 PetscCall(PCAppendOptionsPrefix(def->pc, "pc_")); 664 PetscCall(PCGetDM(pc, &dm)); 665 PetscCall(PCSetDM(def->pc, dm)); 666 PetscCall(PCSetFromOptions(def->pc)); 667 PetscCall(PCSetUp(def->pc)); 668 } 669 670 /* create work vecs */ 671 PetscCall(MatCreateVecs(Amat, NULL, &def->work)); 672 PetscCall(KSPCreateVecs(def->WtAWinv, 2, &def->workcoarse, 0, NULL)); 673 PetscFunctionReturn(PETSC_SUCCESS); 674 } 675 676 static PetscErrorCode PCReset_Deflation(PC pc) 677 { 678 PC_Deflation *def = (PC_Deflation *)pc->data; 679 680 PetscFunctionBegin; 681 PetscCall(VecDestroy(&def->work)); 682 PetscCall(VecDestroyVecs(2, &def->workcoarse)); 683 PetscCall(MatDestroy(&def->W)); 684 PetscCall(MatDestroy(&def->Wt)); 685 PetscCall(MatDestroy(&def->WtA)); 686 PetscCall(MatDestroy(&def->WtAW)); 687 PetscCall(KSPDestroy(&def->WtAWinv)); 688 PetscCall(PCDestroy(&def->pc)); 689 PetscFunctionReturn(PETSC_SUCCESS); 690 } 691 692 static PetscErrorCode PCDestroy_Deflation(PC pc) 693 { 694 PetscFunctionBegin; 695 PetscCall(PCReset_Deflation(pc)); 696 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetInitOnly_C", NULL)); 697 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetLevels_C", NULL)); 698 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetReductionFactor_C", NULL)); 699 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetCorrectionFactor_C", NULL)); 700 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetSpaceToCompute_C", NULL)); 701 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetSpace_C", NULL)); 702 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetProjectionNullSpaceMat_C", NULL)); 703 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetCoarseMat_C", NULL)); 704 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationGetCoarseKSP_C", NULL)); 705 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationGetPC_C", NULL)); 706 PetscCall(PetscFree(pc->data)); 707 PetscFunctionReturn(PETSC_SUCCESS); 708 } 709 710 static PetscErrorCode PCView_Deflation(PC pc, PetscViewer viewer) 711 { 712 PC_Deflation *def = (PC_Deflation *)pc->data; 713 PetscInt its; 714 PetscBool iascii; 715 716 PetscFunctionBegin; 717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 718 if (iascii) { 719 if (def->correct) PetscCall(PetscViewerASCIIPrintf(viewer, "using CP correction, factor = %g+%gi\n", (double)PetscRealPart(def->correctfact), (double)PetscImaginaryPart(def->correctfact))); 720 if (!def->lvl) PetscCall(PetscViewerASCIIPrintf(viewer, "deflation space type: %s\n", PCDeflationSpaceTypes[def->spacetype])); 721 722 PetscCall(PetscViewerASCIIPrintf(viewer, "--- Additional PC:\n")); 723 PetscCall(PetscViewerASCIIPushTab(viewer)); 724 PetscCall(PCView(def->pc, viewer)); 725 PetscCall(PetscViewerASCIIPopTab(viewer)); 726 727 PetscCall(PetscViewerASCIIPrintf(viewer, "--- Coarse problem solver:\n")); 728 PetscCall(PetscViewerASCIIPushTab(viewer)); 729 PetscCall(KSPGetTotalIterations(def->WtAWinv, &its)); 730 PetscCall(PetscViewerASCIIPrintf(viewer, "total number of iterations: %" PetscInt_FMT "\n", its)); 731 PetscCall(KSPView(def->WtAWinv, viewer)); 732 PetscCall(PetscViewerASCIIPopTab(viewer)); 733 } 734 PetscFunctionReturn(PETSC_SUCCESS); 735 } 736 737 static PetscErrorCode PCSetFromOptions_Deflation(PC pc, PetscOptionItems *PetscOptionsObject) 738 { 739 PC_Deflation *def = (PC_Deflation *)pc->data; 740 741 PetscFunctionBegin; 742 PetscOptionsHeadBegin(PetscOptionsObject, "Deflation options"); 743 PetscCall(PetscOptionsBool("-pc_deflation_init_only", "Use only initialization step - Initdef", "PCDeflationSetInitOnly", def->init, &def->init, NULL)); 744 PetscCall(PetscOptionsInt("-pc_deflation_levels", "Maximum of deflation levels", "PCDeflationSetLevels", def->maxlvl, &def->maxlvl, NULL)); 745 PetscCall(PetscOptionsInt("-pc_deflation_reduction_factor", "Reduction factor for coarse problem solution using PCTELESCOPE", "PCDeflationSetReductionFactor", def->reductionfact, &def->reductionfact, NULL)); 746 PetscCall(PetscOptionsBool("-pc_deflation_correction", "Add coarse problem correction Q to P", "PCDeflationSetCorrectionFactor", def->correct, &def->correct, NULL)); 747 PetscCall(PetscOptionsScalar("-pc_deflation_correction_factor", "Set multiple of Q to use as coarse problem correction", "PCDeflationSetCorrectionFactor", def->correctfact, &def->correctfact, NULL)); 748 PetscCall(PetscOptionsEnum("-pc_deflation_compute_space", "Compute deflation space", "PCDeflationSetSpace", PCDeflationSpaceTypes, (PetscEnum)def->spacetype, (PetscEnum *)&def->spacetype, NULL)); 749 PetscCall(PetscOptionsInt("-pc_deflation_compute_space_size", "Set size of the deflation space to compute", "PCDeflationSetSpace", def->spacesize, &def->spacesize, NULL)); 750 PetscCall(PetscOptionsBool("-pc_deflation_space_extend", "Extend deflation space instead of truncating (wavelets)", "PCDeflation", def->extendsp, &def->extendsp, NULL)); 751 PetscOptionsHeadEnd(); 752 PetscFunctionReturn(PETSC_SUCCESS); 753 } 754 755 /*MC 756 PCDEFLATION - Deflation preconditioner shifts (deflates) part of the spectrum to zero or to a predefined value. 757 758 Options Database Keys: 759 + -pc_deflation_init_only <false> - if true computes only the special guess 760 . -pc_deflation_max_lvl <0> - maximum number of levels for multilevel deflation 761 . -pc_deflation_reduction_factor <\-1> - reduction factor on bottom level coarse problem for PCTELESCOPE (default based on the size of the coarse problem) 762 . -pc_deflation_correction <false> - if true apply coarse problem correction 763 . -pc_deflation_correction_factor <1.0> - sets coarse problem correction factor 764 . -pc_deflation_compute_space <haar> - compute PCDeflationSpaceType deflation space 765 - -pc_deflation_compute_space_size <1> - size of the deflation space (corresponds to number of levels for wavelet-based deflation) 766 767 Notes: 768 Given a (complex - transpose is always Hermitian) full rank deflation matrix W, the deflation (introduced in [1,2]) 769 preconditioner uses projections Q = W*(W'*A*W)^{-1}*W' and P = I - Q*A, where A is pmat. 770 771 The deflation computes initial guess x0 = x_{-1} - Q*r_{-1}, which is the solution on the deflation space. 772 If `PCDeflationSetInitOnly()` or -pc_deflation_init_only is set to `PETSC_TRUE` (InitDef scheme), the application of the 773 preconditioner consists only of application of the additional preconditioner M^{-1}. Otherwise, the preconditioner 774 application consists of P*M^{-1} + factor*Q. The first part of the preconditioner (PM^{-1}) shifts some eigenvalues 775 to zero while the addition of the coarse problem correction (factor*Q) makes the preconditioner to shift some 776 eigenvalues to the given factor. The InitDef scheme is recommended for deflation using high accuracy estimates 777 of eigenvectors of A when it exhibits similar convergence to the full deflation but is cheaper. 778 779 The deflation matrix is by default automatically computed. The type of deflation matrix and its size to compute can 780 be controlled by `PCDeflationSetSpaceToCompute()` or -pc_deflation_compute_space and -pc_deflation_compute_space_size. 781 User can set an arbitrary deflation space matrix with `PCDeflationSetSpace()`. If the deflation matrix 782 is a multiplicative `MATCOMPOSITE`, a multilevel deflation [3] is used. The first matrix in the composite is used as the 783 deflation matrix, and the coarse problem (W'*A*W)^{-1} is solved by `KSPFCG` (if A is `MAT_SPD`) or `KSPFGMRES` preconditioned 784 by deflation with deflation matrix being the next matrix in the `MATCOMPOSITE`. This scheme repeats until the maximum 785 level is reached or there are no more matrices. If the maximum level is reached, the remaining matrices are merged 786 (multiplied) to create the last deflation matrix. The maximum level defaults to 0 and can be set by 787 `PCDeflationSetLevels()` or by -pc_deflation_levels. 788 789 The coarse problem `KSP` can be controlled from the command line with prefix -deflation_ for the first level and -deflation_[lvl-1] 790 from the second level onward. You can also use 791 `PCDeflationGetCoarseKSP()` to control it from code. The bottom level KSP defaults to 792 `KSPPREONLY` with `PCLU` direct solver (`MATSOLVERSUPERLU`/`MATSOLVERSUPERLU_DIST` if available) wrapped into `PCTELESCOPE`. 793 For convenience, the reduction factor can be set by `PCDeflationSetReductionFactor()` 794 or -pc_deflation_recduction_factor. The default is chosen heuristically based on the coarse problem size. 795 796 The additional preconditioner can be controlled from command line with prefix -deflation_[lvl]_pc (same rules used for 797 coarse problem `KSP` apply for [lvl]_ part of prefix), e.g., -deflation_1_pc_pc_type bjacobi. You can also use 798 `PCDeflationGetPC()` to control the additional preconditioner from code. It defaults to `PCNONE`. 799 800 The coarse problem correction term (factor*Q) can be turned on by -pc_deflation_correction and the factor value can 801 be set by pc_deflation_correction_factor or by `PCDeflationSetCorrectionFactor()`. The coarse problem can 802 significantly improve convergence when the deflation coarse problem is not solved with high enough accuracy. We 803 recommend setting factor to some eigenvalue, e.g., the largest eigenvalue so that the preconditioner does not create 804 an isolated eigenvalue. 805 806 The options are automatically inherited from the previous deflation level. 807 808 The preconditioner supports `KSPMonitorDynamicTolerance()`. This is useful for the multilevel scheme for which we also 809 recommend limiting the number of iterations for the coarse problems. 810 811 See section 3 of [4] for additional references and decription of the algorithm when used for conjugate gradients. 812 Section 4 describes some possible choices for the deflation space. 813 814 Contributed by Jakub Kruzik (PERMON), Institute of Geonics of the Czech 815 Academy of Sciences and VSB - TU Ostrava. 816 817 Developed from PERMON code used in [4] while on a research stay with 818 Prof. Reinhard Nabben at the Institute of Mathematics, TU Berlin. 819 820 References: 821 + * - A. Nicolaides. "Deflation of conjugate gradients with applications to boundary value problems", SIAM J. Numer. Anal. 24.2, 1987. 822 . * - Z. Dostal. "Conjugate gradient method with preconditioning by projector", Int J. Comput. Math. 23.3-4, 1988. 823 . * - Y. A. Erlangga and R. Nabben. "Multilevel Projection-Based Nested Krylov Iteration for Boundary Value Problems", SIAM J. Sci. Comput. 30.3, 2008. 824 - * - 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 825 826 Level: intermediate 827 828 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, 829 `PCDeflationSetInitOnly()`, `PCDeflationSetLevels()`, `PCDeflationSetReductionFactor()`, 830 `PCDeflationSetCorrectionFactor()`, `PCDeflationSetSpaceToCompute()`, 831 `PCDeflationSetSpace()`, `PCDeflationSpaceType`, `PCDeflationSetProjectionNullSpaceMat()`, 832 `PCDeflationSetCoarseMat()`, `PCDeflationGetCoarseKSP()`, `PCDeflationGetPC()` 833 M*/ 834 835 PETSC_EXTERN PetscErrorCode PCCreate_Deflation(PC pc) 836 { 837 PC_Deflation *def; 838 839 PetscFunctionBegin; 840 PetscCall(PetscNew(&def)); 841 pc->data = (void *)def; 842 843 def->init = PETSC_FALSE; 844 def->correct = PETSC_FALSE; 845 def->correctfact = 1.0; 846 def->reductionfact = -1; 847 def->spacetype = PC_DEFLATION_SPACE_HAAR; 848 def->spacesize = 1; 849 def->extendsp = PETSC_FALSE; 850 def->lvl = 0; 851 def->maxlvl = 0; 852 def->W = NULL; 853 def->Wt = NULL; 854 855 pc->ops->apply = PCApply_Deflation; 856 pc->ops->presolve = PCPreSolve_Deflation; 857 pc->ops->setup = PCSetUp_Deflation; 858 pc->ops->reset = PCReset_Deflation; 859 pc->ops->destroy = PCDestroy_Deflation; 860 pc->ops->setfromoptions = PCSetFromOptions_Deflation; 861 pc->ops->view = PCView_Deflation; 862 863 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetInitOnly_C", PCDeflationSetInitOnly_Deflation)); 864 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetLevels_C", PCDeflationSetLevels_Deflation)); 865 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetReductionFactor_C", PCDeflationSetReductionFactor_Deflation)); 866 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetCorrectionFactor_C", PCDeflationSetCorrectionFactor_Deflation)); 867 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetSpaceToCompute_C", PCDeflationSetSpaceToCompute_Deflation)); 868 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetSpace_C", PCDeflationSetSpace_Deflation)); 869 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetProjectionNullSpaceMat_C", PCDeflationSetProjectionNullSpaceMat_Deflation)); 870 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationSetCoarseMat_C", PCDeflationSetCoarseMat_Deflation)); 871 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationGetCoarseKSP_C", PCDeflationGetCoarseKSP_Deflation)); 872 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCDeflationGetPC_C", PCDeflationGetPC_Deflation)); 873 PetscFunctionReturn(PETSC_SUCCESS); 874 } 875