1174b6946SBarry Smith #define PETSCKSP_DLL 2174b6946SBarry Smith 3174b6946SBarry Smith 4174b6946SBarry Smith #include "petscpc.h" /*I "petscpc.h" I*/ 5a9f2baa8SLisandro Dalcin #include "petscmg.h" /*I "petscmg.h" I*/ 6174b6946SBarry Smith #include "petscda.h" /*I "petscda.h" I*/ 77233f9f0SBarry Smith #include "../src/ksp/pc/impls/mg/mgimpl.h" 87233f9f0SBarry Smith 97233f9f0SBarry Smith const char *PCExoticTypes[] = {"face","wirebasket","PCExoticType","PC_Exotic",0}; 10174b6946SBarry Smith 11*064c8009SBarry Smith 12*064c8009SBarry Smith 13*064c8009SBarry Smith #undef __FUNCT__ 14*064c8009SBarry Smith #define __FUNCT__ "DAGetWireBasketInterpolation" 15*064c8009SBarry Smith /* 16*064c8009SBarry Smith DAGetWireBasketInterpolation - Gets the interpolation for a wirebasket based coarse space 17*064c8009SBarry Smith 18*064c8009SBarry Smith */ 19*064c8009SBarry Smith PetscErrorCode DAGetWireBasketInterpolation(DA da,Mat Aglobal,MatReuse reuse,Mat *P) 20*064c8009SBarry Smith { 21*064c8009SBarry Smith PetscErrorCode ierr; 22*064c8009SBarry Smith PetscInt dim,i,j,k,m,n,p,dof,Nint,Nface,Nwire,Nsurf,*Iint,*Isurf,cint = 0,csurf = 0,istart,jstart,kstart,*II,N,c = 0; 23*064c8009SBarry Smith PetscInt mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[26],*globals,Ng,*IIint,*IIsurf; 24*064c8009SBarry Smith Mat Xint, Xsurf,Xint_tmp; 25*064c8009SBarry Smith IS isint,issurf,is,row,col; 26*064c8009SBarry Smith ISLocalToGlobalMapping ltg; 27*064c8009SBarry Smith MPI_Comm comm; 28*064c8009SBarry Smith Mat A,Aii,Ais,Asi,*Aholder,iAii; 29*064c8009SBarry Smith MatFactorInfo info; 30*064c8009SBarry Smith PetscScalar *xsurf,*xint; 31*064c8009SBarry Smith #if defined(PETSC_USE_DEBUG) 32*064c8009SBarry Smith PetscScalar tmp; 33*064c8009SBarry Smith #endif 34*064c8009SBarry Smith PetscTable ht; 35*064c8009SBarry Smith 36*064c8009SBarry Smith PetscFunctionBegin; 37*064c8009SBarry Smith ierr = DAGetInfo(da,&dim,0,0,0,&mp,&np,&pp,&dof,0,0,0);CHKERRQ(ierr); 38*064c8009SBarry Smith if (dof != 1) SETERRQ(PETSC_ERR_SUP,"Only for single field problems"); 39*064c8009SBarry Smith if (dim != 3) SETERRQ(PETSC_ERR_SUP,"Only coded for 3d problems"); 40*064c8009SBarry Smith ierr = DAGetCorners(da,0,0,0,&m,&n,&p);CHKERRQ(ierr); 41*064c8009SBarry Smith ierr = DAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth);CHKERRQ(ierr); 42*064c8009SBarry Smith istart = istart ? -1 : 0; 43*064c8009SBarry Smith jstart = jstart ? -1 : 0; 44*064c8009SBarry Smith kstart = kstart ? -1 : 0; 45*064c8009SBarry Smith 46*064c8009SBarry Smith /* 47*064c8009SBarry Smith the columns of P are the interpolation of each coarse grid point (one for each vertex and edge) 48*064c8009SBarry Smith to all the local degrees of freedom (this includes the vertices, edges and faces). 49*064c8009SBarry Smith 50*064c8009SBarry Smith Xint are the subset of the interpolation into the interior 51*064c8009SBarry Smith 52*064c8009SBarry Smith Xface are the interpolation onto faces but not into the interior 53*064c8009SBarry Smith 54*064c8009SBarry Smith Xsurf are the interpolation onto the vertices and edges (the surfbasket) 55*064c8009SBarry Smith Xint 56*064c8009SBarry Smith Symbolically one could write P = ( Xface ) after interchanging the rows to match the natural ordering on the domain 57*064c8009SBarry Smith Xsurf 58*064c8009SBarry Smith */ 59*064c8009SBarry Smith N = (m - istart)*(n - jstart)*(p - kstart); 60*064c8009SBarry Smith Nint = (m-2-istart)*(n-2-jstart)*(p-2-kstart); 61*064c8009SBarry Smith Nface = 2*( (m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart) ); 62*064c8009SBarry Smith Nwire = 4*( (m-2-istart) + (n-2-jstart) + (p-2-kstart) ) + 8; 63*064c8009SBarry Smith Nsurf = Nface + Nwire; 64*064c8009SBarry Smith ierr = MatCreateSeqDense(MPI_COMM_SELF,Nint,26,PETSC_NULL,&Xint);CHKERRQ(ierr); 65*064c8009SBarry Smith ierr = MatCreateSeqDense(MPI_COMM_SELF,Nsurf,26,PETSC_NULL,&Xsurf);CHKERRQ(ierr); 66*064c8009SBarry Smith ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr); 67*064c8009SBarry Smith 68*064c8009SBarry Smith /* 69*064c8009SBarry Smith Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of 70*064c8009SBarry Smith Xsurf will be all zero (thus making the coarse matrix singular). 71*064c8009SBarry Smith */ 72*064c8009SBarry Smith if (m-istart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in X direction must be at least 3"); 73*064c8009SBarry Smith if (n-jstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Y direction must be at least 3"); 74*064c8009SBarry Smith if (p-kstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Z direction must be at least 3"); 75*064c8009SBarry Smith 76*064c8009SBarry Smith cnt = 0; 77*064c8009SBarry Smith xsurf[cnt++] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + Nsurf] = 1;} xsurf[cnt++ + 2*Nsurf] = 1; 78*064c8009SBarry Smith for (j=1;j<n-1-jstart;j++) { xsurf[cnt++ + 3*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 4*Nsurf] = 1;} xsurf[cnt++ + 5*Nsurf] = 1;} 79*064c8009SBarry Smith xsurf[cnt++ + 6*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 7*Nsurf] = 1;} xsurf[cnt++ + 8*Nsurf] = 1; 80*064c8009SBarry Smith for (k=1;k<p-1-kstart;k++) { 81*064c8009SBarry Smith xsurf[cnt++ + 9*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 10*Nsurf] = 1;} xsurf[cnt++ + 11*Nsurf] = 1; 82*064c8009SBarry Smith for (j=1;j<n-1-jstart;j++) { xsurf[cnt++ + 12*Nsurf] = 1; /* these are the interior nodes */ xsurf[cnt++ + 13*Nsurf] = 1;} 83*064c8009SBarry Smith xsurf[cnt++ + 14*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 15*Nsurf] = 1;} xsurf[cnt++ + 16*Nsurf] = 1; 84*064c8009SBarry Smith } 85*064c8009SBarry Smith xsurf[cnt++ + 17*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 18*Nsurf] = 1;} xsurf[cnt++ + 19*Nsurf] = 1; 86*064c8009SBarry Smith for (j=1;j<n-1-jstart;j++) { xsurf[cnt++ + 20*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 21*Nsurf] = 1;} xsurf[cnt++ + 22*Nsurf] = 1;} 87*064c8009SBarry Smith xsurf[cnt++ + 23*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 24*Nsurf] = 1;} xsurf[cnt++ + 25*Nsurf] = 1; 88*064c8009SBarry Smith 89*064c8009SBarry Smith #if defined(PETSC_USE_DEBUG) 90*064c8009SBarry Smith for (i=0; i<Nsurf; i++) { 91*064c8009SBarry Smith tmp = 0.0; 92*064c8009SBarry Smith for (j=0; j<26; j++) { 93*064c8009SBarry Smith tmp += xsurf[i+j*Nsurf]; 94*064c8009SBarry Smith } 95*064c8009SBarry Smith if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xsurf interpolation at i %D value %G",i,PetscAbsScalar(tmp)); 96*064c8009SBarry Smith } 97*064c8009SBarry Smith #endif 98*064c8009SBarry Smith ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr); 99*064c8009SBarry Smith /* ierr = MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);*/ 100*064c8009SBarry Smith 101*064c8009SBarry Smith 102*064c8009SBarry Smith /* 103*064c8009SBarry Smith I are the indices for all the needed vertices (in global numbering) 104*064c8009SBarry Smith Iint are the indices for the interior values, I surf for the surface values 105*064c8009SBarry Smith (This is just for the part of the global matrix obtained with MatGetSubMatrix(), it 106*064c8009SBarry Smith is NOT the local DA ordering.) 107*064c8009SBarry Smith IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering 108*064c8009SBarry Smith */ 109*064c8009SBarry Smith #define Endpoint(a,start,b) (a == 0 || a == (b-1-start)) 110*064c8009SBarry Smith ierr = PetscMalloc3(N,PetscInt,&II,Nint,PetscInt,&Iint,Nsurf,PetscInt,&Isurf);CHKERRQ(ierr); 111*064c8009SBarry Smith ierr = PetscMalloc2(Nint,PetscInt,&IIint,Nsurf,PetscInt,&IIsurf);CHKERRQ(ierr); 112*064c8009SBarry Smith for (k=0; k<p-kstart; k++) { 113*064c8009SBarry Smith for (j=0; j<n-jstart; j++) { 114*064c8009SBarry Smith for (i=0; i<m-istart; i++) { 115*064c8009SBarry Smith II[c++] = i + j*mwidth + k*mwidth*nwidth; 116*064c8009SBarry Smith 117*064c8009SBarry Smith if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) { 118*064c8009SBarry Smith IIint[cint] = i + j*mwidth + k*mwidth*nwidth; 119*064c8009SBarry Smith Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart); 120*064c8009SBarry Smith } else { 121*064c8009SBarry Smith IIsurf[csurf] = i + j*mwidth + k*mwidth*nwidth; 122*064c8009SBarry Smith Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart); 123*064c8009SBarry Smith } 124*064c8009SBarry Smith } 125*064c8009SBarry Smith } 126*064c8009SBarry Smith } 127*064c8009SBarry Smith if (c != N) SETERRQ(PETSC_ERR_PLIB,"c != N"); 128*064c8009SBarry Smith if (cint != Nint) SETERRQ(PETSC_ERR_PLIB,"cint != Nint"); 129*064c8009SBarry Smith if (csurf != Nsurf) SETERRQ(PETSC_ERR_PLIB,"csurf != Nsurf"); 130*064c8009SBarry Smith ierr = DAGetISLocalToGlobalMapping(da,<g);CHKERRQ(ierr); 131*064c8009SBarry Smith ierr = ISLocalToGlobalMappingApply(ltg,N,II,II);CHKERRQ(ierr); 132*064c8009SBarry Smith ierr = ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint);CHKERRQ(ierr); 133*064c8009SBarry Smith ierr = ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf);CHKERRQ(ierr); 134*064c8009SBarry Smith ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr); 135*064c8009SBarry Smith ierr = ISCreateGeneral(comm,N,II,&is);CHKERRQ(ierr); 136*064c8009SBarry Smith ierr = ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,&isint);CHKERRQ(ierr); 137*064c8009SBarry Smith ierr = ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,&issurf);CHKERRQ(ierr); 138*064c8009SBarry Smith ierr = PetscFree3(II,Iint,Isurf);CHKERRQ(ierr); 139*064c8009SBarry Smith 140*064c8009SBarry Smith ierr = MatGetSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder);CHKERRQ(ierr); 141*064c8009SBarry Smith A = *Aholder; 142*064c8009SBarry Smith ierr = PetscFree(Aholder);CHKERRQ(ierr); 143*064c8009SBarry Smith 144*064c8009SBarry Smith ierr = MatGetSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii);CHKERRQ(ierr); 145*064c8009SBarry Smith ierr = MatGetSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais);CHKERRQ(ierr); 146*064c8009SBarry Smith ierr = MatGetSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi);CHKERRQ(ierr); 147*064c8009SBarry Smith 148*064c8009SBarry Smith /* 149*064c8009SBarry Smith Solve for the interpolation onto the interior Xint 150*064c8009SBarry Smith */ 151*064c8009SBarry Smith ierr = MatGetFactor(Aii,MAT_SOLVER_PETSC,MAT_FACTOR_LU,&iAii);CHKERRQ(ierr); 152*064c8009SBarry Smith ierr = MatFactorInfoInitialize(&info);CHKERRQ(ierr); 153*064c8009SBarry Smith ierr = MatGetOrdering(Aii,MATORDERING_ND,&row,&col);CHKERRQ(ierr); 154*064c8009SBarry Smith ierr = MatLUFactorSymbolic(iAii,Aii,row,col,&info);CHKERRQ(ierr); 155*064c8009SBarry Smith ierr = ISDestroy(row);CHKERRQ(ierr); 156*064c8009SBarry Smith ierr = ISDestroy(col);CHKERRQ(ierr); 157*064c8009SBarry Smith ierr = MatLUFactorNumeric(iAii,Aii,&info);CHKERRQ(ierr); 158*064c8009SBarry Smith ierr = MatDuplicate(Xint,MAT_DO_NOT_COPY_VALUES,&Xint_tmp);CHKERRQ(ierr); 159*064c8009SBarry Smith ierr = MatMatMult(Ais,Xsurf,MAT_REUSE_MATRIX,PETSC_DETERMINE,&Xint_tmp);CHKERRQ(ierr); 160*064c8009SBarry Smith ierr = MatScale(Xint_tmp,-1.0);CHKERRQ(ierr); 161*064c8009SBarry Smith ierr = MatMatSolve(iAii,Xint_tmp,Xint);CHKERRQ(ierr); 162*064c8009SBarry Smith ierr = MatDestroy(Xint_tmp);CHKERRQ(ierr); 163*064c8009SBarry Smith ierr = MatDestroy(iAii);CHKERRQ(ierr); 164*064c8009SBarry Smith 165*064c8009SBarry Smith #if defined(PETSC_USE_DEBUG) 166*064c8009SBarry Smith ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr); 167*064c8009SBarry Smith for (i=0; i<Nint; i++) { 168*064c8009SBarry Smith tmp = 0.0; 169*064c8009SBarry Smith for (j=0; j<26; j++) { 170*064c8009SBarry Smith tmp += xint[i+j*Nint]; 171*064c8009SBarry Smith } 172*064c8009SBarry Smith if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xint interpolation at i %D value %G",i,PetscAbsScalar(tmp)); 173*064c8009SBarry Smith } 174*064c8009SBarry Smith ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr); 175*064c8009SBarry Smith /* ierr =MatView(Xint,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); */ 176*064c8009SBarry Smith #endif 177*064c8009SBarry Smith 178*064c8009SBarry Smith 179*064c8009SBarry Smith /* total vertices total faces total edges */ 180*064c8009SBarry Smith Ntotal = (mp + 1)*(np + 1)*(pp + 1) + mp*np*(pp+1) + mp*pp*(np+1) + np*pp*(mp+1) + mp*(np+1)*(pp+1) + np*(mp+1)*(pp+1) + pp*(mp+1)*(np+1); 181*064c8009SBarry Smith 182*064c8009SBarry Smith /* 183*064c8009SBarry Smith For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points 184*064c8009SBarry Smith */ 185*064c8009SBarry Smith cnt = 0; 186*064c8009SBarry Smith gl[cnt++] = 0; { gl[cnt++] = 1;} gl[cnt++] = m-istart-1; 187*064c8009SBarry Smith { gl[cnt++] = mwidth; { gl[cnt++] = mwidth+1;} gl[cnt++] = mwidth + m-istart-1;} 188*064c8009SBarry Smith gl[cnt++] = mwidth*(n-jstart-1); { gl[cnt++] = mwidth*(n-jstart-1)+1;} gl[cnt++] = mwidth*(n-jstart-1) + m-istart-1; 189*064c8009SBarry Smith { 190*064c8009SBarry Smith gl[cnt++] = mwidth*nwidth; { gl[cnt++] = mwidth*nwidth+1;} gl[cnt++] = mwidth*nwidth+ m-istart-1; 191*064c8009SBarry Smith { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;} 192*064c8009SBarry Smith gl[cnt++] = mwidth*nwidth+ mwidth*(n-jstart-1); { gl[cnt++] = mwidth*nwidth+mwidth*(n-jstart-1)+1;} gl[cnt++] = mwidth*nwidth+mwidth*(n-jstart-1) + m-istart-1; 193*064c8009SBarry Smith } 194*064c8009SBarry Smith gl[cnt++] = mwidth*nwidth*(p-kstart-1); { gl[cnt++] = mwidth*nwidth*(p-kstart-1)+1;} gl[cnt++] = mwidth*nwidth*(p-kstart-1) + m-istart-1; 195*064c8009SBarry Smith { gl[cnt++] = mwidth*nwidth*(p-kstart-1) + mwidth; { gl[cnt++] = mwidth*nwidth*(p-kstart-1) + mwidth+1;} gl[cnt++] = mwidth*nwidth*(p-kstart-1)+mwidth+m-istart-1;} 196*064c8009SBarry Smith gl[cnt++] = mwidth*nwidth*(p-kstart-1) + mwidth*(n-jstart-1); { gl[cnt++] = mwidth*nwidth*(p-kstart-1)+ mwidth*(n-jstart-1)+1;} gl[cnt++] = mwidth*nwidth*(p-kstart-1) + mwidth*(n-jstart-1) + m-istart-1; 197*064c8009SBarry Smith 198*064c8009SBarry Smith /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */ 199*064c8009SBarry Smith /* convert that to global numbering and get them on all processes */ 200*064c8009SBarry Smith ierr = ISLocalToGlobalMappingApply(ltg,26,gl,gl);CHKERRQ(ierr); 201*064c8009SBarry Smith /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */ 202*064c8009SBarry Smith ierr = PetscMalloc(26*mp*np*pp*sizeof(PetscInt),&globals);CHKERRQ(ierr); 203*064c8009SBarry Smith ierr = MPI_Allgather(gl,26,MPIU_INT,globals,26,MPIU_INT,((PetscObject)da)->comm);CHKERRQ(ierr); 204*064c8009SBarry Smith 205*064c8009SBarry Smith /* Number the coarse grid points from 0 to Ntotal */ 206*064c8009SBarry Smith ierr = PetscTableCreate(Ntotal/3,&ht);CHKERRQ(ierr); 207*064c8009SBarry Smith for (i=0; i<26*mp*np*pp; i++){ 208*064c8009SBarry Smith ierr = PetscTableAddCount(ht,globals[i]+1);CHKERRQ(ierr); 209*064c8009SBarry Smith } 210*064c8009SBarry Smith ierr = PetscTableGetCount(ht,&cnt);CHKERRQ(ierr); 211*064c8009SBarry Smith if (cnt != Ntotal) SETERRQ2(PETSC_ERR_PLIB,"Hash table size %D not equal to total number coarse grid points %D",cnt,Ntotal); 212*064c8009SBarry Smith ierr = PetscFree(globals);CHKERRQ(ierr); 213*064c8009SBarry Smith for (i=0; i<26; i++) { 214*064c8009SBarry Smith ierr = PetscTableFind(ht,gl[i]+1,&gl[i]);CHKERRQ(ierr); 215*064c8009SBarry Smith gl[i]--; 216*064c8009SBarry Smith } 217*064c8009SBarry Smith ierr = PetscTableDestroy(ht);CHKERRQ(ierr); 218*064c8009SBarry Smith /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */ 219*064c8009SBarry Smith 220*064c8009SBarry Smith /* construct global interpolation matrix */ 221*064c8009SBarry Smith ierr = MatGetLocalSize(Aglobal,&Ng,PETSC_NULL);CHKERRQ(ierr); 222*064c8009SBarry Smith if (reuse == MAT_INITIAL_MATRIX) { 223*064c8009SBarry Smith ierr = MatCreateMPIAIJ(((PetscObject)da)->comm,Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,PETSC_NULL,Nint+Nsurf,PETSC_NULL,P);CHKERRQ(ierr); 224*064c8009SBarry Smith } else { 225*064c8009SBarry Smith ierr = MatZeroEntries(*P);CHKERRQ(ierr); 226*064c8009SBarry Smith } 227*064c8009SBarry Smith ierr = MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr); 228*064c8009SBarry Smith ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr); 229*064c8009SBarry Smith ierr = MatSetValues(*P,Nint,IIint,26,gl,xint,INSERT_VALUES);CHKERRQ(ierr); 230*064c8009SBarry Smith ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr); 231*064c8009SBarry Smith ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr); 232*064c8009SBarry Smith ierr = MatSetValues(*P,Nsurf,IIsurf,26,gl,xsurf,INSERT_VALUES);CHKERRQ(ierr); 233*064c8009SBarry Smith ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr); 234*064c8009SBarry Smith ierr = MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 235*064c8009SBarry Smith ierr = MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 236*064c8009SBarry Smith ierr = PetscFree2(IIint,IIsurf);CHKERRQ(ierr); 237*064c8009SBarry Smith 238*064c8009SBarry Smith #if defined(PETSC_USE_DEBUG) 239*064c8009SBarry Smith { 240*064c8009SBarry Smith Vec x,y; 241*064c8009SBarry Smith PetscScalar *yy; 242*064c8009SBarry Smith ierr = VecCreateMPI(((PetscObject)da)->comm,Ng,PETSC_DETERMINE,&y);CHKERRQ(ierr); 243*064c8009SBarry Smith ierr = VecCreateMPI(((PetscObject)da)->comm,PETSC_DETERMINE,Ntotal,&x);CHKERRQ(ierr); 244*064c8009SBarry Smith ierr = VecSet(x,1.0);CHKERRQ(ierr); 245*064c8009SBarry Smith ierr = MatMult(*P,x,y);CHKERRQ(ierr); 246*064c8009SBarry Smith ierr = VecGetArray(y,&yy);CHKERRQ(ierr); 247*064c8009SBarry Smith for (i=0; i<Ng; i++) { 248*064c8009SBarry Smith if (PetscAbsScalar(yy[i]-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong p interpolation at i %D value %G",i,PetscAbsScalar(yy[i])); 249*064c8009SBarry Smith } 250*064c8009SBarry Smith ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr); 251*064c8009SBarry Smith ierr = VecDestroy(x);CHKERRQ(ierr); 252*064c8009SBarry Smith ierr = VecDestroy(y);CHKERRQ(ierr); 253*064c8009SBarry Smith } 254*064c8009SBarry Smith #endif 255*064c8009SBarry Smith 256*064c8009SBarry Smith ierr = MatDestroy(Aii);CHKERRQ(ierr); 257*064c8009SBarry Smith ierr = MatDestroy(Ais);CHKERRQ(ierr); 258*064c8009SBarry Smith ierr = MatDestroy(Asi);CHKERRQ(ierr); 259*064c8009SBarry Smith ierr = MatDestroy(A);CHKERRQ(ierr); 260*064c8009SBarry Smith ierr = ISDestroy(is);CHKERRQ(ierr); 261*064c8009SBarry Smith ierr = ISDestroy(isint);CHKERRQ(ierr); 262*064c8009SBarry Smith ierr = ISDestroy(issurf);CHKERRQ(ierr); 263*064c8009SBarry Smith ierr = MatDestroy(Xint);CHKERRQ(ierr); 264*064c8009SBarry Smith ierr = MatDestroy(Xsurf);CHKERRQ(ierr); 265*064c8009SBarry Smith PetscFunctionReturn(0); 266*064c8009SBarry Smith } 267*064c8009SBarry Smith 268*064c8009SBarry Smith #undef __FUNCT__ 269*064c8009SBarry Smith #define __FUNCT__ "DAGetFaceInterpolation" 270*064c8009SBarry Smith /* 271*064c8009SBarry Smith DAGetFaceInterpolation - Gets the interpolation for a face based coarse space 272*064c8009SBarry Smith 273*064c8009SBarry Smith */ 274*064c8009SBarry Smith PetscErrorCode DAGetFaceInterpolation(DA da,Mat Aglobal,MatReuse reuse,Mat *P) 275*064c8009SBarry Smith { 276*064c8009SBarry Smith PetscErrorCode ierr; 277*064c8009SBarry Smith PetscInt dim,i,j,k,m,n,p,dof,Nint,Nface,Nwire,Nsurf,*Iint,*Isurf,cint = 0,csurf = 0,istart,jstart,kstart,*II,N,c = 0; 278*064c8009SBarry Smith PetscInt mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[6],*globals,Ng,*IIint,*IIsurf; 279*064c8009SBarry Smith Mat Xint, Xsurf,Xint_tmp; 280*064c8009SBarry Smith IS isint,issurf,is,row,col; 281*064c8009SBarry Smith ISLocalToGlobalMapping ltg; 282*064c8009SBarry Smith MPI_Comm comm; 283*064c8009SBarry Smith Mat A,Aii,Ais,Asi,*Aholder,iAii; 284*064c8009SBarry Smith MatFactorInfo info; 285*064c8009SBarry Smith PetscScalar *xsurf,*xint; 286*064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo) 287*064c8009SBarry Smith PetscScalar tmp; 288*064c8009SBarry Smith #endif 289*064c8009SBarry Smith PetscTable ht; 290*064c8009SBarry Smith 291*064c8009SBarry Smith PetscFunctionBegin; 292*064c8009SBarry Smith ierr = DAGetInfo(da,&dim,0,0,0,&mp,&np,&pp,&dof,0,0,0);CHKERRQ(ierr); 293*064c8009SBarry Smith if (dof != 1) SETERRQ(PETSC_ERR_SUP,"Only for single field problems"); 294*064c8009SBarry Smith if (dim != 3) SETERRQ(PETSC_ERR_SUP,"Only coded for 3d problems"); 295*064c8009SBarry Smith ierr = DAGetCorners(da,0,0,0,&m,&n,&p);CHKERRQ(ierr); 296*064c8009SBarry Smith ierr = DAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth);CHKERRQ(ierr); 297*064c8009SBarry Smith istart = istart ? -1 : 0; 298*064c8009SBarry Smith jstart = jstart ? -1 : 0; 299*064c8009SBarry Smith kstart = kstart ? -1 : 0; 300*064c8009SBarry Smith 301*064c8009SBarry Smith /* 302*064c8009SBarry Smith the columns of P are the interpolation of each coarse grid point (one for each vertex and edge) 303*064c8009SBarry Smith to all the local degrees of freedom (this includes the vertices, edges and faces). 304*064c8009SBarry Smith 305*064c8009SBarry Smith Xint are the subset of the interpolation into the interior 306*064c8009SBarry Smith 307*064c8009SBarry Smith Xface are the interpolation onto faces but not into the interior 308*064c8009SBarry Smith 309*064c8009SBarry Smith Xsurf are the interpolation onto the vertices and edges (the surfbasket) 310*064c8009SBarry Smith Xint 311*064c8009SBarry Smith Symbolically one could write P = ( Xface ) after interchanging the rows to match the natural ordering on the domain 312*064c8009SBarry Smith Xsurf 313*064c8009SBarry Smith */ 314*064c8009SBarry Smith N = (m - istart)*(n - jstart)*(p - kstart); 315*064c8009SBarry Smith Nint = (m-2-istart)*(n-2-jstart)*(p-2-kstart); 316*064c8009SBarry Smith Nface = 2*( (m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart) ); 317*064c8009SBarry Smith Nwire = 4*( (m-2-istart) + (n-2-jstart) + (p-2-kstart) ) + 8; 318*064c8009SBarry Smith Nsurf = Nface + Nwire; 319*064c8009SBarry Smith ierr = MatCreateSeqDense(MPI_COMM_SELF,Nint,6,PETSC_NULL,&Xint);CHKERRQ(ierr); 320*064c8009SBarry Smith ierr = MatCreateSeqDense(MPI_COMM_SELF,Nsurf,6,PETSC_NULL,&Xsurf);CHKERRQ(ierr); 321*064c8009SBarry Smith ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr); 322*064c8009SBarry Smith 323*064c8009SBarry Smith /* 324*064c8009SBarry Smith Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of 325*064c8009SBarry Smith Xsurf will be all zero (thus making the coarse matrix singular). 326*064c8009SBarry Smith */ 327*064c8009SBarry Smith if (m-istart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in X direction must be at least 3"); 328*064c8009SBarry Smith if (n-jstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Y direction must be at least 3"); 329*064c8009SBarry Smith if (p-kstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Z direction must be at least 3"); 330*064c8009SBarry Smith 331*064c8009SBarry Smith cnt = 0; 332*064c8009SBarry Smith for (j=1;j<n-1-jstart;j++) { for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 0*Nsurf] = 1;} } 333*064c8009SBarry Smith for (k=1;k<p-1-kstart;k++) { 334*064c8009SBarry Smith for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 1*Nsurf] = 1;} 335*064c8009SBarry Smith for (j=1;j<n-1-jstart;j++) { xsurf[cnt++ + 2*Nsurf] = 1; /* these are the interior nodes */ xsurf[cnt++ + 3*Nsurf] = 1;} 336*064c8009SBarry Smith for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 4*Nsurf] = 1;} 337*064c8009SBarry Smith } 338*064c8009SBarry Smith for (j=1;j<n-1-jstart;j++) {for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 5*Nsurf] = 1;} } 339*064c8009SBarry Smith 340*064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo) 341*064c8009SBarry Smith for (i=0; i<Nsurf; i++) { 342*064c8009SBarry Smith tmp = 0.0; 343*064c8009SBarry Smith for (j=0; j<6; j++) { 344*064c8009SBarry Smith tmp += xsurf[i+j*Nsurf]; 345*064c8009SBarry Smith } 346*064c8009SBarry Smith if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xsurf interpolation at i %D value %G",i,PetscAbsScalar(tmp)); 347*064c8009SBarry Smith } 348*064c8009SBarry Smith #endif 349*064c8009SBarry Smith ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr); 350*064c8009SBarry Smith /* ierr = MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);*/ 351*064c8009SBarry Smith 352*064c8009SBarry Smith 353*064c8009SBarry Smith /* 354*064c8009SBarry Smith I are the indices for all the needed vertices (in global numbering) 355*064c8009SBarry Smith Iint are the indices for the interior values, I surf for the surface values 356*064c8009SBarry Smith (This is just for the part of the global matrix obtained with MatGetSubMatrix(), it 357*064c8009SBarry Smith is NOT the local DA ordering.) 358*064c8009SBarry Smith IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering 359*064c8009SBarry Smith */ 360*064c8009SBarry Smith #define Endpoint(a,start,b) (a == 0 || a == (b-1-start)) 361*064c8009SBarry Smith ierr = PetscMalloc3(N,PetscInt,&II,Nint,PetscInt,&Iint,Nsurf,PetscInt,&Isurf);CHKERRQ(ierr); 362*064c8009SBarry Smith ierr = PetscMalloc2(Nint,PetscInt,&IIint,Nsurf,PetscInt,&IIsurf);CHKERRQ(ierr); 363*064c8009SBarry Smith for (k=0; k<p-kstart; k++) { 364*064c8009SBarry Smith for (j=0; j<n-jstart; j++) { 365*064c8009SBarry Smith for (i=0; i<m-istart; i++) { 366*064c8009SBarry Smith II[c++] = i + j*mwidth + k*mwidth*nwidth; 367*064c8009SBarry Smith 368*064c8009SBarry Smith if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) { 369*064c8009SBarry Smith IIint[cint] = i + j*mwidth + k*mwidth*nwidth; 370*064c8009SBarry Smith Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart); 371*064c8009SBarry Smith } else { 372*064c8009SBarry Smith IIsurf[csurf] = i + j*mwidth + k*mwidth*nwidth; 373*064c8009SBarry Smith Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart); 374*064c8009SBarry Smith } 375*064c8009SBarry Smith } 376*064c8009SBarry Smith } 377*064c8009SBarry Smith } 378*064c8009SBarry Smith if (c != N) SETERRQ(PETSC_ERR_PLIB,"c != N"); 379*064c8009SBarry Smith if (cint != Nint) SETERRQ(PETSC_ERR_PLIB,"cint != Nint"); 380*064c8009SBarry Smith if (csurf != Nsurf) SETERRQ(PETSC_ERR_PLIB,"csurf != Nsurf"); 381*064c8009SBarry Smith ierr = DAGetISLocalToGlobalMapping(da,<g);CHKERRQ(ierr); 382*064c8009SBarry Smith ierr = ISLocalToGlobalMappingApply(ltg,N,II,II);CHKERRQ(ierr); 383*064c8009SBarry Smith ierr = ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint);CHKERRQ(ierr); 384*064c8009SBarry Smith ierr = ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf);CHKERRQ(ierr); 385*064c8009SBarry Smith ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr); 386*064c8009SBarry Smith ierr = ISCreateGeneral(comm,N,II,&is);CHKERRQ(ierr); 387*064c8009SBarry Smith ierr = ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,&isint);CHKERRQ(ierr); 388*064c8009SBarry Smith ierr = ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,&issurf);CHKERRQ(ierr); 389*064c8009SBarry Smith ierr = PetscFree3(II,Iint,Isurf);CHKERRQ(ierr); 390*064c8009SBarry Smith 391*064c8009SBarry Smith ierr = MatGetSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder);CHKERRQ(ierr); 392*064c8009SBarry Smith A = *Aholder; 393*064c8009SBarry Smith ierr = PetscFree(Aholder);CHKERRQ(ierr); 394*064c8009SBarry Smith 395*064c8009SBarry Smith ierr = MatGetSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii);CHKERRQ(ierr); 396*064c8009SBarry Smith ierr = MatGetSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais);CHKERRQ(ierr); 397*064c8009SBarry Smith ierr = MatGetSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi);CHKERRQ(ierr); 398*064c8009SBarry Smith 399*064c8009SBarry Smith /* 400*064c8009SBarry Smith Solve for the interpolation onto the interior Xint 401*064c8009SBarry Smith */ 402*064c8009SBarry Smith ierr = MatDuplicate(Xint,MAT_DO_NOT_COPY_VALUES,&Xint_tmp);CHKERRQ(ierr); 403*064c8009SBarry Smith ierr = MatMatMult(Ais,Xsurf,MAT_REUSE_MATRIX,PETSC_DETERMINE,&Xint_tmp);CHKERRQ(ierr); 404*064c8009SBarry Smith ierr = MatScale(Xint_tmp,-1.0);CHKERRQ(ierr); 405*064c8009SBarry Smith 406*064c8009SBarry Smith if (0) { 407*064c8009SBarry Smith ierr = MatGetFactor(Aii,MAT_SOLVER_PETSC,MAT_FACTOR_LU,&iAii);CHKERRQ(ierr); 408*064c8009SBarry Smith ierr = MatFactorInfoInitialize(&info);CHKERRQ(ierr); 409*064c8009SBarry Smith ierr = MatGetOrdering(Aii,MATORDERING_ND,&row,&col);CHKERRQ(ierr); 410*064c8009SBarry Smith ierr = MatLUFactorSymbolic(iAii,Aii,row,col,&info);CHKERRQ(ierr); 411*064c8009SBarry Smith ierr = ISDestroy(row);CHKERRQ(ierr); 412*064c8009SBarry Smith ierr = ISDestroy(col);CHKERRQ(ierr); 413*064c8009SBarry Smith ierr = MatLUFactorNumeric(iAii,Aii,&info);CHKERRQ(ierr); 414*064c8009SBarry Smith ierr = MatMatSolve(iAii,Xint_tmp,Xint);CHKERRQ(ierr); 415*064c8009SBarry Smith ierr = MatDestroy(iAii);CHKERRQ(ierr); 416*064c8009SBarry Smith } else { 417*064c8009SBarry Smith KSP ksp; 418*064c8009SBarry Smith Vec b,x; 419*064c8009SBarry Smith PetscScalar *xint_tmp; 420*064c8009SBarry Smith 421*064c8009SBarry Smith ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr); 422*064c8009SBarry Smith ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,Nint,0,&x);CHKERRQ(ierr); 423*064c8009SBarry Smith ierr = MatGetArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr); 424*064c8009SBarry Smith ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,Nint,0,&b);CHKERRQ(ierr); 425*064c8009SBarry Smith ierr = KSPCreate(PETSC_COMM_SELF,&ksp);CHKERRQ(ierr); 426*064c8009SBarry Smith ierr = KSPSetOperators(ksp,Aii,Aii,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 427*064c8009SBarry Smith for (i=0; i<6; i++) { 428*064c8009SBarry Smith ierr = VecPlaceArray(x,xint+i*Nint);CHKERRQ(ierr); 429*064c8009SBarry Smith ierr = VecPlaceArray(b,xint_tmp+i*Nint);CHKERRQ(ierr); 430*064c8009SBarry Smith ierr = KSPSolve(ksp,b,x);CHKERRQ(ierr); 431*064c8009SBarry Smith ierr = VecResetArray(x);CHKERRQ(ierr); 432*064c8009SBarry Smith ierr = VecResetArray(b);CHKERRQ(ierr); 433*064c8009SBarry Smith } 434*064c8009SBarry Smith ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr); 435*064c8009SBarry Smith ierr = MatRestoreArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr); 436*064c8009SBarry Smith ierr = KSPDestroy(ksp);CHKERRQ(ierr); 437*064c8009SBarry Smith ierr = VecDestroy(x);CHKERRQ(ierr); 438*064c8009SBarry Smith ierr = VecDestroy(b);CHKERRQ(ierr); 439*064c8009SBarry Smith } 440*064c8009SBarry Smith ierr = MatDestroy(Xint_tmp);CHKERRQ(ierr); 441*064c8009SBarry Smith 442*064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo) 443*064c8009SBarry Smith ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr); 444*064c8009SBarry Smith for (i=0; i<Nint; i++) { 445*064c8009SBarry Smith tmp = 0.0; 446*064c8009SBarry Smith for (j=0; j<6; j++) { 447*064c8009SBarry Smith tmp += xint[i+j*Nint]; 448*064c8009SBarry Smith } 449*064c8009SBarry Smith if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xint interpolation at i %D value %G",i,PetscAbsScalar(tmp)); 450*064c8009SBarry Smith } 451*064c8009SBarry Smith ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr); 452*064c8009SBarry Smith /* ierr =MatView(Xint,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); */ 453*064c8009SBarry Smith #endif 454*064c8009SBarry Smith 455*064c8009SBarry Smith 456*064c8009SBarry Smith /* total faces */ 457*064c8009SBarry Smith Ntotal = mp*np*(pp+1) + mp*pp*(np+1) + np*pp*(mp+1); 458*064c8009SBarry Smith 459*064c8009SBarry Smith /* 460*064c8009SBarry Smith For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points 461*064c8009SBarry Smith */ 462*064c8009SBarry Smith cnt = 0; 463*064c8009SBarry Smith { gl[cnt++] = mwidth+1;} 464*064c8009SBarry Smith { 465*064c8009SBarry Smith { gl[cnt++] = mwidth*nwidth+1;} 466*064c8009SBarry Smith { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;} 467*064c8009SBarry Smith { gl[cnt++] = mwidth*nwidth+mwidth*(n-jstart-1)+1;} 468*064c8009SBarry Smith } 469*064c8009SBarry Smith { gl[cnt++] = mwidth*nwidth*(p-kstart-1) + mwidth+1;} 470*064c8009SBarry Smith 471*064c8009SBarry Smith /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */ 472*064c8009SBarry Smith /* convert that to global numbering and get them on all processes */ 473*064c8009SBarry Smith ierr = ISLocalToGlobalMappingApply(ltg,6,gl,gl);CHKERRQ(ierr); 474*064c8009SBarry Smith /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */ 475*064c8009SBarry Smith ierr = PetscMalloc(6*mp*np*pp*sizeof(PetscInt),&globals);CHKERRQ(ierr); 476*064c8009SBarry Smith ierr = MPI_Allgather(gl,6,MPIU_INT,globals,6,MPIU_INT,((PetscObject)da)->comm);CHKERRQ(ierr); 477*064c8009SBarry Smith 478*064c8009SBarry Smith /* Number the coarse grid points from 0 to Ntotal */ 479*064c8009SBarry Smith ierr = PetscTableCreate(Ntotal/3,&ht);CHKERRQ(ierr); 480*064c8009SBarry Smith for (i=0; i<6*mp*np*pp; i++){ 481*064c8009SBarry Smith ierr = PetscTableAddCount(ht,globals[i]+1);CHKERRQ(ierr); 482*064c8009SBarry Smith } 483*064c8009SBarry Smith ierr = PetscTableGetCount(ht,&cnt);CHKERRQ(ierr); 484*064c8009SBarry Smith if (cnt != Ntotal) SETERRQ2(PETSC_ERR_PLIB,"Hash table size %D not equal to total number coarse grid points %D",cnt,Ntotal); 485*064c8009SBarry Smith ierr = PetscFree(globals);CHKERRQ(ierr); 486*064c8009SBarry Smith for (i=0; i<6; i++) { 487*064c8009SBarry Smith ierr = PetscTableFind(ht,gl[i]+1,&gl[i]);CHKERRQ(ierr); 488*064c8009SBarry Smith gl[i]--; 489*064c8009SBarry Smith } 490*064c8009SBarry Smith ierr = PetscTableDestroy(ht);CHKERRQ(ierr); 491*064c8009SBarry Smith /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */ 492*064c8009SBarry Smith 493*064c8009SBarry Smith /* construct global interpolation matrix */ 494*064c8009SBarry Smith ierr = MatGetLocalSize(Aglobal,&Ng,PETSC_NULL);CHKERRQ(ierr); 495*064c8009SBarry Smith if (reuse == MAT_INITIAL_MATRIX) { 496*064c8009SBarry Smith ierr = MatCreateMPIAIJ(((PetscObject)da)->comm,Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,PETSC_NULL,Nint,PETSC_NULL,P);CHKERRQ(ierr); 497*064c8009SBarry Smith } else { 498*064c8009SBarry Smith ierr = MatZeroEntries(*P);CHKERRQ(ierr); 499*064c8009SBarry Smith } 500*064c8009SBarry Smith ierr = MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr); 501*064c8009SBarry Smith ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr); 502*064c8009SBarry Smith ierr = MatSetValues(*P,Nint,IIint,6,gl,xint,INSERT_VALUES);CHKERRQ(ierr); 503*064c8009SBarry Smith ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr); 504*064c8009SBarry Smith ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr); 505*064c8009SBarry Smith ierr = MatSetValues(*P,Nsurf,IIsurf,6,gl,xsurf,INSERT_VALUES);CHKERRQ(ierr); 506*064c8009SBarry Smith ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr); 507*064c8009SBarry Smith ierr = MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 508*064c8009SBarry Smith ierr = MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 509*064c8009SBarry Smith ierr = PetscFree2(IIint,IIsurf);CHKERRQ(ierr); 510*064c8009SBarry Smith 511*064c8009SBarry Smith 512*064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo) 513*064c8009SBarry Smith { 514*064c8009SBarry Smith Vec x,y; 515*064c8009SBarry Smith PetscScalar *yy; 516*064c8009SBarry Smith ierr = VecCreateMPI(((PetscObject)da)->comm,Ng,PETSC_DETERMINE,&y);CHKERRQ(ierr); 517*064c8009SBarry Smith ierr = VecCreateMPI(((PetscObject)da)->comm,PETSC_DETERMINE,Ntotal,&x);CHKERRQ(ierr); 518*064c8009SBarry Smith ierr = VecSet(x,1.0);CHKERRQ(ierr); 519*064c8009SBarry Smith ierr = MatMult(*P,x,y);CHKERRQ(ierr); 520*064c8009SBarry Smith ierr = VecGetArray(y,&yy);CHKERRQ(ierr); 521*064c8009SBarry Smith for (i=0; i<Ng; i++) { 522*064c8009SBarry Smith if (PetscAbsScalar(yy[i]-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong p interpolation at i %D value %G",i,PetscAbsScalar(yy[i])); 523*064c8009SBarry Smith } 524*064c8009SBarry Smith ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr); 525*064c8009SBarry Smith ierr = VecDestroy(x);CHKERRQ(ierr); 526*064c8009SBarry Smith ierr = VecDestroy(y);CHKERRQ(ierr); 527*064c8009SBarry Smith } 528*064c8009SBarry Smith #endif 529*064c8009SBarry Smith 530*064c8009SBarry Smith ierr = MatDestroy(Aii);CHKERRQ(ierr); 531*064c8009SBarry Smith ierr = MatDestroy(Ais);CHKERRQ(ierr); 532*064c8009SBarry Smith ierr = MatDestroy(Asi);CHKERRQ(ierr); 533*064c8009SBarry Smith ierr = MatDestroy(A);CHKERRQ(ierr); 534*064c8009SBarry Smith ierr = ISDestroy(is);CHKERRQ(ierr); 535*064c8009SBarry Smith ierr = ISDestroy(isint);CHKERRQ(ierr); 536*064c8009SBarry Smith ierr = ISDestroy(issurf);CHKERRQ(ierr); 537*064c8009SBarry Smith ierr = MatDestroy(Xint);CHKERRQ(ierr); 538*064c8009SBarry Smith ierr = MatDestroy(Xsurf);CHKERRQ(ierr); 539*064c8009SBarry Smith PetscFunctionReturn(0); 540*064c8009SBarry Smith } 541174b6946SBarry Smith 5427233f9f0SBarry Smith typedef struct { 5437233f9f0SBarry Smith DA da; 5447233f9f0SBarry Smith PCExoticType type; 54596bdf778SBarry Smith Mat P; /* the interpolation matrix */ 5467233f9f0SBarry Smith } PC_Exotic; 5477233f9f0SBarry Smith 548174b6946SBarry Smith #undef __FUNCT__ 5497233f9f0SBarry Smith #define __FUNCT__ "PCExoticSetType" 5507233f9f0SBarry Smith /*@ 5517233f9f0SBarry Smith PCExoticSetType - Sets the type of coarse grid interpolation to use 5527233f9f0SBarry Smith 5537233f9f0SBarry Smith Collective on PC 5547233f9f0SBarry Smith 5557233f9f0SBarry Smith Input Parameters: 5567233f9f0SBarry Smith + pc - the preconditioner context 5577233f9f0SBarry Smith - type - either PC_EXOTIC_FACE or PC_EXOTIC_WIREBASKET (defaults to face) 5587233f9f0SBarry Smith 559563e08c6SBarry Smith Notes: The face based interpolation has 1 degree of freedom per face and ignores the 560563e08c6SBarry Smith edge and vertex values completely in the coarse problem. For any seven point 561563e08c6SBarry Smith stencil the interpolation of a constant on all faces into the interior is that constant. 562563e08c6SBarry Smith 563563e08c6SBarry Smith The wirebasket interpolation has 1 degree of freedom per vertex, per edge and 564563e08c6SBarry Smith per face. A constant on the subdomain boundary is interpolated as that constant 565563e08c6SBarry Smith in the interior of the domain. 566563e08c6SBarry Smith 567563e08c6SBarry Smith The coarse grid matrix is obtained via the Galerkin computation A_c = R A R^T, hence 568563e08c6SBarry Smith if A is nonsingular A_c is also nonsingular. 569563e08c6SBarry Smith 570563e08c6SBarry Smith Both interpolations are suitable for only scalar problems. 571563e08c6SBarry Smith 5727233f9f0SBarry Smith Level: intermediate 5737233f9f0SBarry Smith 5747233f9f0SBarry Smith 5757233f9f0SBarry Smith .seealso: PCEXOTIC, PCExoticType() 5767233f9f0SBarry Smith @*/ 5777233f9f0SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCExoticSetType(PC pc,PCExoticType type) 5787233f9f0SBarry Smith { 5797233f9f0SBarry Smith PetscErrorCode ierr,(*f)(PC,PCExoticType); 5807233f9f0SBarry Smith 5817233f9f0SBarry Smith PetscFunctionBegin; 5827233f9f0SBarry Smith PetscValidHeaderSpecific(pc,PC_COOKIE,1); 5837233f9f0SBarry Smith ierr = PetscObjectQueryFunction((PetscObject)pc,"PCExoticSetType_C",(void (**)(void))&f);CHKERRQ(ierr); 5847233f9f0SBarry Smith if (f) { 5857233f9f0SBarry Smith ierr = (*f)(pc,type);CHKERRQ(ierr); 5867233f9f0SBarry Smith } 5877233f9f0SBarry Smith PetscFunctionReturn(0); 5887233f9f0SBarry Smith } 5897233f9f0SBarry Smith 5907233f9f0SBarry Smith #undef __FUNCT__ 5917233f9f0SBarry Smith #define __FUNCT__ "PCExoticSetType_Exotic" 5927233f9f0SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCExoticSetType_Exotic(PC pc,PCExoticType type) 5937233f9f0SBarry Smith { 5947233f9f0SBarry Smith PC_MG **mg = (PC_MG**)pc->data; 595bedee52eSLisandro Dalcin PC_Exotic *ctx = (PC_Exotic*) mg[0]->innerctx; 5967233f9f0SBarry Smith 5977233f9f0SBarry Smith PetscFunctionBegin; 5987233f9f0SBarry Smith ctx->type = type; 5997233f9f0SBarry Smith PetscFunctionReturn(0); 6007233f9f0SBarry Smith } 6017233f9f0SBarry Smith 6027233f9f0SBarry Smith #undef __FUNCT__ 6037233f9f0SBarry Smith #define __FUNCT__ "PCSetUp_Exotic" 6047233f9f0SBarry Smith PetscErrorCode PCSetUp_Exotic(PC pc) 605174b6946SBarry Smith { 606174b6946SBarry Smith PetscErrorCode ierr; 60796bdf778SBarry Smith Mat A; 6087233f9f0SBarry Smith PC_MG **mg = (PC_MG**)pc->data; 6097233f9f0SBarry Smith PC_Exotic *ex = (PC_Exotic*) mg[0]->innerctx; 6107233f9f0SBarry Smith DA da = ex->da; 61196bdf778SBarry Smith MatReuse reuse = (ex->P) ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX; 612174b6946SBarry Smith 613174b6946SBarry Smith PetscFunctionBegin; 614174b6946SBarry Smith ierr = PCGetOperators(pc,PETSC_NULL,&A,PETSC_NULL);CHKERRQ(ierr); 6157233f9f0SBarry Smith if (ex->type == PC_EXOTIC_FACE) { 61696bdf778SBarry Smith ierr = DAGetFaceInterpolation(da,A,reuse,&ex->P);CHKERRQ(ierr); 6177233f9f0SBarry Smith } else if (ex->type == PC_EXOTIC_WIREBASKET) { 61896bdf778SBarry Smith ierr = DAGetWireBasketInterpolation(da,A,reuse,&ex->P);CHKERRQ(ierr); 6197233f9f0SBarry Smith } else SETERRQ1(PETSC_ERR_PLIB,"Unknown exotic coarse space %d",ex->type); 62096bdf778SBarry Smith ierr = PCMGSetInterpolation(pc,1,ex->P);CHKERRQ(ierr); 6217233f9f0SBarry Smith ierr = PCSetUp_MG(pc);CHKERRQ(ierr); 622174b6946SBarry Smith PetscFunctionReturn(0); 623174b6946SBarry Smith } 624174b6946SBarry Smith 625174b6946SBarry Smith #undef __FUNCT__ 6267233f9f0SBarry Smith #define __FUNCT__ "PCDestroy_Exotic" 6277233f9f0SBarry Smith PetscErrorCode PCDestroy_Exotic(PC pc) 628174b6946SBarry Smith { 629174b6946SBarry Smith PetscErrorCode ierr; 6307233f9f0SBarry Smith PC_MG **mg = (PC_MG**)pc->data; 631bedee52eSLisandro Dalcin PC_Exotic *ctx = (PC_Exotic*) mg[0]->innerctx; 632174b6946SBarry Smith 633174b6946SBarry Smith PetscFunctionBegin; 63496bdf778SBarry Smith if (ctx->da) {ierr = DADestroy(ctx->da);CHKERRQ(ierr);} 63596bdf778SBarry Smith if (ctx->P) {ierr = MatDestroy(ctx->P);CHKERRQ(ierr);} 6367233f9f0SBarry Smith ierr = PetscFree(ctx);CHKERRQ(ierr); 6377233f9f0SBarry Smith ierr = PCDestroy_MG(pc);CHKERRQ(ierr); 638174b6946SBarry Smith PetscFunctionReturn(0); 639174b6946SBarry Smith } 640174b6946SBarry Smith 641174b6946SBarry Smith #undef __FUNCT__ 6427233f9f0SBarry Smith #define __FUNCT__ "PCSetUp_Exotic_Error" 6437233f9f0SBarry Smith PetscErrorCode PCSetUp_Exotic_Error(PC pc) 644174b6946SBarry Smith { 645174b6946SBarry Smith PetscFunctionBegin; 646f91d8e95SBarry Smith SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"You are using the Exotic preconditioner but never called PCSetDA()"); 647174b6946SBarry Smith PetscFunctionReturn(0); 648174b6946SBarry Smith } 649174b6946SBarry Smith 650174b6946SBarry Smith #undef __FUNCT__ 651f91d8e95SBarry Smith #define __FUNCT__ "PCSetDA" 6527233f9f0SBarry Smith /*@ 653f91d8e95SBarry Smith PCSetDA - Sets the DA that is to be used by the PCEXOTIC or certain other preconditioners 6547233f9f0SBarry Smith 6557233f9f0SBarry Smith Collective on PC 6567233f9f0SBarry Smith 6577233f9f0SBarry Smith Input Parameters: 6587233f9f0SBarry Smith + pc - the preconditioner context 6597233f9f0SBarry Smith - da - the da 6607233f9f0SBarry Smith 6617233f9f0SBarry Smith Level: intermediate 6627233f9f0SBarry Smith 6637233f9f0SBarry Smith 6647233f9f0SBarry Smith .seealso: PCEXOTIC, PCExoticType() 6657233f9f0SBarry Smith @*/ 666f91d8e95SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCSetDA(PC pc,DA da) 667174b6946SBarry Smith { 6687233f9f0SBarry Smith PetscErrorCode ierr,(*f)(PC,DA); 669174b6946SBarry Smith 670174b6946SBarry Smith PetscFunctionBegin; 671174b6946SBarry Smith PetscValidHeaderSpecific(pc,PC_COOKIE,1); 672174b6946SBarry Smith PetscValidHeaderSpecific(da,DM_COOKIE,1); 673f91d8e95SBarry Smith ierr = PetscObjectQueryFunction((PetscObject)pc,"PCSetDA_C",(void (**)(void))&f);CHKERRQ(ierr); 6747233f9f0SBarry Smith if (f) { 6757233f9f0SBarry Smith ierr = (*f)(pc,da);CHKERRQ(ierr); 6767233f9f0SBarry Smith } 6777233f9f0SBarry Smith PetscFunctionReturn(0); 6787233f9f0SBarry Smith } 679174b6946SBarry Smith 6807233f9f0SBarry Smith 6817233f9f0SBarry Smith #undef __FUNCT__ 682f91d8e95SBarry Smith #define __FUNCT__ "PCSetDA_Exotic" 683f91d8e95SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCSetDA_Exotic(PC pc,DA da) 6847233f9f0SBarry Smith { 6857233f9f0SBarry Smith PetscErrorCode ierr; 6867233f9f0SBarry Smith PC_MG **mg = (PC_MG**)pc->data; 687bedee52eSLisandro Dalcin PC_Exotic *ctx = (PC_Exotic*) mg[0]->innerctx; 6887233f9f0SBarry Smith 6897233f9f0SBarry Smith PetscFunctionBegin; 6907233f9f0SBarry Smith ctx->da = da; 6917233f9f0SBarry Smith pc->ops->setup = PCSetUp_Exotic; 692174b6946SBarry Smith ierr = PetscObjectReference((PetscObject)da);CHKERRQ(ierr); 693174b6946SBarry Smith PetscFunctionReturn(0); 694174b6946SBarry Smith } 695174b6946SBarry Smith 6967233f9f0SBarry Smith #undef __FUNCT__ 6977233f9f0SBarry Smith #define __FUNCT__ "PCView_Exotic" 6987233f9f0SBarry Smith PetscErrorCode PCView_Exotic(PC pc,PetscViewer viewer) 6997233f9f0SBarry Smith { 7007233f9f0SBarry Smith PC_MG **mg = (PC_MG**)pc->data; 7017233f9f0SBarry Smith PetscErrorCode ierr; 7027233f9f0SBarry Smith PetscTruth iascii; 703bedee52eSLisandro Dalcin PC_Exotic *ctx = (PC_Exotic*) mg[0]->innerctx; 7047233f9f0SBarry Smith 7057233f9f0SBarry Smith PetscFunctionBegin; 7067233f9f0SBarry Smith ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr); 7077233f9f0SBarry Smith if (iascii) { 7087233f9f0SBarry Smith ierr = PetscViewerASCIIPrintf(viewer," Exotic type = %s\n",PCExoticTypes[ctx->type]);CHKERRQ(ierr); 7097233f9f0SBarry Smith } 7107233f9f0SBarry Smith ierr = PCView_MG(pc,viewer);CHKERRQ(ierr); 7117233f9f0SBarry Smith PetscFunctionReturn(0); 7127233f9f0SBarry Smith } 7137233f9f0SBarry Smith 7147233f9f0SBarry Smith #undef __FUNCT__ 7157233f9f0SBarry Smith #define __FUNCT__ "PCSetFromOptions_Exotic" 7167233f9f0SBarry Smith PetscErrorCode PCSetFromOptions_Exotic(PC pc) 7177233f9f0SBarry Smith { 7187233f9f0SBarry Smith PetscErrorCode ierr; 7197233f9f0SBarry Smith PetscTruth flg; 7207233f9f0SBarry Smith PC_MG **mg = (PC_MG**)pc->data; 7217233f9f0SBarry Smith PCExoticType mgctype; 722bedee52eSLisandro Dalcin PC_Exotic *ctx = (PC_Exotic*) mg[0]->innerctx; 7237233f9f0SBarry Smith 7247233f9f0SBarry Smith PetscFunctionBegin; 7257233f9f0SBarry Smith ierr = PetscOptionsHead("Exotic coarse space options");CHKERRQ(ierr); 7267233f9f0SBarry Smith ierr = PetscOptionsEnum("-pc_exotic_type","face or wirebasket","PCExoticSetType",PCExoticTypes,(PetscEnum)ctx->type,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr); 7277233f9f0SBarry Smith if (flg) { 7287233f9f0SBarry Smith ierr = PCExoticSetType(pc,mgctype);CHKERRQ(ierr); 7297233f9f0SBarry Smith } 7307233f9f0SBarry Smith ierr = PetscOptionsTail();CHKERRQ(ierr); 7317233f9f0SBarry Smith PetscFunctionReturn(0); 7327233f9f0SBarry Smith } 7337233f9f0SBarry Smith 734174b6946SBarry Smith 735174b6946SBarry Smith /*MC 7367233f9f0SBarry Smith PCEXOTIC - Two level overlapping Schwarz preconditioner with exotic (non-standard) coarse grid spaces 737174b6946SBarry Smith 7387233f9f0SBarry Smith This uses the PCMG infrastructure restricted to two levels and the face and wirebasket based coarse 7393b65e785SBarry Smith grid spaces. These coarse grid spaces originate in the work of Bramble, Pasciak and Schatz, "The Construction 7403b65e785SBarry Smith of Preconditioners for Elliptic Problems by Substructing IV", Mathematics of Computation, volume 53 pages 1--24, 1989. 7413b65e785SBarry Smith They were generalized slightly in "Domain Decomposition Method for Linear Elasticity", Ph. D. thesis, Barry Smith, 7423b65e785SBarry Smith New York University, 1990. They were then explored in great detail in Dryja, Smith, Widlund, "Schwarz Analysis 7433b65e785SBarry Smith of Iterative Substructuring Methods for Elliptic Problems in Three Dimensions, SIAM Journal on Numerical 7443b65e785SBarry Smith Analysis, volume 31. pages 1662-1694, 1994. These were developed in the context of iterative substructuring preconditioners. 7453b65e785SBarry Smith They were then ingeniously applied as coarse grid spaces for overlapping Schwarz methods by Dohrmann and Widlund. 7463b65e785SBarry Smith They refer to them as GDSW (generalized Dryja, Smith, Widlund preconditioners). See, for example, 7473b65e785SBarry Smith Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Extending theory for domain decomposition algorithms to irregular subdomains. In Ulrich Langer, Marco 7483b65e785SBarry Smith Discacciati, David Keyes, Olof Widlund, and Walter Zulehner, editors, Proceedings 7493b65e785SBarry Smith of the 17th International Conference on Domain Decomposition Methods in 7503b65e785SBarry Smith Science and Engineering, held in Strobl, Austria, July 3-7, 2006, number 60 in 7513b65e785SBarry Smith Springer-Verlag, Lecture Notes in Computational Science and Engineering, pages 255-261, 2007. 7523b65e785SBarry Smith Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. A family of energy min- 7533b65e785SBarry Smith imizing coarse spaces for overlapping Schwarz preconditioners. In Ulrich Langer, 7543b65e785SBarry Smith Marco Discacciati, David Keyes, OlofWidlund, andWalter Zulehner, editors, Proceedings 7553b65e785SBarry Smith of the 17th International Conference on Domain Decomposition Methods 7563b65e785SBarry Smith in Science and Engineering, held in Strobl, Austria, July 3-7, 2006, number 60 in 7573b65e785SBarry Smith Springer-Verlag, Lecture Notes in Computational Science and Engineering, pages 247-254, 2007 7583b65e785SBarry Smith Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Domain decomposition 7593b65e785SBarry Smith for less regular subdomains: Overlapping Schwarz in two dimensions. SIAM J. 7603b65e785SBarry Smith Numer. Anal., 46(4):2153-2168, 2008. 7613b65e785SBarry Smith Clark R. Dohrmann and Olof B. Widlund. An overlapping Schwarz 7623b65e785SBarry Smith algorithm for almost incompressible elasticity. Technical Report 7633b65e785SBarry Smith TR2008-912, Department of Computer Science, Courant Institute 7643b65e785SBarry Smith of Mathematical Sciences, New York University, May 2008. URL: 7653b65e785SBarry Smith http://cs.nyu.edu/csweb/Research/TechReports/TR2008-912/TR2008-912.pdf 7667233f9f0SBarry Smith 7677233f9f0SBarry Smith Options Database: The usual PCMG options are supported, such as -mg_levels_pc_type <type> -mg_coarse_pc_type <type> 7687233f9f0SBarry Smith -pc_mg_type <type> 7697233f9f0SBarry Smith 77025a35f6fSSatish Balay Level: advanced 771174b6946SBarry Smith 772f91d8e95SBarry Smith .seealso: PCMG, PCSetDA(), PCExoticType, PCExoticSetType() 773174b6946SBarry Smith M*/ 774174b6946SBarry Smith 775174b6946SBarry Smith EXTERN_C_BEGIN 776174b6946SBarry Smith #undef __FUNCT__ 7777233f9f0SBarry Smith #define __FUNCT__ "PCCreate_Exotic" 7787233f9f0SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_Exotic(PC pc) 779174b6946SBarry Smith { 780174b6946SBarry Smith PetscErrorCode ierr; 7817233f9f0SBarry Smith PC_Exotic *ex; 7827233f9f0SBarry Smith PC_MG **mg; 783174b6946SBarry Smith 784174b6946SBarry Smith PetscFunctionBegin; 785f91d8e95SBarry Smith /* if type was previously mg; must manually destroy it because call to PCSetType(pc,PCMG) will not destroy it */ 786f91d8e95SBarry Smith if (pc->ops->destroy) { ierr = (*pc->ops->destroy)(pc);CHKERRQ(ierr); pc->data = 0;} 787f91d8e95SBarry Smith ierr = PetscStrfree(((PetscObject)pc)->type_name);CHKERRQ(ierr); 788f91d8e95SBarry Smith ((PetscObject)pc)->type_name = 0; 789f91d8e95SBarry Smith 790174b6946SBarry Smith ierr = PCSetType(pc,PCMG);CHKERRQ(ierr); 791174b6946SBarry Smith ierr = PCMGSetLevels(pc,2,PETSC_NULL);CHKERRQ(ierr); 792174b6946SBarry Smith ierr = PCMGSetGalerkin(pc);CHKERRQ(ierr); 79396bdf778SBarry Smith ierr = PetscNew(PC_Exotic,&ex);CHKERRQ(ierr);\ 7947233f9f0SBarry Smith ex->type = PC_EXOTIC_FACE; 795a36ce94aSMatthew Knepley mg = (PC_MG**) pc->data; 7967233f9f0SBarry Smith mg[0]->innerctx = ex; 7977233f9f0SBarry Smith 7987233f9f0SBarry Smith 7997233f9f0SBarry Smith pc->ops->setfromoptions = PCSetFromOptions_Exotic; 8007233f9f0SBarry Smith pc->ops->view = PCView_Exotic; 8017233f9f0SBarry Smith pc->ops->destroy = PCDestroy_Exotic; 8027233f9f0SBarry Smith pc->ops->setup = PCSetUp_Exotic_Error; 8037233f9f0SBarry Smith ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCExoticSetType_C","PCExoticSetType_Exotic",PCExoticSetType_Exotic);CHKERRQ(ierr); 804f91d8e95SBarry Smith ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCSetDA_C","PCSetDA_Exotic",PCSetDA_Exotic);CHKERRQ(ierr); 805174b6946SBarry Smith PetscFunctionReturn(0); 806174b6946SBarry Smith } 807174b6946SBarry Smith EXTERN_C_END 808