xref: /petsc/src/ksp/pc/impls/wb/wb.c (revision b4876bcb73c673da1466dabf4fdfd52d4f02e063)
1174b6946SBarry Smith 
2c6db04a5SJed Brown #include <petscdmda.h>   /*I "petscdmda.h" I*/
3*b4876bcbSBarry Smith #include <../src/ksp/pc/impls/mg/mgimpl.h>   /*I "petscksp.h" I*/
47233f9f0SBarry Smith 
58e722e36SBarry Smith typedef struct {
68e722e36SBarry Smith   PCExoticType type;
78e722e36SBarry Smith   Mat          P;            /* the constructed interpolation matrix */
8ace3abfcSBarry Smith   PetscBool    directSolve;  /* use direct LU factorization to construct interpolation */
98e722e36SBarry Smith   KSP          ksp;
108e722e36SBarry Smith } PC_Exotic;
11174b6946SBarry Smith 
126a6fc655SJed Brown const char *const PCExoticTypes[] = {"face","wirebasket","PCExoticType","PC_Exotic",0};
13064c8009SBarry Smith 
14064c8009SBarry Smith 
15064c8009SBarry Smith #undef __FUNCT__
16aa219208SBarry Smith #define __FUNCT__ "DMDAGetWireBasketInterpolation"
17064c8009SBarry Smith /*
18aa219208SBarry Smith       DMDAGetWireBasketInterpolation - Gets the interpolation for a wirebasket based coarse space
19064c8009SBarry Smith 
20064c8009SBarry Smith */
21aa219208SBarry Smith PetscErrorCode DMDAGetWireBasketInterpolation(DM da,PC_Exotic *exotic,Mat Aglobal,MatReuse reuse,Mat *P)
22064c8009SBarry Smith {
23064c8009SBarry Smith   PetscErrorCode         ierr;
24064c8009SBarry 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;
2528d20b34SBarry Smith   PetscInt               mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[26],*globals,Ng,*IIint,*IIsurf,Nt;
26064c8009SBarry Smith   Mat                    Xint, Xsurf,Xint_tmp;
27064c8009SBarry Smith   IS                     isint,issurf,is,row,col;
28064c8009SBarry Smith   ISLocalToGlobalMapping ltg;
29064c8009SBarry Smith   MPI_Comm               comm;
30064c8009SBarry Smith   Mat                    A,Aii,Ais,Asi,*Aholder,iAii;
31064c8009SBarry Smith   MatFactorInfo          info;
32064c8009SBarry Smith   PetscScalar            *xsurf,*xint;
338e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
34064c8009SBarry Smith   PetscScalar            tmp;
35064c8009SBarry Smith #endif
36064c8009SBarry Smith   PetscTable             ht;
37064c8009SBarry Smith 
38064c8009SBarry Smith   PetscFunctionBegin;
391321219cSEthan Coon   ierr = DMDAGetInfo(da,&dim,0,0,0,&mp,&np,&pp,&dof,0,0,0,0,0);CHKERRQ(ierr);
40ce94432eSBarry Smith   if (dof != 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only for single field problems");
41ce94432eSBarry Smith   if (dim != 3) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only coded for 3d problems");
42aa219208SBarry Smith   ierr   = DMDAGetCorners(da,0,0,0,&m,&n,&p);CHKERRQ(ierr);
43aa219208SBarry Smith   ierr   = DMDAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth);CHKERRQ(ierr);
44064c8009SBarry Smith   istart = istart ? -1 : 0;
45064c8009SBarry Smith   jstart = jstart ? -1 : 0;
46064c8009SBarry Smith   kstart = kstart ? -1 : 0;
47064c8009SBarry Smith 
48064c8009SBarry Smith   /*
49064c8009SBarry Smith     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
50064c8009SBarry Smith     to all the local degrees of freedom (this includes the vertices, edges and faces).
51064c8009SBarry Smith 
52064c8009SBarry Smith     Xint are the subset of the interpolation into the interior
53064c8009SBarry Smith 
54064c8009SBarry Smith     Xface are the interpolation onto faces but not into the interior
55064c8009SBarry Smith 
56064c8009SBarry Smith     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
57064c8009SBarry Smith                                       Xint
58064c8009SBarry Smith     Symbolically one could write P = (Xface) after interchanging the rows to match the natural ordering on the domain
59064c8009SBarry Smith                                       Xsurf
60064c8009SBarry Smith   */
61064c8009SBarry Smith   N     = (m - istart)*(n - jstart)*(p - kstart);
62064c8009SBarry Smith   Nint  = (m-2-istart)*(n-2-jstart)*(p-2-kstart);
63064c8009SBarry Smith   Nface = 2*((m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart));
64064c8009SBarry Smith   Nwire = 4*((m-2-istart) + (n-2-jstart) + (p-2-kstart)) + 8;
65064c8009SBarry Smith   Nsurf = Nface + Nwire;
660298fd71SBarry Smith   ierr  = MatCreateSeqDense(MPI_COMM_SELF,Nint,26,NULL,&Xint);CHKERRQ(ierr);
670298fd71SBarry Smith   ierr  = MatCreateSeqDense(MPI_COMM_SELF,Nsurf,26,NULL,&Xsurf);CHKERRQ(ierr);
688c778c55SBarry Smith   ierr  = MatDenseGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
69064c8009SBarry Smith 
70064c8009SBarry Smith   /*
71064c8009SBarry Smith      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
72064c8009SBarry Smith      Xsurf will be all zero (thus making the coarse matrix singular).
73064c8009SBarry Smith   */
74e32f2f54SBarry Smith   if (m-istart < 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in X direction must be at least 3");
75e32f2f54SBarry Smith   if (n-jstart < 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in Y direction must be at least 3");
76e32f2f54SBarry Smith   if (p-kstart < 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in Z direction must be at least 3");
77064c8009SBarry Smith 
78064c8009SBarry Smith   cnt = 0;
792fa5cd67SKarl Rupp 
802fa5cd67SKarl Rupp   xsurf[cnt++] = 1;
812fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + Nsurf] = 1;
822fa5cd67SKarl Rupp   xsurf[cnt++ + 2*Nsurf] = 1;
832fa5cd67SKarl Rupp 
842fa5cd67SKarl Rupp   for (j=1; j<n-1-jstart; j++) {
852fa5cd67SKarl Rupp     xsurf[cnt++ + 3*Nsurf] = 1;
862fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 4*Nsurf] = 1;
872fa5cd67SKarl Rupp     xsurf[cnt++ + 5*Nsurf] = 1;
88064c8009SBarry Smith   }
892fa5cd67SKarl Rupp 
902fa5cd67SKarl Rupp   xsurf[cnt++ + 6*Nsurf] = 1;
912fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 7*Nsurf] = 1;
922fa5cd67SKarl Rupp   xsurf[cnt++ + 8*Nsurf] = 1;
932fa5cd67SKarl Rupp 
942fa5cd67SKarl Rupp   for (k=1; k<p-1-kstart; k++) {
952fa5cd67SKarl Rupp     xsurf[cnt++ + 9*Nsurf] = 1;
962fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 10*Nsurf] = 1;
972fa5cd67SKarl Rupp     xsurf[cnt++ + 11*Nsurf] = 1;
982fa5cd67SKarl Rupp 
992fa5cd67SKarl Rupp     for (j=1; j<n-1-jstart; j++) {
1002fa5cd67SKarl Rupp       xsurf[cnt++ + 12*Nsurf] = 1;
1012fa5cd67SKarl Rupp       /* these are the interior nodes */
1022fa5cd67SKarl Rupp       xsurf[cnt++ + 13*Nsurf] = 1;
1032fa5cd67SKarl Rupp     }
1042fa5cd67SKarl Rupp 
1052fa5cd67SKarl Rupp     xsurf[cnt++ + 14*Nsurf] = 1;
1062fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 15*Nsurf] = 1;
1072fa5cd67SKarl Rupp     xsurf[cnt++ + 16*Nsurf] = 1;
1082fa5cd67SKarl Rupp   }
1092fa5cd67SKarl Rupp 
1102fa5cd67SKarl Rupp   xsurf[cnt++ + 17*Nsurf] = 1;
1112fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 18*Nsurf] = 1;
1122fa5cd67SKarl Rupp   xsurf[cnt++ + 19*Nsurf] = 1;
1132fa5cd67SKarl Rupp 
1142fa5cd67SKarl Rupp   for (j=1;j<n-1-jstart;j++) {
1152fa5cd67SKarl Rupp     xsurf[cnt++ + 20*Nsurf] = 1;
1162fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 21*Nsurf] = 1;
1172fa5cd67SKarl Rupp     xsurf[cnt++ + 22*Nsurf] = 1;
1182fa5cd67SKarl Rupp   }
1192fa5cd67SKarl Rupp 
1202fa5cd67SKarl Rupp   xsurf[cnt++ + 23*Nsurf] = 1;
1212fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 24*Nsurf] = 1;
1222fa5cd67SKarl Rupp   xsurf[cnt++ + 25*Nsurf] = 1;
1232fa5cd67SKarl Rupp 
124064c8009SBarry Smith 
1258e722e36SBarry Smith   /* interpolations only sum to 1 when using direct solver */
1268e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
127064c8009SBarry Smith   for (i=0; i<Nsurf; i++) {
128064c8009SBarry Smith     tmp = 0.0;
1292fa5cd67SKarl Rupp     for (j=0; j<26; j++) tmp += xsurf[i+j*Nsurf];
130e32f2f54SBarry Smith     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong Xsurf interpolation at i %D value %G",i,PetscAbsScalar(tmp));
131064c8009SBarry Smith   }
132064c8009SBarry Smith #endif
1338c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
134064c8009SBarry Smith   /* ierr = MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);*/
135064c8009SBarry Smith 
136064c8009SBarry Smith 
137064c8009SBarry Smith   /*
138064c8009SBarry Smith        I are the indices for all the needed vertices (in global numbering)
139064c8009SBarry Smith        Iint are the indices for the interior values, I surf for the surface values
140064c8009SBarry Smith             (This is just for the part of the global matrix obtained with MatGetSubMatrix(), it
141aa219208SBarry Smith              is NOT the local DMDA ordering.)
142064c8009SBarry Smith        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
143064c8009SBarry Smith   */
144064c8009SBarry Smith #define Endpoint(a,start,b) (a == 0 || a == (b-1-start))
145064c8009SBarry Smith   ierr = PetscMalloc3(N,PetscInt,&II,Nint,PetscInt,&Iint,Nsurf,PetscInt,&Isurf);CHKERRQ(ierr);
146064c8009SBarry Smith   ierr = PetscMalloc2(Nint,PetscInt,&IIint,Nsurf,PetscInt,&IIsurf);CHKERRQ(ierr);
147064c8009SBarry Smith   for (k=0; k<p-kstart; k++) {
148064c8009SBarry Smith     for (j=0; j<n-jstart; j++) {
149064c8009SBarry Smith       for (i=0; i<m-istart; i++) {
150064c8009SBarry Smith         II[c++] = i + j*mwidth + k*mwidth*nwidth;
151064c8009SBarry Smith 
152064c8009SBarry Smith         if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) {
153064c8009SBarry Smith           IIint[cint]  = i + j*mwidth + k*mwidth*nwidth;
154064c8009SBarry Smith           Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
155064c8009SBarry Smith         } else {
156064c8009SBarry Smith           IIsurf[csurf]  = i + j*mwidth + k*mwidth*nwidth;
157064c8009SBarry Smith           Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
158064c8009SBarry Smith         }
159064c8009SBarry Smith       }
160064c8009SBarry Smith     }
161064c8009SBarry Smith   }
162e32f2f54SBarry Smith   if (c != N) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"c != N");
163e32f2f54SBarry Smith   if (cint != Nint) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"cint != Nint");
164e32f2f54SBarry Smith   if (csurf != Nsurf) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"csurf != Nsurf");
1651411c6eeSJed Brown   ierr = DMGetLocalToGlobalMapping(da,&ltg);CHKERRQ(ierr);
166064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,N,II,II);CHKERRQ(ierr);
167064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint);CHKERRQ(ierr);
168064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf);CHKERRQ(ierr);
169064c8009SBarry Smith   ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr);
17070b3c8c7SBarry Smith   ierr = ISCreateGeneral(comm,N,II,PETSC_COPY_VALUES,&is);CHKERRQ(ierr);
17170b3c8c7SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,PETSC_COPY_VALUES,&isint);CHKERRQ(ierr);
17270b3c8c7SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,PETSC_COPY_VALUES,&issurf);CHKERRQ(ierr);
173064c8009SBarry Smith   ierr = PetscFree3(II,Iint,Isurf);CHKERRQ(ierr);
174064c8009SBarry Smith 
175064c8009SBarry Smith   ierr = MatGetSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder);CHKERRQ(ierr);
176064c8009SBarry Smith   A    = *Aholder;
177064c8009SBarry Smith   ierr = PetscFree(Aholder);CHKERRQ(ierr);
178064c8009SBarry Smith 
179064c8009SBarry Smith   ierr = MatGetSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii);CHKERRQ(ierr);
180064c8009SBarry Smith   ierr = MatGetSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais);CHKERRQ(ierr);
181064c8009SBarry Smith   ierr = MatGetSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi);CHKERRQ(ierr);
182064c8009SBarry Smith 
183064c8009SBarry Smith   /*
184064c8009SBarry Smith      Solve for the interpolation onto the interior Xint
185064c8009SBarry Smith   */
18692e4c2edSBarry Smith   ierr = MatMatMult(Ais,Xsurf,MAT_INITIAL_MATRIX,PETSC_DETERMINE,&Xint_tmp);CHKERRQ(ierr);
1878e722e36SBarry Smith   ierr = MatScale(Xint_tmp,-1.0);CHKERRQ(ierr);
1888e722e36SBarry Smith   if (exotic->directSolve) {
1892692d6eeSBarry Smith     ierr = MatGetFactor(Aii,MATSOLVERPETSC,MAT_FACTOR_LU,&iAii);CHKERRQ(ierr);
190064c8009SBarry Smith     ierr = MatFactorInfoInitialize(&info);CHKERRQ(ierr);
1912692d6eeSBarry Smith     ierr = MatGetOrdering(Aii,MATORDERINGND,&row,&col);CHKERRQ(ierr);
192064c8009SBarry Smith     ierr = MatLUFactorSymbolic(iAii,Aii,row,col,&info);CHKERRQ(ierr);
193fcfd50ebSBarry Smith     ierr = ISDestroy(&row);CHKERRQ(ierr);
194fcfd50ebSBarry Smith     ierr = ISDestroy(&col);CHKERRQ(ierr);
195064c8009SBarry Smith     ierr = MatLUFactorNumeric(iAii,Aii,&info);CHKERRQ(ierr);
196064c8009SBarry Smith     ierr = MatMatSolve(iAii,Xint_tmp,Xint);CHKERRQ(ierr);
1976bf464f9SBarry Smith     ierr = MatDestroy(&iAii);CHKERRQ(ierr);
1988e722e36SBarry Smith   } else {
1998e722e36SBarry Smith     Vec         b,x;
2008e722e36SBarry Smith     PetscScalar *xint_tmp;
201064c8009SBarry Smith 
2028c778c55SBarry Smith     ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
203778a2246SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,0,&x);CHKERRQ(ierr);
2048c778c55SBarry Smith     ierr = MatDenseGetArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
205778a2246SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,0,&b);CHKERRQ(ierr);
2068e722e36SBarry Smith     ierr = KSPSetOperators(exotic->ksp,Aii,Aii,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
2078e722e36SBarry Smith     for (i=0; i<26; i++) {
2088e722e36SBarry Smith       ierr = VecPlaceArray(x,xint+i*Nint);CHKERRQ(ierr);
2098e722e36SBarry Smith       ierr = VecPlaceArray(b,xint_tmp+i*Nint);CHKERRQ(ierr);
2108e722e36SBarry Smith       ierr = KSPSolve(exotic->ksp,b,x);CHKERRQ(ierr);
2118e722e36SBarry Smith       ierr = VecResetArray(x);CHKERRQ(ierr);
2128e722e36SBarry Smith       ierr = VecResetArray(b);CHKERRQ(ierr);
2138e722e36SBarry Smith     }
2148c778c55SBarry Smith     ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
2158c778c55SBarry Smith     ierr = MatDenseRestoreArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
2166bf464f9SBarry Smith     ierr = VecDestroy(&x);CHKERRQ(ierr);
2176bf464f9SBarry Smith     ierr = VecDestroy(&b);CHKERRQ(ierr);
2188e722e36SBarry Smith   }
2196bf464f9SBarry Smith   ierr = MatDestroy(&Xint_tmp);CHKERRQ(ierr);
2208e722e36SBarry Smith 
2218e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
2228c778c55SBarry Smith   ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
223064c8009SBarry Smith   for (i=0; i<Nint; i++) {
224064c8009SBarry Smith     tmp = 0.0;
2252fa5cd67SKarl Rupp     for (j=0; j<26; j++) tmp += xint[i+j*Nint];
2262fa5cd67SKarl Rupp 
227e32f2f54SBarry Smith     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong Xint interpolation at i %D value %G",i,PetscAbsScalar(tmp));
228064c8009SBarry Smith   }
2298c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
230064c8009SBarry Smith   /* ierr =MatView(Xint,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); */
231064c8009SBarry Smith #endif
232064c8009SBarry Smith 
233064c8009SBarry Smith 
234064c8009SBarry Smith   /*         total vertices             total faces                                  total edges */
235064c8009SBarry 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);
236064c8009SBarry Smith 
237064c8009SBarry Smith   /*
238064c8009SBarry Smith       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
239064c8009SBarry Smith   */
240064c8009SBarry Smith   cnt = 0;
2412fa5cd67SKarl Rupp 
242064c8009SBarry Smith   gl[cnt++] = 0;  { gl[cnt++] = 1;} gl[cnt++] = m-istart-1;
243064c8009SBarry Smith   { gl[cnt++] = mwidth;  { gl[cnt++] = mwidth+1;} gl[cnt++] = mwidth + m-istart-1;}
244064c8009SBarry Smith   gl[cnt++] = mwidth*(n-jstart-1);  { gl[cnt++] = mwidth*(n-jstart-1)+1;} gl[cnt++] = mwidth*(n-jstart-1) + m-istart-1;
245064c8009SBarry Smith   {
246064c8009SBarry Smith     gl[cnt++] = mwidth*nwidth;  { gl[cnt++] = mwidth*nwidth+1;}  gl[cnt++] = mwidth*nwidth+ m-istart-1;
247064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;}
248064c8009SBarry 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;
249064c8009SBarry Smith   }
250064c8009SBarry 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;
251064c8009SBarry 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;}
252064c8009SBarry 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;
253064c8009SBarry Smith 
254064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
255064c8009SBarry Smith   /* convert that to global numbering and get them on all processes */
256064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,26,gl,gl);CHKERRQ(ierr);
257064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
258064c8009SBarry Smith   ierr = PetscMalloc(26*mp*np*pp*sizeof(PetscInt),&globals);CHKERRQ(ierr);
259ce94432eSBarry Smith   ierr = MPI_Allgather(gl,26,MPIU_INT,globals,26,MPIU_INT,PetscObjectComm((PetscObject)da));CHKERRQ(ierr);
260064c8009SBarry Smith 
261064c8009SBarry Smith   /* Number the coarse grid points from 0 to Ntotal */
2620298fd71SBarry Smith   ierr = MatGetSize(Aglobal,&Nt,NULL);CHKERRQ(ierr);
26312dd4568SBarry Smith   ierr = PetscTableCreate(Ntotal/3,Nt+1,&ht);CHKERRQ(ierr);
264064c8009SBarry Smith   for (i=0; i<26*mp*np*pp; i++) {
265064c8009SBarry Smith     ierr = PetscTableAddCount(ht,globals[i]+1);CHKERRQ(ierr);
266064c8009SBarry Smith   }
267064c8009SBarry Smith   ierr = PetscTableGetCount(ht,&cnt);CHKERRQ(ierr);
268e32f2f54SBarry Smith   if (cnt != Ntotal) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Hash table size %D not equal to total number coarse grid points %D",cnt,Ntotal);
269064c8009SBarry Smith   ierr = PetscFree(globals);CHKERRQ(ierr);
270064c8009SBarry Smith   for (i=0; i<26; i++) {
271064c8009SBarry Smith     ierr = PetscTableFind(ht,gl[i]+1,&gl[i]);CHKERRQ(ierr);
272064c8009SBarry Smith     gl[i]--;
273064c8009SBarry Smith   }
2746bc0bbbfSBarry Smith   ierr = PetscTableDestroy(&ht);CHKERRQ(ierr);
275064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
276064c8009SBarry Smith 
277064c8009SBarry Smith   /* construct global interpolation matrix */
2780298fd71SBarry Smith   ierr = MatGetLocalSize(Aglobal,&Ng,NULL);CHKERRQ(ierr);
279064c8009SBarry Smith   if (reuse == MAT_INITIAL_MATRIX) {
280ce94432eSBarry Smith     ierr = MatCreateAIJ(PetscObjectComm((PetscObject)da),Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,NULL,Nint+Nsurf,NULL,P);CHKERRQ(ierr);
281064c8009SBarry Smith   } else {
282064c8009SBarry Smith     ierr = MatZeroEntries(*P);CHKERRQ(ierr);
283064c8009SBarry Smith   }
284064c8009SBarry Smith   ierr = MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
2858c778c55SBarry Smith   ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
286064c8009SBarry Smith   ierr = MatSetValues(*P,Nint,IIint,26,gl,xint,INSERT_VALUES);CHKERRQ(ierr);
2878c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
2888c778c55SBarry Smith   ierr = MatDenseGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
289064c8009SBarry Smith   ierr = MatSetValues(*P,Nsurf,IIsurf,26,gl,xsurf,INSERT_VALUES);CHKERRQ(ierr);
2908c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
291064c8009SBarry Smith   ierr = MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
292064c8009SBarry Smith   ierr = MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
293064c8009SBarry Smith   ierr = PetscFree2(IIint,IIsurf);CHKERRQ(ierr);
294064c8009SBarry Smith 
2958e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
296064c8009SBarry Smith   {
297064c8009SBarry Smith     Vec         x,y;
298064c8009SBarry Smith     PetscScalar *yy;
299ce94432eSBarry Smith     ierr = VecCreateMPI(PetscObjectComm((PetscObject)da),Ng,PETSC_DETERMINE,&y);CHKERRQ(ierr);
300ce94432eSBarry Smith     ierr = VecCreateMPI(PetscObjectComm((PetscObject)da),PETSC_DETERMINE,Ntotal,&x);CHKERRQ(ierr);
301064c8009SBarry Smith     ierr = VecSet(x,1.0);CHKERRQ(ierr);
302064c8009SBarry Smith     ierr = MatMult(*P,x,y);CHKERRQ(ierr);
303064c8009SBarry Smith     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
304064c8009SBarry Smith     for (i=0; i<Ng; i++) {
305e32f2f54SBarry Smith       if (PetscAbsScalar(yy[i]-1.0) > 1.e-10) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong p interpolation at i %D value %G",i,PetscAbsScalar(yy[i]));
306064c8009SBarry Smith     }
307064c8009SBarry Smith     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
308064c8009SBarry Smith     ierr = VecDestroy(x);CHKERRQ(ierr);
309064c8009SBarry Smith     ierr = VecDestroy(y);CHKERRQ(ierr);
310064c8009SBarry Smith   }
311064c8009SBarry Smith #endif
312064c8009SBarry Smith 
313fcfd50ebSBarry Smith   ierr = MatDestroy(&Aii);CHKERRQ(ierr);
314fcfd50ebSBarry Smith   ierr = MatDestroy(&Ais);CHKERRQ(ierr);
315fcfd50ebSBarry Smith   ierr = MatDestroy(&Asi);CHKERRQ(ierr);
316fcfd50ebSBarry Smith   ierr = MatDestroy(&A);CHKERRQ(ierr);
317fcfd50ebSBarry Smith   ierr = ISDestroy(&is);CHKERRQ(ierr);
318fcfd50ebSBarry Smith   ierr = ISDestroy(&isint);CHKERRQ(ierr);
319fcfd50ebSBarry Smith   ierr = ISDestroy(&issurf);CHKERRQ(ierr);
320fcfd50ebSBarry Smith   ierr = MatDestroy(&Xint);CHKERRQ(ierr);
321fcfd50ebSBarry Smith   ierr = MatDestroy(&Xsurf);CHKERRQ(ierr);
322064c8009SBarry Smith   PetscFunctionReturn(0);
323064c8009SBarry Smith }
324064c8009SBarry Smith 
325064c8009SBarry Smith #undef __FUNCT__
326aa219208SBarry Smith #define __FUNCT__ "DMDAGetFaceInterpolation"
327064c8009SBarry Smith /*
328aa219208SBarry Smith       DMDAGetFaceInterpolation - Gets the interpolation for a face based coarse space
329064c8009SBarry Smith 
330064c8009SBarry Smith */
331aa219208SBarry Smith PetscErrorCode DMDAGetFaceInterpolation(DM da,PC_Exotic *exotic,Mat Aglobal,MatReuse reuse,Mat *P)
332064c8009SBarry Smith {
333064c8009SBarry Smith   PetscErrorCode         ierr;
334064c8009SBarry 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;
33528d20b34SBarry Smith   PetscInt               mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[6],*globals,Ng,*IIint,*IIsurf,Nt;
336064c8009SBarry Smith   Mat                    Xint, Xsurf,Xint_tmp;
337064c8009SBarry Smith   IS                     isint,issurf,is,row,col;
338064c8009SBarry Smith   ISLocalToGlobalMapping ltg;
339064c8009SBarry Smith   MPI_Comm               comm;
340064c8009SBarry Smith   Mat                    A,Aii,Ais,Asi,*Aholder,iAii;
341064c8009SBarry Smith   MatFactorInfo          info;
342064c8009SBarry Smith   PetscScalar            *xsurf,*xint;
343064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
344064c8009SBarry Smith   PetscScalar            tmp;
345064c8009SBarry Smith #endif
346064c8009SBarry Smith   PetscTable             ht;
347064c8009SBarry Smith 
348064c8009SBarry Smith   PetscFunctionBegin;
3491321219cSEthan Coon   ierr = DMDAGetInfo(da,&dim,0,0,0,&mp,&np,&pp,&dof,0,0,0,0,0);CHKERRQ(ierr);
350ce94432eSBarry Smith   if (dof != 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only for single field problems");
351ce94432eSBarry Smith   if (dim != 3) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only coded for 3d problems");
352aa219208SBarry Smith   ierr   = DMDAGetCorners(da,0,0,0,&m,&n,&p);CHKERRQ(ierr);
353aa219208SBarry Smith   ierr   = DMDAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth);CHKERRQ(ierr);
354064c8009SBarry Smith   istart = istart ? -1 : 0;
355064c8009SBarry Smith   jstart = jstart ? -1 : 0;
356064c8009SBarry Smith   kstart = kstart ? -1 : 0;
357064c8009SBarry Smith 
358064c8009SBarry Smith   /*
359064c8009SBarry Smith     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
360064c8009SBarry Smith     to all the local degrees of freedom (this includes the vertices, edges and faces).
361064c8009SBarry Smith 
362064c8009SBarry Smith     Xint are the subset of the interpolation into the interior
363064c8009SBarry Smith 
364064c8009SBarry Smith     Xface are the interpolation onto faces but not into the interior
365064c8009SBarry Smith 
366064c8009SBarry Smith     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
367064c8009SBarry Smith                                       Xint
368064c8009SBarry Smith     Symbolically one could write P = (Xface) after interchanging the rows to match the natural ordering on the domain
369064c8009SBarry Smith                                       Xsurf
370064c8009SBarry Smith   */
371064c8009SBarry Smith   N     = (m - istart)*(n - jstart)*(p - kstart);
372064c8009SBarry Smith   Nint  = (m-2-istart)*(n-2-jstart)*(p-2-kstart);
373064c8009SBarry Smith   Nface = 2*((m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart));
374064c8009SBarry Smith   Nwire = 4*((m-2-istart) + (n-2-jstart) + (p-2-kstart)) + 8;
375064c8009SBarry Smith   Nsurf = Nface + Nwire;
3760298fd71SBarry Smith   ierr  = MatCreateSeqDense(MPI_COMM_SELF,Nint,6,NULL,&Xint);CHKERRQ(ierr);
3770298fd71SBarry Smith   ierr  = MatCreateSeqDense(MPI_COMM_SELF,Nsurf,6,NULL,&Xsurf);CHKERRQ(ierr);
3788c778c55SBarry Smith   ierr  = MatDenseGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
379064c8009SBarry Smith 
380064c8009SBarry Smith   /*
381064c8009SBarry Smith      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
382064c8009SBarry Smith      Xsurf will be all zero (thus making the coarse matrix singular).
383064c8009SBarry Smith   */
384e32f2f54SBarry Smith   if (m-istart < 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in X direction must be at least 3");
385e32f2f54SBarry Smith   if (n-jstart < 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in Y direction must be at least 3");
386e32f2f54SBarry Smith   if (p-kstart < 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in Z direction must be at least 3");
387064c8009SBarry Smith 
388064c8009SBarry Smith   cnt = 0;
3892fa5cd67SKarl Rupp   for (j=1; j<n-1-jstart; j++) {
3902fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 0*Nsurf] = 1;
391064c8009SBarry Smith   }
3922fa5cd67SKarl Rupp 
3932fa5cd67SKarl Rupp   for (k=1; k<p-1-kstart; k++) {
3942fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 1*Nsurf] = 1;
3952fa5cd67SKarl Rupp     for (j=1; j<n-1-jstart; j++) {
3962fa5cd67SKarl Rupp       xsurf[cnt++ + 2*Nsurf] = 1;
3972fa5cd67SKarl Rupp       /* these are the interior nodes */
3982fa5cd67SKarl Rupp       xsurf[cnt++ + 3*Nsurf] = 1;
3992fa5cd67SKarl Rupp     }
4002fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 4*Nsurf] = 1;
4012fa5cd67SKarl Rupp   }
4022fa5cd67SKarl Rupp   for (j=1;j<n-1-jstart;j++) {
4032fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 5*Nsurf] = 1;
4042fa5cd67SKarl Rupp   }
405064c8009SBarry Smith 
406064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
407064c8009SBarry Smith   for (i=0; i<Nsurf; i++) {
408064c8009SBarry Smith     tmp = 0.0;
4092fa5cd67SKarl Rupp     for (j=0; j<6; j++) tmp += xsurf[i+j*Nsurf];
4102fa5cd67SKarl Rupp 
411e32f2f54SBarry Smith     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong Xsurf interpolation at i %D value %G",i,PetscAbsScalar(tmp));
412064c8009SBarry Smith   }
413064c8009SBarry Smith #endif
4148c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
415064c8009SBarry Smith   /* ierr = MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);*/
416064c8009SBarry Smith 
417064c8009SBarry Smith 
418064c8009SBarry Smith   /*
419064c8009SBarry Smith        I are the indices for all the needed vertices (in global numbering)
420064c8009SBarry Smith        Iint are the indices for the interior values, I surf for the surface values
421064c8009SBarry Smith             (This is just for the part of the global matrix obtained with MatGetSubMatrix(), it
422aa219208SBarry Smith              is NOT the local DMDA ordering.)
423064c8009SBarry Smith        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
424064c8009SBarry Smith   */
425064c8009SBarry Smith #define Endpoint(a,start,b) (a == 0 || a == (b-1-start))
426064c8009SBarry Smith   ierr = PetscMalloc3(N,PetscInt,&II,Nint,PetscInt,&Iint,Nsurf,PetscInt,&Isurf);CHKERRQ(ierr);
427064c8009SBarry Smith   ierr = PetscMalloc2(Nint,PetscInt,&IIint,Nsurf,PetscInt,&IIsurf);CHKERRQ(ierr);
428064c8009SBarry Smith   for (k=0; k<p-kstart; k++) {
429064c8009SBarry Smith     for (j=0; j<n-jstart; j++) {
430064c8009SBarry Smith       for (i=0; i<m-istart; i++) {
431064c8009SBarry Smith         II[c++] = i + j*mwidth + k*mwidth*nwidth;
432064c8009SBarry Smith 
433064c8009SBarry Smith         if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) {
434064c8009SBarry Smith           IIint[cint]  = i + j*mwidth + k*mwidth*nwidth;
435064c8009SBarry Smith           Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
436064c8009SBarry Smith         } else {
437064c8009SBarry Smith           IIsurf[csurf]  = i + j*mwidth + k*mwidth*nwidth;
438064c8009SBarry Smith           Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
439064c8009SBarry Smith         }
440064c8009SBarry Smith       }
441064c8009SBarry Smith     }
442064c8009SBarry Smith   }
443e32f2f54SBarry Smith   if (c != N) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"c != N");
444e32f2f54SBarry Smith   if (cint != Nint) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"cint != Nint");
445e32f2f54SBarry Smith   if (csurf != Nsurf) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"csurf != Nsurf");
4461411c6eeSJed Brown   ierr = DMGetLocalToGlobalMapping(da,&ltg);CHKERRQ(ierr);
447064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,N,II,II);CHKERRQ(ierr);
448064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint);CHKERRQ(ierr);
449064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf);CHKERRQ(ierr);
450064c8009SBarry Smith   ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr);
45170b3c8c7SBarry Smith   ierr = ISCreateGeneral(comm,N,II,PETSC_COPY_VALUES,&is);CHKERRQ(ierr);
45270b3c8c7SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,PETSC_COPY_VALUES,&isint);CHKERRQ(ierr);
45370b3c8c7SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,PETSC_COPY_VALUES,&issurf);CHKERRQ(ierr);
454064c8009SBarry Smith   ierr = PetscFree3(II,Iint,Isurf);CHKERRQ(ierr);
455064c8009SBarry Smith 
456671e8369SHong Zhang   ierr = ISSort(is);CHKERRQ(ierr);
457064c8009SBarry Smith   ierr = MatGetSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder);CHKERRQ(ierr);
458064c8009SBarry Smith   A    = *Aholder;
459064c8009SBarry Smith   ierr = PetscFree(Aholder);CHKERRQ(ierr);
460064c8009SBarry Smith 
461064c8009SBarry Smith   ierr = MatGetSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii);CHKERRQ(ierr);
462064c8009SBarry Smith   ierr = MatGetSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais);CHKERRQ(ierr);
463064c8009SBarry Smith   ierr = MatGetSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi);CHKERRQ(ierr);
464064c8009SBarry Smith 
465064c8009SBarry Smith   /*
466064c8009SBarry Smith      Solve for the interpolation onto the interior Xint
467064c8009SBarry Smith   */
46892e4c2edSBarry Smith   ierr = MatMatMult(Ais,Xsurf,MAT_INITIAL_MATRIX,PETSC_DETERMINE,&Xint_tmp);CHKERRQ(ierr);
469064c8009SBarry Smith   ierr = MatScale(Xint_tmp,-1.0);CHKERRQ(ierr);
470064c8009SBarry Smith 
4718e722e36SBarry Smith   if (exotic->directSolve) {
4722692d6eeSBarry Smith     ierr = MatGetFactor(Aii,MATSOLVERPETSC,MAT_FACTOR_LU,&iAii);CHKERRQ(ierr);
473064c8009SBarry Smith     ierr = MatFactorInfoInitialize(&info);CHKERRQ(ierr);
4742692d6eeSBarry Smith     ierr = MatGetOrdering(Aii,MATORDERINGND,&row,&col);CHKERRQ(ierr);
475064c8009SBarry Smith     ierr = MatLUFactorSymbolic(iAii,Aii,row,col,&info);CHKERRQ(ierr);
476fcfd50ebSBarry Smith     ierr = ISDestroy(&row);CHKERRQ(ierr);
477fcfd50ebSBarry Smith     ierr = ISDestroy(&col);CHKERRQ(ierr);
478064c8009SBarry Smith     ierr = MatLUFactorNumeric(iAii,Aii,&info);CHKERRQ(ierr);
479064c8009SBarry Smith     ierr = MatMatSolve(iAii,Xint_tmp,Xint);CHKERRQ(ierr);
480fcfd50ebSBarry Smith     ierr = MatDestroy(&iAii);CHKERRQ(ierr);
481064c8009SBarry Smith   } else {
482064c8009SBarry Smith     Vec         b,x;
483064c8009SBarry Smith     PetscScalar *xint_tmp;
484064c8009SBarry Smith 
4858c778c55SBarry Smith     ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
486778a2246SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,0,&x);CHKERRQ(ierr);
4878c778c55SBarry Smith     ierr = MatDenseGetArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
488778a2246SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,0,&b);CHKERRQ(ierr);
4898e722e36SBarry Smith     ierr = KSPSetOperators(exotic->ksp,Aii,Aii,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
490064c8009SBarry Smith     for (i=0; i<6; i++) {
491064c8009SBarry Smith       ierr = VecPlaceArray(x,xint+i*Nint);CHKERRQ(ierr);
492064c8009SBarry Smith       ierr = VecPlaceArray(b,xint_tmp+i*Nint);CHKERRQ(ierr);
4938e722e36SBarry Smith       ierr = KSPSolve(exotic->ksp,b,x);CHKERRQ(ierr);
494064c8009SBarry Smith       ierr = VecResetArray(x);CHKERRQ(ierr);
495064c8009SBarry Smith       ierr = VecResetArray(b);CHKERRQ(ierr);
496064c8009SBarry Smith     }
4978c778c55SBarry Smith     ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
4988c778c55SBarry Smith     ierr = MatDenseRestoreArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
4996bf464f9SBarry Smith     ierr = VecDestroy(&x);CHKERRQ(ierr);
5006bf464f9SBarry Smith     ierr = VecDestroy(&b);CHKERRQ(ierr);
501064c8009SBarry Smith   }
5026bf464f9SBarry Smith   ierr = MatDestroy(&Xint_tmp);CHKERRQ(ierr);
503064c8009SBarry Smith 
504064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
5058c778c55SBarry Smith   ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
506064c8009SBarry Smith   for (i=0; i<Nint; i++) {
507064c8009SBarry Smith     tmp = 0.0;
5082fa5cd67SKarl Rupp     for (j=0; j<6; j++) tmp += xint[i+j*Nint];
5092fa5cd67SKarl Rupp 
510e32f2f54SBarry Smith     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong Xint interpolation at i %D value %G",i,PetscAbsScalar(tmp));
511064c8009SBarry Smith   }
5128c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
513064c8009SBarry Smith   /* ierr =MatView(Xint,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); */
514064c8009SBarry Smith #endif
515064c8009SBarry Smith 
516064c8009SBarry Smith 
517064c8009SBarry Smith   /*         total faces    */
518064c8009SBarry Smith   Ntotal =  mp*np*(pp+1) + mp*pp*(np+1) + np*pp*(mp+1);
519064c8009SBarry Smith 
520064c8009SBarry Smith   /*
521064c8009SBarry Smith       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
522064c8009SBarry Smith   */
523064c8009SBarry Smith   cnt = 0;
524064c8009SBarry Smith   { gl[cnt++] = mwidth+1;}
525064c8009SBarry Smith   {
526064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth+1;}
527064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;}
528064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth+mwidth*(n-jstart-1)+1;}
529064c8009SBarry Smith   }
530064c8009SBarry Smith   { gl[cnt++] = mwidth*nwidth*(p-kstart-1) + mwidth+1;}
531064c8009SBarry Smith 
532064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
533064c8009SBarry Smith   /* convert that to global numbering and get them on all processes */
534064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,6,gl,gl);CHKERRQ(ierr);
535064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
536064c8009SBarry Smith   ierr = PetscMalloc(6*mp*np*pp*sizeof(PetscInt),&globals);CHKERRQ(ierr);
537ce94432eSBarry Smith   ierr = MPI_Allgather(gl,6,MPIU_INT,globals,6,MPIU_INT,PetscObjectComm((PetscObject)da));CHKERRQ(ierr);
538064c8009SBarry Smith 
539064c8009SBarry Smith   /* Number the coarse grid points from 0 to Ntotal */
5400298fd71SBarry Smith   ierr = MatGetSize(Aglobal,&Nt,NULL);CHKERRQ(ierr);
54128d20b34SBarry Smith   ierr = PetscTableCreate(Ntotal/3,Nt+1,&ht);CHKERRQ(ierr);
542064c8009SBarry Smith   for (i=0; i<6*mp*np*pp; i++) {
543064c8009SBarry Smith     ierr = PetscTableAddCount(ht,globals[i]+1);CHKERRQ(ierr);
544064c8009SBarry Smith   }
545064c8009SBarry Smith   ierr = PetscTableGetCount(ht,&cnt);CHKERRQ(ierr);
546e32f2f54SBarry Smith   if (cnt != Ntotal) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Hash table size %D not equal to total number coarse grid points %D",cnt,Ntotal);
547064c8009SBarry Smith   ierr = PetscFree(globals);CHKERRQ(ierr);
548064c8009SBarry Smith   for (i=0; i<6; i++) {
549064c8009SBarry Smith     ierr = PetscTableFind(ht,gl[i]+1,&gl[i]);CHKERRQ(ierr);
550064c8009SBarry Smith     gl[i]--;
551064c8009SBarry Smith   }
5526bc0bbbfSBarry Smith   ierr = PetscTableDestroy(&ht);CHKERRQ(ierr);
553064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
554064c8009SBarry Smith 
555064c8009SBarry Smith   /* construct global interpolation matrix */
5560298fd71SBarry Smith   ierr = MatGetLocalSize(Aglobal,&Ng,NULL);CHKERRQ(ierr);
557064c8009SBarry Smith   if (reuse == MAT_INITIAL_MATRIX) {
558ce94432eSBarry Smith     ierr = MatCreateAIJ(PetscObjectComm((PetscObject)da),Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,NULL,Nint,NULL,P);CHKERRQ(ierr);
559064c8009SBarry Smith   } else {
560064c8009SBarry Smith     ierr = MatZeroEntries(*P);CHKERRQ(ierr);
561064c8009SBarry Smith   }
562064c8009SBarry Smith   ierr = MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
5638c778c55SBarry Smith   ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
564064c8009SBarry Smith   ierr = MatSetValues(*P,Nint,IIint,6,gl,xint,INSERT_VALUES);CHKERRQ(ierr);
5658c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
5668c778c55SBarry Smith   ierr = MatDenseGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
567064c8009SBarry Smith   ierr = MatSetValues(*P,Nsurf,IIsurf,6,gl,xsurf,INSERT_VALUES);CHKERRQ(ierr);
5688c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
569064c8009SBarry Smith   ierr = MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
570064c8009SBarry Smith   ierr = MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
571064c8009SBarry Smith   ierr = PetscFree2(IIint,IIsurf);CHKERRQ(ierr);
572064c8009SBarry Smith 
573064c8009SBarry Smith 
574064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
575064c8009SBarry Smith   {
576064c8009SBarry Smith     Vec         x,y;
577064c8009SBarry Smith     PetscScalar *yy;
578ce94432eSBarry Smith     ierr = VecCreateMPI(PetscObjectComm((PetscObject)da),Ng,PETSC_DETERMINE,&y);CHKERRQ(ierr);
579ce94432eSBarry Smith     ierr = VecCreateMPI(PetscObjectComm((PetscObject)da),PETSC_DETERMINE,Ntotal,&x);CHKERRQ(ierr);
580064c8009SBarry Smith     ierr = VecSet(x,1.0);CHKERRQ(ierr);
581064c8009SBarry Smith     ierr = MatMult(*P,x,y);CHKERRQ(ierr);
582064c8009SBarry Smith     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
583064c8009SBarry Smith     for (i=0; i<Ng; i++) {
584e32f2f54SBarry Smith       if (PetscAbsScalar(yy[i]-1.0) > 1.e-10) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong p interpolation at i %D value %G",i,PetscAbsScalar(yy[i]));
585064c8009SBarry Smith     }
586064c8009SBarry Smith     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
587064c8009SBarry Smith     ierr = VecDestroy(x);CHKERRQ(ierr);
588064c8009SBarry Smith     ierr = VecDestroy(y);CHKERRQ(ierr);
589064c8009SBarry Smith   }
590064c8009SBarry Smith #endif
591064c8009SBarry Smith 
592fcfd50ebSBarry Smith   ierr = MatDestroy(&Aii);CHKERRQ(ierr);
593fcfd50ebSBarry Smith   ierr = MatDestroy(&Ais);CHKERRQ(ierr);
594fcfd50ebSBarry Smith   ierr = MatDestroy(&Asi);CHKERRQ(ierr);
595fcfd50ebSBarry Smith   ierr = MatDestroy(&A);CHKERRQ(ierr);
596fcfd50ebSBarry Smith   ierr = ISDestroy(&is);CHKERRQ(ierr);
597fcfd50ebSBarry Smith   ierr = ISDestroy(&isint);CHKERRQ(ierr);
598fcfd50ebSBarry Smith   ierr = ISDestroy(&issurf);CHKERRQ(ierr);
599fcfd50ebSBarry Smith   ierr = MatDestroy(&Xint);CHKERRQ(ierr);
600fcfd50ebSBarry Smith   ierr = MatDestroy(&Xsurf);CHKERRQ(ierr);
601064c8009SBarry Smith   PetscFunctionReturn(0);
602064c8009SBarry Smith }
603174b6946SBarry Smith 
6047233f9f0SBarry Smith 
605174b6946SBarry Smith #undef __FUNCT__
6067233f9f0SBarry Smith #define __FUNCT__ "PCExoticSetType"
6077233f9f0SBarry Smith /*@
6087233f9f0SBarry Smith    PCExoticSetType - Sets the type of coarse grid interpolation to use
6097233f9f0SBarry Smith 
6103f9fe445SBarry Smith    Logically Collective on PC
6117233f9f0SBarry Smith 
6127233f9f0SBarry Smith    Input Parameters:
6137233f9f0SBarry Smith +  pc - the preconditioner context
6147233f9f0SBarry Smith -  type - either PC_EXOTIC_FACE or PC_EXOTIC_WIREBASKET (defaults to face)
6157233f9f0SBarry Smith 
616563e08c6SBarry Smith    Notes: The face based interpolation has 1 degree of freedom per face and ignores the
617563e08c6SBarry Smith      edge and vertex values completely in the coarse problem. For any seven point
618563e08c6SBarry Smith      stencil the interpolation of a constant on all faces into the interior is that constant.
619563e08c6SBarry Smith 
620563e08c6SBarry Smith      The wirebasket interpolation has 1 degree of freedom per vertex, per edge and
621563e08c6SBarry Smith      per face. A constant on the subdomain boundary is interpolated as that constant
622563e08c6SBarry Smith      in the interior of the domain.
623563e08c6SBarry Smith 
624563e08c6SBarry Smith      The coarse grid matrix is obtained via the Galerkin computation A_c = R A R^T, hence
625563e08c6SBarry Smith      if A is nonsingular A_c is also nonsingular.
626563e08c6SBarry Smith 
627563e08c6SBarry Smith      Both interpolations are suitable for only scalar problems.
628563e08c6SBarry Smith 
6297233f9f0SBarry Smith    Level: intermediate
6307233f9f0SBarry Smith 
6317233f9f0SBarry Smith 
6327233f9f0SBarry Smith .seealso: PCEXOTIC, PCExoticType()
6337233f9f0SBarry Smith @*/
6347087cfbeSBarry Smith PetscErrorCode  PCExoticSetType(PC pc,PCExoticType type)
6357233f9f0SBarry Smith {
6364ac538c5SBarry Smith   PetscErrorCode ierr;
6377233f9f0SBarry Smith 
6387233f9f0SBarry Smith   PetscFunctionBegin;
6390700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
640c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc,type,2);
6414ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCExoticSetType_C",(PC,PCExoticType),(pc,type));CHKERRQ(ierr);
6427233f9f0SBarry Smith   PetscFunctionReturn(0);
6437233f9f0SBarry Smith }
6447233f9f0SBarry Smith 
6457233f9f0SBarry Smith #undef __FUNCT__
6467233f9f0SBarry Smith #define __FUNCT__ "PCExoticSetType_Exotic"
6477087cfbeSBarry Smith PetscErrorCode  PCExoticSetType_Exotic(PC pc,PCExoticType type)
6487233f9f0SBarry Smith {
649f3fbd535SBarry Smith   PC_MG     *mg  = (PC_MG*)pc->data;
65031567311SBarry Smith   PC_Exotic *ctx = (PC_Exotic*) mg->innerctx;
6517233f9f0SBarry Smith 
6527233f9f0SBarry Smith   PetscFunctionBegin;
6537233f9f0SBarry Smith   ctx->type = type;
6547233f9f0SBarry Smith   PetscFunctionReturn(0);
6557233f9f0SBarry Smith }
6567233f9f0SBarry Smith 
6577233f9f0SBarry Smith #undef __FUNCT__
6587233f9f0SBarry Smith #define __FUNCT__ "PCSetUp_Exotic"
6597233f9f0SBarry Smith PetscErrorCode PCSetUp_Exotic(PC pc)
660174b6946SBarry Smith {
661174b6946SBarry Smith   PetscErrorCode ierr;
66296bdf778SBarry Smith   Mat            A;
663f3fbd535SBarry Smith   PC_MG          *mg   = (PC_MG*)pc->data;
66431567311SBarry Smith   PC_Exotic      *ex   = (PC_Exotic*) mg->innerctx;
66596bdf778SBarry Smith   MatReuse       reuse = (ex->P) ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
666174b6946SBarry Smith 
667174b6946SBarry Smith   PetscFunctionBegin;
668ce94432eSBarry Smith   if (!pc->dm) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Need to call PCSetDM() before using this PC");
6690298fd71SBarry Smith   ierr = PCGetOperators(pc,NULL,&A,NULL);CHKERRQ(ierr);
6707233f9f0SBarry Smith   if (ex->type == PC_EXOTIC_FACE) {
671aa219208SBarry Smith     ierr = DMDAGetFaceInterpolation(pc->dm,ex,A,reuse,&ex->P);CHKERRQ(ierr);
6727233f9f0SBarry Smith   } else if (ex->type == PC_EXOTIC_WIREBASKET) {
673aa219208SBarry Smith     ierr = DMDAGetWireBasketInterpolation(pc->dm,ex,A,reuse,&ex->P);CHKERRQ(ierr);
674ce94432eSBarry Smith   } else SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Unknown exotic coarse space %d",ex->type);
67596bdf778SBarry Smith   ierr = PCMGSetInterpolation(pc,1,ex->P);CHKERRQ(ierr);
676d0660788SBarry Smith   /* if PC has attached DM we must remove it or the PCMG will use it to compute incorrect sized vectors and interpolations */
6770298fd71SBarry Smith   ierr = PCSetDM(pc,NULL);CHKERRQ(ierr);
6787233f9f0SBarry Smith   ierr = PCSetUp_MG(pc);CHKERRQ(ierr);
679174b6946SBarry Smith   PetscFunctionReturn(0);
680174b6946SBarry Smith }
681174b6946SBarry Smith 
682174b6946SBarry Smith #undef __FUNCT__
6837233f9f0SBarry Smith #define __FUNCT__ "PCDestroy_Exotic"
6847233f9f0SBarry Smith PetscErrorCode PCDestroy_Exotic(PC pc)
685174b6946SBarry Smith {
686174b6946SBarry Smith   PetscErrorCode ierr;
687f3fbd535SBarry Smith   PC_MG          *mg  = (PC_MG*)pc->data;
68831567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
689174b6946SBarry Smith 
690174b6946SBarry Smith   PetscFunctionBegin;
691fcfd50ebSBarry Smith   ierr = MatDestroy(&ctx->P);CHKERRQ(ierr);
692fcfd50ebSBarry Smith   ierr = KSPDestroy(&ctx->ksp);CHKERRQ(ierr);
6937233f9f0SBarry Smith   ierr = PetscFree(ctx);CHKERRQ(ierr);
6947233f9f0SBarry Smith   ierr = PCDestroy_MG(pc);CHKERRQ(ierr);
695174b6946SBarry Smith   PetscFunctionReturn(0);
696174b6946SBarry Smith }
697174b6946SBarry Smith 
698174b6946SBarry Smith #undef __FUNCT__
6997233f9f0SBarry Smith #define __FUNCT__ "PCView_Exotic"
7007233f9f0SBarry Smith PetscErrorCode PCView_Exotic(PC pc,PetscViewer viewer)
7017233f9f0SBarry Smith {
702f3fbd535SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
7037233f9f0SBarry Smith   PetscErrorCode ierr;
704ace3abfcSBarry Smith   PetscBool      iascii;
70531567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
7067233f9f0SBarry Smith 
7077233f9f0SBarry Smith   PetscFunctionBegin;
708251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
7097233f9f0SBarry Smith   if (iascii) {
7107233f9f0SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"    Exotic type = %s\n",PCExoticTypes[ctx->type]);CHKERRQ(ierr);
7118e722e36SBarry Smith     if (ctx->directSolve) {
7128e722e36SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"      Using direct solver to construct interpolation\n");CHKERRQ(ierr);
7138e722e36SBarry Smith     } else {
7148e722e36SBarry Smith       PetscViewer sviewer;
7158e722e36SBarry Smith       PetscMPIInt rank;
7168e722e36SBarry Smith 
7178e722e36SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"      Using iterative solver to construct interpolation\n");CHKERRQ(ierr);
7188e722e36SBarry Smith       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
7198e722e36SBarry Smith       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);  /* should not need to push this twice? */
7208e722e36SBarry Smith       ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr);
721ce94432eSBarry Smith       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)pc),&rank);CHKERRQ(ierr);
7228e722e36SBarry Smith       if (!rank) {
7238e722e36SBarry Smith         ierr = KSPView(ctx->ksp,sviewer);CHKERRQ(ierr);
7248e722e36SBarry Smith       }
7258e722e36SBarry Smith       ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr);
7268e722e36SBarry Smith       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
7278e722e36SBarry Smith       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
7288e722e36SBarry Smith     }
7297233f9f0SBarry Smith   }
7307233f9f0SBarry Smith   ierr = PCView_MG(pc,viewer);CHKERRQ(ierr);
7317233f9f0SBarry Smith   PetscFunctionReturn(0);
7327233f9f0SBarry Smith }
7337233f9f0SBarry Smith 
7347233f9f0SBarry Smith #undef __FUNCT__
7357233f9f0SBarry Smith #define __FUNCT__ "PCSetFromOptions_Exotic"
7367233f9f0SBarry Smith PetscErrorCode PCSetFromOptions_Exotic(PC pc)
7377233f9f0SBarry Smith {
7387233f9f0SBarry Smith   PetscErrorCode ierr;
739ace3abfcSBarry Smith   PetscBool      flg;
740f3fbd535SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
7417233f9f0SBarry Smith   PCExoticType   mgctype;
74231567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
7437233f9f0SBarry Smith 
7447233f9f0SBarry Smith   PetscFunctionBegin;
7457233f9f0SBarry Smith   ierr = PetscOptionsHead("Exotic coarse space options");CHKERRQ(ierr);
7467233f9f0SBarry Smith   ierr = PetscOptionsEnum("-pc_exotic_type","face or wirebasket","PCExoticSetType",PCExoticTypes,(PetscEnum)ctx->type,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr);
7477233f9f0SBarry Smith   if (flg) {
7487233f9f0SBarry Smith     ierr = PCExoticSetType(pc,mgctype);CHKERRQ(ierr);
7497233f9f0SBarry Smith   }
7500298fd71SBarry Smith   ierr = PetscOptionsBool("-pc_exotic_direct_solver","use direct solver to construct interpolation","None",ctx->directSolve,&ctx->directSolve,NULL);CHKERRQ(ierr);
7518e722e36SBarry Smith   if (!ctx->directSolve) {
7528e722e36SBarry Smith     if (!ctx->ksp) {
7538e722e36SBarry Smith       const char *prefix;
7548e722e36SBarry Smith       ierr = KSPCreate(PETSC_COMM_SELF,&ctx->ksp);CHKERRQ(ierr);
7558e722e36SBarry Smith       ierr = PetscObjectIncrementTabLevel((PetscObject)ctx->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
7568e722e36SBarry Smith       ierr = PetscLogObjectParent(pc,ctx->ksp);CHKERRQ(ierr);
7578e722e36SBarry Smith       ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
7588e722e36SBarry Smith       ierr = KSPSetOptionsPrefix(ctx->ksp,prefix);CHKERRQ(ierr);
7598e722e36SBarry Smith       ierr = KSPAppendOptionsPrefix(ctx->ksp,"exotic_");CHKERRQ(ierr);
7608e722e36SBarry Smith     }
7618e722e36SBarry Smith     ierr = KSPSetFromOptions(ctx->ksp);CHKERRQ(ierr);
7628e722e36SBarry Smith   }
7637233f9f0SBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
7647233f9f0SBarry Smith   PetscFunctionReturn(0);
7657233f9f0SBarry Smith }
7667233f9f0SBarry Smith 
767174b6946SBarry Smith 
768174b6946SBarry Smith /*MC
7697233f9f0SBarry Smith      PCEXOTIC - Two level overlapping Schwarz preconditioner with exotic (non-standard) coarse grid spaces
770174b6946SBarry Smith 
7717233f9f0SBarry Smith      This uses the PCMG infrastructure restricted to two levels and the face and wirebasket based coarse
77224c3aa18SBarry Smith    grid spaces.
77324c3aa18SBarry Smith 
77424c3aa18SBarry Smith    Notes: By default this uses GMRES on the fine grid smoother so this should be used with KSPFGMRES or the smoother changed to not use GMRES
77524c3aa18SBarry Smith 
77624c3aa18SBarry Smith    References: These coarse grid spaces originate in the work of Bramble, Pasciak  and Schatz, "The Construction
7773b65e785SBarry Smith    of Preconditioners for Elliptic Problems by Substructing IV", Mathematics of Computation, volume 53 pages 1--24, 1989.
7783b65e785SBarry Smith    They were generalized slightly in "Domain Decomposition Method for Linear Elasticity", Ph. D. thesis, Barry Smith,
7793b65e785SBarry Smith    New York University, 1990. They were then explored in great detail in Dryja, Smith, Widlund, "Schwarz Analysis
7803b65e785SBarry Smith    of Iterative Substructuring Methods for Elliptic Problems in Three Dimensions, SIAM Journal on Numerical
7813b65e785SBarry Smith    Analysis, volume 31. pages 1662-1694, 1994. These were developed in the context of iterative substructuring preconditioners.
7823b65e785SBarry Smith    They were then ingeniously applied as coarse grid spaces for overlapping Schwarz methods by Dohrmann and Widlund.
7833b65e785SBarry Smith    They refer to them as GDSW (generalized Dryja, Smith, Widlund preconditioners). See, for example,
7843b65e785SBarry Smith    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Extending theory for domain decomposition algorithms to irregular subdomains. In Ulrich Langer, Marco
7853b65e785SBarry Smith    Discacciati, David Keyes, Olof Widlund, and Walter Zulehner, editors, Proceedings
7863b65e785SBarry Smith    of the 17th International Conference on Domain Decomposition Methods in
7873b65e785SBarry Smith    Science and Engineering, held in Strobl, Austria, July 3-7, 2006, number 60 in
7883b65e785SBarry Smith    Springer-Verlag, Lecture Notes in Computational Science and Engineering, pages 255-261, 2007.
7893b65e785SBarry Smith    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. A family of energy min-
7903b65e785SBarry Smith    imizing coarse spaces for overlapping Schwarz preconditioners. In Ulrich Langer,
7913b65e785SBarry Smith    Marco Discacciati, David Keyes, Olof Widlund, and Walter Zulehner, editors, Proceedings
7923b65e785SBarry Smith    of the 17th International Conference on Domain Decomposition Methods
7933b65e785SBarry Smith    in Science and Engineering, held in Strobl, Austria, July 3-7, 2006, number 60 in
7943b65e785SBarry Smith    Springer-Verlag, Lecture Notes in Computational Science and Engineering, pages 247-254, 2007
7953b65e785SBarry Smith    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Domain decomposition
7963b65e785SBarry Smith    for less regular subdomains: Overlapping Schwarz in two dimensions. SIAM J.
7973b65e785SBarry Smith    Numer. Anal., 46(4):2153-2168, 2008.
7983b65e785SBarry Smith    Clark R. Dohrmann and Olof B. Widlund. An overlapping Schwarz
7993b65e785SBarry Smith    algorithm for almost incompressible elasticity. Technical Report
8003b65e785SBarry Smith    TR2008-912, Department of Computer Science, Courant Institute
8013b65e785SBarry Smith    of Mathematical Sciences, New York University, May 2008. URL:
8023b65e785SBarry Smith    http://cs.nyu.edu/csweb/Research/TechReports/TR2008-912/TR2008-912.pdf
8037233f9f0SBarry Smith 
8047233f9f0SBarry Smith    Options Database: The usual PCMG options are supported, such as -mg_levels_pc_type <type> -mg_coarse_pc_type <type>
8057233f9f0SBarry Smith       -pc_mg_type <type>
8067233f9f0SBarry Smith 
80725a35f6fSSatish Balay    Level: advanced
808174b6946SBarry Smith 
8096c699258SBarry Smith .seealso:  PCMG, PCSetDM(), PCExoticType, PCExoticSetType()
810174b6946SBarry Smith M*/
811174b6946SBarry Smith 
812174b6946SBarry Smith EXTERN_C_BEGIN
813174b6946SBarry Smith #undef __FUNCT__
8147233f9f0SBarry Smith #define __FUNCT__ "PCCreate_Exotic"
8157087cfbeSBarry Smith PetscErrorCode  PCCreate_Exotic(PC pc)
816174b6946SBarry Smith {
817174b6946SBarry Smith   PetscErrorCode ierr;
8187233f9f0SBarry Smith   PC_Exotic      *ex;
819f3fbd535SBarry Smith   PC_MG          *mg;
820174b6946SBarry Smith 
821174b6946SBarry Smith   PetscFunctionBegin;
822f91d8e95SBarry Smith   /* if type was previously mg; must manually destroy it because call to PCSetType(pc,PCMG) will not destroy it */
8232fa5cd67SKarl Rupp   if (pc->ops->destroy) {
8242fa5cd67SKarl Rupp     ierr =  (*pc->ops->destroy)(pc);CHKERRQ(ierr);
8252fa5cd67SKarl Rupp     pc->data = 0;
8262fa5cd67SKarl Rupp   }
827503cfb0cSBarry Smith   ierr = PetscFree(((PetscObject)pc)->type_name);CHKERRQ(ierr);
828f91d8e95SBarry Smith   ((PetscObject)pc)->type_name = 0;
829f91d8e95SBarry Smith 
830174b6946SBarry Smith   ierr         = PCSetType(pc,PCMG);CHKERRQ(ierr);
8310298fd71SBarry Smith   ierr         = PCMGSetLevels(pc,2,NULL);CHKERRQ(ierr);
832c91913d3SJed Brown   ierr         = PCMGSetGalerkin(pc,PETSC_TRUE);CHKERRQ(ierr);
83396bdf778SBarry Smith   ierr         = PetscNew(PC_Exotic,&ex);CHKERRQ(ierr); \
8347233f9f0SBarry Smith   ex->type     = PC_EXOTIC_FACE;
835f3fbd535SBarry Smith   mg           = (PC_MG*) pc->data;
83631567311SBarry Smith   mg->innerctx = ex;
8377233f9f0SBarry Smith 
8387233f9f0SBarry Smith 
8397233f9f0SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_Exotic;
8407233f9f0SBarry Smith   pc->ops->view           = PCView_Exotic;
8417233f9f0SBarry Smith   pc->ops->destroy        = PCDestroy_Exotic;
8426c699258SBarry Smith   pc->ops->setup          = PCSetUp_Exotic;
8432fa5cd67SKarl Rupp 
8447233f9f0SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCExoticSetType_C","PCExoticSetType_Exotic",PCExoticSetType_Exotic);CHKERRQ(ierr);
845174b6946SBarry Smith   PetscFunctionReturn(0);
846174b6946SBarry Smith }
847174b6946SBarry Smith EXTERN_C_END
848