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