Actual source code: redundant.c

  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>

  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;

 21: static PetscErrorCode PCFactorSetShiftType_Redundant(PC pc, MatFactorShiftType shifttype)
 22: {
 23:   PC_Redundant *red = (PC_Redundant *)pc->data;

 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: }

 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;

 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: }

 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;

 74:   PetscFunctionBegin;
 75:   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));

 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;

 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);

 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));

 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:       }

110:       PetscCall(KSPSetOperators(red->ksp, red->pmats, red->pmats));

112:       /* get working vectors xsub and ysub */
113:       PetscCall(MatCreateVecs(red->pmats, &red->xsub, &red->ysub));

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));

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;

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));

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:   }

176:   if (pc->setfromoptionscalled) PetscCall(KSPSetFromOptions(red->ksp));
177:   PetscCall(KSPSetUp(red->ksp));

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: }

186: static PetscErrorCode PCApply_Redundant(PC pc, Vec x, Vec y)
187: {
188:   PC_Redundant *red = (PC_Redundant *)pc->data;
189:   PetscScalar  *array;

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:   }

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));

202:   /* place xdup's local array into xsub */
203:   PetscCall(VecGetArray(red->xdup, &array));
204:   PetscCall(VecPlaceArray(red->xsub, (const PetscScalar *)array));

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));

212:   /* place ysub's local array into ydup */
213:   PetscCall(VecGetArray(red->ysub, &array));
214:   PetscCall(VecPlaceArray(red->ydup, (const PetscScalar *)array));

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: }

224: static PetscErrorCode PCApplyTranspose_Redundant(PC pc, Vec x, Vec y)
225: {
226:   PC_Redundant *red = (PC_Redundant *)pc->data;
227:   PetscScalar  *array;

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:   }

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));

240:   /* place xdup's local array into xsub */
241:   PetscCall(VecGetArray(red->xdup, &array));
242:   PetscCall(VecPlaceArray(red->xsub, (const PetscScalar *)array));

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));

250:   /* place ysub's local array into ydup */
251:   PetscCall(VecGetArray(red->ysub, &array));
252:   PetscCall(VecPlaceArray(red->ydup, (const PetscScalar *)array));

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: }

262: static PetscErrorCode PCReset_Redundant(PC pc)
263: {
264:   PC_Redundant *red = (PC_Redundant *)pc->data;

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: }

280: static PetscErrorCode PCDestroy_Redundant(PC pc)
281: {
282:   PC_Redundant *red = (PC_Redundant *)pc->data;

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: }

297: static PetscErrorCode PCSetFromOptions_Redundant(PC pc, PetscOptionItems *PetscOptionsObject)
298: {
299:   PC_Redundant *red = (PC_Redundant *)pc->data;

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: }

308: static PetscErrorCode PCRedundantSetNumber_Redundant(PC pc, PetscInt nreds)
309: {
310:   PC_Redundant *red = (PC_Redundant *)pc->data;

312:   PetscFunctionBegin;
313:   red->nsubcomm = nreds;
314:   PetscFunctionReturn(PETSC_SUCCESS);
315: }

317: /*@
318:   PCRedundantSetNumber - Sets the number of redundant preconditioner contexts.

320:   Logically Collective

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.

327:   Level: advanced

329: .seealso: [](ch_ksp), `PCREDUNDANT`
330: @*/
331: PetscErrorCode PCRedundantSetNumber(PC pc, PetscInt nredundant)
332: {
333:   PetscFunctionBegin;
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: }

340: static PetscErrorCode PCRedundantSetScatter_Redundant(PC pc, VecScatter in, VecScatter out)
341: {
342:   PC_Redundant *red = (PC_Redundant *)pc->data;

344:   PetscFunctionBegin;
345:   PetscCall(PetscObjectReference((PetscObject)in));
346:   PetscCall(VecScatterDestroy(&red->scatterin));

348:   red->scatterin = in;

350:   PetscCall(PetscObjectReference((PetscObject)out));
351:   PetscCall(VecScatterDestroy(&red->scatterout));
352:   red->scatterout = out;
353:   PetscFunctionReturn(PETSC_SUCCESS);
354: }

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.

