xref: /petsc/src/ksp/pc/impls/redundant/redundant.c (revision 1fbd8f88be04a6f76165902250720fde906a4c29)
1dba47a55SKris Buschelman #define PETSCKSP_DLL
2dba47a55SKris Buschelman 
34b9ad928SBarry Smith /*
43f457be1SHong Zhang   This file defines a "solve the problem redundantly on each subgroup of processor" preconditioner.
54b9ad928SBarry Smith */
66356e834SBarry Smith #include "private/pcimpl.h"     /*I "petscpc.h" I*/
74b9ad928SBarry Smith #include "petscksp.h"
84b9ad928SBarry Smith 
94b9ad928SBarry Smith typedef struct {
10*1fbd8f88SHong Zhang   MPI_Comm   parent;      /* parent communicator */
11*1fbd8f88SHong Zhang   MPI_Comm   dupparent;   /* duplicate parent communicator, under which the processors of this subcomm have contiguous rank */
12*1fbd8f88SHong Zhang   MPI_Comm   comm;        /* this communicator */
13*1fbd8f88SHong Zhang   PetscInt   n;           /* num of subcommunicators under the parent communicator */
14*1fbd8f88SHong Zhang   PetscInt   color;       /* color of processors belong to this communicator */
15*1fbd8f88SHong Zhang } PetscSubcomm;
16*1fbd8f88SHong Zhang 
17*1fbd8f88SHong Zhang #undef __FUNCT__
18*1fbd8f88SHong Zhang #define __FUNCT__ "PetscSubcommDestroy"
19*1fbd8f88SHong Zhang PetscErrorCode PetscSubcommDestroy(PetscSubcomm *psubcomm)
20*1fbd8f88SHong Zhang {
21*1fbd8f88SHong Zhang   PetscErrorCode ierr;
22*1fbd8f88SHong Zhang 
23*1fbd8f88SHong Zhang   PetscFunctionBegin;
24*1fbd8f88SHong Zhang   ierr = PetscFree(psubcomm);CHKERRQ(ierr);
25*1fbd8f88SHong Zhang   PetscFunctionReturn(0);
26*1fbd8f88SHong Zhang }
27*1fbd8f88SHong Zhang 
28*1fbd8f88SHong Zhang /*--------------------------------------------------------------------------------------------------
29*1fbd8f88SHong Zhang     To avoid data scattering from subcomm back to original comm, we create subcomm by iteratively taking a
30*1fbd8f88SHong Zhang      processe into a subcomm.
31*1fbd8f88SHong Zhang      An example: size=4, nsubcomm=3
32*1fbd8f88SHong Zhang       pc->comm:
33*1fbd8f88SHong Zhang       rank:     [0]  [1]  [2]  [3]
34*1fbd8f88SHong Zhang       color:     0    1    2    0
35*1fbd8f88SHong Zhang 
36*1fbd8f88SHong Zhang      subcomm:
37*1fbd8f88SHong Zhang       subrank:  [0]  [0]  [0]  [1]
38*1fbd8f88SHong Zhang 
39*1fbd8f88SHong Zhang      dupcomm:
40*1fbd8f88SHong Zhang       duprank:  [0]  [2]  [3]  [1]
41*1fbd8f88SHong Zhang 
42*1fbd8f88SHong Zhang      Here, subcomm[color = 0] has subsize=2, owns process [0] and [3]
43*1fbd8f88SHong Zhang            subcomm[color = 1] has subsize=1, owns process [1]
44*1fbd8f88SHong Zhang            subcomm[color = 2] has subsize=1, owns process [2]
45*1fbd8f88SHong Zhang           dupcomm has same number of processes as pc->comm, and its duprank maps
46*1fbd8f88SHong Zhang           processes in subcomm contiguously into a 1d array:
47*1fbd8f88SHong Zhang             duprank: [0] [1]      [2]         [3]
48*1fbd8f88SHong Zhang             rank:    [0] [3]      [1]         [2]
49*1fbd8f88SHong Zhang                     subcomm[0] subcomm[1]  subcomm[2]
50*1fbd8f88SHong Zhang      ----------------------------------------------------------------------------------------*/
51*1fbd8f88SHong Zhang #undef __FUNCT__
52*1fbd8f88SHong Zhang #define __FUNCT__ "PetscSubcommCreate"
53*1fbd8f88SHong Zhang PetscErrorCode PetscSubcommCreate(MPI_Comm comm,PetscInt nsubcomm,PetscSubcomm **psubcomm)
54*1fbd8f88SHong Zhang {
55*1fbd8f88SHong Zhang   PetscErrorCode ierr;
56*1fbd8f88SHong Zhang   PetscMPIInt    rank,size,*subsize,duprank,subrank;
57*1fbd8f88SHong Zhang   PetscInt       np_subcomm,nleftover,i,j,color;
58*1fbd8f88SHong Zhang   MPI_Comm       subcomm=0,dupcomm=0;
59*1fbd8f88SHong Zhang   const char     *prefix;
60*1fbd8f88SHong Zhang   PetscSubcomm   *psubcomm_tmp;
61*1fbd8f88SHong Zhang 
62*1fbd8f88SHong Zhang   PetscFunctionBegin;
63*1fbd8f88SHong Zhang   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
64*1fbd8f88SHong Zhang   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
65*1fbd8f88SHong Zhang   if (nsubcomm < 1 || nsubcomm > size) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE, "Num of subcommunicators %D cannot be < 1 or > input comm size %D",nsubcomm,size);
66*1fbd8f88SHong Zhang 
67*1fbd8f88SHong Zhang   /* get size of each subcommunicator */
68*1fbd8f88SHong Zhang   ierr = PetscMalloc((1+nsubcomm)*sizeof(PetscMPIInt),&subsize);CHKERRQ(ierr);
69*1fbd8f88SHong Zhang   np_subcomm = size/nsubcomm;
70*1fbd8f88SHong Zhang   nleftover  = size - nsubcomm*np_subcomm;
71*1fbd8f88SHong Zhang   for (i=0; i<nsubcomm; i++){
72*1fbd8f88SHong Zhang     subsize[i] = np_subcomm;
73*1fbd8f88SHong Zhang     if (i<nleftover) subsize[i]++;
74*1fbd8f88SHong Zhang   }
75*1fbd8f88SHong Zhang 
76*1fbd8f88SHong Zhang   /* find color for this proc */
77*1fbd8f88SHong Zhang   color   = rank%nsubcomm;
78*1fbd8f88SHong Zhang   subrank = rank/nsubcomm;
79*1fbd8f88SHong Zhang 
80*1fbd8f88SHong Zhang   ierr = MPI_Comm_split(comm,color,subrank,&subcomm);CHKERRQ(ierr);
81*1fbd8f88SHong Zhang 
82*1fbd8f88SHong Zhang   j = 0; duprank = 0;
83*1fbd8f88SHong Zhang   for (i=0; i<nsubcomm; i++){
84*1fbd8f88SHong Zhang     if (j == color){
85*1fbd8f88SHong Zhang       duprank += subrank;
86*1fbd8f88SHong Zhang       break;
87*1fbd8f88SHong Zhang     }
88*1fbd8f88SHong Zhang     duprank += subsize[i]; j++;
89*1fbd8f88SHong Zhang   }
90*1fbd8f88SHong Zhang 
91*1fbd8f88SHong Zhang   /* create dupcomm with same size as comm, but its rank, duprank, maps subcomm's contiguously into dupcomm */
92*1fbd8f88SHong Zhang   ierr = MPI_Comm_split(comm,0,duprank,&dupcomm);CHKERRQ(ierr);
93*1fbd8f88SHong Zhang   ierr = PetscFree(subsize);CHKERRQ(ierr);
94*1fbd8f88SHong Zhang 
95*1fbd8f88SHong Zhang   ierr = PetscNew(PetscSubcomm,&psubcomm_tmp);CHKERRQ(ierr);
96*1fbd8f88SHong Zhang   psubcomm_tmp->parent    = comm;
97*1fbd8f88SHong Zhang   psubcomm_tmp->dupparent = dupcomm;
98*1fbd8f88SHong Zhang   psubcomm_tmp->comm      = subcomm;
99*1fbd8f88SHong Zhang   psubcomm_tmp->n         = nsubcomm;
100*1fbd8f88SHong Zhang   psubcomm_tmp->color     = color;
101*1fbd8f88SHong Zhang   *psubcomm = psubcomm_tmp;
102*1fbd8f88SHong Zhang   PetscFunctionReturn(0);
103*1fbd8f88SHong Zhang }
104*1fbd8f88SHong Zhang 
105*1fbd8f88SHong Zhang typedef struct {
1064b9ad928SBarry Smith   PC           pc;                   /* actual preconditioner used on each processor */
1073f457be1SHong Zhang   Vec          xsub,ysub;            /* vectors of a subcommunicator to hold parallel vectors of pc->comm */
1083f457be1SHong Zhang   Vec          xdup,ydup;            /* parallel vector that congregates xsub or ysub facilitating vector scattering */
109b3804887SHong Zhang   Mat          pmats;                /* matrix and optional preconditioner matrix belong to a subcommunicator */
1103f457be1SHong Zhang   VecScatter   scatterin,scatterout; /* scatter used to move all values to each processor group (subcommunicator) */
1114b9ad928SBarry Smith   PetscTruth   useparallelmat;
112*1fbd8f88SHong Zhang   PetscSubcomm *psubcomm;
113*1fbd8f88SHong Zhang   PetscInt     nsubcomm;           /* num of data structure PetscSubcomm */
1144b9ad928SBarry Smith } PC_Redundant;
1154b9ad928SBarry Smith 
1164b9ad928SBarry Smith #undef __FUNCT__
1174b9ad928SBarry Smith #define __FUNCT__ "PCView_Redundant"
1186849ba73SBarry Smith static PetscErrorCode PCView_Redundant(PC pc,PetscViewer viewer)
1194b9ad928SBarry Smith {
1204b9ad928SBarry Smith   PC_Redundant   *red = (PC_Redundant*)pc->data;
121dfbe8321SBarry Smith   PetscErrorCode ierr;
12213f74950SBarry Smith   PetscMPIInt    rank;
12332077d6dSBarry Smith   PetscTruth     iascii,isstring;
124a47c9f9aSHong Zhang   PetscViewer    sviewer,subviewer;
125*1fbd8f88SHong Zhang   PetscInt       color = red->psubcomm->color;
1264b9ad928SBarry Smith 
1274b9ad928SBarry Smith   PetscFunctionBegin;
1284b9ad928SBarry Smith   ierr = MPI_Comm_rank(pc->comm,&rank);CHKERRQ(ierr);
12932077d6dSBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
1304b9ad928SBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_STRING,&isstring);CHKERRQ(ierr);
13132077d6dSBarry Smith   if (iascii) {
132a98ce0f4SHong Zhang     ierr = PetscViewerASCIIPrintf(viewer,"  Redundant solver preconditioner: First PC (color=0) follows\n");CHKERRQ(ierr);
133a98ce0f4SHong Zhang     ierr = PetscViewerGetSubcomm(viewer,red->pc->comm,&subviewer);CHKERRQ(ierr);
134a98ce0f4SHong Zhang     if (!color) { /* only view first redundant pc */
1354b9ad928SBarry Smith       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
136a47c9f9aSHong Zhang       ierr = PCView(red->pc,subviewer);CHKERRQ(ierr);
1374b9ad928SBarry Smith       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1384b9ad928SBarry Smith     }
139a98ce0f4SHong Zhang     ierr = PetscViewerRestoreSubcomm(viewer,red->pc->comm,&subviewer);CHKERRQ(ierr);
140a98ce0f4SHong Zhang   } else if (isstring) { /* not test it yet! */
1414b9ad928SBarry Smith     ierr = PetscViewerStringSPrintf(viewer," Redundant solver preconditioner");CHKERRQ(ierr);
1424b9ad928SBarry Smith     ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr);
1434b9ad928SBarry Smith     if (!rank) {
1444b9ad928SBarry Smith       ierr = PCView(red->pc,sviewer);CHKERRQ(ierr);
1454b9ad928SBarry Smith     }
1464b9ad928SBarry Smith     ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr);
1474b9ad928SBarry Smith   } else {
14879a5c55eSBarry Smith     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PC redundant",((PetscObject)viewer)->type_name);
1494b9ad928SBarry Smith   }
1504b9ad928SBarry Smith   PetscFunctionReturn(0);
1514b9ad928SBarry Smith }
1524b9ad928SBarry Smith 
153b9147fbbSdalcinl #include "include/private/matimpl.h"        /*I "petscmat.h" I*/
1543f457be1SHong Zhang #include "private/vecimpl.h"
1553f457be1SHong Zhang #include "src/mat/impls/aij/mpi/mpiaij.h"   /*I "petscmat.h" I*/
1563f457be1SHong Zhang #include "src/mat/impls/aij/seq/aij.h"      /*I "petscmat.h" I*/
1573f457be1SHong Zhang 
158b3804887SHong Zhang typedef struct { /* used by MatGetRedundantMatrix() for reusing matredundant */
159b3804887SHong Zhang   PetscInt       nzlocal,nsends,nrecvs;
160b3804887SHong Zhang   PetscInt       *send_rank,*sbuf_nz,*sbuf_j,**rbuf_j;
161b3804887SHong Zhang   PetscScalar    *sbuf_a,**rbuf_a;
162b3804887SHong Zhang   PetscErrorCode (*MatDestroy)(Mat);
163b3804887SHong Zhang } Mat_Redundant;
164b3804887SHong Zhang 
165b3804887SHong Zhang #undef __FUNCT__
166776b82aeSLisandro Dalcin #define __FUNCT__ "PetscContainerDestroy_MatRedundant"
167776b82aeSLisandro Dalcin PetscErrorCode PetscContainerDestroy_MatRedundant(void *ptr)
168b3804887SHong Zhang {
169b3804887SHong Zhang   PetscErrorCode       ierr;
170b3804887SHong Zhang   Mat_Redundant        *redund=(Mat_Redundant*)ptr;
171b3804887SHong Zhang   PetscInt             i;
172b3804887SHong Zhang 
173b3804887SHong Zhang   PetscFunctionBegin;
174b3804887SHong Zhang   ierr = PetscFree(redund->send_rank);CHKERRQ(ierr);
175b3804887SHong Zhang   ierr = PetscFree(redund->sbuf_j);CHKERRQ(ierr);
176b3804887SHong Zhang   ierr = PetscFree(redund->sbuf_a);CHKERRQ(ierr);
177b3804887SHong Zhang   for (i=0; i<redund->nrecvs; i++){
178b3804887SHong Zhang     ierr = PetscFree(redund->rbuf_j[i]);CHKERRQ(ierr);
179b3804887SHong Zhang     ierr = PetscFree(redund->rbuf_a[i]);CHKERRQ(ierr);
180b3804887SHong Zhang   }
181b3804887SHong Zhang   ierr = PetscFree3(redund->sbuf_nz,redund->rbuf_j,redund->rbuf_a);CHKERRQ(ierr);
182b3804887SHong Zhang   ierr = PetscFree(redund);CHKERRQ(ierr);
183b3804887SHong Zhang   PetscFunctionReturn(0);
184b3804887SHong Zhang }
185b3804887SHong Zhang 
186b3804887SHong Zhang #undef __FUNCT__
187b3804887SHong Zhang #define __FUNCT__ "MatDestroy_MatRedundant"
188b3804887SHong Zhang PetscErrorCode MatDestroy_MatRedundant(Mat A)
189b3804887SHong Zhang {
190b3804887SHong Zhang   PetscErrorCode  ierr;
191776b82aeSLisandro Dalcin   PetscContainer  container;
192b3804887SHong Zhang   Mat_Redundant   *redund=PETSC_NULL;
193b3804887SHong Zhang 
194b3804887SHong Zhang   PetscFunctionBegin;
195b3804887SHong Zhang   ierr = PetscObjectQuery((PetscObject)A,"Mat_Redundant",(PetscObject *)&container);CHKERRQ(ierr);
196b3804887SHong Zhang   if (container) {
197776b82aeSLisandro Dalcin     ierr = PetscContainerGetPointer(container,(void **)&redund);CHKERRQ(ierr);
198b3804887SHong Zhang   } else {
199b3804887SHong Zhang     SETERRQ(PETSC_ERR_PLIB,"Container does not exit");
200b3804887SHong Zhang   }
201b3804887SHong Zhang   A->ops->destroy = redund->MatDestroy;
202b3804887SHong Zhang   ierr = PetscObjectCompose((PetscObject)A,"Mat_Redundant",0);CHKERRQ(ierr);
203b3804887SHong Zhang   ierr = (*A->ops->destroy)(A);CHKERRQ(ierr);
204776b82aeSLisandro Dalcin   ierr = PetscContainerDestroy(container);CHKERRQ(ierr);
205b3804887SHong Zhang   PetscFunctionReturn(0);
206b3804887SHong Zhang }
207b3804887SHong Zhang 
2083f457be1SHong Zhang #undef __FUNCT__
2093f457be1SHong Zhang #define __FUNCT__ "MatGetRedundantMatrix"
210f664ae05SHong Zhang PetscErrorCode MatGetRedundantMatrix_AIJ(Mat mat,PetscInt nsubcomm,MPI_Comm subcomm,PetscInt mlocal_sub,MatReuse reuse,Mat *matredundant)
2113f457be1SHong Zhang {
212b3804887SHong Zhang   PetscMPIInt    rank,size;
2133f457be1SHong Zhang   MPI_Comm       comm=mat->comm;
2143f457be1SHong Zhang   PetscErrorCode ierr;
2157c7c70f1SSatish Balay   PetscInt       nsends=0,nrecvs=0,i,rownz_max=0;
2163365e775SHong Zhang   PetscMPIInt    *send_rank=PETSC_NULL,*recv_rank=PETSC_NULL;
217b3804887SHong Zhang   PetscInt       *rowrange=mat->rmap.range;
2183f457be1SHong Zhang   Mat_MPIAIJ     *aij = (Mat_MPIAIJ*)mat->data;
219b3804887SHong Zhang   Mat            A=aij->A,B=aij->B,C=*matredundant;
2203f457be1SHong Zhang   Mat_SeqAIJ     *a=(Mat_SeqAIJ*)A->data,*b=(Mat_SeqAIJ*)B->data;
2213f457be1SHong Zhang   PetscScalar    *sbuf_a;
222b3804887SHong Zhang   PetscInt       nzlocal=a->nz+b->nz;
223b3804887SHong Zhang   PetscInt       j,cstart=mat->cmap.rstart,cend=mat->cmap.rend,row,nzA,nzB,ncols,*cworkA,*cworkB;
2243f457be1SHong Zhang   PetscInt       rstart=mat->rmap.rstart,rend=mat->rmap.rend,*bmap=aij->garray,M,N;
225b3804887SHong Zhang   PetscInt       *cols,ctmp,lwrite,*rptr,l,*sbuf_j;
2263f457be1SHong Zhang   PetscScalar    *vals,*aworkA,*aworkB;
2273f457be1SHong Zhang   PetscMPIInt    tag1,tag2,tag3,imdex;
2283365e775SHong Zhang   MPI_Request    *s_waits1=PETSC_NULL,*s_waits2=PETSC_NULL,*s_waits3=PETSC_NULL,
2293365e775SHong Zhang                  *r_waits1=PETSC_NULL,*r_waits2=PETSC_NULL,*r_waits3=PETSC_NULL;
2303f457be1SHong Zhang   MPI_Status     recv_status,*send_status;
2313365e775SHong Zhang   PetscInt       *sbuf_nz=PETSC_NULL,*rbuf_nz=PETSC_NULL,count;
2323365e775SHong Zhang   PetscInt       **rbuf_j=PETSC_NULL;
2333365e775SHong Zhang   PetscScalar    **rbuf_a=PETSC_NULL;
234b3804887SHong Zhang   Mat_Redundant  *redund=PETSC_NULL;
235776b82aeSLisandro Dalcin   PetscContainer container;
2363f457be1SHong Zhang 
2373f457be1SHong Zhang   PetscFunctionBegin;
2383f457be1SHong Zhang   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
2393f457be1SHong Zhang   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
240b3804887SHong Zhang 
241b3804887SHong Zhang   if (reuse == MAT_REUSE_MATRIX) {
242b3804887SHong Zhang     ierr = MatGetSize(C,&M,&N);CHKERRQ(ierr);
243b3804887SHong Zhang     if (M != N || M != mat->rmap.N) SETERRQ(PETSC_ERR_ARG_SIZ,"Cannot reuse matrix. Wrong global size");
244b3804887SHong Zhang     ierr = MatGetLocalSize(C,&M,&N);CHKERRQ(ierr);
245b3804887SHong Zhang     if (M != N || M != mlocal_sub) SETERRQ(PETSC_ERR_ARG_SIZ,"Cannot reuse matrix. Wrong local size");
246b3804887SHong Zhang     ierr = PetscObjectQuery((PetscObject)C,"Mat_Redundant",(PetscObject *)&container);CHKERRQ(ierr);
247b3804887SHong Zhang     if (container) {
248776b82aeSLisandro Dalcin       ierr = PetscContainerGetPointer(container,(void **)&redund);CHKERRQ(ierr);
249b3804887SHong Zhang     } else {
250b3804887SHong Zhang       SETERRQ(PETSC_ERR_PLIB,"Container does not exit");
251b3804887SHong Zhang     }
252b3804887SHong Zhang     if (nzlocal != redund->nzlocal) SETERRQ(PETSC_ERR_ARG_SIZ,"Cannot reuse matrix. Wrong nzlocal");
253b3804887SHong Zhang 
254b3804887SHong Zhang     nsends    = redund->nsends;
255b3804887SHong Zhang     nrecvs    = redund->nrecvs;
256b3804887SHong Zhang     send_rank = redund->send_rank; recv_rank = send_rank + size;
257b3804887SHong Zhang     sbuf_nz   = redund->sbuf_nz;     rbuf_nz = sbuf_nz + nsends;
258b3804887SHong Zhang     sbuf_j    = redund->sbuf_j;
259b3804887SHong Zhang     sbuf_a    = redund->sbuf_a;
260b3804887SHong Zhang     rbuf_j    = redund->rbuf_j;
261b3804887SHong Zhang     rbuf_a    = redund->rbuf_a;
262b3804887SHong Zhang   }
263b3804887SHong Zhang 
264b3804887SHong Zhang   if (reuse == MAT_INITIAL_MATRIX){
265b3804887SHong Zhang     PetscMPIInt  subrank,subsize;
266b3804887SHong Zhang     PetscInt     nleftover,np_subcomm;
267b3804887SHong Zhang     /* get the destination processors' id send_rank, nsends and nrecvs */
2683f457be1SHong Zhang     ierr = MPI_Comm_rank(subcomm,&subrank);CHKERRQ(ierr);
2693f457be1SHong Zhang     ierr = MPI_Comm_size(subcomm,&subsize);CHKERRQ(ierr);
2703f457be1SHong Zhang     ierr = PetscMalloc((2*size+1)*sizeof(PetscMPIInt),&send_rank);
2713f457be1SHong Zhang     recv_rank = send_rank + size;
2723f457be1SHong Zhang     np_subcomm = size/nsubcomm;
2733f457be1SHong Zhang     nleftover  = size - nsubcomm*np_subcomm;
2743f457be1SHong Zhang     nsends = 0; nrecvs = 0;
2753f457be1SHong Zhang     for (i=0; i<size; i++){ /* i=rank*/
2763f457be1SHong Zhang       if (subrank == i/nsubcomm && rank != i){ /* my_subrank == other's subrank */
2773f457be1SHong Zhang         send_rank[nsends] = i; nsends++;
2783f457be1SHong Zhang         recv_rank[nrecvs++] = i;
2793f457be1SHong Zhang       }
2803f457be1SHong Zhang     }
2813f457be1SHong Zhang     if (rank >= size - nleftover){/* this proc is a leftover processor */
2823f457be1SHong Zhang       i = size-nleftover-1;
2833f457be1SHong Zhang       j = 0;
2843f457be1SHong Zhang       while (j < nsubcomm - nleftover){
2853f457be1SHong Zhang         send_rank[nsends++] = i;
2863f457be1SHong Zhang         i--; j++;
2873f457be1SHong Zhang       }
2883f457be1SHong Zhang     }
2893f457be1SHong Zhang 
2903f457be1SHong Zhang     if (nleftover && subsize == size/nsubcomm && subrank==subsize-1){ /* this proc recvs from leftover processors */
2913f457be1SHong Zhang       for (i=0; i<nleftover; i++){
2923f457be1SHong Zhang         recv_rank[nrecvs++] = size-nleftover+i;
2933f457be1SHong Zhang       }
2943f457be1SHong Zhang     }
2953f457be1SHong Zhang 
296b3804887SHong Zhang     /* allocate sbuf_j, sbuf_a */
297b3804887SHong Zhang     i = nzlocal + rowrange[rank+1] - rowrange[rank] + 2;
298b3804887SHong Zhang     ierr = PetscMalloc(i*sizeof(PetscInt),&sbuf_j);CHKERRQ(ierr);
2993f457be1SHong Zhang     ierr = PetscMalloc((nzlocal+1)*sizeof(PetscScalar),&sbuf_a);CHKERRQ(ierr);
300b3804887SHong Zhang   } /* endof if (reuse == MAT_INITIAL_MATRIX) */
3013f457be1SHong Zhang 
302b3804887SHong Zhang   /* copy mat's local entries into the buffers */
303b3804887SHong Zhang   if (reuse == MAT_INITIAL_MATRIX){
304b3804887SHong Zhang     rownz_max = 0;
3053f457be1SHong Zhang     rptr = sbuf_j;
3063f457be1SHong Zhang     cols = sbuf_j + rend-rstart + 1;
3073f457be1SHong Zhang     vals = sbuf_a;
3083f457be1SHong Zhang     rptr[0] = 0;
3093f457be1SHong Zhang     for (i=0; i<rend-rstart; i++){
3103f457be1SHong Zhang       row = i + rstart;
3113f457be1SHong Zhang       nzA    = a->i[i+1] - a->i[i]; nzB = b->i[i+1] - b->i[i];
3123f457be1SHong Zhang       ncols  = nzA + nzB;
3133f457be1SHong Zhang       cworkA = a->j + a->i[i]; cworkB = b->j + b->i[i];
3143f457be1SHong Zhang       aworkA = a->a + a->i[i]; aworkB = b->a + b->i[i];
3153f457be1SHong Zhang       /* load the column indices for this row into cols */
3163f457be1SHong Zhang       lwrite = 0;
3173f457be1SHong Zhang       for (l=0; l<nzB; l++) {
3183f457be1SHong Zhang         if ((ctmp = bmap[cworkB[l]]) < cstart){
3193f457be1SHong Zhang           vals[lwrite]   = aworkB[l];
3203f457be1SHong Zhang           cols[lwrite++] = ctmp;
3213f457be1SHong Zhang         }
3223f457be1SHong Zhang       }
3233f457be1SHong Zhang       for (l=0; l<nzA; l++){
3243f457be1SHong Zhang         vals[lwrite]   = aworkA[l];
3253f457be1SHong Zhang         cols[lwrite++] = cstart + cworkA[l];
3263f457be1SHong Zhang       }
3273f457be1SHong Zhang       for (l=0; l<nzB; l++) {
3283f457be1SHong Zhang         if ((ctmp = bmap[cworkB[l]]) >= cend){
3293f457be1SHong Zhang           vals[lwrite]   = aworkB[l];
3303f457be1SHong Zhang           cols[lwrite++] = ctmp;
3313f457be1SHong Zhang         }
3323f457be1SHong Zhang       }
3333f457be1SHong Zhang       vals += ncols;
3343f457be1SHong Zhang       cols += ncols;
3353f457be1SHong Zhang       rptr[i+1] = rptr[i] + ncols;
336b3804887SHong Zhang       if (rownz_max < ncols) rownz_max = ncols;
3373f457be1SHong Zhang     }
3383f457be1SHong Zhang     if (rptr[rend-rstart] != a->nz + b->nz) SETERRQ4(1, "rptr[%d] %d != %d + %d",rend-rstart,rptr[rend-rstart+1],a->nz,b->nz);
339b3804887SHong Zhang   } else { /* only copy matrix values into sbuf_a */
340b3804887SHong Zhang     rptr = sbuf_j;
341b3804887SHong Zhang     vals = sbuf_a;
342b3804887SHong Zhang     rptr[0] = 0;
343b3804887SHong Zhang     for (i=0; i<rend-rstart; i++){
344b3804887SHong Zhang       row = i + rstart;
345b3804887SHong Zhang       nzA    = a->i[i+1] - a->i[i]; nzB = b->i[i+1] - b->i[i];
346b3804887SHong Zhang       ncols  = nzA + nzB;
347b3804887SHong Zhang       cworkA = a->j + a->i[i]; cworkB = b->j + b->i[i];
348b3804887SHong Zhang       aworkA = a->a + a->i[i]; aworkB = b->a + b->i[i];
349b3804887SHong Zhang       lwrite = 0;
350b3804887SHong Zhang       for (l=0; l<nzB; l++) {
351b3804887SHong Zhang         if ((ctmp = bmap[cworkB[l]]) < cstart) vals[lwrite++] = aworkB[l];
352b3804887SHong Zhang       }
353b3804887SHong Zhang       for (l=0; l<nzA; l++) vals[lwrite++] = aworkA[l];
354b3804887SHong Zhang       for (l=0; l<nzB; l++) {
355b3804887SHong Zhang         if ((ctmp = bmap[cworkB[l]]) >= cend) vals[lwrite++] = aworkB[l];
356b3804887SHong Zhang       }
357b3804887SHong Zhang       vals += ncols;
358b3804887SHong Zhang       rptr[i+1] = rptr[i] + ncols;
359b3804887SHong Zhang     }
360b3804887SHong Zhang   } /* endof if (reuse == MAT_INITIAL_MATRIX) */
3613f457be1SHong Zhang 
3623f457be1SHong Zhang   /* send nzlocal to others, and recv other's nzlocal */
3633f457be1SHong Zhang   /*--------------------------------------------------*/
364b3804887SHong Zhang   if (reuse == MAT_INITIAL_MATRIX){
365b3804887SHong Zhang     ierr = PetscMalloc2(3*(nsends + nrecvs)+1,MPI_Request,&s_waits3,nsends+1,MPI_Status,&send_status);CHKERRQ(ierr);
366b3804887SHong Zhang     s_waits2 = s_waits3 + nsends;
367b3804887SHong Zhang     s_waits1 = s_waits2 + nsends;
368b3804887SHong Zhang     r_waits1 = s_waits1 + nsends;
3693f457be1SHong Zhang     r_waits2 = r_waits1 + nrecvs;
3703f457be1SHong Zhang     r_waits3 = r_waits2 + nrecvs;
371b3804887SHong Zhang   } else {
372b3804887SHong Zhang     ierr = PetscMalloc2(nsends + nrecvs +1,MPI_Request,&s_waits3,nsends+1,MPI_Status,&send_status);CHKERRQ(ierr);
373b3804887SHong Zhang     r_waits3 = s_waits3 + nsends;
374b3804887SHong Zhang   }
3753f457be1SHong Zhang 
376b3804887SHong Zhang   ierr = PetscObjectGetNewTag((PetscObject)mat,&tag3);CHKERRQ(ierr);
377b3804887SHong Zhang   if (reuse == MAT_INITIAL_MATRIX){
378b3804887SHong Zhang     /* get new tags to keep the communication clean */
379b3804887SHong Zhang     ierr = PetscObjectGetNewTag((PetscObject)mat,&tag1);CHKERRQ(ierr);
380b3804887SHong Zhang     ierr = PetscObjectGetNewTag((PetscObject)mat,&tag2);CHKERRQ(ierr);
381b3804887SHong Zhang     ierr = PetscMalloc3(nsends+nrecvs+1,PetscInt,&sbuf_nz,nrecvs,PetscInt*,&rbuf_j,nrecvs,PetscScalar*,&rbuf_a);CHKERRQ(ierr);
382b3804887SHong Zhang     rbuf_nz = sbuf_nz + nsends;
3833f457be1SHong Zhang 
3843f457be1SHong Zhang     /* post receives of other's nzlocal */
3853f457be1SHong Zhang     for (i=0; i<nrecvs; i++){
3863f457be1SHong Zhang       ierr = MPI_Irecv(rbuf_nz+i,1,MPIU_INT,MPI_ANY_SOURCE,tag1,comm,r_waits1+i);CHKERRQ(ierr);
3873f457be1SHong Zhang     }
3883f457be1SHong Zhang     /* send nzlocal to others */
3893f457be1SHong Zhang     for (i=0; i<nsends; i++){
3903f457be1SHong Zhang       sbuf_nz[i] = nzlocal;
3913f457be1SHong Zhang       ierr = MPI_Isend(sbuf_nz+i,1,MPIU_INT,send_rank[i],tag1,comm,s_waits1+i);CHKERRQ(ierr);
3923f457be1SHong Zhang     }
3933f457be1SHong Zhang     /* wait on receives of nzlocal; allocate space for rbuf_j, rbuf_a */
3943f457be1SHong Zhang     count = nrecvs;
3953f457be1SHong Zhang     while (count) {
3963f457be1SHong Zhang       ierr = MPI_Waitany(nrecvs,r_waits1,&imdex,&recv_status);CHKERRQ(ierr);
3973f457be1SHong Zhang       recv_rank[imdex] = recv_status.MPI_SOURCE;
398b3804887SHong Zhang       /* allocate rbuf_a and rbuf_j; then post receives of rbuf_j */
3993f457be1SHong Zhang       ierr = PetscMalloc((rbuf_nz[imdex]+1)*sizeof(PetscScalar),&rbuf_a[imdex]);CHKERRQ(ierr);
4003f457be1SHong Zhang 
401b3804887SHong Zhang       i = rowrange[recv_status.MPI_SOURCE+1] - rowrange[recv_status.MPI_SOURCE]; /* number of expected mat->i */
402b3804887SHong Zhang       rbuf_nz[imdex] += i + 2;
4033f457be1SHong Zhang       ierr = PetscMalloc(rbuf_nz[imdex]*sizeof(PetscInt),&rbuf_j[imdex]);CHKERRQ(ierr);
4043f457be1SHong Zhang       ierr = MPI_Irecv(rbuf_j[imdex],rbuf_nz[imdex],MPIU_INT,recv_status.MPI_SOURCE,tag2,comm,r_waits2+imdex);CHKERRQ(ierr);
4053f457be1SHong Zhang       count--;
4063f457be1SHong Zhang     }
4073f457be1SHong Zhang     /* wait on sends of nzlocal */
4083f457be1SHong Zhang     if (nsends) {ierr = MPI_Waitall(nsends,s_waits1,send_status);CHKERRQ(ierr);}
409b3804887SHong Zhang     /* send mat->i,j to others, and recv from other's */
410b3804887SHong Zhang     /*------------------------------------------------*/
411b3804887SHong Zhang     for (i=0; i<nsends; i++){
412b3804887SHong Zhang       j = nzlocal + rowrange[rank+1] - rowrange[rank] + 1;
413b3804887SHong Zhang       ierr = MPI_Isend(sbuf_j,j,MPIU_INT,send_rank[i],tag2,comm,s_waits2+i);CHKERRQ(ierr);
414b3804887SHong Zhang     }
415b3804887SHong Zhang     /* wait on receives of mat->i,j */
416b3804887SHong Zhang     /*------------------------------*/
417b3804887SHong Zhang     count = nrecvs;
418b3804887SHong Zhang     while (count) {
419b3804887SHong Zhang       ierr = MPI_Waitany(nrecvs,r_waits2,&imdex,&recv_status);CHKERRQ(ierr);
420b3804887SHong Zhang       if (recv_rank[imdex] != recv_status.MPI_SOURCE) SETERRQ2(1, "recv_rank %d != MPI_SOURCE %d",recv_rank[imdex],recv_status.MPI_SOURCE);
421b3804887SHong Zhang       count--;
422b3804887SHong Zhang     }
423b3804887SHong Zhang     /* wait on sends of mat->i,j */
424b3804887SHong Zhang     /*---------------------------*/
425b3804887SHong Zhang     if (nsends) {
426b3804887SHong Zhang       ierr = MPI_Waitall(nsends,s_waits2,send_status);CHKERRQ(ierr);
427b3804887SHong Zhang     }
428b3804887SHong Zhang   } /* endof if (reuse == MAT_INITIAL_MATRIX) */
4293f457be1SHong Zhang 
430b3804887SHong Zhang   /* post receives, send and receive mat->a */
431b3804887SHong Zhang   /*----------------------------------------*/
432b3804887SHong Zhang   for (imdex=0; imdex<nrecvs; imdex++) {
433b3804887SHong Zhang     ierr = MPI_Irecv(rbuf_a[imdex],rbuf_nz[imdex],MPIU_SCALAR,recv_rank[imdex],tag3,comm,r_waits3+imdex);CHKERRQ(ierr);
434b3804887SHong Zhang   }
4353f457be1SHong Zhang   for (i=0; i<nsends; i++){
4363f457be1SHong Zhang     ierr = MPI_Isend(sbuf_a,nzlocal,MPIU_SCALAR,send_rank[i],tag3,comm,s_waits3+i);CHKERRQ(ierr);
4373f457be1SHong Zhang   }
4383f457be1SHong Zhang   count = nrecvs;
4393f457be1SHong Zhang   while (count) {
4403f457be1SHong Zhang     ierr = MPI_Waitany(nrecvs,r_waits3,&imdex,&recv_status);CHKERRQ(ierr);
4413f457be1SHong Zhang     if (recv_rank[imdex] != recv_status.MPI_SOURCE) SETERRQ2(1, "recv_rank %d != MPI_SOURCE %d",recv_rank[imdex],recv_status.MPI_SOURCE);
4423f457be1SHong Zhang     count--;
4433f457be1SHong Zhang   }
4443f457be1SHong Zhang   if (nsends) {
4453f457be1SHong Zhang     ierr = MPI_Waitall(nsends,s_waits3,send_status);CHKERRQ(ierr);
4463f457be1SHong Zhang   }
447b3804887SHong Zhang 
448b3804887SHong Zhang   ierr = PetscFree2(s_waits3,send_status);CHKERRQ(ierr);
4493f457be1SHong Zhang 
4503f457be1SHong Zhang   /* create redundant matrix */
4513f457be1SHong Zhang   /*-------------------------*/
4520ae51fcdSHong Zhang   if (reuse == MAT_INITIAL_MATRIX){
453b3804887SHong Zhang     /* compute rownz_max for preallocation */
454b3804887SHong Zhang     for (imdex=0; imdex<nrecvs; imdex++){
455b3804887SHong Zhang       j = rowrange[recv_rank[imdex]+1] - rowrange[recv_rank[imdex]];
456b3804887SHong Zhang       rptr = rbuf_j[imdex];
457b3804887SHong Zhang       for (i=0; i<j; i++){
458b3804887SHong Zhang         ncols = rptr[i+1] - rptr[i];
459b3804887SHong Zhang         if (rownz_max < ncols) rownz_max = ncols;
460b3804887SHong Zhang       }
461b3804887SHong Zhang     }
462b3804887SHong Zhang 
4633f457be1SHong Zhang     ierr = MatCreate(subcomm,&C);CHKERRQ(ierr);
4643f457be1SHong Zhang     ierr = MatSetSizes(C,mlocal_sub,mlocal_sub,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
4653f457be1SHong Zhang     ierr = MatSetFromOptions(C);CHKERRQ(ierr);
466b3804887SHong Zhang     ierr = MatSeqAIJSetPreallocation(C,rownz_max,PETSC_NULL);CHKERRQ(ierr);
467b3804887SHong Zhang     ierr = MatMPIAIJSetPreallocation(C,rownz_max,PETSC_NULL,rownz_max,PETSC_NULL);CHKERRQ(ierr);
4680ae51fcdSHong Zhang   } else {
4690ae51fcdSHong Zhang     C = *matredundant;
4700ae51fcdSHong Zhang   }
471b3804887SHong Zhang 
4723f457be1SHong Zhang   /* insert local matrix entries */
4733f457be1SHong Zhang   rptr = sbuf_j;
4743f457be1SHong Zhang   cols = sbuf_j + rend-rstart + 1;
4753f457be1SHong Zhang   vals = sbuf_a;
4763f457be1SHong Zhang   for (i=0; i<rend-rstart; i++){
4773f457be1SHong Zhang     row   = i + rstart;
4783f457be1SHong Zhang     ncols = rptr[i+1] - rptr[i];
4793f457be1SHong Zhang     ierr = MatSetValues(C,1,&row,ncols,cols,vals,INSERT_VALUES);CHKERRQ(ierr);
4803f457be1SHong Zhang     vals += ncols;
4813f457be1SHong Zhang     cols += ncols;
4823f457be1SHong Zhang   }
4833f457be1SHong Zhang   /* insert received matrix entries */
4843f457be1SHong Zhang   for (imdex=0; imdex<nrecvs; imdex++){
4853f457be1SHong Zhang     rstart = rowrange[recv_rank[imdex]];
4863f457be1SHong Zhang     rend   = rowrange[recv_rank[imdex]+1];
4873f457be1SHong Zhang     rptr = rbuf_j[imdex];
4883f457be1SHong Zhang     cols = rbuf_j[imdex] + rend-rstart + 1;
4893f457be1SHong Zhang     vals = rbuf_a[imdex];
4903f457be1SHong Zhang     for (i=0; i<rend-rstart; i++){
4913f457be1SHong Zhang       row   = i + rstart;
4923f457be1SHong Zhang       ncols = rptr[i+1] - rptr[i];
4933f457be1SHong Zhang       ierr = MatSetValues(C,1,&row,ncols,cols,vals,INSERT_VALUES);CHKERRQ(ierr);
4943f457be1SHong Zhang       vals += ncols;
4953f457be1SHong Zhang       cols += ncols;
4963f457be1SHong Zhang     }
4973f457be1SHong Zhang   }
4983f457be1SHong Zhang   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
4993f457be1SHong Zhang   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
5003f457be1SHong Zhang   ierr = MatGetSize(C,&M,&N);CHKERRQ(ierr);
5013f457be1SHong Zhang   if (M != mat->rmap.N || N != mat->cmap.N) SETERRQ2(PETSC_ERR_ARG_INCOMP,"redundant mat size %d != input mat size %d",M,mat->rmap.N);
5020ae51fcdSHong Zhang   if (reuse == MAT_INITIAL_MATRIX){
503776b82aeSLisandro Dalcin     PetscContainer container;
5043f457be1SHong Zhang     *matredundant = C;
505b3804887SHong Zhang     /* create a supporting struct and attach it to C for reuse */
506b3804887SHong Zhang     ierr = PetscNew(Mat_Redundant,&redund);CHKERRQ(ierr);
507776b82aeSLisandro Dalcin     ierr = PetscContainerCreate(PETSC_COMM_SELF,&container);CHKERRQ(ierr);
508776b82aeSLisandro Dalcin     ierr = PetscContainerSetPointer(container,redund);CHKERRQ(ierr);
509b3804887SHong Zhang     ierr = PetscObjectCompose((PetscObject)C,"Mat_Redundant",(PetscObject)container);CHKERRQ(ierr);
510776b82aeSLisandro Dalcin     ierr = PetscContainerSetUserDestroy(container,PetscContainerDestroy_MatRedundant);CHKERRQ(ierr);
5113f457be1SHong Zhang 
512b3804887SHong Zhang     redund->nzlocal = nzlocal;
513b3804887SHong Zhang     redund->nsends  = nsends;
514b3804887SHong Zhang     redund->nrecvs  = nrecvs;
515b3804887SHong Zhang     redund->send_rank = send_rank;
516b3804887SHong Zhang     redund->sbuf_nz = sbuf_nz;
517b3804887SHong Zhang     redund->sbuf_j  = sbuf_j;
518b3804887SHong Zhang     redund->sbuf_a  = sbuf_a;
519b3804887SHong Zhang     redund->rbuf_j  = rbuf_j;
520b3804887SHong Zhang     redund->rbuf_a  = rbuf_a;
521b3804887SHong Zhang 
522b3804887SHong Zhang     redund->MatDestroy = C->ops->destroy;
523b3804887SHong Zhang     C->ops->destroy    = MatDestroy_MatRedundant;
5243f457be1SHong Zhang   }
5253f457be1SHong Zhang   PetscFunctionReturn(0);
5263f457be1SHong Zhang }
5273f457be1SHong Zhang 
5284b9ad928SBarry Smith #undef __FUNCT__
5294b9ad928SBarry Smith #define __FUNCT__ "PCSetUp_Redundant"
5306849ba73SBarry Smith static PetscErrorCode PCSetUp_Redundant(PC pc)
5314b9ad928SBarry Smith {
5324b9ad928SBarry Smith   PC_Redundant   *red = (PC_Redundant*)pc->data;
533dfbe8321SBarry Smith   PetscErrorCode ierr;
5343f457be1SHong Zhang   PetscInt       mstart,mend,mlocal,m;
53513f74950SBarry Smith   PetscMPIInt    size;
5364b9ad928SBarry Smith   MatReuse       reuse = MAT_INITIAL_MATRIX;
5374b9ad928SBarry Smith   MatStructure   str   = DIFFERENT_NONZERO_PATTERN;
538*1fbd8f88SHong Zhang   MPI_Comm       comm = pc->comm;
53923ce1328SBarry Smith   Vec            vec;
5403f457be1SHong Zhang   PetscInt       mlocal_sub;
5413f457be1SHong Zhang   PetscMPIInt    subsize,subrank;
542*1fbd8f88SHong Zhang   PetscInt       rstart_sub,rend_sub,mloc_sub,nsubcomm;
543*1fbd8f88SHong Zhang   const char     *prefix;
5443f457be1SHong Zhang 
5454b9ad928SBarry Smith   PetscFunctionBegin;
54623ce1328SBarry Smith   ierr = MatGetVecs(pc->pmat,&vec,0);CHKERRQ(ierr);
54723ce1328SBarry Smith   ierr = VecGetSize(vec,&m);CHKERRQ(ierr);
548*1fbd8f88SHong Zhang 
5494b9ad928SBarry Smith   if (!pc->setupcalled) {
550*1fbd8f88SHong Zhang     ierr = PetscSubcommCreate(comm,red->nsubcomm,&red->psubcomm);CHKERRQ(ierr);
551*1fbd8f88SHong Zhang     ierr = PetscLogObjectMemory(pc,sizeof(PetscSubcomm));CHKERRQ(ierr);
552*1fbd8f88SHong Zhang 
553*1fbd8f88SHong Zhang     /* create a new PC that processors in each subcomm have copy of */
554*1fbd8f88SHong Zhang     MPI_Comm subcomm = red->psubcomm->comm;
555*1fbd8f88SHong Zhang     ierr = PCCreate(subcomm,&red->pc);CHKERRQ(ierr);
556*1fbd8f88SHong Zhang     ierr = PCSetType(red->pc,PCLU);CHKERRQ(ierr);
557*1fbd8f88SHong Zhang     ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
558*1fbd8f88SHong Zhang     ierr = PCSetOptionsPrefix(red->pc,prefix);CHKERRQ(ierr);
559*1fbd8f88SHong Zhang     ierr = PCAppendOptionsPrefix(red->pc,"redundant_");CHKERRQ(ierr);
560*1fbd8f88SHong Zhang     ierr = PCSetFromOptions(red->pc);CHKERRQ(ierr);
561*1fbd8f88SHong Zhang 
5623f457be1SHong Zhang     /* create working vectors xsub/ysub and xdup/ydup */
56323ce1328SBarry Smith     ierr = VecGetLocalSize(vec,&mlocal);CHKERRQ(ierr);
5643f457be1SHong Zhang     ierr = VecGetOwnershipRange(vec,&mstart,&mend);CHKERRQ(ierr);
5654b9ad928SBarry Smith 
5663f457be1SHong Zhang     /* get local size of xsub/ysub */
567*1fbd8f88SHong Zhang     ierr = MPI_Comm_size(subcomm,&subsize);CHKERRQ(ierr);
568*1fbd8f88SHong Zhang     ierr = MPI_Comm_rank(subcomm,&subrank);CHKERRQ(ierr);
569*1fbd8f88SHong Zhang     rstart_sub = pc->pmat->rmap.range[red->psubcomm->n*subrank]; /* rstart in xsub/ysub */
5703f457be1SHong Zhang     if (subrank+1 < subsize){
571*1fbd8f88SHong Zhang       rend_sub = pc->pmat->rmap.range[red->psubcomm->n*(subrank+1)];
5723f457be1SHong Zhang     } else {
5733f457be1SHong Zhang       rend_sub = m;
5743f457be1SHong Zhang     }
5753f457be1SHong Zhang     mloc_sub = rend_sub - rstart_sub;
576*1fbd8f88SHong Zhang     ierr = VecCreateMPI(subcomm,mloc_sub,PETSC_DECIDE,&red->ysub);CHKERRQ(ierr);
5773f457be1SHong Zhang     /* create xsub with empty local arrays, because xdup's arrays will be placed into it */
578*1fbd8f88SHong Zhang     ierr = VecCreateMPIWithArray(subcomm,mloc_sub,PETSC_DECIDE,PETSC_NULL,&red->xsub);CHKERRQ(ierr);
5793f457be1SHong Zhang 
5803f457be1SHong Zhang     /* create xdup and ydup. ydup has empty local arrays because ysub's arrays will be place into it.
5813f457be1SHong Zhang        Note: we use communicator dupcomm, not pc->comm! */
582*1fbd8f88SHong Zhang     ierr = VecCreateMPI(red->psubcomm->dupparent,mloc_sub,PETSC_DECIDE,&red->xdup);CHKERRQ(ierr);
583*1fbd8f88SHong Zhang     ierr = VecCreateMPIWithArray(red->psubcomm->dupparent,mloc_sub,PETSC_DECIDE,PETSC_NULL,&red->ydup);CHKERRQ(ierr);
5843f457be1SHong Zhang 
5853f457be1SHong Zhang     /* create vec scatters */
5863f457be1SHong Zhang     if (!red->scatterin){
5873f457be1SHong Zhang       IS       is1,is2;
5883f457be1SHong Zhang       PetscInt *idx1,*idx2,i,j,k;
589*1fbd8f88SHong Zhang       ierr = PetscMalloc(2*red->psubcomm->n*mlocal*sizeof(PetscInt),&idx1);CHKERRQ(ierr);
590*1fbd8f88SHong Zhang       idx2 = idx1 + red->psubcomm->n*mlocal;
5913f457be1SHong Zhang       j = 0;
592*1fbd8f88SHong Zhang       for (k=0; k<red->psubcomm->n; k++){
5933f457be1SHong Zhang         for (i=mstart; i<mend; i++){
5943f457be1SHong Zhang           idx1[j]   = i;
5953f457be1SHong Zhang           idx2[j++] = i + m*k;
5963f457be1SHong Zhang         }
5973f457be1SHong Zhang       }
598*1fbd8f88SHong Zhang       ierr = ISCreateGeneral(comm,red->psubcomm->n*mlocal,idx1,&is1);CHKERRQ(ierr);
599*1fbd8f88SHong Zhang       ierr = ISCreateGeneral(comm,red->psubcomm->n*mlocal,idx2,&is2);CHKERRQ(ierr);
6003f457be1SHong Zhang       ierr = VecScatterCreate(vec,is1,red->xdup,is2,&red->scatterin);CHKERRQ(ierr);
6013f457be1SHong Zhang       ierr = ISDestroy(is1);CHKERRQ(ierr);
6023f457be1SHong Zhang       ierr = ISDestroy(is2);CHKERRQ(ierr);
6033f457be1SHong Zhang 
604*1fbd8f88SHong Zhang       ierr = ISCreateStride(comm,mlocal,mstart+ red->psubcomm->color*m,1,&is1);CHKERRQ(ierr);
6053f457be1SHong Zhang       ierr = ISCreateStride(comm,mlocal,mstart,1,&is2);CHKERRQ(ierr);
6063f457be1SHong Zhang       ierr = VecScatterCreate(red->xdup,is1,vec,is2,&red->scatterout);CHKERRQ(ierr);
6073f457be1SHong Zhang       ierr = ISDestroy(is1);CHKERRQ(ierr);
6083f457be1SHong Zhang       ierr = ISDestroy(is2);CHKERRQ(ierr);
6093f457be1SHong Zhang       ierr = PetscFree(idx1);CHKERRQ(ierr);
6104b9ad928SBarry Smith     }
6114b9ad928SBarry Smith   }
61223ce1328SBarry Smith   ierr = VecDestroy(vec);CHKERRQ(ierr);
6134b9ad928SBarry Smith 
6144b9ad928SBarry Smith   /* if pmatrix set by user is sequential then we do not need to gather the parallel matrix */
6153f457be1SHong Zhang   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
6164b9ad928SBarry Smith   if (size == 1) {
6174b9ad928SBarry Smith     red->useparallelmat = PETSC_FALSE;
6184b9ad928SBarry Smith   }
6194b9ad928SBarry Smith 
6204b9ad928SBarry Smith   if (red->useparallelmat) {
6214b9ad928SBarry Smith     if (pc->setupcalled == 1 && pc->flag == DIFFERENT_NONZERO_PATTERN) {
6224b9ad928SBarry Smith       /* destroy old matrices */
6234b9ad928SBarry Smith       if (red->pmats) {
624b3804887SHong Zhang         ierr = MatDestroy(red->pmats);CHKERRQ(ierr);
6254b9ad928SBarry Smith       }
6264b9ad928SBarry Smith     } else if (pc->setupcalled == 1) {
6274b9ad928SBarry Smith       reuse = MAT_REUSE_MATRIX;
6284b9ad928SBarry Smith       str   = SAME_NONZERO_PATTERN;
6294b9ad928SBarry Smith     }
6304b9ad928SBarry Smith 
6313f457be1SHong Zhang     /* grab the parallel matrix and put it into processors of a subcomminicator */
632f664ae05SHong Zhang     /*--------------------------------------------------------------------------*/
633f664ae05SHong Zhang     ierr = VecGetLocalSize(red->ysub,&mlocal_sub);CHKERRQ(ierr);
634*1fbd8f88SHong Zhang     ierr = MatGetRedundantMatrix_AIJ(pc->pmat,red->psubcomm->n,red->psubcomm->comm,mlocal_sub,reuse,&red->pmats);CHKERRQ(ierr);
6353f457be1SHong Zhang     /* tell PC of the subcommunicator its operators */
636b3804887SHong Zhang     ierr = PCSetOperators(red->pc,red->pmats,red->pmats,str);CHKERRQ(ierr);
6374b9ad928SBarry Smith   } else {
6384b9ad928SBarry Smith     ierr = PCSetOperators(red->pc,pc->mat,pc->pmat,pc->flag);CHKERRQ(ierr);
6394b9ad928SBarry Smith   }
6404b9ad928SBarry Smith   ierr = PCSetFromOptions(red->pc);CHKERRQ(ierr);
6414b9ad928SBarry Smith   ierr = PCSetUp(red->pc);CHKERRQ(ierr);
6424b9ad928SBarry Smith   PetscFunctionReturn(0);
6434b9ad928SBarry Smith }
6444b9ad928SBarry Smith 
6454b9ad928SBarry Smith #undef __FUNCT__
6464b9ad928SBarry Smith #define __FUNCT__ "PCApply_Redundant"
6476849ba73SBarry Smith static PetscErrorCode PCApply_Redundant(PC pc,Vec x,Vec y)
6484b9ad928SBarry Smith {
6494b9ad928SBarry Smith   PC_Redundant   *red = (PC_Redundant*)pc->data;
650dfbe8321SBarry Smith   PetscErrorCode ierr;
6513f457be1SHong Zhang   PetscScalar    *array;
6524b9ad928SBarry Smith 
6534b9ad928SBarry Smith   PetscFunctionBegin;
6543f457be1SHong Zhang   /* scatter x to xdup */
6553f457be1SHong Zhang   ierr = VecScatterBegin(x,red->xdup,INSERT_VALUES,SCATTER_FORWARD,red->scatterin);CHKERRQ(ierr);
6563f457be1SHong Zhang   ierr = VecScatterEnd(x,red->xdup,INSERT_VALUES,SCATTER_FORWARD,red->scatterin);CHKERRQ(ierr);
6573f457be1SHong Zhang 
6583f457be1SHong Zhang   /* place xdup's local array into xsub */
6593f457be1SHong Zhang   ierr = VecGetArray(red->xdup,&array);CHKERRQ(ierr);
6603f457be1SHong Zhang   ierr = VecPlaceArray(red->xsub,(const PetscScalar*)array);CHKERRQ(ierr);
6614b9ad928SBarry Smith 
6624b9ad928SBarry Smith   /* apply preconditioner on each processor */
6633f457be1SHong Zhang   ierr = PCApply(red->pc,red->xsub,red->ysub);CHKERRQ(ierr);
6643f457be1SHong Zhang   ierr = VecResetArray(red->xsub);CHKERRQ(ierr);
6653f457be1SHong Zhang   ierr = VecRestoreArray(red->xdup,&array);CHKERRQ(ierr);
6664b9ad928SBarry Smith 
6673f457be1SHong Zhang   /* place ysub's local array into ydup */
6683f457be1SHong Zhang   ierr = VecGetArray(red->ysub,&array);CHKERRQ(ierr);
6693f457be1SHong Zhang   ierr = VecPlaceArray(red->ydup,(const PetscScalar*)array);CHKERRQ(ierr);
6703f457be1SHong Zhang 
6713f457be1SHong Zhang   /* scatter ydup to y */
6723f457be1SHong Zhang   ierr = VecScatterBegin(red->ydup,y,INSERT_VALUES,SCATTER_FORWARD,red->scatterout);CHKERRQ(ierr);
6733f457be1SHong Zhang   ierr = VecScatterEnd(red->ydup,y,INSERT_VALUES,SCATTER_FORWARD,red->scatterout);CHKERRQ(ierr);
6743f457be1SHong Zhang   ierr = VecResetArray(red->ydup);CHKERRQ(ierr);
6753f457be1SHong Zhang   ierr = VecRestoreArray(red->ysub,&array);CHKERRQ(ierr);
6764b9ad928SBarry Smith   PetscFunctionReturn(0);
6774b9ad928SBarry Smith }
6784b9ad928SBarry Smith 
6794b9ad928SBarry Smith #undef __FUNCT__
6804b9ad928SBarry Smith #define __FUNCT__ "PCDestroy_Redundant"
6816849ba73SBarry Smith static PetscErrorCode PCDestroy_Redundant(PC pc)
6824b9ad928SBarry Smith {
6834b9ad928SBarry Smith   PC_Redundant   *red = (PC_Redundant*)pc->data;
684dfbe8321SBarry Smith   PetscErrorCode ierr;
6854b9ad928SBarry Smith 
6864b9ad928SBarry Smith   PetscFunctionBegin;
6874b9ad928SBarry Smith   if (red->scatterin)  {ierr = VecScatterDestroy(red->scatterin);CHKERRQ(ierr);}
6884b9ad928SBarry Smith   if (red->scatterout) {ierr = VecScatterDestroy(red->scatterout);CHKERRQ(ierr);}
6893f457be1SHong Zhang   if (red->ysub)       {ierr = VecDestroy(red->ysub);CHKERRQ(ierr);}
6903f457be1SHong Zhang   if (red->xsub)       {ierr = VecDestroy(red->xsub);CHKERRQ(ierr);}
6913f457be1SHong Zhang   if (red->xdup)       {ierr = VecDestroy(red->xdup);CHKERRQ(ierr);}
6923f457be1SHong Zhang   if (red->ydup)       {ierr = VecDestroy(red->ydup);CHKERRQ(ierr);}
693b3804887SHong Zhang   if (red->pmats) {
694b3804887SHong Zhang     ierr = MatDestroy(red->pmats);CHKERRQ(ierr);
6953f457be1SHong Zhang   }
696*1fbd8f88SHong Zhang   ierr = PetscSubcommDestroy(red->psubcomm);CHKERRQ(ierr);
6974b9ad928SBarry Smith   ierr = PCDestroy(red->pc);CHKERRQ(ierr);
6984b9ad928SBarry Smith   ierr = PetscFree(red);CHKERRQ(ierr);
6994b9ad928SBarry Smith   PetscFunctionReturn(0);
7004b9ad928SBarry Smith }
7014b9ad928SBarry Smith 
7024b9ad928SBarry Smith #undef __FUNCT__
7034b9ad928SBarry Smith #define __FUNCT__ "PCSetFromOptions_Redundant"
7046849ba73SBarry Smith static PetscErrorCode PCSetFromOptions_Redundant(PC pc)
7054b9ad928SBarry Smith {
706a98ce0f4SHong Zhang   PetscErrorCode ierr;
707a98ce0f4SHong Zhang   PC_Redundant   *red = (PC_Redundant*)pc->data;
708*1fbd8f88SHong Zhang   PetscMPIInt    size;
709a98ce0f4SHong Zhang 
7104b9ad928SBarry Smith   PetscFunctionBegin;
711a98ce0f4SHong Zhang   ierr = PetscOptionsHead("Redundant options");CHKERRQ(ierr);
712*1fbd8f88SHong Zhang   ierr = MPI_Comm_size(pc->comm,&size);CHKERRQ(ierr);
713*1fbd8f88SHong Zhang   ierr = PetscOptionsInt("-pc_redundant_number_comm","Number of subcommunicators","PCRedundantSetNumComm",size,&red->nsubcomm,0);CHKERRQ(ierr);
714a98ce0f4SHong Zhang   ierr = PetscOptionsTail();CHKERRQ(ierr);
7154b9ad928SBarry Smith   PetscFunctionReturn(0);
7164b9ad928SBarry Smith }
7174b9ad928SBarry Smith 
7184b9ad928SBarry Smith EXTERN_C_BEGIN
7194b9ad928SBarry Smith #undef __FUNCT__
7204b9ad928SBarry Smith #define __FUNCT__ "PCRedundantSetScatter_Redundant"
721dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantSetScatter_Redundant(PC pc,VecScatter in,VecScatter out)
7224b9ad928SBarry Smith {
7234b9ad928SBarry Smith   PC_Redundant   *red = (PC_Redundant*)pc->data;
724dfbe8321SBarry Smith   PetscErrorCode ierr;
7254b9ad928SBarry Smith 
7264b9ad928SBarry Smith   PetscFunctionBegin;
7274b9ad928SBarry Smith   red->scatterin  = in;
7284b9ad928SBarry Smith   red->scatterout = out;
7294b9ad928SBarry Smith   ierr = PetscObjectReference((PetscObject)in);CHKERRQ(ierr);
7304b9ad928SBarry Smith   ierr = PetscObjectReference((PetscObject)out);CHKERRQ(ierr);
7314b9ad928SBarry Smith   PetscFunctionReturn(0);
7324b9ad928SBarry Smith }
7334b9ad928SBarry Smith EXTERN_C_END
7344b9ad928SBarry Smith 
7354b9ad928SBarry Smith #undef __FUNCT__
7364b9ad928SBarry Smith #define __FUNCT__ "PCRedundantSetScatter"
7374b9ad928SBarry Smith /*@
7384b9ad928SBarry Smith    PCRedundantSetScatter - Sets the scatter used to copy values into the
7394b9ad928SBarry Smith      redundant local solve and the scatter to move them back into the global
7404b9ad928SBarry Smith      vector.
7414b9ad928SBarry Smith 
7424b9ad928SBarry Smith    Collective on PC
7434b9ad928SBarry Smith 
7444b9ad928SBarry Smith    Input Parameters:
7454b9ad928SBarry Smith +  pc - the preconditioner context
7464b9ad928SBarry Smith .  in - the scatter to move the values in
7474b9ad928SBarry Smith -  out - the scatter to move them out
7484b9ad928SBarry Smith 
7494b9ad928SBarry Smith    Level: advanced
7504b9ad928SBarry Smith 
7514b9ad928SBarry Smith .keywords: PC, redundant solve
7524b9ad928SBarry Smith @*/
753dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantSetScatter(PC pc,VecScatter in,VecScatter out)
7544b9ad928SBarry Smith {
755dfbe8321SBarry Smith   PetscErrorCode ierr,(*f)(PC,VecScatter,VecScatter);
7564b9ad928SBarry Smith 
7574b9ad928SBarry Smith   PetscFunctionBegin;
7584482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
7594482741eSBarry Smith   PetscValidHeaderSpecific(in,VEC_SCATTER_COOKIE,2);
7604482741eSBarry Smith   PetscValidHeaderSpecific(out,VEC_SCATTER_COOKIE,3);
7614b9ad928SBarry Smith   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCRedundantSetScatter_C",(void (**)(void))&f);CHKERRQ(ierr);
7624b9ad928SBarry Smith   if (f) {
7634b9ad928SBarry Smith     ierr = (*f)(pc,in,out);CHKERRQ(ierr);
7644b9ad928SBarry Smith   }
7654b9ad928SBarry Smith   PetscFunctionReturn(0);
7664b9ad928SBarry Smith }
7674b9ad928SBarry Smith 
7684b9ad928SBarry Smith EXTERN_C_BEGIN
7694b9ad928SBarry Smith #undef __FUNCT__
7704b9ad928SBarry Smith #define __FUNCT__ "PCRedundantGetPC_Redundant"
771dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantGetPC_Redundant(PC pc,PC *innerpc)
7724b9ad928SBarry Smith {
7734b9ad928SBarry Smith   PC_Redundant *red = (PC_Redundant*)pc->data;
7744b9ad928SBarry Smith 
7754b9ad928SBarry Smith   PetscFunctionBegin;
7764b9ad928SBarry Smith   *innerpc = red->pc;
7774b9ad928SBarry Smith   PetscFunctionReturn(0);
7784b9ad928SBarry Smith }
7794b9ad928SBarry Smith EXTERN_C_END
7804b9ad928SBarry Smith 
7814b9ad928SBarry Smith #undef __FUNCT__
7824b9ad928SBarry Smith #define __FUNCT__ "PCRedundantGetPC"
7834b9ad928SBarry Smith /*@
7844b9ad928SBarry Smith    PCRedundantGetPC - Gets the sequential PC created by the redundant PC.
7854b9ad928SBarry Smith 
7864b9ad928SBarry Smith    Not Collective
7874b9ad928SBarry Smith 
7884b9ad928SBarry Smith    Input Parameter:
7894b9ad928SBarry Smith .  pc - the preconditioner context
7904b9ad928SBarry Smith 
7914b9ad928SBarry Smith    Output Parameter:
7924b9ad928SBarry Smith .  innerpc - the sequential PC
7934b9ad928SBarry Smith 
7944b9ad928SBarry Smith    Level: advanced
7954b9ad928SBarry Smith 
7964b9ad928SBarry Smith .keywords: PC, redundant solve
7974b9ad928SBarry Smith @*/
798dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantGetPC(PC pc,PC *innerpc)
7994b9ad928SBarry Smith {
800dfbe8321SBarry Smith   PetscErrorCode ierr,(*f)(PC,PC*);
8014b9ad928SBarry Smith 
8024b9ad928SBarry Smith   PetscFunctionBegin;
8034482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
8044482741eSBarry Smith   PetscValidPointer(innerpc,2);
8054b9ad928SBarry Smith   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCRedundantGetPC_C",(void (**)(void))&f);CHKERRQ(ierr);
8064b9ad928SBarry Smith   if (f) {
8074b9ad928SBarry Smith     ierr = (*f)(pc,innerpc);CHKERRQ(ierr);
8084b9ad928SBarry Smith   }
8094b9ad928SBarry Smith   PetscFunctionReturn(0);
8104b9ad928SBarry Smith }
8114b9ad928SBarry Smith 
8124b9ad928SBarry Smith EXTERN_C_BEGIN
8134b9ad928SBarry Smith #undef __FUNCT__
8144b9ad928SBarry Smith #define __FUNCT__ "PCRedundantGetOperators_Redundant"
815dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantGetOperators_Redundant(PC pc,Mat *mat,Mat *pmat)
8164b9ad928SBarry Smith {
8174b9ad928SBarry Smith   PC_Redundant *red = (PC_Redundant*)pc->data;
8184b9ad928SBarry Smith 
8194b9ad928SBarry Smith   PetscFunctionBegin;
820b3804887SHong Zhang   if (mat)  *mat  = red->pmats;
821b3804887SHong Zhang   if (pmat) *pmat = red->pmats;
8224b9ad928SBarry Smith   PetscFunctionReturn(0);
8234b9ad928SBarry Smith }
8244b9ad928SBarry Smith EXTERN_C_END
8254b9ad928SBarry Smith 
8264b9ad928SBarry Smith #undef __FUNCT__
8274b9ad928SBarry Smith #define __FUNCT__ "PCRedundantGetOperators"
8284b9ad928SBarry Smith /*@
8294b9ad928SBarry Smith    PCRedundantGetOperators - gets the sequential matrix and preconditioner matrix
8304b9ad928SBarry Smith 
8314b9ad928SBarry Smith    Not Collective
8324b9ad928SBarry Smith 
8334b9ad928SBarry Smith    Input Parameter:
8344b9ad928SBarry Smith .  pc - the preconditioner context
8354b9ad928SBarry Smith 
8364b9ad928SBarry Smith    Output Parameters:
8374b9ad928SBarry Smith +  mat - the matrix
8384b9ad928SBarry Smith -  pmat - the (possibly different) preconditioner matrix
8394b9ad928SBarry Smith 
8404b9ad928SBarry Smith    Level: advanced
8414b9ad928SBarry Smith 
8424b9ad928SBarry Smith .keywords: PC, redundant solve
8434b9ad928SBarry Smith @*/
844dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantGetOperators(PC pc,Mat *mat,Mat *pmat)
8454b9ad928SBarry Smith {
846dfbe8321SBarry Smith   PetscErrorCode ierr,(*f)(PC,Mat*,Mat*);
8474b9ad928SBarry Smith 
8484b9ad928SBarry Smith   PetscFunctionBegin;
8494482741eSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
8504482741eSBarry Smith   if (mat)  PetscValidPointer(mat,2);
8514482741eSBarry Smith   if (pmat) PetscValidPointer(pmat,3);
8524b9ad928SBarry Smith   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCRedundantGetOperators_C",(void (**)(void))&f);CHKERRQ(ierr);
8534b9ad928SBarry Smith   if (f) {
8544b9ad928SBarry Smith     ierr = (*f)(pc,mat,pmat);CHKERRQ(ierr);
8554b9ad928SBarry Smith   }
8564b9ad928SBarry Smith   PetscFunctionReturn(0);
8574b9ad928SBarry Smith }
8584b9ad928SBarry Smith 
8594b9ad928SBarry Smith /* -------------------------------------------------------------------------------------*/
86037a17b4dSBarry Smith /*MC
861a98ce0f4SHong Zhang      PCREDUNDANT - Runs a preconditioner for the entire problem on subgroups of processors
86237a17b4dSBarry Smith 
86337a17b4dSBarry Smith      Options for the redundant preconditioners can be set with -redundant_pc_xxx
86437a17b4dSBarry Smith 
86509391456SBarry Smith   Options Database:
86609391456SBarry Smith .  -pc_redundant_number_comm - number of sub communicators to use
86709391456SBarry Smith 
86837a17b4dSBarry Smith    Level: intermediate
86937a17b4dSBarry Smith 
87037a17b4dSBarry Smith .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PCRedundantSetScatter(),
87137a17b4dSBarry Smith            PCRedundantGetPC(), PCRedundantGetOperators()
87237a17b4dSBarry Smith M*/
87337a17b4dSBarry Smith 
8744b9ad928SBarry Smith EXTERN_C_BEGIN
8754b9ad928SBarry Smith #undef __FUNCT__
8764b9ad928SBarry Smith #define __FUNCT__ "PCCreate_Redundant"
877dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_Redundant(PC pc)
8784b9ad928SBarry Smith {
879dfbe8321SBarry Smith   PetscErrorCode ierr;
8804b9ad928SBarry Smith   PC_Redundant   *red;
8813f457be1SHong Zhang 
8824b9ad928SBarry Smith   PetscFunctionBegin;
8834b9ad928SBarry Smith   ierr = PetscNew(PC_Redundant,&red);CHKERRQ(ierr);
88452e6d16bSBarry Smith   ierr = PetscLogObjectMemory(pc,sizeof(PC_Redundant));CHKERRQ(ierr);
8854b9ad928SBarry Smith   red->useparallelmat = PETSC_TRUE;
886*1fbd8f88SHong Zhang   pc->data            = (void*)red;
8874b9ad928SBarry Smith 
8884b9ad928SBarry Smith   pc->ops->apply           = PCApply_Redundant;
8894b9ad928SBarry Smith   pc->ops->applytranspose  = 0;
8904b9ad928SBarry Smith   pc->ops->setup           = PCSetUp_Redundant;
8914b9ad928SBarry Smith   pc->ops->destroy         = PCDestroy_Redundant;
8924b9ad928SBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_Redundant;
8934b9ad928SBarry Smith   pc->ops->view            = PCView_Redundant;
8944b9ad928SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCRedundantSetScatter_C","PCRedundantSetScatter_Redundant",
8954b9ad928SBarry Smith                     PCRedundantSetScatter_Redundant);CHKERRQ(ierr);
8964b9ad928SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCRedundantGetPC_C","PCRedundantGetPC_Redundant",
8974b9ad928SBarry Smith                     PCRedundantGetPC_Redundant);CHKERRQ(ierr);
8984b9ad928SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCRedundantGetOperators_C","PCRedundantGetOperators_Redundant",
8994b9ad928SBarry Smith                     PCRedundantGetOperators_Redundant);CHKERRQ(ierr);
9004b9ad928SBarry Smith   PetscFunctionReturn(0);
9014b9ad928SBarry Smith }
9024b9ad928SBarry Smith EXTERN_C_END
903