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