361:   Logically Collective

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

368:   Level: advanced

370: .seealso: [](ch_ksp), `PCREDUNDANT`
371: @*/
372: PetscErrorCode PCRedundantSetScatter(PC pc, VecScatter in, VecScatter out)
373: {
374:   PetscFunctionBegin;
378:   PetscTryMethod(pc, "PCRedundantSetScatter_C", (PC, VecScatter, VecScatter), (pc, in, out));
379:   PetscFunctionReturn(PETSC_SUCCESS);
380: }

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;

389:   PetscFunctionBegin;
390:   if (!red->psubcomm) {
391:     PetscCall(PCGetOptionsPrefix(pc, &prefix));

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));

398:     PetscCall(PetscSubcommSetOptionsPrefix(red->psubcomm, prefix));
399:     PetscCall(PetscSubcommSetFromOptions(red->psubcomm));

401:     /* create a new PC that processors in each subcomm have copy of */
402:     subcomm = PetscSubcommChild(red->psubcomm);

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: }

428: /*@
429:   PCRedundantGetKSP - Gets the less parallel `KSP` created by the redundant `PC`.

431:   Not Collective

433:   Input Parameter:
434: . pc - the preconditioner context

436:   Output Parameter:
437: . innerksp - the `KSP` on the smaller set of processes

439:   Level: advanced

441: .seealso: [](ch_ksp), `PCREDUNDANT`
442: @*/
443: PetscErrorCode PCRedundantGetKSP(PC pc, KSP *innerksp)
444: {
445:   PetscFunctionBegin;
447:   PetscAssertPointer(innerksp, 2);
448:   PetscUseMethod(pc, "PCRedundantGetKSP_C", (PC, KSP *), (pc, innerksp));
449:   PetscFunctionReturn(PETSC_SUCCESS);
450: }

452: static PetscErrorCode PCRedundantGetOperators_Redundant(PC pc, Mat *mat, Mat *pmat)
453: {
454:   PC_Redundant *red = (PC_Redundant *)pc->data;

456:   PetscFunctionBegin;
457:   if (mat) *mat = red->pmats;
458:   if (pmat) *pmat = red->pmats;
459:   PetscFunctionReturn(PETSC_SUCCESS);
460: }

462: /*@
463:   PCRedundantGetOperators - gets the sequential matrix and preconditioner matrix

465:   Not Collective

467:   Input Parameter:
468: . pc - the preconditioner context

470:   Output Parameters:
471: + mat  - the matrix
472: - pmat - the (possibly different) preconditioner matrix

474:   Level: advanced

476: .seealso: [](ch_ksp), `PCREDUNDANT`
477: @*/
478: PetscErrorCode PCRedundantGetOperators(PC pc, Mat *mat, Mat *pmat)
479: {
480:   PetscFunctionBegin;
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: }

488: /*MC
489:      PCREDUNDANT - Runs a `KSP` solver with preconditioner for the entire problem on subgroups of processors

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.

495:    Level: intermediate

497:    Notes:
498:    Options for the redundant preconditioners can be set using the options database prefix -redundant_

500:    The default `KSP` is preonly and the default `PC` is `PCLU` or `PCCHOLESKY` if Pmat is of type `MATSBAIJ`.

502:    `PCFactorSetShiftType()` applied to this `PC` will convey they shift type into the inner `PC` if it is factorization based.

504:    Developer Note:
505:    `PCSetInitialGuessNonzero()` is not used by this class but likely should be.

507: .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PCRedundantSetScatter()`,
508:           `PCRedundantGetKSP()`, `PCRedundantGetOperators()`, `PCRedundantSetNumber()`, `PCREDISTRIBUTE`
509: M*/

511: PETSC_EXTERN PetscErrorCode PCCreate_Redundant(PC pc)
512: {
513:   PC_Redundant *red;
514:   PetscMPIInt   size;

516:   PetscFunctionBegin;
517:   PetscCall(PetscNew(&red));
518:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc), &size));

520:   red->nsubcomm       = size;
521:   red->useparallelmat = PETSC_TRUE;
522:   pc->data            = (void *)red;

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;

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: }