xref: /petsc/src/ksp/pc/impls/wb/wb.c (revision 7dae84e064f15683b0c1756735f0ad1de62763f6)
1174b6946SBarry Smith 
2c6db04a5SJed Brown #include <petscdmda.h>   /*I "petscdmda.h" I*/
3af0996ceSBarry Smith #include <petsc/private/pcmgimpl.h>   /*I "petscksp.h" I*/
482c86c8fSBarry Smith #include <petscctable.h>
57233f9f0SBarry Smith 
68e722e36SBarry Smith typedef struct {
78e722e36SBarry Smith   PCExoticType type;
88e722e36SBarry Smith   Mat          P;            /* the constructed interpolation matrix */
9ace3abfcSBarry Smith   PetscBool    directSolve;  /* use direct LU factorization to construct interpolation */
108e722e36SBarry Smith   KSP          ksp;
118e722e36SBarry Smith } PC_Exotic;
12174b6946SBarry Smith 
136a6fc655SJed Brown const char *const PCExoticTypes[] = {"face","wirebasket","PCExoticType","PC_Exotic",0};
14064c8009SBarry Smith 
15064c8009SBarry Smith 
16064c8009SBarry Smith /*
17aa219208SBarry Smith       DMDAGetWireBasketInterpolation - Gets the interpolation for a wirebasket based coarse space
18064c8009SBarry Smith 
19064c8009SBarry Smith */
20aa219208SBarry Smith PetscErrorCode DMDAGetWireBasketInterpolation(DM da,PC_Exotic *exotic,Mat Aglobal,MatReuse reuse,Mat *P)
21064c8009SBarry Smith {
22064c8009SBarry Smith   PetscErrorCode         ierr;
23064c8009SBarry 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;
2428d20b34SBarry Smith   PetscInt               mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[26],*globals,Ng,*IIint,*IIsurf,Nt;
25064c8009SBarry Smith   Mat                    Xint, Xsurf,Xint_tmp;
26064c8009SBarry Smith   IS                     isint,issurf,is,row,col;
27064c8009SBarry Smith   ISLocalToGlobalMapping ltg;
28064c8009SBarry Smith   MPI_Comm               comm;
29064c8009SBarry Smith   Mat                    A,Aii,Ais,Asi,*Aholder,iAii;
30064c8009SBarry Smith   MatFactorInfo          info;
31064c8009SBarry Smith   PetscScalar            *xsurf,*xint;
328e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
33064c8009SBarry Smith   PetscScalar            tmp;
34064c8009SBarry Smith #endif
35064c8009SBarry Smith   PetscTable             ht;
36064c8009SBarry Smith 
37064c8009SBarry Smith   PetscFunctionBegin;
381321219cSEthan Coon   ierr = DMDAGetInfo(da,&dim,0,0,0,&mp,&np,&pp,&dof,0,0,0,0,0);CHKERRQ(ierr);
39ce94432eSBarry Smith   if (dof != 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only for single field problems");
40ce94432eSBarry Smith   if (dim != 3) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only coded for 3d problems");
41aa219208SBarry Smith   ierr   = DMDAGetCorners(da,0,0,0,&m,&n,&p);CHKERRQ(ierr);
42aa219208SBarry Smith   ierr   = DMDAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth);CHKERRQ(ierr);
43064c8009SBarry Smith   istart = istart ? -1 : 0;
44064c8009SBarry Smith   jstart = jstart ? -1 : 0;
45064c8009SBarry Smith   kstart = kstart ? -1 : 0;
46064c8009SBarry Smith 
47064c8009SBarry Smith   /*
48064c8009SBarry Smith     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
49064c8009SBarry Smith     to all the local degrees of freedom (this includes the vertices, edges and faces).
50064c8009SBarry Smith 
51064c8009SBarry Smith     Xint are the subset of the interpolation into the interior
52064c8009SBarry Smith 
53064c8009SBarry Smith     Xface are the interpolation onto faces but not into the interior
54064c8009SBarry Smith 
55064c8009SBarry Smith     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
56064c8009SBarry Smith                                       Xint
57064c8009SBarry Smith     Symbolically one could write P = (Xface) after interchanging the rows to match the natural ordering on the domain
58064c8009SBarry Smith                                       Xsurf
59064c8009SBarry Smith   */
60064c8009SBarry Smith   N     = (m - istart)*(n - jstart)*(p - kstart);
61064c8009SBarry Smith   Nint  = (m-2-istart)*(n-2-jstart)*(p-2-kstart);
62064c8009SBarry Smith   Nface = 2*((m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart));
63064c8009SBarry Smith   Nwire = 4*((m-2-istart) + (n-2-jstart) + (p-2-kstart)) + 8;
64064c8009SBarry Smith   Nsurf = Nface + Nwire;
650298fd71SBarry Smith   ierr  = MatCreateSeqDense(MPI_COMM_SELF,Nint,26,NULL,&Xint);CHKERRQ(ierr);
660298fd71SBarry Smith   ierr  = MatCreateSeqDense(MPI_COMM_SELF,Nsurf,26,NULL,&Xsurf);CHKERRQ(ierr);
678c778c55SBarry Smith   ierr  = MatDenseGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
68064c8009SBarry Smith 
69064c8009SBarry Smith   /*
70064c8009SBarry Smith      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
71064c8009SBarry Smith      Xsurf will be all zero (thus making the coarse matrix singular).
72064c8009SBarry Smith   */
73e32f2f54SBarry 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");
74e32f2f54SBarry 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");
75e32f2f54SBarry 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");
76064c8009SBarry Smith 
77064c8009SBarry Smith   cnt = 0;
782fa5cd67SKarl Rupp 
792fa5cd67SKarl Rupp   xsurf[cnt++] = 1;
802fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + Nsurf] = 1;
812fa5cd67SKarl Rupp   xsurf[cnt++ + 2*Nsurf] = 1;
822fa5cd67SKarl Rupp 
832fa5cd67SKarl Rupp   for (j=1; j<n-1-jstart; j++) {
842fa5cd67SKarl Rupp     xsurf[cnt++ + 3*Nsurf] = 1;
852fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 4*Nsurf] = 1;
862fa5cd67SKarl Rupp     xsurf[cnt++ + 5*Nsurf] = 1;
87064c8009SBarry Smith   }
882fa5cd67SKarl Rupp 
892fa5cd67SKarl Rupp   xsurf[cnt++ + 6*Nsurf] = 1;
902fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 7*Nsurf] = 1;
912fa5cd67SKarl Rupp   xsurf[cnt++ + 8*Nsurf] = 1;
922fa5cd67SKarl Rupp 
932fa5cd67SKarl Rupp   for (k=1; k<p-1-kstart; k++) {
942fa5cd67SKarl Rupp     xsurf[cnt++ + 9*Nsurf] = 1;
952fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 10*Nsurf] = 1;
962fa5cd67SKarl Rupp     xsurf[cnt++ + 11*Nsurf] = 1;
972fa5cd67SKarl Rupp 
982fa5cd67SKarl Rupp     for (j=1; j<n-1-jstart; j++) {
992fa5cd67SKarl Rupp       xsurf[cnt++ + 12*Nsurf] = 1;
1002fa5cd67SKarl Rupp       /* these are the interior nodes */
1012fa5cd67SKarl Rupp       xsurf[cnt++ + 13*Nsurf] = 1;
1022fa5cd67SKarl Rupp     }
1032fa5cd67SKarl Rupp 
1042fa5cd67SKarl Rupp     xsurf[cnt++ + 14*Nsurf] = 1;
1052fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 15*Nsurf] = 1;
1062fa5cd67SKarl Rupp     xsurf[cnt++ + 16*Nsurf] = 1;
1072fa5cd67SKarl Rupp   }
1082fa5cd67SKarl Rupp 
1092fa5cd67SKarl Rupp   xsurf[cnt++ + 17*Nsurf] = 1;
1102fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 18*Nsurf] = 1;
1112fa5cd67SKarl Rupp   xsurf[cnt++ + 19*Nsurf] = 1;
1122fa5cd67SKarl Rupp 
1132fa5cd67SKarl Rupp   for (j=1;j<n-1-jstart;j++) {
1142fa5cd67SKarl Rupp     xsurf[cnt++ + 20*Nsurf] = 1;
1152fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 21*Nsurf] = 1;
1162fa5cd67SKarl Rupp     xsurf[cnt++ + 22*Nsurf] = 1;
1172fa5cd67SKarl Rupp   }
1182fa5cd67SKarl Rupp 
1192fa5cd67SKarl Rupp   xsurf[cnt++ + 23*Nsurf] = 1;
1202fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 24*Nsurf] = 1;
1212fa5cd67SKarl Rupp   xsurf[cnt++ + 25*Nsurf] = 1;
1222fa5cd67SKarl Rupp 
123064c8009SBarry Smith 
1248e722e36SBarry Smith   /* interpolations only sum to 1 when using direct solver */
1258e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
126064c8009SBarry Smith   for (i=0; i<Nsurf; i++) {
127064c8009SBarry Smith     tmp = 0.0;
1282fa5cd67SKarl Rupp     for (j=0; j<26; j++) tmp += xsurf[i+j*Nsurf];
12957622a8eSBarry 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,(double)PetscAbsScalar(tmp));
130064c8009SBarry Smith   }
131064c8009SBarry Smith #endif
1328c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
133064c8009SBarry Smith   /* ierr = MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);*/
134064c8009SBarry Smith 
135064c8009SBarry Smith 
136064c8009SBarry Smith   /*
137064c8009SBarry Smith        I are the indices for all the needed vertices (in global numbering)
138064c8009SBarry Smith        Iint are the indices for the interior values, I surf for the surface values
139*7dae84e0SHong Zhang             (This is just for the part of the global matrix obtained with MatCreateSubMatrix(), it
140aa219208SBarry Smith              is NOT the local DMDA ordering.)
141064c8009SBarry Smith        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
142064c8009SBarry Smith   */
143064c8009SBarry Smith #define Endpoint(a,start,b) (a == 0 || a == (b-1-start))
144dcca6d9dSJed Brown   ierr = PetscMalloc3(N,&II,Nint,&Iint,Nsurf,&Isurf);CHKERRQ(ierr);
145dcca6d9dSJed Brown   ierr = PetscMalloc2(Nint,&IIint,Nsurf,&IIsurf);CHKERRQ(ierr);
146064c8009SBarry Smith   for (k=0; k<p-kstart; k++) {
147064c8009SBarry Smith     for (j=0; j<n-jstart; j++) {
148064c8009SBarry Smith       for (i=0; i<m-istart; i++) {
149064c8009SBarry Smith         II[c++] = i + j*mwidth + k*mwidth*nwidth;
150064c8009SBarry Smith 
151064c8009SBarry Smith         if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) {
152064c8009SBarry Smith           IIint[cint]  = i + j*mwidth + k*mwidth*nwidth;
153064c8009SBarry Smith           Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
154064c8009SBarry Smith         } else {
155064c8009SBarry Smith           IIsurf[csurf]  = i + j*mwidth + k*mwidth*nwidth;
156064c8009SBarry Smith           Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
157064c8009SBarry Smith         }
158064c8009SBarry Smith       }
159064c8009SBarry Smith     }
160064c8009SBarry Smith   }
161e32f2f54SBarry Smith   if (c != N) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"c != N");
162e32f2f54SBarry Smith   if (cint != Nint) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"cint != Nint");
163e32f2f54SBarry Smith   if (csurf != Nsurf) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"csurf != Nsurf");
1641411c6eeSJed Brown   ierr = DMGetLocalToGlobalMapping(da,&ltg);CHKERRQ(ierr);
165064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,N,II,II);CHKERRQ(ierr);
166064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint);CHKERRQ(ierr);
167064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf);CHKERRQ(ierr);
168064c8009SBarry Smith   ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr);
16970b3c8c7SBarry Smith   ierr = ISCreateGeneral(comm,N,II,PETSC_COPY_VALUES,&is);CHKERRQ(ierr);
17070b3c8c7SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,PETSC_COPY_VALUES,&isint);CHKERRQ(ierr);
17170b3c8c7SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,PETSC_COPY_VALUES,&issurf);CHKERRQ(ierr);
172064c8009SBarry Smith   ierr = PetscFree3(II,Iint,Isurf);CHKERRQ(ierr);
173064c8009SBarry Smith 
174*7dae84e0SHong Zhang   ierr = MatCreateSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder);CHKERRQ(ierr);
175064c8009SBarry Smith   A    = *Aholder;
176064c8009SBarry Smith   ierr = PetscFree(Aholder);CHKERRQ(ierr);
177064c8009SBarry Smith 
178*7dae84e0SHong Zhang   ierr = MatCreateSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii);CHKERRQ(ierr);
179*7dae84e0SHong Zhang   ierr = MatCreateSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais);CHKERRQ(ierr);
180*7dae84e0SHong Zhang   ierr = MatCreateSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi);CHKERRQ(ierr);
181064c8009SBarry Smith 
182064c8009SBarry Smith   /*
183064c8009SBarry Smith      Solve for the interpolation onto the interior Xint
184064c8009SBarry Smith   */
18592e4c2edSBarry Smith   ierr = MatMatMult(Ais,Xsurf,MAT_INITIAL_MATRIX,PETSC_DETERMINE,&Xint_tmp);CHKERRQ(ierr);
1868e722e36SBarry Smith   ierr = MatScale(Xint_tmp,-1.0);CHKERRQ(ierr);
1878e722e36SBarry Smith   if (exotic->directSolve) {
1882692d6eeSBarry Smith     ierr = MatGetFactor(Aii,MATSOLVERPETSC,MAT_FACTOR_LU,&iAii);CHKERRQ(ierr);
189064c8009SBarry Smith     ierr = MatFactorInfoInitialize(&info);CHKERRQ(ierr);
1902692d6eeSBarry Smith     ierr = MatGetOrdering(Aii,MATORDERINGND,&row,&col);CHKERRQ(ierr);
191064c8009SBarry Smith     ierr = MatLUFactorSymbolic(iAii,Aii,row,col,&info);CHKERRQ(ierr);
192fcfd50ebSBarry Smith     ierr = ISDestroy(&row);CHKERRQ(ierr);
193fcfd50ebSBarry Smith     ierr = ISDestroy(&col);CHKERRQ(ierr);
194064c8009SBarry Smith     ierr = MatLUFactorNumeric(iAii,Aii,&info);CHKERRQ(ierr);
195064c8009SBarry Smith     ierr = MatMatSolve(iAii,Xint_tmp,Xint);CHKERRQ(ierr);
1966bf464f9SBarry Smith     ierr = MatDestroy(&iAii);CHKERRQ(ierr);
1978e722e36SBarry Smith   } else {
1988e722e36SBarry Smith     Vec         b,x;
1998e722e36SBarry Smith     PetscScalar *xint_tmp;
200064c8009SBarry Smith 
2018c778c55SBarry Smith     ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
202778a2246SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,0,&x);CHKERRQ(ierr);
2038c778c55SBarry Smith     ierr = MatDenseGetArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
204778a2246SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,0,&b);CHKERRQ(ierr);
20523ee1639SBarry Smith     ierr = KSPSetOperators(exotic->ksp,Aii,Aii);CHKERRQ(ierr);
2068e722e36SBarry Smith     for (i=0; i<26; i++) {
2078e722e36SBarry Smith       ierr = VecPlaceArray(x,xint+i*Nint);CHKERRQ(ierr);
2088e722e36SBarry Smith       ierr = VecPlaceArray(b,xint_tmp+i*Nint);CHKERRQ(ierr);
2098e722e36SBarry Smith       ierr = KSPSolve(exotic->ksp,b,x);CHKERRQ(ierr);
2108e722e36SBarry Smith       ierr = VecResetArray(x);CHKERRQ(ierr);
2118e722e36SBarry Smith       ierr = VecResetArray(b);CHKERRQ(ierr);
2128e722e36SBarry Smith     }
2138c778c55SBarry Smith     ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
2148c778c55SBarry Smith     ierr = MatDenseRestoreArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
2156bf464f9SBarry Smith     ierr = VecDestroy(&x);CHKERRQ(ierr);
2166bf464f9SBarry Smith     ierr = VecDestroy(&b);CHKERRQ(ierr);
2178e722e36SBarry Smith   }
2186bf464f9SBarry Smith   ierr = MatDestroy(&Xint_tmp);CHKERRQ(ierr);
2198e722e36SBarry Smith 
2208e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
2218c778c55SBarry Smith   ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
222064c8009SBarry Smith   for (i=0; i<Nint; i++) {
223064c8009SBarry Smith     tmp = 0.0;
2242fa5cd67SKarl Rupp     for (j=0; j<26; j++) tmp += xint[i+j*Nint];
2252fa5cd67SKarl Rupp 
22657622a8eSBarry 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,(double)PetscAbsScalar(tmp));
227064c8009SBarry Smith   }
2288c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
229064c8009SBarry Smith   /* ierr =MatView(Xint,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); */
230064c8009SBarry Smith #endif
231064c8009SBarry Smith 
232064c8009SBarry Smith 
233064c8009SBarry Smith   /*         total vertices             total faces                                  total edges */
234064c8009SBarry 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);
235064c8009SBarry Smith 
236064c8009SBarry Smith   /*
237064c8009SBarry Smith       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
238064c8009SBarry Smith   */
239064c8009SBarry Smith   cnt = 0;
2402fa5cd67SKarl Rupp 
241064c8009SBarry Smith   gl[cnt++] = 0;  { gl[cnt++] = 1;} gl[cnt++] = m-istart-1;
242064c8009SBarry Smith   { gl[cnt++] = mwidth;  { gl[cnt++] = mwidth+1;} gl[cnt++] = mwidth + m-istart-1;}
243064c8009SBarry Smith   gl[cnt++] = mwidth*(n-jstart-1);  { gl[cnt++] = mwidth*(n-jstart-1)+1;} gl[cnt++] = mwidth*(n-jstart-1) + m-istart-1;
244064c8009SBarry Smith   {
245064c8009SBarry Smith     gl[cnt++] = mwidth*nwidth;  { gl[cnt++] = mwidth*nwidth+1;}  gl[cnt++] = mwidth*nwidth+ m-istart-1;
246064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;}
247064c8009SBarry 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;
248064c8009SBarry Smith   }
249064c8009SBarry 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;
250064c8009SBarry 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;}
251064c8009SBarry 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;
252064c8009SBarry Smith 
253064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
254064c8009SBarry Smith   /* convert that to global numbering and get them on all processes */
255064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,26,gl,gl);CHKERRQ(ierr);
256064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
257785e854fSJed Brown   ierr = PetscMalloc1(26*mp*np*pp,&globals);CHKERRQ(ierr);
258ce94432eSBarry Smith   ierr = MPI_Allgather(gl,26,MPIU_INT,globals,26,MPIU_INT,PetscObjectComm((PetscObject)da));CHKERRQ(ierr);
259064c8009SBarry Smith 
260064c8009SBarry Smith   /* Number the coarse grid points from 0 to Ntotal */
2610298fd71SBarry Smith   ierr = MatGetSize(Aglobal,&Nt,NULL);CHKERRQ(ierr);
26212dd4568SBarry Smith   ierr = PetscTableCreate(Ntotal/3,Nt+1,&ht);CHKERRQ(ierr);
263064c8009SBarry Smith   for (i=0; i<26*mp*np*pp; i++) {
264064c8009SBarry Smith     ierr = PetscTableAddCount(ht,globals[i]+1);CHKERRQ(ierr);
265064c8009SBarry Smith   }
266064c8009SBarry Smith   ierr = PetscTableGetCount(ht,&cnt);CHKERRQ(ierr);
267e32f2f54SBarry 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);
268064c8009SBarry Smith   ierr = PetscFree(globals);CHKERRQ(ierr);
269064c8009SBarry Smith   for (i=0; i<26; i++) {
270064c8009SBarry Smith     ierr = PetscTableFind(ht,gl[i]+1,&gl[i]);CHKERRQ(ierr);
271064c8009SBarry Smith     gl[i]--;
272064c8009SBarry Smith   }
2736bc0bbbfSBarry Smith   ierr = PetscTableDestroy(&ht);CHKERRQ(ierr);
274064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
275064c8009SBarry Smith 
276064c8009SBarry Smith   /* construct global interpolation matrix */
2770298fd71SBarry Smith   ierr = MatGetLocalSize(Aglobal,&Ng,NULL);CHKERRQ(ierr);
278064c8009SBarry Smith   if (reuse == MAT_INITIAL_MATRIX) {
279ce94432eSBarry Smith     ierr = MatCreateAIJ(PetscObjectComm((PetscObject)da),Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,NULL,Nint+Nsurf,NULL,P);CHKERRQ(ierr);
280064c8009SBarry Smith   } else {
281064c8009SBarry Smith     ierr = MatZeroEntries(*P);CHKERRQ(ierr);
282064c8009SBarry Smith   }
283064c8009SBarry Smith   ierr = MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
2848c778c55SBarry Smith   ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
285064c8009SBarry Smith   ierr = MatSetValues(*P,Nint,IIint,26,gl,xint,INSERT_VALUES);CHKERRQ(ierr);
2868c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
2878c778c55SBarry Smith   ierr = MatDenseGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
288064c8009SBarry Smith   ierr = MatSetValues(*P,Nsurf,IIsurf,26,gl,xsurf,INSERT_VALUES);CHKERRQ(ierr);
2898c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
290064c8009SBarry Smith   ierr = MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
291064c8009SBarry Smith   ierr = MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
292064c8009SBarry Smith   ierr = PetscFree2(IIint,IIsurf);CHKERRQ(ierr);
293064c8009SBarry Smith 
2948e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
295064c8009SBarry Smith   {
296064c8009SBarry Smith     Vec         x,y;
297064c8009SBarry Smith     PetscScalar *yy;
298ce94432eSBarry Smith     ierr = VecCreateMPI(PetscObjectComm((PetscObject)da),Ng,PETSC_DETERMINE,&y);CHKERRQ(ierr);
299ce94432eSBarry Smith     ierr = VecCreateMPI(PetscObjectComm((PetscObject)da),PETSC_DETERMINE,Ntotal,&x);CHKERRQ(ierr);
300064c8009SBarry Smith     ierr = VecSet(x,1.0);CHKERRQ(ierr);
301064c8009SBarry Smith     ierr = MatMult(*P,x,y);CHKERRQ(ierr);
302064c8009SBarry Smith     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
303064c8009SBarry Smith     for (i=0; i<Ng; i++) {
30457622a8eSBarry 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,(double)PetscAbsScalar(yy[i]));
305064c8009SBarry Smith     }
306064c8009SBarry Smith     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
307064c8009SBarry Smith     ierr = VecDestroy(x);CHKERRQ(ierr);
308064c8009SBarry Smith     ierr = VecDestroy(y);CHKERRQ(ierr);
309064c8009SBarry Smith   }
310064c8009SBarry Smith #endif
311064c8009SBarry Smith 
312fcfd50ebSBarry Smith   ierr = MatDestroy(&Aii);CHKERRQ(ierr);
313fcfd50ebSBarry Smith   ierr = MatDestroy(&Ais);CHKERRQ(ierr);
314fcfd50ebSBarry Smith   ierr = MatDestroy(&Asi);CHKERRQ(ierr);
315fcfd50ebSBarry Smith   ierr = MatDestroy(&A);CHKERRQ(ierr);
316fcfd50ebSBarry Smith   ierr = ISDestroy(&is);CHKERRQ(ierr);
317fcfd50ebSBarry Smith   ierr = ISDestroy(&isint);CHKERRQ(ierr);
318fcfd50ebSBarry Smith   ierr = ISDestroy(&issurf);CHKERRQ(ierr);
319fcfd50ebSBarry Smith   ierr = MatDestroy(&Xint);CHKERRQ(ierr);
320fcfd50ebSBarry Smith   ierr = MatDestroy(&Xsurf);CHKERRQ(ierr);
321064c8009SBarry Smith   PetscFunctionReturn(0);
322064c8009SBarry Smith }
323064c8009SBarry Smith 
324064c8009SBarry Smith /*
325aa219208SBarry Smith       DMDAGetFaceInterpolation - Gets the interpolation for a face based coarse space
326064c8009SBarry Smith 
327064c8009SBarry Smith */
328aa219208SBarry Smith PetscErrorCode DMDAGetFaceInterpolation(DM da,PC_Exotic *exotic,Mat Aglobal,MatReuse reuse,Mat *P)
329064c8009SBarry Smith {
330064c8009SBarry Smith   PetscErrorCode         ierr;
331064c8009SBarry 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;
33228d20b34SBarry Smith   PetscInt               mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[6],*globals,Ng,*IIint,*IIsurf,Nt;
333064c8009SBarry Smith   Mat                    Xint, Xsurf,Xint_tmp;
334064c8009SBarry Smith   IS                     isint,issurf,is,row,col;
335064c8009SBarry Smith   ISLocalToGlobalMapping ltg;
336064c8009SBarry Smith   MPI_Comm               comm;
337064c8009SBarry Smith   Mat                    A,Aii,Ais,Asi,*Aholder,iAii;
338064c8009SBarry Smith   MatFactorInfo          info;
339064c8009SBarry Smith   PetscScalar            *xsurf,*xint;
340064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
341064c8009SBarry Smith   PetscScalar            tmp;
342064c8009SBarry Smith #endif
343064c8009SBarry Smith   PetscTable             ht;
344064c8009SBarry Smith 
345064c8009SBarry Smith   PetscFunctionBegin;
3461321219cSEthan Coon   ierr = DMDAGetInfo(da,&dim,0,0,0,&mp,&np,&pp,&dof,0,0,0,0,0);CHKERRQ(ierr);
347ce94432eSBarry Smith   if (dof != 1) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only for single field problems");
348ce94432eSBarry Smith   if (dim != 3) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only coded for 3d problems");
349aa219208SBarry Smith   ierr   = DMDAGetCorners(da,0,0,0,&m,&n,&p);CHKERRQ(ierr);
350aa219208SBarry Smith   ierr   = DMDAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth);CHKERRQ(ierr);
351064c8009SBarry Smith   istart = istart ? -1 : 0;
352064c8009SBarry Smith   jstart = jstart ? -1 : 0;
353064c8009SBarry Smith   kstart = kstart ? -1 : 0;
354064c8009SBarry Smith 
355064c8009SBarry Smith   /*
356064c8009SBarry Smith     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
357064c8009SBarry Smith     to all the local degrees of freedom (this includes the vertices, edges and faces).
358064c8009SBarry Smith 
359064c8009SBarry Smith     Xint are the subset of the interpolation into the interior
360064c8009SBarry Smith 
361064c8009SBarry Smith     Xface are the interpolation onto faces but not into the interior
362064c8009SBarry Smith 
363064c8009SBarry Smith     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
364064c8009SBarry Smith                                       Xint
365064c8009SBarry Smith     Symbolically one could write P = (Xface) after interchanging the rows to match the natural ordering on the domain
366064c8009SBarry Smith                                       Xsurf
367064c8009SBarry Smith   */
368064c8009SBarry Smith   N     = (m - istart)*(n - jstart)*(p - kstart);
369064c8009SBarry Smith   Nint  = (m-2-istart)*(n-2-jstart)*(p-2-kstart);
370064c8009SBarry Smith   Nface = 2*((m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart));
371064c8009SBarry Smith   Nwire = 4*((m-2-istart) + (n-2-jstart) + (p-2-kstart)) + 8;
372064c8009SBarry Smith   Nsurf = Nface + Nwire;
3730298fd71SBarry Smith   ierr  = MatCreateSeqDense(MPI_COMM_SELF,Nint,6,NULL,&Xint);CHKERRQ(ierr);
3740298fd71SBarry Smith   ierr  = MatCreateSeqDense(MPI_COMM_SELF,Nsurf,6,NULL,&Xsurf);CHKERRQ(ierr);
3758c778c55SBarry Smith   ierr  = MatDenseGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
376064c8009SBarry Smith 
377064c8009SBarry Smith   /*
378064c8009SBarry Smith      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
379064c8009SBarry Smith      Xsurf will be all zero (thus making the coarse matrix singular).
380064c8009SBarry Smith   */
381e32f2f54SBarry 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");
382e32f2f54SBarry 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");
383e32f2f54SBarry 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");
384064c8009SBarry Smith 
385064c8009SBarry Smith   cnt = 0;
3862fa5cd67SKarl Rupp   for (j=1; j<n-1-jstart; j++) {
3872fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 0*Nsurf] = 1;
388064c8009SBarry Smith   }
3892fa5cd67SKarl Rupp 
3902fa5cd67SKarl Rupp   for (k=1; k<p-1-kstart; k++) {
3912fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 1*Nsurf] = 1;
3922fa5cd67SKarl Rupp     for (j=1; j<n-1-jstart; j++) {
3932fa5cd67SKarl Rupp       xsurf[cnt++ + 2*Nsurf] = 1;
3942fa5cd67SKarl Rupp       /* these are the interior nodes */
3952fa5cd67SKarl Rupp       xsurf[cnt++ + 3*Nsurf] = 1;
3962fa5cd67SKarl Rupp     }
3972fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 4*Nsurf] = 1;
3982fa5cd67SKarl Rupp   }
3992fa5cd67SKarl Rupp   for (j=1;j<n-1-jstart;j++) {
4002fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 5*Nsurf] = 1;
4012fa5cd67SKarl Rupp   }
402064c8009SBarry Smith 
403064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
404064c8009SBarry Smith   for (i=0; i<Nsurf; i++) {
405064c8009SBarry Smith     tmp = 0.0;
4062fa5cd67SKarl Rupp     for (j=0; j<6; j++) tmp += xsurf[i+j*Nsurf];
4072fa5cd67SKarl Rupp 
40857622a8eSBarry 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,(double)PetscAbsScalar(tmp));
409064c8009SBarry Smith   }
410064c8009SBarry Smith #endif
4118c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
412064c8009SBarry Smith   /* ierr = MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);*/
413064c8009SBarry Smith 
414064c8009SBarry Smith 
415064c8009SBarry Smith   /*
416064c8009SBarry Smith        I are the indices for all the needed vertices (in global numbering)
417064c8009SBarry Smith        Iint are the indices for the interior values, I surf for the surface values
418*7dae84e0SHong Zhang             (This is just for the part of the global matrix obtained with MatCreateSubMatrix(), it
419aa219208SBarry Smith              is NOT the local DMDA ordering.)
420064c8009SBarry Smith        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
421064c8009SBarry Smith   */
422064c8009SBarry Smith #define Endpoint(a,start,b) (a == 0 || a == (b-1-start))
423dcca6d9dSJed Brown   ierr = PetscMalloc3(N,&II,Nint,&Iint,Nsurf,&Isurf);CHKERRQ(ierr);
424dcca6d9dSJed Brown   ierr = PetscMalloc2(Nint,&IIint,Nsurf,&IIsurf);CHKERRQ(ierr);
425064c8009SBarry Smith   for (k=0; k<p-kstart; k++) {
426064c8009SBarry Smith     for (j=0; j<n-jstart; j++) {
427064c8009SBarry Smith       for (i=0; i<m-istart; i++) {
428064c8009SBarry Smith         II[c++] = i + j*mwidth + k*mwidth*nwidth;
429064c8009SBarry Smith 
430064c8009SBarry Smith         if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) {
431064c8009SBarry Smith           IIint[cint]  = i + j*mwidth + k*mwidth*nwidth;
432064c8009SBarry Smith           Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
433064c8009SBarry Smith         } else {
434064c8009SBarry Smith           IIsurf[csurf]  = i + j*mwidth + k*mwidth*nwidth;
435064c8009SBarry Smith           Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
436064c8009SBarry Smith         }
437064c8009SBarry Smith       }
438064c8009SBarry Smith     }
439064c8009SBarry Smith   }
440e32f2f54SBarry Smith   if (c != N) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"c != N");
441e32f2f54SBarry Smith   if (cint != Nint) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"cint != Nint");
442e32f2f54SBarry Smith   if (csurf != Nsurf) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"csurf != Nsurf");
4431411c6eeSJed Brown   ierr = DMGetLocalToGlobalMapping(da,&ltg);CHKERRQ(ierr);
444064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,N,II,II);CHKERRQ(ierr);
445064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint);CHKERRQ(ierr);
446064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf);CHKERRQ(ierr);
447064c8009SBarry Smith   ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr);
44870b3c8c7SBarry Smith   ierr = ISCreateGeneral(comm,N,II,PETSC_COPY_VALUES,&is);CHKERRQ(ierr);
44970b3c8c7SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,PETSC_COPY_VALUES,&isint);CHKERRQ(ierr);
45070b3c8c7SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,PETSC_COPY_VALUES,&issurf);CHKERRQ(ierr);
451064c8009SBarry Smith   ierr = PetscFree3(II,Iint,Isurf);CHKERRQ(ierr);
452064c8009SBarry Smith 
453671e8369SHong Zhang   ierr = ISSort(is);CHKERRQ(ierr);
454*7dae84e0SHong Zhang   ierr = MatCreateSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder);CHKERRQ(ierr);
455064c8009SBarry Smith   A    = *Aholder;
456064c8009SBarry Smith   ierr = PetscFree(Aholder);CHKERRQ(ierr);
457064c8009SBarry Smith 
458*7dae84e0SHong Zhang   ierr = MatCreateSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii);CHKERRQ(ierr);
459*7dae84e0SHong Zhang   ierr = MatCreateSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais);CHKERRQ(ierr);
460*7dae84e0SHong Zhang   ierr = MatCreateSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi);CHKERRQ(ierr);
461064c8009SBarry Smith 
462064c8009SBarry Smith   /*
463064c8009SBarry Smith      Solve for the interpolation onto the interior Xint
464064c8009SBarry Smith   */
46592e4c2edSBarry Smith   ierr = MatMatMult(Ais,Xsurf,MAT_INITIAL_MATRIX,PETSC_DETERMINE,&Xint_tmp);CHKERRQ(ierr);
466064c8009SBarry Smith   ierr = MatScale(Xint_tmp,-1.0);CHKERRQ(ierr);
467064c8009SBarry Smith 
4688e722e36SBarry Smith   if (exotic->directSolve) {
4692692d6eeSBarry Smith     ierr = MatGetFactor(Aii,MATSOLVERPETSC,MAT_FACTOR_LU,&iAii);CHKERRQ(ierr);
470064c8009SBarry Smith     ierr = MatFactorInfoInitialize(&info);CHKERRQ(ierr);
4712692d6eeSBarry Smith     ierr = MatGetOrdering(Aii,MATORDERINGND,&row,&col);CHKERRQ(ierr);
472064c8009SBarry Smith     ierr = MatLUFactorSymbolic(iAii,Aii,row,col,&info);CHKERRQ(ierr);
473fcfd50ebSBarry Smith     ierr = ISDestroy(&row);CHKERRQ(ierr);
474fcfd50ebSBarry Smith     ierr = ISDestroy(&col);CHKERRQ(ierr);
475064c8009SBarry Smith     ierr = MatLUFactorNumeric(iAii,Aii,&info);CHKERRQ(ierr);
476064c8009SBarry Smith     ierr = MatMatSolve(iAii,Xint_tmp,Xint);CHKERRQ(ierr);
477fcfd50ebSBarry Smith     ierr = MatDestroy(&iAii);CHKERRQ(ierr);
478064c8009SBarry Smith   } else {
479064c8009SBarry Smith     Vec         b,x;
480064c8009SBarry Smith     PetscScalar *xint_tmp;
481064c8009SBarry Smith 
4828c778c55SBarry Smith     ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
483778a2246SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,0,&x);CHKERRQ(ierr);
4848c778c55SBarry Smith     ierr = MatDenseGetArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
485778a2246SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,0,&b);CHKERRQ(ierr);
48623ee1639SBarry Smith     ierr = KSPSetOperators(exotic->ksp,Aii,Aii);CHKERRQ(ierr);
487064c8009SBarry Smith     for (i=0; i<6; i++) {
488064c8009SBarry Smith       ierr = VecPlaceArray(x,xint+i*Nint);CHKERRQ(ierr);
489064c8009SBarry Smith       ierr = VecPlaceArray(b,xint_tmp+i*Nint);CHKERRQ(ierr);
4908e722e36SBarry Smith       ierr = KSPSolve(exotic->ksp,b,x);CHKERRQ(ierr);
491064c8009SBarry Smith       ierr = VecResetArray(x);CHKERRQ(ierr);
492064c8009SBarry Smith       ierr = VecResetArray(b);CHKERRQ(ierr);
493064c8009SBarry Smith     }
4948c778c55SBarry Smith     ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
4958c778c55SBarry Smith     ierr = MatDenseRestoreArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
4966bf464f9SBarry Smith     ierr = VecDestroy(&x);CHKERRQ(ierr);
4976bf464f9SBarry Smith     ierr = VecDestroy(&b);CHKERRQ(ierr);
498064c8009SBarry Smith   }
4996bf464f9SBarry Smith   ierr = MatDestroy(&Xint_tmp);CHKERRQ(ierr);
500064c8009SBarry Smith 
501064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
5028c778c55SBarry Smith   ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
503064c8009SBarry Smith   for (i=0; i<Nint; i++) {
504064c8009SBarry Smith     tmp = 0.0;
5052fa5cd67SKarl Rupp     for (j=0; j<6; j++) tmp += xint[i+j*Nint];
5062fa5cd67SKarl Rupp 
50757622a8eSBarry 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,(double)PetscAbsScalar(tmp));
508064c8009SBarry Smith   }
5098c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
510064c8009SBarry Smith   /* ierr =MatView(Xint,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); */
511064c8009SBarry Smith #endif
512064c8009SBarry Smith 
513064c8009SBarry Smith 
514064c8009SBarry Smith   /*         total faces    */
515064c8009SBarry Smith   Ntotal =  mp*np*(pp+1) + mp*pp*(np+1) + np*pp*(mp+1);
516064c8009SBarry Smith 
517064c8009SBarry Smith   /*
518064c8009SBarry Smith       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
519064c8009SBarry Smith   */
520064c8009SBarry Smith   cnt = 0;
521064c8009SBarry Smith   { gl[cnt++] = mwidth+1;}
522064c8009SBarry Smith   {
523064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth+1;}
524064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;}
525064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth+mwidth*(n-jstart-1)+1;}
526064c8009SBarry Smith   }
527064c8009SBarry Smith   { gl[cnt++] = mwidth*nwidth*(p-kstart-1) + mwidth+1;}
528064c8009SBarry Smith 
529064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
530064c8009SBarry Smith   /* convert that to global numbering and get them on all processes */
531064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,6,gl,gl);CHKERRQ(ierr);
532064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
533785e854fSJed Brown   ierr = PetscMalloc1(6*mp*np*pp,&globals);CHKERRQ(ierr);
534ce94432eSBarry Smith   ierr = MPI_Allgather(gl,6,MPIU_INT,globals,6,MPIU_INT,PetscObjectComm((PetscObject)da));CHKERRQ(ierr);
535064c8009SBarry Smith 
536064c8009SBarry Smith   /* Number the coarse grid points from 0 to Ntotal */
5370298fd71SBarry Smith   ierr = MatGetSize(Aglobal,&Nt,NULL);CHKERRQ(ierr);
53828d20b34SBarry Smith   ierr = PetscTableCreate(Ntotal/3,Nt+1,&ht);CHKERRQ(ierr);
539064c8009SBarry Smith   for (i=0; i<6*mp*np*pp; i++) {
540064c8009SBarry Smith     ierr = PetscTableAddCount(ht,globals[i]+1);CHKERRQ(ierr);
541064c8009SBarry Smith   }
542064c8009SBarry Smith   ierr = PetscTableGetCount(ht,&cnt);CHKERRQ(ierr);
543e32f2f54SBarry 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);
544064c8009SBarry Smith   ierr = PetscFree(globals);CHKERRQ(ierr);
545064c8009SBarry Smith   for (i=0; i<6; i++) {
546064c8009SBarry Smith     ierr = PetscTableFind(ht,gl[i]+1,&gl[i]);CHKERRQ(ierr);
547064c8009SBarry Smith     gl[i]--;
548064c8009SBarry Smith   }
5496bc0bbbfSBarry Smith   ierr = PetscTableDestroy(&ht);CHKERRQ(ierr);
550064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
551064c8009SBarry Smith 
552064c8009SBarry Smith   /* construct global interpolation matrix */
5530298fd71SBarry Smith   ierr = MatGetLocalSize(Aglobal,&Ng,NULL);CHKERRQ(ierr);
554064c8009SBarry Smith   if (reuse == MAT_INITIAL_MATRIX) {
555ce94432eSBarry Smith     ierr = MatCreateAIJ(PetscObjectComm((PetscObject)da),Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,NULL,Nint,NULL,P);CHKERRQ(ierr);
556064c8009SBarry Smith   } else {
557064c8009SBarry Smith     ierr = MatZeroEntries(*P);CHKERRQ(ierr);
558064c8009SBarry Smith   }
559064c8009SBarry Smith   ierr = MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
5608c778c55SBarry Smith   ierr = MatDenseGetArray(Xint,&xint);CHKERRQ(ierr);
561064c8009SBarry Smith   ierr = MatSetValues(*P,Nint,IIint,6,gl,xint,INSERT_VALUES);CHKERRQ(ierr);
5628c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xint,&xint);CHKERRQ(ierr);
5638c778c55SBarry Smith   ierr = MatDenseGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
564064c8009SBarry Smith   ierr = MatSetValues(*P,Nsurf,IIsurf,6,gl,xsurf,INSERT_VALUES);CHKERRQ(ierr);
5658c778c55SBarry Smith   ierr = MatDenseRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
566064c8009SBarry Smith   ierr = MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
567064c8009SBarry Smith   ierr = MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
568064c8009SBarry Smith   ierr = PetscFree2(IIint,IIsurf);CHKERRQ(ierr);
569064c8009SBarry Smith 
570064c8009SBarry Smith 
571064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
572064c8009SBarry Smith   {
573064c8009SBarry Smith     Vec         x,y;
574064c8009SBarry Smith     PetscScalar *yy;
575ce94432eSBarry Smith     ierr = VecCreateMPI(PetscObjectComm((PetscObject)da),Ng,PETSC_DETERMINE,&y);CHKERRQ(ierr);
576ce94432eSBarry Smith     ierr = VecCreateMPI(PetscObjectComm((PetscObject)da),PETSC_DETERMINE,Ntotal,&x);CHKERRQ(ierr);
577064c8009SBarry Smith     ierr = VecSet(x,1.0);CHKERRQ(ierr);
578064c8009SBarry Smith     ierr = MatMult(*P,x,y);CHKERRQ(ierr);
579064c8009SBarry Smith     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
580064c8009SBarry Smith     for (i=0; i<Ng; i++) {
58157622a8eSBarry 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,(double)PetscAbsScalar(yy[i]));
582064c8009SBarry Smith     }
583064c8009SBarry Smith     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
584064c8009SBarry Smith     ierr = VecDestroy(x);CHKERRQ(ierr);
585064c8009SBarry Smith     ierr = VecDestroy(y);CHKERRQ(ierr);
586064c8009SBarry Smith   }
587064c8009SBarry Smith #endif
588064c8009SBarry Smith 
589fcfd50ebSBarry Smith   ierr = MatDestroy(&Aii);CHKERRQ(ierr);
590fcfd50ebSBarry Smith   ierr = MatDestroy(&Ais);CHKERRQ(ierr);
591fcfd50ebSBarry Smith   ierr = MatDestroy(&Asi);CHKERRQ(ierr);
592fcfd50ebSBarry Smith   ierr = MatDestroy(&A);CHKERRQ(ierr);
593fcfd50ebSBarry Smith   ierr = ISDestroy(&is);CHKERRQ(ierr);
594fcfd50ebSBarry Smith   ierr = ISDestroy(&isint);CHKERRQ(ierr);
595fcfd50ebSBarry Smith   ierr = ISDestroy(&issurf);CHKERRQ(ierr);
596fcfd50ebSBarry Smith   ierr = MatDestroy(&Xint);CHKERRQ(ierr);
597fcfd50ebSBarry Smith   ierr = MatDestroy(&Xsurf);CHKERRQ(ierr);
598064c8009SBarry Smith   PetscFunctionReturn(0);
599064c8009SBarry Smith }
600174b6946SBarry Smith 
6017233f9f0SBarry Smith 
6027233f9f0SBarry Smith /*@
6037233f9f0SBarry Smith    PCExoticSetType - Sets the type of coarse grid interpolation to use
6047233f9f0SBarry Smith 
6053f9fe445SBarry Smith    Logically Collective on PC
6067233f9f0SBarry Smith 
6077233f9f0SBarry Smith    Input Parameters:
6087233f9f0SBarry Smith +  pc - the preconditioner context
6097233f9f0SBarry Smith -  type - either PC_EXOTIC_FACE or PC_EXOTIC_WIREBASKET (defaults to face)
6107233f9f0SBarry Smith 
611563e08c6SBarry Smith    Notes: The face based interpolation has 1 degree of freedom per face and ignores the
612563e08c6SBarry Smith      edge and vertex values completely in the coarse problem. For any seven point
613563e08c6SBarry Smith      stencil the interpolation of a constant on all faces into the interior is that constant.
614563e08c6SBarry Smith 
615563e08c6SBarry Smith      The wirebasket interpolation has 1 degree of freedom per vertex, per edge and
616563e08c6SBarry Smith      per face. A constant on the subdomain boundary is interpolated as that constant
617563e08c6SBarry Smith      in the interior of the domain.
618563e08c6SBarry Smith 
619563e08c6SBarry Smith      The coarse grid matrix is obtained via the Galerkin computation A_c = R A R^T, hence
620563e08c6SBarry Smith      if A is nonsingular A_c is also nonsingular.
621563e08c6SBarry Smith 
622563e08c6SBarry Smith      Both interpolations are suitable for only scalar problems.
623563e08c6SBarry Smith 
6247233f9f0SBarry Smith    Level: intermediate
6257233f9f0SBarry Smith 
6267233f9f0SBarry Smith 
6277233f9f0SBarry Smith .seealso: PCEXOTIC, PCExoticType()
6287233f9f0SBarry Smith @*/
6297087cfbeSBarry Smith PetscErrorCode  PCExoticSetType(PC pc,PCExoticType type)
6307233f9f0SBarry Smith {
6314ac538c5SBarry Smith   PetscErrorCode ierr;
6327233f9f0SBarry Smith 
6337233f9f0SBarry Smith   PetscFunctionBegin;
6340700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
635c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc,type,2);
6364ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCExoticSetType_C",(PC,PCExoticType),(pc,type));CHKERRQ(ierr);
6377233f9f0SBarry Smith   PetscFunctionReturn(0);
6387233f9f0SBarry Smith }
6397233f9f0SBarry Smith 
640f7a08781SBarry Smith static PetscErrorCode  PCExoticSetType_Exotic(PC pc,PCExoticType type)
6417233f9f0SBarry Smith {
642f3fbd535SBarry Smith   PC_MG     *mg  = (PC_MG*)pc->data;
64331567311SBarry Smith   PC_Exotic *ctx = (PC_Exotic*) mg->innerctx;
6447233f9f0SBarry Smith 
6457233f9f0SBarry Smith   PetscFunctionBegin;
6467233f9f0SBarry Smith   ctx->type = type;
6477233f9f0SBarry Smith   PetscFunctionReturn(0);
6487233f9f0SBarry Smith }
6497233f9f0SBarry Smith 
6507233f9f0SBarry Smith PetscErrorCode PCSetUp_Exotic(PC pc)
651174b6946SBarry Smith {
652174b6946SBarry Smith   PetscErrorCode ierr;
65396bdf778SBarry Smith   Mat            A;
654f3fbd535SBarry Smith   PC_MG          *mg   = (PC_MG*)pc->data;
65531567311SBarry Smith   PC_Exotic      *ex   = (PC_Exotic*) mg->innerctx;
65696bdf778SBarry Smith   MatReuse       reuse = (ex->P) ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
657174b6946SBarry Smith 
658174b6946SBarry Smith   PetscFunctionBegin;
659ce94432eSBarry Smith   if (!pc->dm) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Need to call PCSetDM() before using this PC");
66023ee1639SBarry Smith   ierr = PCGetOperators(pc,NULL,&A);CHKERRQ(ierr);
6617233f9f0SBarry Smith   if (ex->type == PC_EXOTIC_FACE) {
662aa219208SBarry Smith     ierr = DMDAGetFaceInterpolation(pc->dm,ex,A,reuse,&ex->P);CHKERRQ(ierr);
6637233f9f0SBarry Smith   } else if (ex->type == PC_EXOTIC_WIREBASKET) {
664aa219208SBarry Smith     ierr = DMDAGetWireBasketInterpolation(pc->dm,ex,A,reuse,&ex->P);CHKERRQ(ierr);
665ce94432eSBarry Smith   } else SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Unknown exotic coarse space %d",ex->type);
66696bdf778SBarry Smith   ierr = PCMGSetInterpolation(pc,1,ex->P);CHKERRQ(ierr);
667d0660788SBarry Smith   /* if PC has attached DM we must remove it or the PCMG will use it to compute incorrect sized vectors and interpolations */
6680298fd71SBarry Smith   ierr = PCSetDM(pc,NULL);CHKERRQ(ierr);
6697233f9f0SBarry Smith   ierr = PCSetUp_MG(pc);CHKERRQ(ierr);
670174b6946SBarry Smith   PetscFunctionReturn(0);
671174b6946SBarry Smith }
672174b6946SBarry Smith 
6737233f9f0SBarry Smith PetscErrorCode PCDestroy_Exotic(PC pc)
674174b6946SBarry Smith {
675174b6946SBarry Smith   PetscErrorCode ierr;
676f3fbd535SBarry Smith   PC_MG          *mg  = (PC_MG*)pc->data;
67731567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
678174b6946SBarry Smith 
679174b6946SBarry Smith   PetscFunctionBegin;
680fcfd50ebSBarry Smith   ierr = MatDestroy(&ctx->P);CHKERRQ(ierr);
681fcfd50ebSBarry Smith   ierr = KSPDestroy(&ctx->ksp);CHKERRQ(ierr);
6827233f9f0SBarry Smith   ierr = PetscFree(ctx);CHKERRQ(ierr);
6837233f9f0SBarry Smith   ierr = PCDestroy_MG(pc);CHKERRQ(ierr);
684174b6946SBarry Smith   PetscFunctionReturn(0);
685174b6946SBarry Smith }
686174b6946SBarry Smith 
6877233f9f0SBarry Smith PetscErrorCode PCView_Exotic(PC pc,PetscViewer viewer)
6887233f9f0SBarry Smith {
689f3fbd535SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
6907233f9f0SBarry Smith   PetscErrorCode ierr;
691ace3abfcSBarry Smith   PetscBool      iascii;
69231567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
6937233f9f0SBarry Smith 
6947233f9f0SBarry Smith   PetscFunctionBegin;
695251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
6967233f9f0SBarry Smith   if (iascii) {
6977233f9f0SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"    Exotic type = %s\n",PCExoticTypes[ctx->type]);CHKERRQ(ierr);
6988e722e36SBarry Smith     if (ctx->directSolve) {
6998e722e36SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"      Using direct solver to construct interpolation\n");CHKERRQ(ierr);
7008e722e36SBarry Smith     } else {
7018e722e36SBarry Smith       PetscViewer sviewer;
7028e722e36SBarry Smith       PetscMPIInt rank;
7038e722e36SBarry Smith 
7048e722e36SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"      Using iterative solver to construct interpolation\n");CHKERRQ(ierr);
7058e722e36SBarry Smith       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
7068e722e36SBarry Smith       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);  /* should not need to push this twice? */
7073f08860eSBarry Smith       ierr = PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr);
708ce94432eSBarry Smith       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)pc),&rank);CHKERRQ(ierr);
7098e722e36SBarry Smith       if (!rank) {
7108e722e36SBarry Smith         ierr = KSPView(ctx->ksp,sviewer);CHKERRQ(ierr);
7118e722e36SBarry Smith       }
7123f08860eSBarry Smith       ierr = PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);CHKERRQ(ierr);
7138e722e36SBarry Smith       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
7148e722e36SBarry Smith       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
7158e722e36SBarry Smith     }
7167233f9f0SBarry Smith   }
7177233f9f0SBarry Smith   ierr = PCView_MG(pc,viewer);CHKERRQ(ierr);
7187233f9f0SBarry Smith   PetscFunctionReturn(0);
7197233f9f0SBarry Smith }
7207233f9f0SBarry Smith 
7214416b707SBarry Smith PetscErrorCode PCSetFromOptions_Exotic(PetscOptionItems *PetscOptionsObject,PC pc)
7227233f9f0SBarry Smith {
7237233f9f0SBarry Smith   PetscErrorCode ierr;
724ace3abfcSBarry Smith   PetscBool      flg;
725f3fbd535SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
7267233f9f0SBarry Smith   PCExoticType   mgctype;
72731567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
7287233f9f0SBarry Smith 
7297233f9f0SBarry Smith   PetscFunctionBegin;
730e55864a3SBarry Smith   ierr = PetscOptionsHead(PetscOptionsObject,"Exotic coarse space options");CHKERRQ(ierr);
7317233f9f0SBarry Smith   ierr = PetscOptionsEnum("-pc_exotic_type","face or wirebasket","PCExoticSetType",PCExoticTypes,(PetscEnum)ctx->type,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr);
7327233f9f0SBarry Smith   if (flg) {
7337233f9f0SBarry Smith     ierr = PCExoticSetType(pc,mgctype);CHKERRQ(ierr);
7347233f9f0SBarry Smith   }
7350298fd71SBarry Smith   ierr = PetscOptionsBool("-pc_exotic_direct_solver","use direct solver to construct interpolation","None",ctx->directSolve,&ctx->directSolve,NULL);CHKERRQ(ierr);
7368e722e36SBarry Smith   if (!ctx->directSolve) {
7378e722e36SBarry Smith     if (!ctx->ksp) {
7388e722e36SBarry Smith       const char *prefix;
7398e722e36SBarry Smith       ierr = KSPCreate(PETSC_COMM_SELF,&ctx->ksp);CHKERRQ(ierr);
740422a814eSBarry Smith       ierr = KSPSetErrorIfNotConverged(ctx->ksp,pc->erroriffailure);CHKERRQ(ierr);
7418e722e36SBarry Smith       ierr = PetscObjectIncrementTabLevel((PetscObject)ctx->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
7423bb1ff40SBarry Smith       ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)ctx->ksp);CHKERRQ(ierr);
7438e722e36SBarry Smith       ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
7448e722e36SBarry Smith       ierr = KSPSetOptionsPrefix(ctx->ksp,prefix);CHKERRQ(ierr);
7458e722e36SBarry Smith       ierr = KSPAppendOptionsPrefix(ctx->ksp,"exotic_");CHKERRQ(ierr);
7468e722e36SBarry Smith     }
7478e722e36SBarry Smith     ierr = KSPSetFromOptions(ctx->ksp);CHKERRQ(ierr);
7488e722e36SBarry Smith   }
7497233f9f0SBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
7507233f9f0SBarry Smith   PetscFunctionReturn(0);
7517233f9f0SBarry Smith }
7527233f9f0SBarry Smith 
753174b6946SBarry Smith 
754174b6946SBarry Smith /*MC
7557233f9f0SBarry Smith      PCEXOTIC - Two level overlapping Schwarz preconditioner with exotic (non-standard) coarse grid spaces
756174b6946SBarry Smith 
7577233f9f0SBarry Smith      This uses the PCMG infrastructure restricted to two levels and the face and wirebasket based coarse
75824c3aa18SBarry Smith    grid spaces.
75924c3aa18SBarry Smith 
76024c3aa18SBarry 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
76124c3aa18SBarry Smith 
76296a0c994SBarry Smith    References:
76396a0c994SBarry Smith +  1. - These coarse grid spaces originate in the work of Bramble, Pasciak  and Schatz, "The Construction
76496a0c994SBarry Smith    of Preconditioners for Elliptic Problems by Substructing IV", Mathematics of Computation, volume 53, 1989.
76596a0c994SBarry Smith .  2. - They were generalized slightly in "Domain Decomposition Method for Linear Elasticity", Ph. D. thesis, Barry Smith,
7664f02bc6aSBarry Smith    New York University, 1990.
76796a0c994SBarry Smith .  3. - They were then explored in great detail in Dryja, Smith, Widlund, "Schwarz Analysis
7683b65e785SBarry Smith    of Iterative Substructuring Methods for Elliptic Problems in Three Dimensions, SIAM Journal on Numerical
76996a0c994SBarry Smith    Analysis, volume 31. 1994. These were developed in the context of iterative substructuring preconditioners.
77096a0c994SBarry Smith .  4. - They were then ingeniously applied as coarse grid spaces for overlapping Schwarz methods by Dohrmann and Widlund.
7713b65e785SBarry Smith    They refer to them as GDSW (generalized Dryja, Smith, Widlund preconditioners). See, for example,
7723b65e785SBarry Smith    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Extending theory for domain decomposition algorithms to irregular subdomains. In Ulrich Langer, Marco
7733b65e785SBarry Smith    Discacciati, David Keyes, Olof Widlund, and Walter Zulehner, editors, Proceedings
7743b65e785SBarry Smith    of the 17th International Conference on Domain Decomposition Methods in
77596a0c994SBarry Smith    Science and Engineering, held in Strobl, Austria, 2006, number 60 in
77696a0c994SBarry Smith    Springer Verlag, Lecture Notes in Computational Science and Engineering, 2007.
77796a0c994SBarry Smith .  5. -  Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. A family of energy minimizing coarse spaces for overlapping Schwarz preconditioners. In Ulrich Langer,
7783b65e785SBarry Smith    Marco Discacciati, David Keyes, Olof Widlund, and Walter Zulehner, editors, Proceedings
7793b65e785SBarry Smith    of the 17th International Conference on Domain Decomposition Methods
78096a0c994SBarry Smith    in Science and Engineering, held in Strobl, Austria, 2006, number 60 in
78196a0c994SBarry Smith    Springer Verlag, Lecture Notes in Computational Science and Engineering, 2007
78296a0c994SBarry Smith .  6. - Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Domain decomposition
7833b65e785SBarry Smith    for less regular subdomains: Overlapping Schwarz in two dimensions. SIAM J.
78496a0c994SBarry Smith    Numer. Anal., 46(4), 2008.
78596a0c994SBarry Smith -  7. - Clark R. Dohrmann and Olof B. Widlund. An overlapping Schwarz
7863b65e785SBarry Smith    algorithm for almost incompressible elasticity. Technical Report
78796a0c994SBarry Smith    TR2008 912, Department of Computer Science, Courant Institute
7883b65e785SBarry Smith    of Mathematical Sciences, New York University, May 2008. URL:
7897233f9f0SBarry Smith 
7907233f9f0SBarry Smith    Options Database: The usual PCMG options are supported, such as -mg_levels_pc_type <type> -mg_coarse_pc_type <type>
7917233f9f0SBarry Smith       -pc_mg_type <type>
7927233f9f0SBarry Smith 
79325a35f6fSSatish Balay    Level: advanced
794174b6946SBarry Smith 
7956c699258SBarry Smith .seealso:  PCMG, PCSetDM(), PCExoticType, PCExoticSetType()
796174b6946SBarry Smith M*/
797174b6946SBarry Smith 
7988cc058d9SJed Brown PETSC_EXTERN PetscErrorCode PCCreate_Exotic(PC pc)
799174b6946SBarry Smith {
800174b6946SBarry Smith   PetscErrorCode ierr;
8017233f9f0SBarry Smith   PC_Exotic      *ex;
802f3fbd535SBarry Smith   PC_MG          *mg;
803174b6946SBarry Smith 
804174b6946SBarry Smith   PetscFunctionBegin;
805f91d8e95SBarry Smith   /* if type was previously mg; must manually destroy it because call to PCSetType(pc,PCMG) will not destroy it */
8062fa5cd67SKarl Rupp   if (pc->ops->destroy) {
8072fa5cd67SKarl Rupp     ierr =  (*pc->ops->destroy)(pc);CHKERRQ(ierr);
8082fa5cd67SKarl Rupp     pc->data = 0;
8092fa5cd67SKarl Rupp   }
810503cfb0cSBarry Smith   ierr = PetscFree(((PetscObject)pc)->type_name);CHKERRQ(ierr);
811f91d8e95SBarry Smith   ((PetscObject)pc)->type_name = 0;
812f91d8e95SBarry Smith 
813174b6946SBarry Smith   ierr         = PCSetType(pc,PCMG);CHKERRQ(ierr);
8140298fd71SBarry Smith   ierr         = PCMGSetLevels(pc,2,NULL);CHKERRQ(ierr);
8152134b1e4SBarry Smith   ierr         = PCMGSetGalerkin(pc,PC_MG_GALERKIN_PMAT);CHKERRQ(ierr);
816b00a9115SJed Brown   ierr         = PetscNew(&ex);CHKERRQ(ierr); \
8177233f9f0SBarry Smith   ex->type     = PC_EXOTIC_FACE;
818f3fbd535SBarry Smith   mg           = (PC_MG*) pc->data;
81931567311SBarry Smith   mg->innerctx = ex;
8207233f9f0SBarry Smith 
8217233f9f0SBarry Smith 
8227233f9f0SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_Exotic;
8237233f9f0SBarry Smith   pc->ops->view           = PCView_Exotic;
8247233f9f0SBarry Smith   pc->ops->destroy        = PCDestroy_Exotic;
8256c699258SBarry Smith   pc->ops->setup          = PCSetUp_Exotic;
8262fa5cd67SKarl Rupp 
827bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCExoticSetType_C",PCExoticSetType_Exotic);CHKERRQ(ierr);
828174b6946SBarry Smith   PetscFunctionReturn(0);
829174b6946SBarry Smith }
830