1 /* 2 This file defines a "solve the problem redundantly on each subgroup of processor" preconditioner. 3 */ 4 #include <petsc/private/pcimpl.h> 5 #include <petscksp.h> /*I "petscksp.h" I*/ 6 7 typedef struct { 8 KSP ksp; 9 PC pc; /* actual preconditioner used on each processor */ 10 Vec xsub, ysub; /* vectors of a subcommunicator to hold parallel vectors of PetscObjectComm((PetscObject)pc) */ 11 Vec xdup, ydup; /* parallel vector that congregates xsub or ysub facilitating vector scattering */ 12 Mat pmats; /* matrix and optional preconditioner matrix belong to a subcommunicator */ 13 VecScatter scatterin, scatterout; /* scatter used to move all values to each processor group (subcommunicator) */ 14 PetscBool useparallelmat; 15 PetscSubcomm psubcomm; 16 PetscInt nsubcomm; /* num of data structure PetscSubcomm */ 17 PetscBool shifttypeset; 18 MatFactorShiftType shifttype; 19 } PC_Redundant; 20 21 PetscErrorCode PCFactorSetShiftType_Redundant(PC pc, MatFactorShiftType shifttype) 22 { 23 PC_Redundant *red = (PC_Redundant *)pc->data; 24 25 PetscFunctionBegin; 26 if (red->ksp) { 27 PC pc; 28 PetscCall(KSPGetPC(red->ksp, &pc)); 29 PetscCall(PCFactorSetShiftType(pc, shifttype)); 30 } else { 31 red->shifttypeset = PETSC_TRUE; 32 red->shifttype = shifttype; 33 } 34 PetscFunctionReturn(PETSC_SUCCESS); 35 } 36 37 static PetscErrorCode PCView_Redundant(PC pc, PetscViewer viewer) 38 { 39 PC_Redundant *red = (PC_Redundant *)pc->data; 40 PetscBool iascii, isstring; 41 PetscViewer subviewer; 42 43 PetscFunctionBegin; 44 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 45 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring)); 46 if (iascii) { 47 if (!red->psubcomm) { 48 PetscCall(PetscViewerASCIIPrintf(viewer, " Not yet setup\n")); 49 } else { 50 PetscCall(PetscViewerASCIIPrintf(viewer, " First (color=0) of %" PetscInt_FMT " PCs follows\n", red->nsubcomm)); 51 PetscCall(PetscViewerGetSubViewer(viewer, ((PetscObject)red->pc)->comm, &subviewer)); 52 if (!red->psubcomm->color) { /* only view first redundant pc */ 53 PetscCall(PetscViewerASCIIPushTab(subviewer)); 54 PetscCall(KSPView(red->ksp, subviewer)); 55 PetscCall(PetscViewerASCIIPopTab(subviewer)); 56 } 57 PetscCall(PetscViewerRestoreSubViewer(viewer, ((PetscObject)red->pc)->comm, &subviewer)); 58 } 59 } else if (isstring) { 60 PetscCall(PetscViewerStringSPrintf(viewer, " Redundant solver preconditioner")); 61 } 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 65 #include <../src/mat/impls/aij/mpi/mpiaij.h> 66 static PetscErrorCode PCSetUp_Redundant(PC pc) 67 { 68 PC_Redundant *red = (PC_Redundant *)pc->data; 69 PetscInt mstart, mend, mlocal, M; 70 PetscMPIInt size; 71 MPI_Comm comm, subcomm; 72 Vec x; 73 74 PetscFunctionBegin; 75 PetscCall(PetscObjectGetComm((PetscObject)pc, &comm)); 76 77 /* if pmatrix set by user is sequential then we do not need to gather the parallel matrix */ 78 PetscCallMPI(MPI_Comm_size(comm, &size)); 79 if (size == 1) red->useparallelmat = PETSC_FALSE; 80 81 if (!pc->setupcalled) { 82 PetscInt mloc_sub; 83 if (!red->psubcomm) { /* create red->psubcomm, new ksp and pc over subcomm */ 84 KSP ksp; 85 PetscCall(PCRedundantGetKSP(pc, &ksp)); 86 } 87 subcomm = PetscSubcommChild(red->psubcomm); 88 89 if (red->useparallelmat) { 90 /* grab the parallel matrix and put it into the processes of a subcommunicator */ 91 PetscCall(MatCreateRedundantMatrix(pc->pmat, red->psubcomm->n, subcomm, MAT_INITIAL_MATRIX, &red->pmats)); 92 93 PetscCallMPI(MPI_Comm_size(subcomm, &size)); 94 if (size > 1) { 95 PetscBool foundpack, issbaij; 96 PetscCall(PetscObjectTypeCompare((PetscObject)red->pmats, MATMPISBAIJ, &issbaij)); 97 if (!issbaij) { 98 PetscCall(MatGetFactorAvailable(red->pmats, NULL, MAT_FACTOR_LU, &foundpack)); 99 } else { 100 PetscCall(MatGetFactorAvailable(red->pmats, NULL, MAT_FACTOR_CHOLESKY, &foundpack)); 101 } 102 if (!foundpack) { /* reset default ksp and pc */ 103 PetscCall(KSPSetType(red->ksp, KSPGMRES)); 104 PetscCall(PCSetType(red->pc, PCBJACOBI)); 105 } else { 106 PetscCall(PCFactorSetMatSolverType(red->pc, NULL)); 107 } 108 } 109 110 PetscCall(KSPSetOperators(red->ksp, red->pmats, red->pmats)); 111 112 /* get working vectors xsub and ysub */ 113 PetscCall(MatCreateVecs(red->pmats, &red->xsub, &red->ysub)); 114 115 /* create working vectors xdup and ydup. 116 xdup concatenates all xsub's contigously to form a mpi vector over dupcomm (see PetscSubcommCreate_interlaced()) 117 ydup concatenates all ysub and has empty local arrays because ysub's arrays will be place into it. 118 Note: we use communicator dupcomm, not PetscObjectComm((PetscObject)pc)! */ 119 PetscCall(MatGetLocalSize(red->pmats, &mloc_sub, NULL)); 120 PetscCall(VecCreateMPI(PetscSubcommContiguousParent(red->psubcomm), mloc_sub, PETSC_DECIDE, &red->xdup)); 121 PetscCall(VecCreateMPIWithArray(PetscSubcommContiguousParent(red->psubcomm), 1, mloc_sub, PETSC_DECIDE, NULL, &red->ydup)); 122 123 /* create vecscatters */ 124 if (!red->scatterin) { /* efficiency of scatterin is independent from psubcomm_type! */ 125 IS is1, is2; 126 PetscInt *idx1, *idx2, i, j, k; 127 128 PetscCall(MatCreateVecs(pc->pmat, &x, NULL)); 129 PetscCall(VecGetSize(x, &M)); 130 PetscCall(VecGetOwnershipRange(x, &mstart, &mend)); 131 mlocal = mend - mstart; 132 PetscCall(PetscMalloc2(red->psubcomm->n * mlocal, &idx1, red->psubcomm->n * mlocal, &idx2)); 133 j = 0; 134 for (k = 0; k < red->psubcomm->n; k++) { 135 for (i = mstart; i < mend; i++) { 136 idx1[j] = i; 137 idx2[j++] = i + M * k; 138 } 139 } 140 PetscCall(ISCreateGeneral(comm, red->psubcomm->n * mlocal, idx1, PETSC_COPY_VALUES, &is1)); 141 PetscCall(ISCreateGeneral(comm, red->psubcomm->n * mlocal, idx2, PETSC_COPY_VALUES, &is2)); 142 PetscCall(VecScatterCreate(x, is1, red->xdup, is2, &red->scatterin)); 143 PetscCall(ISDestroy(&is1)); 144 PetscCall(ISDestroy(&is2)); 145 146 /* Impl below is good for PETSC_SUBCOMM_INTERLACED (no inter-process communication) and PETSC_SUBCOMM_CONTIGUOUS (communication within subcomm) */ 147 PetscCall(ISCreateStride(comm, mlocal, mstart + red->psubcomm->color * M, 1, &is1)); 148 PetscCall(ISCreateStride(comm, mlocal, mstart, 1, &is2)); 149 PetscCall(VecScatterCreate(red->xdup, is1, x, is2, &red->scatterout)); 150 PetscCall(ISDestroy(&is1)); 151 PetscCall(ISDestroy(&is2)); 152 PetscCall(PetscFree2(idx1, idx2)); 153 PetscCall(VecDestroy(&x)); 154 } 155 } else { /* !red->useparallelmat */ 156 PetscCall(KSPSetOperators(red->ksp, pc->mat, pc->pmat)); 157 } 158 } else { /* pc->setupcalled */ 159 if (red->useparallelmat) { 160 MatReuse reuse; 161 /* grab the parallel matrix and put it into the processes of a subcommunicator */ 162 if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 163 /* destroy old matrices */ 164 PetscCall(MatDestroy(&red->pmats)); 165 reuse = MAT_INITIAL_MATRIX; 166 } else { 167 reuse = MAT_REUSE_MATRIX; 168 } 169 PetscCall(MatCreateRedundantMatrix(pc->pmat, red->psubcomm->n, PetscSubcommChild(red->psubcomm), reuse, &red->pmats)); 170 PetscCall(KSPSetOperators(red->ksp, red->pmats, red->pmats)); 171 } else { /* !red->useparallelmat */ 172 PetscCall(KSPSetOperators(red->ksp, pc->mat, pc->pmat)); 173 } 174 } 175 176 if (pc->setfromoptionscalled) PetscCall(KSPSetFromOptions(red->ksp)); 177 PetscCall(KSPSetUp(red->ksp)); 178 179 /* Detect failure */ 180 KSPConvergedReason redreason; 181 PetscCall(KSPGetConvergedReason(red->ksp, &redreason)); 182 if (redreason) pc->failedreason = PC_SUBPC_ERROR; 183 PetscFunctionReturn(PETSC_SUCCESS); 184 } 185 186 static PetscErrorCode PCApply_Redundant(PC pc, Vec x, Vec y) 187 { 188 PC_Redundant *red = (PC_Redundant *)pc->data; 189 PetscScalar *array; 190 191 PetscFunctionBegin; 192 if (!red->useparallelmat) { 193 PetscCall(KSPSolve(red->ksp, x, y)); 194 PetscCall(KSPCheckSolve(red->ksp, pc, y)); 195 PetscFunctionReturn(PETSC_SUCCESS); 196 } 197 198 /* scatter x to xdup */ 199 PetscCall(VecScatterBegin(red->scatterin, x, red->xdup, INSERT_VALUES, SCATTER_FORWARD)); 200 PetscCall(VecScatterEnd(red->scatterin, x, red->xdup, INSERT_VALUES, SCATTER_FORWARD)); 201 202 /* place xdup's local array into xsub */ 203 PetscCall(VecGetArray(red->xdup, &array)); 204 PetscCall(VecPlaceArray(red->xsub, (const PetscScalar *)array)); 205 206 /* apply preconditioner on each processor */ 207 PetscCall(KSPSolve(red->ksp, red->xsub, red->ysub)); 208 PetscCall(KSPCheckSolve(red->ksp, pc, red->ysub)); 209 PetscCall(VecResetArray(red->xsub)); 210 PetscCall(VecRestoreArray(red->xdup, &array)); 211 212 /* place ysub's local array into ydup */ 213 PetscCall(VecGetArray(red->ysub, &array)); 214 PetscCall(VecPlaceArray(red->ydup, (const PetscScalar *)array)); 215 216 /* scatter ydup to y */ 217 PetscCall(VecScatterBegin(red->scatterout, red->ydup, y, INSERT_VALUES, SCATTER_FORWARD)); 218 PetscCall(VecScatterEnd(red->scatterout, red->ydup, y, INSERT_VALUES, SCATTER_FORWARD)); 219 PetscCall(VecResetArray(red->ydup)); 220 PetscCall(VecRestoreArray(red->ysub, &array)); 221 PetscFunctionReturn(PETSC_SUCCESS); 222 } 223 224 static PetscErrorCode PCApplyTranspose_Redundant(PC pc, Vec x, Vec y) 225 { 226 PC_Redundant *red = (PC_Redundant *)pc->data; 227 PetscScalar *array; 228 229 PetscFunctionBegin; 230 if (!red->useparallelmat) { 231 PetscCall(KSPSolveTranspose(red->ksp, x, y)); 232 PetscCall(KSPCheckSolve(red->ksp, pc, y)); 233 PetscFunctionReturn(PETSC_SUCCESS); 234 } 235 236 /* scatter x to xdup */ 237 PetscCall(VecScatterBegin(red->scatterin, x, red->xdup, INSERT_VALUES, SCATTER_FORWARD)); 238 PetscCall(VecScatterEnd(red->scatterin, x, red->xdup, INSERT_VALUES, SCATTER_FORWARD)); 239 240 /* place xdup's local array into xsub */ 241 PetscCall(VecGetArray(red->xdup, &array)); 242 PetscCall(VecPlaceArray(red->xsub, (const PetscScalar *)array)); 243 244 /* apply preconditioner on each processor */ 245 PetscCall(KSPSolveTranspose(red->ksp, red->xsub, red->ysub)); 246 PetscCall(KSPCheckSolve(red->ksp, pc, red->ysub)); 247 PetscCall(VecResetArray(red->xsub)); 248 PetscCall(VecRestoreArray(red->xdup, &array)); 249 250 /* place ysub's local array into ydup */ 251 PetscCall(VecGetArray(red->ysub, &array)); 252 PetscCall(VecPlaceArray(red->ydup, (const PetscScalar *)array)); 253 254 /* scatter ydup to y */ 255 PetscCall(VecScatterBegin(red->scatterout, red->ydup, y, INSERT_VALUES, SCATTER_FORWARD)); 256 PetscCall(VecScatterEnd(red->scatterout, red->ydup, y, INSERT_VALUES, SCATTER_FORWARD)); 257 PetscCall(VecResetArray(red->ydup)); 258 PetscCall(VecRestoreArray(red->ysub, &array)); 259 PetscFunctionReturn(PETSC_SUCCESS); 260 } 261 262 static PetscErrorCode PCReset_Redundant(PC pc) 263 { 264 PC_Redundant *red = (PC_Redundant *)pc->data; 265 266 PetscFunctionBegin; 267 if (red->useparallelmat) { 268 PetscCall(VecScatterDestroy(&red->scatterin)); 269 PetscCall(VecScatterDestroy(&red->scatterout)); 270 PetscCall(VecDestroy(&red->ysub)); 271 PetscCall(VecDestroy(&red->xsub)); 272 PetscCall(VecDestroy(&red->xdup)); 273 PetscCall(VecDestroy(&red->ydup)); 274 } 275 PetscCall(MatDestroy(&red->pmats)); 276 PetscCall(KSPReset(red->ksp)); 277 PetscFunctionReturn(PETSC_SUCCESS); 278 } 279 280 static PetscErrorCode PCDestroy_Redundant(PC pc) 281 { 282 PC_Redundant *red = (PC_Redundant *)pc->data; 283 284 PetscFunctionBegin; 285 PetscCall(PCReset_Redundant(pc)); 286 PetscCall(KSPDestroy(&red->ksp)); 287 PetscCall(PetscSubcommDestroy(&red->psubcomm)); 288 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantSetScatter_C", NULL)); 289 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantSetNumber_C", NULL)); 290 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantGetKSP_C", NULL)); 291 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantGetOperators_C", NULL)); 292 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFactorSetShiftType_C", NULL)); 293 PetscCall(PetscFree(pc->data)); 294 PetscFunctionReturn(PETSC_SUCCESS); 295 } 296 297 static PetscErrorCode PCSetFromOptions_Redundant(PC pc, PetscOptionItems *PetscOptionsObject) 298 { 299 PC_Redundant *red = (PC_Redundant *)pc->data; 300 301 PetscFunctionBegin; 302 PetscOptionsHeadBegin(PetscOptionsObject, "Redundant options"); 303 PetscCall(PetscOptionsInt("-pc_redundant_number", "Number of redundant pc", "PCRedundantSetNumber", red->nsubcomm, &red->nsubcomm, NULL)); 304 PetscOptionsHeadEnd(); 305 PetscFunctionReturn(PETSC_SUCCESS); 306 } 307 308 static PetscErrorCode PCRedundantSetNumber_Redundant(PC pc, PetscInt nreds) 309 { 310 PC_Redundant *red = (PC_Redundant *)pc->data; 311 312 PetscFunctionBegin; 313 red->nsubcomm = nreds; 314 PetscFunctionReturn(PETSC_SUCCESS); 315 } 316 317 /*@ 318 PCRedundantSetNumber - Sets the number of redundant preconditioner contexts. 319 320 Logically Collective 321 322 Input Parameters: 323 + pc - the preconditioner context 324 - nredundant - number of redundant preconditioner contexts; for example if you are using 64 MPI processes and 325 use an nredundant of 4 there will be 4 parallel solves each on 16 = 64/4 processes. 326 327 Level: advanced 328 329 .seealso: `PCREDUNDANT` 330 @*/ 331 PetscErrorCode PCRedundantSetNumber(PC pc, PetscInt nredundant) 332 { 333 PetscFunctionBegin; 334 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 335 PetscCheck(nredundant > 0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "num of redundant pc %" PetscInt_FMT " must be positive", nredundant); 336 PetscTryMethod(pc, "PCRedundantSetNumber_C", (PC, PetscInt), (pc, nredundant)); 337 PetscFunctionReturn(PETSC_SUCCESS); 338 } 339 340 static PetscErrorCode PCRedundantSetScatter_Redundant(PC pc, VecScatter in, VecScatter out) 341 { 342 PC_Redundant *red = (PC_Redundant *)pc->data; 343 344 PetscFunctionBegin; 345 PetscCall(PetscObjectReference((PetscObject)in)); 346 PetscCall(VecScatterDestroy(&red->scatterin)); 347 348 red->scatterin = in; 349 350 PetscCall(PetscObjectReference((PetscObject)out)); 351 PetscCall(VecScatterDestroy(&red->scatterout)); 352 red->scatterout = out; 353 PetscFunctionReturn(PETSC_SUCCESS); 354 } 355 356 /*@ 357 PCRedundantSetScatter - Sets the scatter used to copy values into the 358 redundant local solve and the scatter to move them back into the global 359 vector. 360 361 Logically Collective 362 363 Input Parameters: 364 + pc - the preconditioner context 365 . in - the scatter to move the values in 366 - out - the scatter to move them out 367 368 Level: advanced 369 370 .seealso: `PCREDUNDANT` 371 @*/ 372 PetscErrorCode PCRedundantSetScatter(PC pc, VecScatter in, VecScatter out) 373 { 374 PetscFunctionBegin; 375 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 376 PetscValidHeaderSpecific(in, PETSCSF_CLASSID, 2); 377 PetscValidHeaderSpecific(out, PETSCSF_CLASSID, 3); 378 PetscTryMethod(pc, "PCRedundantSetScatter_C", (PC, VecScatter, VecScatter), (pc, in, out)); 379 PetscFunctionReturn(PETSC_SUCCESS); 380 } 381 382 static PetscErrorCode PCRedundantGetKSP_Redundant(PC pc, KSP *innerksp) 383 { 384 PC_Redundant *red = (PC_Redundant *)pc->data; 385 MPI_Comm comm, subcomm; 386 const char *prefix; 387 PetscBool issbaij; 388 389 PetscFunctionBegin; 390 if (!red->psubcomm) { 391 PetscCall(PCGetOptionsPrefix(pc, &prefix)); 392 393 PetscCall(PetscObjectGetComm((PetscObject)pc, &comm)); 394 PetscCall(PetscSubcommCreate(comm, &red->psubcomm)); 395 PetscCall(PetscSubcommSetNumber(red->psubcomm, red->nsubcomm)); 396 PetscCall(PetscSubcommSetType(red->psubcomm, PETSC_SUBCOMM_CONTIGUOUS)); 397 398 PetscCall(PetscSubcommSetOptionsPrefix(red->psubcomm, prefix)); 399 PetscCall(PetscSubcommSetFromOptions(red->psubcomm)); 400 401 /* create a new PC that processors in each subcomm have copy of */ 402 subcomm = PetscSubcommChild(red->psubcomm); 403 404 PetscCall(KSPCreate(subcomm, &red->ksp)); 405 PetscCall(KSPSetNestLevel(red->ksp, pc->kspnestlevel)); 406 PetscCall(KSPSetErrorIfNotConverged(red->ksp, pc->erroriffailure)); 407 PetscCall(PetscObjectIncrementTabLevel((PetscObject)red->ksp, (PetscObject)pc, 1)); 408 PetscCall(KSPSetType(red->ksp, KSPPREONLY)); 409 PetscCall(KSPGetPC(red->ksp, &red->pc)); 410 PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATSEQSBAIJ, &issbaij)); 411 if (!issbaij) PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATMPISBAIJ, &issbaij)); 412 if (!issbaij) { 413 PetscCall(PCSetType(red->pc, PCLU)); 414 } else { 415 PetscCall(PCSetType(red->pc, PCCHOLESKY)); 416 } 417 if (red->shifttypeset) { 418 PetscCall(PCFactorSetShiftType(red->pc, red->shifttype)); 419 red->shifttypeset = PETSC_FALSE; 420 } 421 PetscCall(KSPSetOptionsPrefix(red->ksp, prefix)); 422 PetscCall(KSPAppendOptionsPrefix(red->ksp, "redundant_")); 423 } 424 *innerksp = red->ksp; 425 PetscFunctionReturn(PETSC_SUCCESS); 426 } 427 428 /*@ 429 PCRedundantGetKSP - Gets the less parallel `KSP` created by the redundant `PC`. 430 431 Not Collective 432 433 Input Parameter: 434 . pc - the preconditioner context 435 436 Output Parameter: 437 . innerksp - the `KSP` on the smaller set of processes 438 439 Level: advanced 440 441 .seealso: `PCREDUNDANT` 442 @*/ 443 PetscErrorCode PCRedundantGetKSP(PC pc, KSP *innerksp) 444 { 445 PetscFunctionBegin; 446 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 447 PetscAssertPointer(innerksp, 2); 448 PetscUseMethod(pc, "PCRedundantGetKSP_C", (PC, KSP *), (pc, innerksp)); 449 PetscFunctionReturn(PETSC_SUCCESS); 450 } 451 452 static PetscErrorCode PCRedundantGetOperators_Redundant(PC pc, Mat *mat, Mat *pmat) 453 { 454 PC_Redundant *red = (PC_Redundant *)pc->data; 455 456 PetscFunctionBegin; 457 if (mat) *mat = red->pmats; 458 if (pmat) *pmat = red->pmats; 459 PetscFunctionReturn(PETSC_SUCCESS); 460 } 461 462 /*@ 463 PCRedundantGetOperators - gets the sequential matrix and preconditioner matrix 464 465 Not Collective 466 467 Input Parameter: 468 . pc - the preconditioner context 469 470 Output Parameters: 471 + mat - the matrix 472 - pmat - the (possibly different) preconditioner matrix 473 474 Level: advanced 475 476 .seealso: `PCREDUNDANT` 477 @*/ 478 PetscErrorCode PCRedundantGetOperators(PC pc, Mat *mat, Mat *pmat) 479 { 480 PetscFunctionBegin; 481 PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 482 if (mat) PetscAssertPointer(mat, 2); 483 if (pmat) PetscAssertPointer(pmat, 3); 484 PetscUseMethod(pc, "PCRedundantGetOperators_C", (PC, Mat *, Mat *), (pc, mat, pmat)); 485 PetscFunctionReturn(PETSC_SUCCESS); 486 } 487 488 /*MC 489 PCREDUNDANT - Runs a `KSP` solver with preconditioner for the entire problem on subgroups of processors 490 491 Options Database Key: 492 . -pc_redundant_number <n> - number of redundant solves, for example if you are using 64 MPI processes and 493 use an n of 4 there will be 4 parallel solves each on 16 = 64/4 processes. 494 495 Level: intermediate 496 497 Notes: 498 Options for the redundant preconditioners can be set using the options database prefix -redundant_ 499 500 The default `KSP` is preonly and the default `PC` is `PCLU` or `PCCHOLESKY` if Pmat is of type `MATSBAIJ`. 501 502 `PCFactorSetShiftType()` applied to this `PC` will convey they shift type into the inner `PC` if it is factorization based. 503 504 Developer Note: 505 `PCSetInitialGuessNonzero()` is not used by this class but likely should be. 506 507 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PCRedundantSetScatter()`, 508 `PCRedundantGetKSP()`, `PCRedundantGetOperators()`, `PCRedundantSetNumber()`, `PCREDISTRIBUTE` 509 M*/ 510 511 PETSC_EXTERN PetscErrorCode PCCreate_Redundant(PC pc) 512 { 513 PC_Redundant *red; 514 PetscMPIInt size; 515 516 PetscFunctionBegin; 517 PetscCall(PetscNew(&red)); 518 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size)); 519 520 red->nsubcomm = size; 521 red->useparallelmat = PETSC_TRUE; 522 pc->data = (void *)red; 523 524 pc->ops->apply = PCApply_Redundant; 525 pc->ops->applytranspose = PCApplyTranspose_Redundant; 526 pc->ops->setup = PCSetUp_Redundant; 527 pc->ops->destroy = PCDestroy_Redundant; 528 pc->ops->reset = PCReset_Redundant; 529 pc->ops->setfromoptions = PCSetFromOptions_Redundant; 530 pc->ops->view = PCView_Redundant; 531 532 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantSetScatter_C", PCRedundantSetScatter_Redundant)); 533 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantSetNumber_C", PCRedundantSetNumber_Redundant)); 534 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantGetKSP_C", PCRedundantGetKSP_Redundant)); 535 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCRedundantGetOperators_C", PCRedundantGetOperators_Redundant)); 536 PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFactorSetShiftType_C", PCFactorSetShiftType_Redundant)); 537 PetscFunctionReturn(PETSC_SUCCESS); 538 } 539