xref: /petsc/src/ksp/pc/impls/wb/wb.c (revision 0be760fb6018fd3ee12cc798109c979e25d8d805)
1 #define PETSCKSP_DLL
2 
3 
4 #include "petscpc.h"   /*I "petscpc.h" I*/
5 #include "petscmg.h"   /*I "petscmg.h" I*/
6 #include "petscda.h"   /*I "petscda.h" I*/
7 #include "../src/ksp/pc/impls/mg/mgimpl.h"
8 
9 const char *PCExoticTypes[] = {"face","wirebasket","PCExoticType","PC_Exotic",0};
10 
11 
12 
13 #undef __FUNCT__
14 #define __FUNCT__ "DAGetWireBasketInterpolation"
15 /*
16       DAGetWireBasketInterpolation - Gets the interpolation for a wirebasket based coarse space
17 
18 */
19 PetscErrorCode DAGetWireBasketInterpolation(DA da,Mat Aglobal,MatReuse reuse,Mat *P)
20 {
21   PetscErrorCode         ierr;
22   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   PetscInt               mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[26],*globals,Ng,*IIint,*IIsurf;
24   Mat                    Xint, Xsurf,Xint_tmp;
25   IS                     isint,issurf,is,row,col;
26   ISLocalToGlobalMapping ltg;
27   MPI_Comm               comm;
28   Mat                    A,Aii,Ais,Asi,*Aholder,iAii;
29   MatFactorInfo          info;
30   PetscScalar            *xsurf,*xint;
31 #if defined(PETSC_USE_DEBUG)
32   PetscScalar            tmp;
33 #endif
34   PetscTable             ht;
35 
36   PetscFunctionBegin;
37   ierr = DAGetInfo(da,&dim,0,0,0,&mp,&np,&pp,&dof,0,0,0);CHKERRQ(ierr);
38   if (dof != 1) SETERRQ(PETSC_ERR_SUP,"Only for single field problems");
39   if (dim != 3) SETERRQ(PETSC_ERR_SUP,"Only coded for 3d problems");
40   ierr = DAGetCorners(da,0,0,0,&m,&n,&p);CHKERRQ(ierr);
41   ierr = DAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth);CHKERRQ(ierr);
42   istart = istart ? -1 : 0;
43   jstart = jstart ? -1 : 0;
44   kstart = kstart ? -1 : 0;
45 
46   /*
47     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
48     to all the local degrees of freedom (this includes the vertices, edges and faces).
49 
50     Xint are the subset of the interpolation into the interior
51 
52     Xface are the interpolation onto faces but not into the interior
53 
54     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
55                                         Xint
56     Symbolically one could write P = (  Xface  ) after interchanging the rows to match the natural ordering on the domain
57                                         Xsurf
58   */
59   N     = (m - istart)*(n - jstart)*(p - kstart);
60   Nint  = (m-2-istart)*(n-2-jstart)*(p-2-kstart);
61   Nface = 2*( (m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart) );
62   Nwire = 4*( (m-2-istart) + (n-2-jstart) + (p-2-kstart) ) + 8;
63   Nsurf = Nface + Nwire;
64   ierr = MatCreateSeqDense(MPI_COMM_SELF,Nint,26,PETSC_NULL,&Xint);CHKERRQ(ierr);
65   ierr = MatCreateSeqDense(MPI_COMM_SELF,Nsurf,26,PETSC_NULL,&Xsurf);CHKERRQ(ierr);
66   ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
67 
68   /*
69      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
70      Xsurf will be all zero (thus making the coarse matrix singular).
71   */
72   if (m-istart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in X direction must be at least 3");
73   if (n-jstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Y direction must be at least 3");
74   if (p-kstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Z direction must be at least 3");
75 
76   cnt = 0;
77   xsurf[cnt++] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + Nsurf] = 1;} xsurf[cnt++ + 2*Nsurf] = 1;
78   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   xsurf[cnt++ + 6*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 7*Nsurf] = 1;} xsurf[cnt++ + 8*Nsurf] = 1;
80   for (k=1;k<p-1-kstart;k++) {
81     xsurf[cnt++ + 9*Nsurf] = 1;  for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 10*Nsurf] = 1;}  xsurf[cnt++ + 11*Nsurf] = 1;
82     for (j=1;j<n-1-jstart;j++) { xsurf[cnt++ + 12*Nsurf] = 1; /* these are the interior nodes */ xsurf[cnt++ + 13*Nsurf] = 1;}
83     xsurf[cnt++ + 14*Nsurf] = 1;  for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 15*Nsurf] = 1;} xsurf[cnt++ + 16*Nsurf] = 1;
84   }
85   xsurf[cnt++ + 17*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 18*Nsurf] = 1;} xsurf[cnt++ + 19*Nsurf] = 1;
86   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   xsurf[cnt++ + 23*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 24*Nsurf] = 1;} xsurf[cnt++ + 25*Nsurf] = 1;
88 
89 #if defined(PETSC_USE_DEBUG)
90   for (i=0; i<Nsurf; i++) {
91     tmp = 0.0;
92     for (j=0; j<26; j++) {
93       tmp += xsurf[i+j*Nsurf];
94     }
95     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xsurf interpolation at i %D value %G",i,PetscAbsScalar(tmp));
96   }
97 #endif
98   ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
99   /* ierr = MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);*/
100 
101 
102   /*
103        I are the indices for all the needed vertices (in global numbering)
104        Iint are the indices for the interior values, I surf for the surface values
105             (This is just for the part of the global matrix obtained with MatGetSubMatrix(), it
106              is NOT the local DA ordering.)
107        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
108   */
109 #define Endpoint(a,start,b) (a == 0 || a == (b-1-start))
110   ierr = PetscMalloc3(N,PetscInt,&II,Nint,PetscInt,&Iint,Nsurf,PetscInt,&Isurf);CHKERRQ(ierr);
111   ierr = PetscMalloc2(Nint,PetscInt,&IIint,Nsurf,PetscInt,&IIsurf);CHKERRQ(ierr);
112   for (k=0; k<p-kstart; k++) {
113     for (j=0; j<n-jstart; j++) {
114       for (i=0; i<m-istart; i++) {
115         II[c++] = i + j*mwidth + k*mwidth*nwidth;
116 
117         if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) {
118           IIint[cint]  = i + j*mwidth + k*mwidth*nwidth;
119           Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
120         } else {
121           IIsurf[csurf]  = i + j*mwidth + k*mwidth*nwidth;
122           Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
123         }
124       }
125     }
126   }
127   if (c != N) SETERRQ(PETSC_ERR_PLIB,"c != N");
128   if (cint != Nint) SETERRQ(PETSC_ERR_PLIB,"cint != Nint");
129   if (csurf != Nsurf) SETERRQ(PETSC_ERR_PLIB,"csurf != Nsurf");
130   ierr = DAGetISLocalToGlobalMapping(da,&ltg);CHKERRQ(ierr);
131   ierr = ISLocalToGlobalMappingApply(ltg,N,II,II);CHKERRQ(ierr);
132   ierr = ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint);CHKERRQ(ierr);
133   ierr = ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf);CHKERRQ(ierr);
134   ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr);
135   ierr = ISCreateGeneral(comm,N,II,&is);CHKERRQ(ierr);
136   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,&isint);CHKERRQ(ierr);
137   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,&issurf);CHKERRQ(ierr);
138   ierr = PetscFree3(II,Iint,Isurf);CHKERRQ(ierr);
139 
140   ierr = MatGetSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder);CHKERRQ(ierr);
141   A    = *Aholder;
142   ierr = PetscFree(Aholder);CHKERRQ(ierr);
143 
144   ierr = MatGetSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii);CHKERRQ(ierr);
145   ierr = MatGetSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais);CHKERRQ(ierr);
146   ierr = MatGetSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi);CHKERRQ(ierr);
147 
148   /*
149      Solve for the interpolation onto the interior Xint
150   */
151   ierr = MatGetFactor(Aii,MAT_SOLVER_PETSC,MAT_FACTOR_LU,&iAii);CHKERRQ(ierr);
152   ierr = MatFactorInfoInitialize(&info);CHKERRQ(ierr);
153   ierr = MatGetOrdering(Aii,MATORDERING_ND,&row,&col);CHKERRQ(ierr);
154   ierr = MatLUFactorSymbolic(iAii,Aii,row,col,&info);CHKERRQ(ierr);
155   ierr = ISDestroy(row);CHKERRQ(ierr);
156   ierr = ISDestroy(col);CHKERRQ(ierr);
157   ierr = MatLUFactorNumeric(iAii,Aii,&info);CHKERRQ(ierr);
158   ierr = MatDuplicate(Xint,MAT_DO_NOT_COPY_VALUES,&Xint_tmp);CHKERRQ(ierr);
159   ierr = MatMatMult(Ais,Xsurf,MAT_REUSE_MATRIX,PETSC_DETERMINE,&Xint_tmp);CHKERRQ(ierr);
160   ierr = MatScale(Xint_tmp,-1.0);CHKERRQ(ierr);
161   ierr = MatMatSolve(iAii,Xint_tmp,Xint);CHKERRQ(ierr);
162   ierr = MatDestroy(Xint_tmp);CHKERRQ(ierr);
163   ierr = MatDestroy(iAii);CHKERRQ(ierr);
164 
165 #if defined(PETSC_USE_DEBUG)
166   ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr);
167   for (i=0; i<Nint; i++) {
168     tmp = 0.0;
169     for (j=0; j<26; j++) {
170       tmp += xint[i+j*Nint];
171     }
172     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xint interpolation at i %D value %G",i,PetscAbsScalar(tmp));
173   }
174   ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr);
175   /* ierr =MatView(Xint,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); */
176 #endif
177 
178 
179   /*         total vertices             total faces                                  total edges */
180   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 
182   /*
183       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
184   */
185   cnt = 0;
186   gl[cnt++] = 0;  { gl[cnt++] = 1;} gl[cnt++] = m-istart-1;
187   { gl[cnt++] = mwidth;  { gl[cnt++] = mwidth+1;} gl[cnt++] = mwidth + m-istart-1;}
188   gl[cnt++] = mwidth*(n-jstart-1);  { gl[cnt++] = mwidth*(n-jstart-1)+1;} gl[cnt++] = mwidth*(n-jstart-1) + m-istart-1;
189   {
190     gl[cnt++] = mwidth*nwidth;  { gl[cnt++] = mwidth*nwidth+1;}  gl[cnt++] = mwidth*nwidth+ m-istart-1;
191     { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;}
192     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   }
194   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   { 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   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 
198   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
199   /* convert that to global numbering and get them on all processes */
200   ierr = ISLocalToGlobalMappingApply(ltg,26,gl,gl);CHKERRQ(ierr);
201   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
202   ierr = PetscMalloc(26*mp*np*pp*sizeof(PetscInt),&globals);CHKERRQ(ierr);
203   ierr = MPI_Allgather(gl,26,MPIU_INT,globals,26,MPIU_INT,((PetscObject)da)->comm);CHKERRQ(ierr);
204 
205   /* Number the coarse grid points from 0 to Ntotal */
206   ierr = PetscTableCreate(Ntotal/3,&ht);CHKERRQ(ierr);
207   for (i=0; i<26*mp*np*pp; i++){
208     ierr = PetscTableAddCount(ht,globals[i]+1);CHKERRQ(ierr);
209   }
210   ierr = PetscTableGetCount(ht,&cnt);CHKERRQ(ierr);
211   if (cnt != Ntotal) SETERRQ2(PETSC_ERR_PLIB,"Hash table size %D not equal to total number coarse grid points %D",cnt,Ntotal);
212   ierr = PetscFree(globals);CHKERRQ(ierr);
213   for (i=0; i<26; i++) {
214     ierr = PetscTableFind(ht,gl[i]+1,&gl[i]);CHKERRQ(ierr);
215     gl[i]--;
216   }
217   ierr = PetscTableDestroy(ht);CHKERRQ(ierr);
218   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
219 
220   /* construct global interpolation matrix */
221   ierr = MatGetLocalSize(Aglobal,&Ng,PETSC_NULL);CHKERRQ(ierr);
222   if (reuse == MAT_INITIAL_MATRIX) {
223     ierr = MatCreateMPIAIJ(((PetscObject)da)->comm,Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,PETSC_NULL,Nint+Nsurf,PETSC_NULL,P);CHKERRQ(ierr);
224   } else {
225     ierr = MatZeroEntries(*P);CHKERRQ(ierr);
226   }
227   ierr = MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
228   ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr);
229   ierr = MatSetValues(*P,Nint,IIint,26,gl,xint,INSERT_VALUES);CHKERRQ(ierr);
230   ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr);
231   ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
232   ierr = MatSetValues(*P,Nsurf,IIsurf,26,gl,xsurf,INSERT_VALUES);CHKERRQ(ierr);
233   ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
234   ierr = MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
235   ierr = MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
236   ierr = PetscFree2(IIint,IIsurf);CHKERRQ(ierr);
237 
238 #if defined(PETSC_USE_DEBUG)
239   {
240     Vec         x,y;
241     PetscScalar *yy;
242     ierr = VecCreateMPI(((PetscObject)da)->comm,Ng,PETSC_DETERMINE,&y);CHKERRQ(ierr);
243     ierr = VecCreateMPI(((PetscObject)da)->comm,PETSC_DETERMINE,Ntotal,&x);CHKERRQ(ierr);
244     ierr = VecSet(x,1.0);CHKERRQ(ierr);
245     ierr = MatMult(*P,x,y);CHKERRQ(ierr);
246     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
247     for (i=0; i<Ng; i++) {
248       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     }
250     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
251     ierr = VecDestroy(x);CHKERRQ(ierr);
252     ierr = VecDestroy(y);CHKERRQ(ierr);
253   }
254 #endif
255 
256   ierr = MatDestroy(Aii);CHKERRQ(ierr);
257   ierr = MatDestroy(Ais);CHKERRQ(ierr);
258   ierr = MatDestroy(Asi);CHKERRQ(ierr);
259   ierr = MatDestroy(A);CHKERRQ(ierr);
260   ierr = ISDestroy(is);CHKERRQ(ierr);
261   ierr = ISDestroy(isint);CHKERRQ(ierr);
262   ierr = ISDestroy(issurf);CHKERRQ(ierr);
263   ierr = MatDestroy(Xint);CHKERRQ(ierr);
264   ierr = MatDestroy(Xsurf);CHKERRQ(ierr);
265   PetscFunctionReturn(0);
266 }
267 
268 #undef __FUNCT__
269 #define __FUNCT__ "DAGetFaceInterpolation"
270 /*
271       DAGetFaceInterpolation - Gets the interpolation for a face based coarse space
272 
273 */
274 PetscErrorCode DAGetFaceInterpolation(DA da,Mat Aglobal,MatReuse reuse,Mat *P)
275 {
276   PetscErrorCode         ierr;
277   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   PetscInt               mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[6],*globals,Ng,*IIint,*IIsurf;
279   Mat                    Xint, Xsurf,Xint_tmp;
280   IS                     isint,issurf,is,row,col;
281   ISLocalToGlobalMapping ltg;
282   MPI_Comm               comm;
283   Mat                    A,Aii,Ais,Asi,*Aholder,iAii;
284   MatFactorInfo          info;
285   PetscScalar            *xsurf,*xint;
286 #if defined(PETSC_USE_DEBUG_foo)
287   PetscScalar            tmp;
288 #endif
289   PetscTable             ht;
290 
291   PetscFunctionBegin;
292   ierr = DAGetInfo(da,&dim,0,0,0,&mp,&np,&pp,&dof,0,0,0);CHKERRQ(ierr);
293   if (dof != 1) SETERRQ(PETSC_ERR_SUP,"Only for single field problems");
294   if (dim != 3) SETERRQ(PETSC_ERR_SUP,"Only coded for 3d problems");
295   ierr = DAGetCorners(da,0,0,0,&m,&n,&p);CHKERRQ(ierr);
296   ierr = DAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth);CHKERRQ(ierr);
297   istart = istart ? -1 : 0;
298   jstart = jstart ? -1 : 0;
299   kstart = kstart ? -1 : 0;
300 
301   /*
302     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
303     to all the local degrees of freedom (this includes the vertices, edges and faces).
304 
305     Xint are the subset of the interpolation into the interior
306 
307     Xface are the interpolation onto faces but not into the interior
308 
309     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
310                                         Xint
311     Symbolically one could write P = (  Xface  ) after interchanging the rows to match the natural ordering on the domain
312                                         Xsurf
313   */
314   N     = (m - istart)*(n - jstart)*(p - kstart);
315   Nint  = (m-2-istart)*(n-2-jstart)*(p-2-kstart);
316   Nface = 2*( (m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart) );
317   Nwire = 4*( (m-2-istart) + (n-2-jstart) + (p-2-kstart) ) + 8;
318   Nsurf = Nface + Nwire;
319   ierr = MatCreateSeqDense(MPI_COMM_SELF,Nint,6,PETSC_NULL,&Xint);CHKERRQ(ierr);
320   ierr = MatCreateSeqDense(MPI_COMM_SELF,Nsurf,6,PETSC_NULL,&Xsurf);CHKERRQ(ierr);
321   ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
322 
323   /*
324      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
325      Xsurf will be all zero (thus making the coarse matrix singular).
326   */
327   if (m-istart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in X direction must be at least 3");
328   if (n-jstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Y direction must be at least 3");
329   if (p-kstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Z direction must be at least 3");
330 
331   cnt = 0;
332   for (j=1;j<n-1-jstart;j++) {  for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 0*Nsurf] = 1;} }
333    for (k=1;k<p-1-kstart;k++) {
334     for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 1*Nsurf] = 1;}
335     for (j=1;j<n-1-jstart;j++) { xsurf[cnt++ + 2*Nsurf] = 1; /* these are the interior nodes */ xsurf[cnt++ + 3*Nsurf] = 1;}
336     for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 4*Nsurf] = 1;}
337   }
338   for (j=1;j<n-1-jstart;j++) {for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 5*Nsurf] = 1;} }
339 
340 #if defined(PETSC_USE_DEBUG_foo)
341   for (i=0; i<Nsurf; i++) {
342     tmp = 0.0;
343     for (j=0; j<6; j++) {
344       tmp += xsurf[i+j*Nsurf];
345     }
346     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xsurf interpolation at i %D value %G",i,PetscAbsScalar(tmp));
347   }
348 #endif
349   ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
350   /* ierr = MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);*/
351 
352 
353   /*
354        I are the indices for all the needed vertices (in global numbering)
355        Iint are the indices for the interior values, I surf for the surface values
356             (This is just for the part of the global matrix obtained with MatGetSubMatrix(), it
357              is NOT the local DA ordering.)
358        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
359   */
360 #define Endpoint(a,start,b) (a == 0 || a == (b-1-start))
361   ierr = PetscMalloc3(N,PetscInt,&II,Nint,PetscInt,&Iint,Nsurf,PetscInt,&Isurf);CHKERRQ(ierr);
362   ierr = PetscMalloc2(Nint,PetscInt,&IIint,Nsurf,PetscInt,&IIsurf);CHKERRQ(ierr);
363   for (k=0; k<p-kstart; k++) {
364     for (j=0; j<n-jstart; j++) {
365       for (i=0; i<m-istart; i++) {
366         II[c++] = i + j*mwidth + k*mwidth*nwidth;
367 
368         if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) {
369           IIint[cint]  = i + j*mwidth + k*mwidth*nwidth;
370           Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
371         } else {
372           IIsurf[csurf]  = i + j*mwidth + k*mwidth*nwidth;
373           Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
374         }
375       }
376     }
377   }
378   if (c != N) SETERRQ(PETSC_ERR_PLIB,"c != N");
379   if (cint != Nint) SETERRQ(PETSC_ERR_PLIB,"cint != Nint");
380   if (csurf != Nsurf) SETERRQ(PETSC_ERR_PLIB,"csurf != Nsurf");
381   ierr = DAGetISLocalToGlobalMapping(da,&ltg);CHKERRQ(ierr);
382   ierr = ISLocalToGlobalMappingApply(ltg,N,II,II);CHKERRQ(ierr);
383   ierr = ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint);CHKERRQ(ierr);
384   ierr = ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf);CHKERRQ(ierr);
385   ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr);
386   ierr = ISCreateGeneral(comm,N,II,&is);CHKERRQ(ierr);
387   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,&isint);CHKERRQ(ierr);
388   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,&issurf);CHKERRQ(ierr);
389   ierr = PetscFree3(II,Iint,Isurf);CHKERRQ(ierr);
390 
391   ierr = MatGetSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder);CHKERRQ(ierr);
392   A    = *Aholder;
393   ierr = PetscFree(Aholder);CHKERRQ(ierr);
394 
395   ierr = MatGetSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii);CHKERRQ(ierr);
396   ierr = MatGetSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais);CHKERRQ(ierr);
397   ierr = MatGetSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi);CHKERRQ(ierr);
398 
399   /*
400      Solve for the interpolation onto the interior Xint
401   */
402   ierr = MatDuplicate(Xint,MAT_DO_NOT_COPY_VALUES,&Xint_tmp);CHKERRQ(ierr);
403   ierr = MatMatMult(Ais,Xsurf,MAT_REUSE_MATRIX,PETSC_DETERMINE,&Xint_tmp);CHKERRQ(ierr);
404   ierr = MatScale(Xint_tmp,-1.0);CHKERRQ(ierr);
405 
406   if (0) {
407     ierr = MatGetFactor(Aii,MAT_SOLVER_PETSC,MAT_FACTOR_LU,&iAii);CHKERRQ(ierr);
408     ierr = MatFactorInfoInitialize(&info);CHKERRQ(ierr);
409     ierr = MatGetOrdering(Aii,MATORDERING_ND,&row,&col);CHKERRQ(ierr);
410     ierr = MatLUFactorSymbolic(iAii,Aii,row,col,&info);CHKERRQ(ierr);
411     ierr = ISDestroy(row);CHKERRQ(ierr);
412     ierr = ISDestroy(col);CHKERRQ(ierr);
413     ierr = MatLUFactorNumeric(iAii,Aii,&info);CHKERRQ(ierr);
414     ierr = MatMatSolve(iAii,Xint_tmp,Xint);CHKERRQ(ierr);
415     ierr = MatDestroy(iAii);CHKERRQ(ierr);
416   } else {
417     KSP         ksp;
418     Vec         b,x;
419     PetscScalar *xint_tmp;
420 
421     ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr);
422     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,Nint,0,&x);CHKERRQ(ierr);
423     ierr = MatGetArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
424     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,Nint,0,&b);CHKERRQ(ierr);
425     ierr = KSPCreate(PETSC_COMM_SELF,&ksp);CHKERRQ(ierr);
426     ierr = KSPSetOperators(ksp,Aii,Aii,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
427     for (i=0; i<6; i++) {
428       ierr = VecPlaceArray(x,xint+i*Nint);CHKERRQ(ierr);
429       ierr = VecPlaceArray(b,xint_tmp+i*Nint);CHKERRQ(ierr);
430       ierr = KSPSolve(ksp,b,x);CHKERRQ(ierr);
431       ierr = VecResetArray(x);CHKERRQ(ierr);
432       ierr = VecResetArray(b);CHKERRQ(ierr);
433     }
434     ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr);
435     ierr = MatRestoreArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
436     ierr = KSPDestroy(ksp);CHKERRQ(ierr);
437     ierr = VecDestroy(x);CHKERRQ(ierr);
438     ierr = VecDestroy(b);CHKERRQ(ierr);
439   }
440   ierr = MatDestroy(Xint_tmp);CHKERRQ(ierr);
441 
442 #if defined(PETSC_USE_DEBUG_foo)
443   ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr);
444   for (i=0; i<Nint; i++) {
445     tmp = 0.0;
446     for (j=0; j<6; j++) {
447       tmp += xint[i+j*Nint];
448     }
449     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xint interpolation at i %D value %G",i,PetscAbsScalar(tmp));
450   }
451   ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr);
452   /* ierr =MatView(Xint,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); */
453 #endif
454 
455 
456   /*         total faces    */
457   Ntotal =  mp*np*(pp+1) + mp*pp*(np+1) + np*pp*(mp+1);
458 
459   /*
460       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
461   */
462   cnt = 0;
463   { gl[cnt++] = mwidth+1;}
464   {
465     { gl[cnt++] = mwidth*nwidth+1;}
466     { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;}
467     { gl[cnt++] = mwidth*nwidth+mwidth*(n-jstart-1)+1;}
468   }
469   { gl[cnt++] = mwidth*nwidth*(p-kstart-1) + mwidth+1;}
470 
471   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
472   /* convert that to global numbering and get them on all processes */
473   ierr = ISLocalToGlobalMappingApply(ltg,6,gl,gl);CHKERRQ(ierr);
474   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
475   ierr = PetscMalloc(6*mp*np*pp*sizeof(PetscInt),&globals);CHKERRQ(ierr);
476   ierr = MPI_Allgather(gl,6,MPIU_INT,globals,6,MPIU_INT,((PetscObject)da)->comm);CHKERRQ(ierr);
477 
478   /* Number the coarse grid points from 0 to Ntotal */
479   ierr = PetscTableCreate(Ntotal/3,&ht);CHKERRQ(ierr);
480   for (i=0; i<6*mp*np*pp; i++){
481     ierr = PetscTableAddCount(ht,globals[i]+1);CHKERRQ(ierr);
482   }
483   ierr = PetscTableGetCount(ht,&cnt);CHKERRQ(ierr);
484   if (cnt != Ntotal) SETERRQ2(PETSC_ERR_PLIB,"Hash table size %D not equal to total number coarse grid points %D",cnt,Ntotal);
485   ierr = PetscFree(globals);CHKERRQ(ierr);
486   for (i=0; i<6; i++) {
487     ierr = PetscTableFind(ht,gl[i]+1,&gl[i]);CHKERRQ(ierr);
488     gl[i]--;
489   }
490   ierr = PetscTableDestroy(ht);CHKERRQ(ierr);
491   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
492 
493   /* construct global interpolation matrix */
494   ierr = MatGetLocalSize(Aglobal,&Ng,PETSC_NULL);CHKERRQ(ierr);
495   if (reuse == MAT_INITIAL_MATRIX) {
496     ierr = MatCreateMPIAIJ(((PetscObject)da)->comm,Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,PETSC_NULL,Nint,PETSC_NULL,P);CHKERRQ(ierr);
497   } else {
498     ierr = MatZeroEntries(*P);CHKERRQ(ierr);
499   }
500   ierr = MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
501   ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr);
502   ierr = MatSetValues(*P,Nint,IIint,6,gl,xint,INSERT_VALUES);CHKERRQ(ierr);
503   ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr);
504   ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
505   ierr = MatSetValues(*P,Nsurf,IIsurf,6,gl,xsurf,INSERT_VALUES);CHKERRQ(ierr);
506   ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
507   ierr = MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
508   ierr = MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
509   ierr = PetscFree2(IIint,IIsurf);CHKERRQ(ierr);
510 
511 
512 #if defined(PETSC_USE_DEBUG_foo)
513   {
514     Vec         x,y;
515     PetscScalar *yy;
516     ierr = VecCreateMPI(((PetscObject)da)->comm,Ng,PETSC_DETERMINE,&y);CHKERRQ(ierr);
517     ierr = VecCreateMPI(((PetscObject)da)->comm,PETSC_DETERMINE,Ntotal,&x);CHKERRQ(ierr);
518     ierr = VecSet(x,1.0);CHKERRQ(ierr);
519     ierr = MatMult(*P,x,y);CHKERRQ(ierr);
520     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
521     for (i=0; i<Ng; i++) {
522       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     }
524     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
525     ierr = VecDestroy(x);CHKERRQ(ierr);
526     ierr = VecDestroy(y);CHKERRQ(ierr);
527   }
528 #endif
529 
530   ierr = MatDestroy(Aii);CHKERRQ(ierr);
531   ierr = MatDestroy(Ais);CHKERRQ(ierr);
532   ierr = MatDestroy(Asi);CHKERRQ(ierr);
533   ierr = MatDestroy(A);CHKERRQ(ierr);
534   ierr = ISDestroy(is);CHKERRQ(ierr);
535   ierr = ISDestroy(isint);CHKERRQ(ierr);
536   ierr = ISDestroy(issurf);CHKERRQ(ierr);
537   ierr = MatDestroy(Xint);CHKERRQ(ierr);
538   ierr = MatDestroy(Xsurf);CHKERRQ(ierr);
539   PetscFunctionReturn(0);
540 }
541 
542 typedef struct {
543   DA           da;
544   PCExoticType type;
545   Mat          P;      /* the interpolation matrix */
546 } PC_Exotic;
547 
548 #undef __FUNCT__
549 #define __FUNCT__ "PCExoticSetType"
550 /*@
551    PCExoticSetType - Sets the type of coarse grid interpolation to use
552 
553    Collective on PC
554 
555    Input Parameters:
556 +  pc - the preconditioner context
557 -  type - either PC_EXOTIC_FACE or PC_EXOTIC_WIREBASKET (defaults to face)
558 
559    Notes: The face based interpolation has 1 degree of freedom per face and ignores the
560      edge and vertex values completely in the coarse problem. For any seven point
561      stencil the interpolation of a constant on all faces into the interior is that constant.
562 
563      The wirebasket interpolation has 1 degree of freedom per vertex, per edge and
564      per face. A constant on the subdomain boundary is interpolated as that constant
565      in the interior of the domain.
566 
567      The coarse grid matrix is obtained via the Galerkin computation A_c = R A R^T, hence
568      if A is nonsingular A_c is also nonsingular.
569 
570      Both interpolations are suitable for only scalar problems.
571 
572    Level: intermediate
573 
574 
575 .seealso: PCEXOTIC, PCExoticType()
576 @*/
577 PetscErrorCode PETSCKSP_DLLEXPORT PCExoticSetType(PC pc,PCExoticType type)
578 {
579   PetscErrorCode ierr,(*f)(PC,PCExoticType);
580 
581   PetscFunctionBegin;
582   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
583   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCExoticSetType_C",(void (**)(void))&f);CHKERRQ(ierr);
584   if (f) {
585     ierr = (*f)(pc,type);CHKERRQ(ierr);
586   }
587   PetscFunctionReturn(0);
588 }
589 
590 #undef __FUNCT__
591 #define __FUNCT__ "PCExoticSetType_Exotic"
592 PetscErrorCode PETSCKSP_DLLEXPORT PCExoticSetType_Exotic(PC pc,PCExoticType type)
593 {
594   PC_MG     **mg = (PC_MG**)pc->data;
595   PC_Exotic *ctx = (PC_Exotic*) mg[0]->innerctx;
596 
597   PetscFunctionBegin;
598   ctx->type = type;
599   PetscFunctionReturn(0);
600 }
601 
602 #undef __FUNCT__
603 #define __FUNCT__ "PCSetUp_Exotic"
604 PetscErrorCode PCSetUp_Exotic(PC pc)
605 {
606   PetscErrorCode ierr;
607   Mat            A;
608   PC_MG          **mg = (PC_MG**)pc->data;
609   PC_Exotic      *ex = (PC_Exotic*) mg[0]->innerctx;
610   DA             da = ex->da;
611   MatReuse       reuse = (ex->P) ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
612 
613   PetscFunctionBegin;
614   ierr = PCGetOperators(pc,PETSC_NULL,&A,PETSC_NULL);CHKERRQ(ierr);
615   if (ex->type == PC_EXOTIC_FACE) {
616     ierr = DAGetFaceInterpolation(da,A,reuse,&ex->P);CHKERRQ(ierr);
617   } else if (ex->type == PC_EXOTIC_WIREBASKET) {
618     ierr = DAGetWireBasketInterpolation(da,A,reuse,&ex->P);CHKERRQ(ierr);
619   } else SETERRQ1(PETSC_ERR_PLIB,"Unknown exotic coarse space %d",ex->type);
620   ierr = PCMGSetInterpolation(pc,1,ex->P);CHKERRQ(ierr);
621   ierr = PCSetUp_MG(pc);CHKERRQ(ierr);
622   PetscFunctionReturn(0);
623 }
624 
625 #undef __FUNCT__
626 #define __FUNCT__ "PCDestroy_Exotic"
627 PetscErrorCode PCDestroy_Exotic(PC pc)
628 {
629   PetscErrorCode ierr;
630   PC_MG          **mg = (PC_MG**)pc->data;
631   PC_Exotic      *ctx = (PC_Exotic*) mg[0]->innerctx;
632 
633   PetscFunctionBegin;
634   if (ctx->da) {ierr = DADestroy(ctx->da);CHKERRQ(ierr);}
635   if (ctx->P) {ierr = MatDestroy(ctx->P);CHKERRQ(ierr);}
636   ierr = PetscFree(ctx);CHKERRQ(ierr);
637   ierr = PCDestroy_MG(pc);CHKERRQ(ierr);
638   PetscFunctionReturn(0);
639 }
640 
641 #undef __FUNCT__
642 #define __FUNCT__ "PCSetUp_Exotic_Error"
643 PetscErrorCode PCSetUp_Exotic_Error(PC pc)
644 {
645   PetscFunctionBegin;
646   SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"You are using the Exotic preconditioner but never called PCSetDA()");
647   PetscFunctionReturn(0);
648 }
649 
650 #undef __FUNCT__
651 #define __FUNCT__ "PCSetDA"
652 /*@
653    PCSetDA - Sets the DA that is to be used by the PCEXOTIC or certain other preconditioners
654 
655    Collective on PC
656 
657    Input Parameters:
658 +  pc - the preconditioner context
659 -  da - the da
660 
661    Level: intermediate
662 
663 
664 .seealso: PCEXOTIC, PCExoticType()
665 @*/
666 PetscErrorCode PETSCKSP_DLLEXPORT PCSetDA(PC pc,DA da)
667 {
668   PetscErrorCode ierr,(*f)(PC,DA);
669 
670   PetscFunctionBegin;
671   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
672   PetscValidHeaderSpecific(da,DM_COOKIE,1);
673   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCSetDA_C",(void (**)(void))&f);CHKERRQ(ierr);
674   if (f) {
675     ierr = (*f)(pc,da);CHKERRQ(ierr);
676   }
677   PetscFunctionReturn(0);
678 }
679 
680 
681 #undef __FUNCT__
682 #define __FUNCT__ "PCSetDA_Exotic"
683 PetscErrorCode PETSCKSP_DLLEXPORT PCSetDA_Exotic(PC pc,DA da)
684 {
685   PetscErrorCode ierr;
686   PC_MG          **mg = (PC_MG**)pc->data;
687   PC_Exotic      *ctx = (PC_Exotic*) mg[0]->innerctx;
688 
689   PetscFunctionBegin;
690   ctx->da = da;
691   pc->ops->setup = PCSetUp_Exotic;
692   ierr   = PetscObjectReference((PetscObject)da);CHKERRQ(ierr);
693   PetscFunctionReturn(0);
694 }
695 
696 #undef __FUNCT__
697 #define __FUNCT__ "PCView_Exotic"
698 PetscErrorCode PCView_Exotic(PC pc,PetscViewer viewer)
699 {
700   PC_MG          **mg = (PC_MG**)pc->data;
701   PetscErrorCode ierr;
702   PetscTruth     iascii;
703   PC_Exotic      *ctx = (PC_Exotic*) mg[0]->innerctx;
704 
705   PetscFunctionBegin;
706   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
707   if (iascii) {
708     ierr = PetscViewerASCIIPrintf(viewer,"    Exotic type = %s\n",PCExoticTypes[ctx->type]);CHKERRQ(ierr);
709   }
710   ierr = PCView_MG(pc,viewer);CHKERRQ(ierr);
711   PetscFunctionReturn(0);
712 }
713 
714 #undef __FUNCT__
715 #define __FUNCT__ "PCSetFromOptions_Exotic"
716 PetscErrorCode PCSetFromOptions_Exotic(PC pc)
717 {
718   PetscErrorCode ierr;
719   PetscTruth     flg;
720   PC_MG          **mg = (PC_MG**)pc->data;
721   PCExoticType   mgctype;
722   PC_Exotic      *ctx = (PC_Exotic*) mg[0]->innerctx;
723 
724   PetscFunctionBegin;
725   ierr = PetscOptionsHead("Exotic coarse space options");CHKERRQ(ierr);
726     ierr = PetscOptionsEnum("-pc_exotic_type","face or wirebasket","PCExoticSetType",PCExoticTypes,(PetscEnum)ctx->type,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr);
727     if (flg) {
728       ierr = PCExoticSetType(pc,mgctype);CHKERRQ(ierr);
729     }
730   ierr = PetscOptionsTail();CHKERRQ(ierr);
731   PetscFunctionReturn(0);
732 }
733 
734 
735 /*MC
736      PCEXOTIC - Two level overlapping Schwarz preconditioner with exotic (non-standard) coarse grid spaces
737 
738      This uses the PCMG infrastructure restricted to two levels and the face and wirebasket based coarse
739    grid spaces. These coarse grid spaces originate in the work of Bramble, Pasciak  and Schatz, "The Construction
740    of Preconditioners for Elliptic Problems by Substructing IV", Mathematics of Computation, volume 53 pages 1--24, 1989.
741    They were generalized slightly in "Domain Decomposition Method for Linear Elasticity", Ph. D. thesis, Barry Smith,
742    New York University, 1990. They were then explored in great detail in Dryja, Smith, Widlund, "Schwarz Analysis
743    of Iterative Substructuring Methods for Elliptic Problems in Three Dimensions, SIAM Journal on Numerical
744    Analysis, volume 31. pages 1662-1694, 1994. These were developed in the context of iterative substructuring preconditioners.
745    They were then ingeniously applied as coarse grid spaces for overlapping Schwarz methods by Dohrmann and Widlund.
746    They refer to them as GDSW (generalized Dryja, Smith, Widlund preconditioners). See, for example,
747    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Extending theory for domain decomposition algorithms to irregular subdomains. In Ulrich Langer, Marco
748    Discacciati, David Keyes, Olof Widlund, and Walter Zulehner, editors, Proceedings
749    of the 17th International Conference on Domain Decomposition Methods in
750    Science and Engineering, held in Strobl, Austria, July 3-7, 2006, number 60 in
751    Springer-Verlag, Lecture Notes in Computational Science and Engineering, pages 255-261, 2007.
752    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. A family of energy min-
753    imizing coarse spaces for overlapping Schwarz preconditioners. In Ulrich Langer,
754    Marco Discacciati, David Keyes, OlofWidlund, andWalter Zulehner, editors, Proceedings
755    of the 17th International Conference on Domain Decomposition Methods
756    in Science and Engineering, held in Strobl, Austria, July 3-7, 2006, number 60 in
757    Springer-Verlag, Lecture Notes in Computational Science and Engineering, pages 247-254, 2007
758    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Domain decomposition
759    for less regular subdomains: Overlapping Schwarz in two dimensions. SIAM J.
760    Numer. Anal., 46(4):2153-2168, 2008.
761    Clark R. Dohrmann and Olof B. Widlund. An overlapping Schwarz
762    algorithm for almost incompressible elasticity. Technical Report
763    TR2008-912, Department of Computer Science, Courant Institute
764    of Mathematical Sciences, New York University, May 2008. URL:
765    http://cs.nyu.edu/csweb/Research/TechReports/TR2008-912/TR2008-912.pdf
766 
767    Options Database: The usual PCMG options are supported, such as -mg_levels_pc_type <type> -mg_coarse_pc_type <type>
768       -pc_mg_type <type>
769 
770    Level: advanced
771 
772 .seealso:  PCMG, PCSetDA(), PCExoticType, PCExoticSetType()
773 M*/
774 
775 EXTERN_C_BEGIN
776 #undef __FUNCT__
777 #define __FUNCT__ "PCCreate_Exotic"
778 PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_Exotic(PC pc)
779 {
780   PetscErrorCode ierr;
781   PC_Exotic      *ex;
782   PC_MG          **mg;
783 
784   PetscFunctionBegin;
785   /* if type was previously mg; must manually destroy it because call to PCSetType(pc,PCMG) will not destroy it */
786   if (pc->ops->destroy) { ierr =  (*pc->ops->destroy)(pc);CHKERRQ(ierr); pc->data = 0;}
787   ierr = PetscStrfree(((PetscObject)pc)->type_name);CHKERRQ(ierr);
788   ((PetscObject)pc)->type_name = 0;
789 
790   ierr = PCSetType(pc,PCMG);CHKERRQ(ierr);
791   ierr = PCMGSetLevels(pc,2,PETSC_NULL);CHKERRQ(ierr);
792   ierr = PCMGSetGalerkin(pc);CHKERRQ(ierr);
793   ierr = PetscNew(PC_Exotic,&ex);CHKERRQ(ierr);\
794   ex->type = PC_EXOTIC_FACE;
795   mg = (PC_MG**) pc->data;
796   mg[0]->innerctx = ex;
797 
798 
799   pc->ops->setfromoptions = PCSetFromOptions_Exotic;
800   pc->ops->view           = PCView_Exotic;
801   pc->ops->destroy        = PCDestroy_Exotic;
802   pc->ops->setup          = PCSetUp_Exotic_Error;
803   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCExoticSetType_C","PCExoticSetType_Exotic",PCExoticSetType_Exotic);CHKERRQ(ierr);
804   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCSetDA_C","PCSetDA_Exotic",PCSetDA_Exotic);CHKERRQ(ierr);
805   PetscFunctionReturn(0);
806 }
807 EXTERN_C_END
808