xref: /petsc/src/ksp/pc/impls/wb/wb.c (revision 5f80ce2ab25dff0f4601e710601cbbcecf323266)
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 
130a545947SLisandro Dalcin const char *const PCExoticTypes[] = {"face","wirebasket","PCExoticType","PC_Exotic",NULL};
14064c8009SBarry Smith 
15064c8009SBarry Smith /*
16aa219208SBarry Smith       DMDAGetWireBasketInterpolation - Gets the interpolation for a wirebasket based coarse space
17064c8009SBarry Smith 
18064c8009SBarry Smith */
19c0decd05SBarry Smith PetscErrorCode DMDAGetWireBasketInterpolation(PC pc,DM da,PC_Exotic *exotic,Mat Aglobal,MatReuse reuse,Mat *P)
20064c8009SBarry Smith {
21064c8009SBarry 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;
2228d20b34SBarry Smith   PetscInt               mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[26],*globals,Ng,*IIint,*IIsurf,Nt;
23064c8009SBarry Smith   Mat                    Xint, Xsurf,Xint_tmp;
24064c8009SBarry Smith   IS                     isint,issurf,is,row,col;
25064c8009SBarry Smith   ISLocalToGlobalMapping ltg;
26064c8009SBarry Smith   MPI_Comm               comm;
27064c8009SBarry Smith   Mat                    A,Aii,Ais,Asi,*Aholder,iAii;
28064c8009SBarry Smith   MatFactorInfo          info;
29064c8009SBarry Smith   PetscScalar            *xsurf,*xint;
301683a169SBarry Smith   const PetscScalar      *rxint;
318e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
32064c8009SBarry Smith   PetscScalar            tmp;
33064c8009SBarry Smith #endif
34064c8009SBarry Smith   PetscTable             ht;
35064c8009SBarry Smith 
36064c8009SBarry Smith   PetscFunctionBegin;
37*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAGetInfo(da,&dim,NULL,NULL,NULL,&mp,&np,&pp,&dof,NULL,NULL,NULL,NULL,NULL));
382c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dof != 1,PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only for single field problems");
392c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dim != 3,PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only coded for 3d problems");
40*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAGetCorners(da,NULL,NULL,NULL,&m,&n,&p));
41*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth));
42064c8009SBarry Smith   istart = istart ? -1 : 0;
43064c8009SBarry Smith   jstart = jstart ? -1 : 0;
44064c8009SBarry Smith   kstart = kstart ? -1 : 0;
45064c8009SBarry Smith 
46064c8009SBarry Smith   /*
47064c8009SBarry Smith     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
48064c8009SBarry Smith     to all the local degrees of freedom (this includes the vertices, edges and faces).
49064c8009SBarry Smith 
50064c8009SBarry Smith     Xint are the subset of the interpolation into the interior
51064c8009SBarry Smith 
52064c8009SBarry Smith     Xface are the interpolation onto faces but not into the interior
53064c8009SBarry Smith 
54064c8009SBarry Smith     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
55064c8009SBarry Smith                                       Xint
56064c8009SBarry Smith     Symbolically one could write P = (Xface) after interchanging the rows to match the natural ordering on the domain
57064c8009SBarry Smith                                       Xsurf
58064c8009SBarry Smith   */
59064c8009SBarry Smith   N     = (m - istart)*(n - jstart)*(p - kstart);
60064c8009SBarry Smith   Nint  = (m-2-istart)*(n-2-jstart)*(p-2-kstart);
61064c8009SBarry Smith   Nface = 2*((m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart));
62064c8009SBarry Smith   Nwire = 4*((m-2-istart) + (n-2-jstart) + (p-2-kstart)) + 8;
63064c8009SBarry Smith   Nsurf = Nface + Nwire;
64*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSeqDense(MPI_COMM_SELF,Nint,26,NULL,&Xint));
65*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSeqDense(MPI_COMM_SELF,Nsurf,26,NULL,&Xsurf));
66*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseGetArray(Xsurf,&xsurf));
67064c8009SBarry Smith 
68064c8009SBarry Smith   /*
69064c8009SBarry Smith      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
70064c8009SBarry Smith      Xsurf will be all zero (thus making the coarse matrix singular).
71064c8009SBarry Smith   */
722c71b3e2SJacob Faibussowitsch   PetscCheckFalse(m-istart < 3,PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in X direction must be at least 3");
732c71b3e2SJacob Faibussowitsch   PetscCheckFalse(n-jstart < 3,PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in Y direction must be at least 3");
742c71b3e2SJacob Faibussowitsch   PetscCheckFalse(p-kstart < 3,PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in Z direction must be at least 3");
75064c8009SBarry Smith 
76064c8009SBarry Smith   cnt = 0;
772fa5cd67SKarl Rupp 
782fa5cd67SKarl Rupp   xsurf[cnt++] = 1;
792fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + Nsurf] = 1;
802fa5cd67SKarl Rupp   xsurf[cnt++ + 2*Nsurf] = 1;
812fa5cd67SKarl Rupp 
822fa5cd67SKarl Rupp   for (j=1; j<n-1-jstart; j++) {
832fa5cd67SKarl Rupp     xsurf[cnt++ + 3*Nsurf] = 1;
842fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 4*Nsurf] = 1;
852fa5cd67SKarl Rupp     xsurf[cnt++ + 5*Nsurf] = 1;
86064c8009SBarry Smith   }
872fa5cd67SKarl Rupp 
882fa5cd67SKarl Rupp   xsurf[cnt++ + 6*Nsurf] = 1;
892fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 7*Nsurf] = 1;
902fa5cd67SKarl Rupp   xsurf[cnt++ + 8*Nsurf] = 1;
912fa5cd67SKarl Rupp 
922fa5cd67SKarl Rupp   for (k=1; k<p-1-kstart; k++) {
932fa5cd67SKarl Rupp     xsurf[cnt++ + 9*Nsurf] = 1;
942fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 10*Nsurf] = 1;
952fa5cd67SKarl Rupp     xsurf[cnt++ + 11*Nsurf] = 1;
962fa5cd67SKarl Rupp 
972fa5cd67SKarl Rupp     for (j=1; j<n-1-jstart; j++) {
982fa5cd67SKarl Rupp       xsurf[cnt++ + 12*Nsurf] = 1;
992fa5cd67SKarl Rupp       /* these are the interior nodes */
1002fa5cd67SKarl Rupp       xsurf[cnt++ + 13*Nsurf] = 1;
1012fa5cd67SKarl Rupp     }
1022fa5cd67SKarl Rupp 
1032fa5cd67SKarl Rupp     xsurf[cnt++ + 14*Nsurf] = 1;
1042fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 15*Nsurf] = 1;
1052fa5cd67SKarl Rupp     xsurf[cnt++ + 16*Nsurf] = 1;
1062fa5cd67SKarl Rupp   }
1072fa5cd67SKarl Rupp 
1082fa5cd67SKarl Rupp   xsurf[cnt++ + 17*Nsurf] = 1;
1092fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 18*Nsurf] = 1;
1102fa5cd67SKarl Rupp   xsurf[cnt++ + 19*Nsurf] = 1;
1112fa5cd67SKarl Rupp 
1122fa5cd67SKarl Rupp   for (j=1;j<n-1-jstart;j++) {
1132fa5cd67SKarl Rupp     xsurf[cnt++ + 20*Nsurf] = 1;
1142fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 21*Nsurf] = 1;
1152fa5cd67SKarl Rupp     xsurf[cnt++ + 22*Nsurf] = 1;
1162fa5cd67SKarl Rupp   }
1172fa5cd67SKarl Rupp 
1182fa5cd67SKarl Rupp   xsurf[cnt++ + 23*Nsurf] = 1;
1192fa5cd67SKarl Rupp   for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 24*Nsurf] = 1;
1202fa5cd67SKarl Rupp   xsurf[cnt++ + 25*Nsurf] = 1;
1212fa5cd67SKarl Rupp 
1228e722e36SBarry Smith   /* interpolations only sum to 1 when using direct solver */
1238e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
124064c8009SBarry Smith   for (i=0; i<Nsurf; i++) {
125064c8009SBarry Smith     tmp = 0.0;
1262fa5cd67SKarl Rupp     for (j=0; j<26; j++) tmp += xsurf[i+j*Nsurf];
1272c71b3e2SJacob Faibussowitsch     PetscCheckFalse(PetscAbsScalar(tmp-1.0) > 1.e-10,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong Xsurf interpolation at i %D value %g",i,(double)PetscAbsScalar(tmp));
128064c8009SBarry Smith   }
129064c8009SBarry Smith #endif
130*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseRestoreArray(Xsurf,&xsurf));
131*5f80ce2aSJacob Faibussowitsch   /* CHKERRQ(MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD));*/
132064c8009SBarry Smith 
133064c8009SBarry Smith   /*
134064c8009SBarry Smith        I are the indices for all the needed vertices (in global numbering)
135064c8009SBarry Smith        Iint are the indices for the interior values, I surf for the surface values
1367dae84e0SHong Zhang             (This is just for the part of the global matrix obtained with MatCreateSubMatrix(), it
137aa219208SBarry Smith              is NOT the local DMDA ordering.)
138064c8009SBarry Smith        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
139064c8009SBarry Smith   */
140064c8009SBarry Smith #define Endpoint(a,start,b) (a == 0 || a == (b-1-start))
141*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc3(N,&II,Nint,&Iint,Nsurf,&Isurf));
142*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(Nint,&IIint,Nsurf,&IIsurf));
143064c8009SBarry Smith   for (k=0; k<p-kstart; k++) {
144064c8009SBarry Smith     for (j=0; j<n-jstart; j++) {
145064c8009SBarry Smith       for (i=0; i<m-istart; i++) {
146064c8009SBarry Smith         II[c++] = i + j*mwidth + k*mwidth*nwidth;
147064c8009SBarry Smith 
148064c8009SBarry Smith         if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) {
149064c8009SBarry Smith           IIint[cint]  = i + j*mwidth + k*mwidth*nwidth;
150064c8009SBarry Smith           Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
151064c8009SBarry Smith         } else {
152064c8009SBarry Smith           IIsurf[csurf]  = i + j*mwidth + k*mwidth*nwidth;
153064c8009SBarry Smith           Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
154064c8009SBarry Smith         }
155064c8009SBarry Smith       }
156064c8009SBarry Smith     }
157064c8009SBarry Smith   }
1582c71b3e2SJacob Faibussowitsch   PetscCheckFalse(c != N,PETSC_COMM_SELF,PETSC_ERR_PLIB,"c != N");
1592c71b3e2SJacob Faibussowitsch   PetscCheckFalse(cint != Nint,PETSC_COMM_SELF,PETSC_ERR_PLIB,"cint != Nint");
1602c71b3e2SJacob Faibussowitsch   PetscCheckFalse(csurf != Nsurf,PETSC_COMM_SELF,PETSC_ERR_PLIB,"csurf != Nsurf");
161*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalToGlobalMapping(da,&ltg));
162*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISLocalToGlobalMappingApply(ltg,N,II,II));
163*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint));
164*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf));
165*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectGetComm((PetscObject)da,&comm));
166*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(comm,N,II,PETSC_COPY_VALUES,&is));
167*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,PETSC_COPY_VALUES,&isint));
168*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,PETSC_COPY_VALUES,&issurf));
169*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree3(II,Iint,Isurf));
170064c8009SBarry Smith 
171*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder));
172064c8009SBarry Smith   A    = *Aholder;
173*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(Aholder));
174064c8009SBarry Smith 
175*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii));
176*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais));
177*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi));
178064c8009SBarry Smith 
179064c8009SBarry Smith   /*
180064c8009SBarry Smith      Solve for the interpolation onto the interior Xint
181064c8009SBarry Smith   */
182*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMatMult(Ais,Xsurf,MAT_INITIAL_MATRIX,PETSC_DETERMINE,&Xint_tmp));
183*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatScale(Xint_tmp,-1.0));
1848e722e36SBarry Smith   if (exotic->directSolve) {
185*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetFactor(Aii,MATSOLVERPETSC,MAT_FACTOR_LU,&iAii));
186*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatFactorInfoInitialize(&info));
187*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetOrdering(Aii,MATORDERINGND,&row,&col));
188*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatLUFactorSymbolic(iAii,Aii,row,col,&info));
189*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&row));
190*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&col));
191*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatLUFactorNumeric(iAii,Aii,&info));
192*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatMatSolve(iAii,Xint_tmp,Xint));
193*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&iAii));
1948e722e36SBarry Smith   } else {
1958e722e36SBarry Smith     Vec         b,x;
1968e722e36SBarry Smith     PetscScalar *xint_tmp;
197064c8009SBarry Smith 
198*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseGetArray(Xint,&xint));
199*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,NULL,&x));
200*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseGetArray(Xint_tmp,&xint_tmp));
201*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,NULL,&b));
202*5f80ce2aSJacob Faibussowitsch     CHKERRQ(KSPSetOperators(exotic->ksp,Aii,Aii));
2038e722e36SBarry Smith     for (i=0; i<26; i++) {
204*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecPlaceArray(x,xint+i*Nint));
205*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecPlaceArray(b,xint_tmp+i*Nint));
206*5f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPSolve(exotic->ksp,b,x));
207*5f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPCheckSolve(exotic->ksp,pc,x));
208*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecResetArray(x));
209*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecResetArray(b));
2108e722e36SBarry Smith     }
211*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseRestoreArray(Xint,&xint));
212*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseRestoreArray(Xint_tmp,&xint_tmp));
213*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(&x));
214*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(&b));
2158e722e36SBarry Smith   }
216*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Xint_tmp));
2178e722e36SBarry Smith 
2188e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
219*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseGetArrayRead(Xint,&rxint));
220064c8009SBarry Smith   for (i=0; i<Nint; i++) {
221064c8009SBarry Smith     tmp = 0.0;
2221683a169SBarry Smith     for (j=0; j<26; j++) tmp += rxint[i+j*Nint];
2232fa5cd67SKarl Rupp 
2242c71b3e2SJacob Faibussowitsch     PetscCheckFalse(PetscAbsScalar(tmp-1.0) > 1.e-10,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong Xint interpolation at i %D value %g",i,(double)PetscAbsScalar(tmp));
225064c8009SBarry Smith   }
226*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseRestoreArrayRead(Xint,&rxint));
227*5f80ce2aSJacob Faibussowitsch   /* CHKERRQ(MatView(Xint,PETSC_VIEWER_STDOUT_WORLD)); */
228064c8009SBarry Smith #endif
229064c8009SBarry Smith 
230064c8009SBarry Smith   /*         total vertices             total faces                                  total edges */
231064c8009SBarry 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);
232064c8009SBarry Smith 
233064c8009SBarry Smith   /*
234064c8009SBarry Smith       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
235064c8009SBarry Smith   */
236064c8009SBarry Smith   cnt = 0;
2372fa5cd67SKarl Rupp 
238064c8009SBarry Smith   gl[cnt++] = 0;  { gl[cnt++] = 1;} gl[cnt++] = m-istart-1;
239064c8009SBarry Smith   { gl[cnt++] = mwidth;  { gl[cnt++] = mwidth+1;} gl[cnt++] = mwidth + m-istart-1;}
240064c8009SBarry Smith   gl[cnt++] = mwidth*(n-jstart-1);  { gl[cnt++] = mwidth*(n-jstart-1)+1;} gl[cnt++] = mwidth*(n-jstart-1) + m-istart-1;
241064c8009SBarry Smith   {
242064c8009SBarry Smith     gl[cnt++] = mwidth*nwidth;  { gl[cnt++] = mwidth*nwidth+1;}  gl[cnt++] = mwidth*nwidth+ m-istart-1;
243064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;}
244064c8009SBarry 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;
245064c8009SBarry Smith   }
246064c8009SBarry 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;
247064c8009SBarry 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;}
248064c8009SBarry 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;
249064c8009SBarry Smith 
250064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
251064c8009SBarry Smith   /* convert that to global numbering and get them on all processes */
252*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISLocalToGlobalMappingApply(ltg,26,gl,gl));
253064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
254*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(26*mp*np*pp,&globals));
255*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Allgather(gl,26,MPIU_INT,globals,26,MPIU_INT,PetscObjectComm((PetscObject)da)));
256064c8009SBarry Smith 
257064c8009SBarry Smith   /* Number the coarse grid points from 0 to Ntotal */
258*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetSize(Aglobal,&Nt,NULL));
259*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTableCreate(Ntotal/3,Nt+1,&ht));
260064c8009SBarry Smith   for (i=0; i<26*mp*np*pp; i++) {
261*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscTableAddCount(ht,globals[i]+1));
262064c8009SBarry Smith   }
263*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTableGetCount(ht,&cnt));
2642c71b3e2SJacob Faibussowitsch   PetscCheckFalse(cnt != Ntotal,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Hash table size %D not equal to total number coarse grid points %D",cnt,Ntotal);
265*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(globals));
266064c8009SBarry Smith   for (i=0; i<26; i++) {
267*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscTableFind(ht,gl[i]+1,&gl[i]));
268064c8009SBarry Smith     gl[i]--;
269064c8009SBarry Smith   }
270*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTableDestroy(&ht));
271064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
272064c8009SBarry Smith 
273064c8009SBarry Smith   /* construct global interpolation matrix */
274*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetLocalSize(Aglobal,&Ng,NULL));
275064c8009SBarry Smith   if (reuse == MAT_INITIAL_MATRIX) {
276*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatCreateAIJ(PetscObjectComm((PetscObject)da),Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,NULL,Nint+Nsurf,NULL,P));
277064c8009SBarry Smith   } else {
278*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatZeroEntries(*P));
279064c8009SBarry Smith   }
280*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE));
281*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseGetArrayRead(Xint,&rxint));
282*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetValues(*P,Nint,IIint,26,gl,rxint,INSERT_VALUES));
283*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseRestoreArrayRead(Xint,&rxint));
284*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseGetArrayRead(Xsurf,&rxint));
285*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetValues(*P,Nsurf,IIsurf,26,gl,rxint,INSERT_VALUES));
286*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseRestoreArrayRead(Xsurf,&rxint));
287*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY));
288*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY));
289*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(IIint,IIsurf));
290064c8009SBarry Smith 
2918e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
292064c8009SBarry Smith   {
293064c8009SBarry Smith     Vec         x,y;
294064c8009SBarry Smith     PetscScalar *yy;
295*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCreateMPI(PetscObjectComm((PetscObject)da),Ng,PETSC_DETERMINE,&y));
296*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCreateMPI(PetscObjectComm((PetscObject)da),PETSC_DETERMINE,Ntotal,&x));
297*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecSet(x,1.0));
298*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatMult(*P,x,y));
299*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArray(y,&yy));
300064c8009SBarry Smith     for (i=0; i<Ng; i++) {
3012c71b3e2SJacob Faibussowitsch       PetscCheckFalse(PetscAbsScalar(yy[i]-1.0) > 1.e-10,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong p interpolation at i %D value %g",i,(double)PetscAbsScalar(yy[i]));
302064c8009SBarry Smith     }
303*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArray(y,&yy));
304*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(x));
305*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(y));
306064c8009SBarry Smith   }
307064c8009SBarry Smith #endif
308064c8009SBarry Smith 
309*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Aii));
310*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Ais));
311*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Asi));
312*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&A));
313*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&is));
314*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&isint));
315*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&issurf));
316*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Xint));
317*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Xsurf));
318064c8009SBarry Smith   PetscFunctionReturn(0);
319064c8009SBarry Smith }
320064c8009SBarry Smith 
321064c8009SBarry Smith /*
322aa219208SBarry Smith       DMDAGetFaceInterpolation - Gets the interpolation for a face based coarse space
323064c8009SBarry Smith 
324064c8009SBarry Smith */
325c0decd05SBarry Smith PetscErrorCode DMDAGetFaceInterpolation(PC pc,DM da,PC_Exotic *exotic,Mat Aglobal,MatReuse reuse,Mat *P)
326064c8009SBarry Smith {
327064c8009SBarry 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;
32828d20b34SBarry Smith   PetscInt               mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[6],*globals,Ng,*IIint,*IIsurf,Nt;
329064c8009SBarry Smith   Mat                    Xint, Xsurf,Xint_tmp;
330064c8009SBarry Smith   IS                     isint,issurf,is,row,col;
331064c8009SBarry Smith   ISLocalToGlobalMapping ltg;
332064c8009SBarry Smith   MPI_Comm               comm;
333064c8009SBarry Smith   Mat                    A,Aii,Ais,Asi,*Aholder,iAii;
334064c8009SBarry Smith   MatFactorInfo          info;
335064c8009SBarry Smith   PetscScalar            *xsurf,*xint;
3361683a169SBarry Smith   const PetscScalar      *rxint;
337064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
338064c8009SBarry Smith   PetscScalar            tmp;
339064c8009SBarry Smith #endif
340064c8009SBarry Smith   PetscTable             ht;
341064c8009SBarry Smith 
342064c8009SBarry Smith   PetscFunctionBegin;
343*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAGetInfo(da,&dim,NULL,NULL,NULL,&mp,&np,&pp,&dof,NULL,NULL,NULL,NULL,NULL));
3442c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dof != 1,PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only for single field problems");
3452c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dim != 3,PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Only coded for 3d problems");
346*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAGetCorners(da,NULL,NULL,NULL,&m,&n,&p));
347*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth));
348064c8009SBarry Smith   istart = istart ? -1 : 0;
349064c8009SBarry Smith   jstart = jstart ? -1 : 0;
350064c8009SBarry Smith   kstart = kstart ? -1 : 0;
351064c8009SBarry Smith 
352064c8009SBarry Smith   /*
353064c8009SBarry Smith     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
354064c8009SBarry Smith     to all the local degrees of freedom (this includes the vertices, edges and faces).
355064c8009SBarry Smith 
356064c8009SBarry Smith     Xint are the subset of the interpolation into the interior
357064c8009SBarry Smith 
358064c8009SBarry Smith     Xface are the interpolation onto faces but not into the interior
359064c8009SBarry Smith 
360064c8009SBarry Smith     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
361064c8009SBarry Smith                                       Xint
362064c8009SBarry Smith     Symbolically one could write P = (Xface) after interchanging the rows to match the natural ordering on the domain
363064c8009SBarry Smith                                       Xsurf
364064c8009SBarry Smith   */
365064c8009SBarry Smith   N     = (m - istart)*(n - jstart)*(p - kstart);
366064c8009SBarry Smith   Nint  = (m-2-istart)*(n-2-jstart)*(p-2-kstart);
367064c8009SBarry Smith   Nface = 2*((m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart));
368064c8009SBarry Smith   Nwire = 4*((m-2-istart) + (n-2-jstart) + (p-2-kstart)) + 8;
369064c8009SBarry Smith   Nsurf = Nface + Nwire;
370*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSeqDense(MPI_COMM_SELF,Nint,6,NULL,&Xint));
371*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSeqDense(MPI_COMM_SELF,Nsurf,6,NULL,&Xsurf));
372*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseGetArray(Xsurf,&xsurf));
373064c8009SBarry Smith 
374064c8009SBarry Smith   /*
375064c8009SBarry Smith      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
376064c8009SBarry Smith      Xsurf will be all zero (thus making the coarse matrix singular).
377064c8009SBarry Smith   */
3782c71b3e2SJacob Faibussowitsch   PetscCheckFalse(m-istart < 3,PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in X direction must be at least 3");
3792c71b3e2SJacob Faibussowitsch   PetscCheckFalse(n-jstart < 3,PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in Y direction must be at least 3");
3802c71b3e2SJacob Faibussowitsch   PetscCheckFalse(p-kstart < 3,PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of grid points per process in Z direction must be at least 3");
381064c8009SBarry Smith 
382064c8009SBarry Smith   cnt = 0;
3832fa5cd67SKarl Rupp   for (j=1; j<n-1-jstart; j++) {
3842fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 0*Nsurf] = 1;
385064c8009SBarry Smith   }
3862fa5cd67SKarl Rupp 
3872fa5cd67SKarl Rupp   for (k=1; k<p-1-kstart; k++) {
3882fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 1*Nsurf] = 1;
3892fa5cd67SKarl Rupp     for (j=1; j<n-1-jstart; j++) {
3902fa5cd67SKarl Rupp       xsurf[cnt++ + 2*Nsurf] = 1;
3912fa5cd67SKarl Rupp       /* these are the interior nodes */
3922fa5cd67SKarl Rupp       xsurf[cnt++ + 3*Nsurf] = 1;
3932fa5cd67SKarl Rupp     }
3942fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 4*Nsurf] = 1;
3952fa5cd67SKarl Rupp   }
3962fa5cd67SKarl Rupp   for (j=1;j<n-1-jstart;j++) {
3972fa5cd67SKarl Rupp     for (i=1; i<m-istart-1; i++) xsurf[cnt++ + 5*Nsurf] = 1;
3982fa5cd67SKarl Rupp   }
399064c8009SBarry Smith 
400064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
401064c8009SBarry Smith   for (i=0; i<Nsurf; i++) {
402064c8009SBarry Smith     tmp = 0.0;
4032fa5cd67SKarl Rupp     for (j=0; j<6; j++) tmp += xsurf[i+j*Nsurf];
4042fa5cd67SKarl Rupp 
4052c71b3e2SJacob Faibussowitsch     PetscCheckFalse(PetscAbsScalar(tmp-1.0) > 1.e-10,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong Xsurf interpolation at i %D value %g",i,(double)PetscAbsScalar(tmp));
406064c8009SBarry Smith   }
407064c8009SBarry Smith #endif
408*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseRestoreArray(Xsurf,&xsurf));
409*5f80ce2aSJacob Faibussowitsch   /* CHKERRQ(MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD));*/
410064c8009SBarry Smith 
411064c8009SBarry Smith   /*
412064c8009SBarry Smith        I are the indices for all the needed vertices (in global numbering)
413064c8009SBarry Smith        Iint are the indices for the interior values, I surf for the surface values
4147dae84e0SHong Zhang             (This is just for the part of the global matrix obtained with MatCreateSubMatrix(), it
415aa219208SBarry Smith              is NOT the local DMDA ordering.)
416064c8009SBarry Smith        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
417064c8009SBarry Smith   */
418064c8009SBarry Smith #define Endpoint(a,start,b) (a == 0 || a == (b-1-start))
419*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc3(N,&II,Nint,&Iint,Nsurf,&Isurf));
420*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(Nint,&IIint,Nsurf,&IIsurf));
421064c8009SBarry Smith   for (k=0; k<p-kstart; k++) {
422064c8009SBarry Smith     for (j=0; j<n-jstart; j++) {
423064c8009SBarry Smith       for (i=0; i<m-istart; i++) {
424064c8009SBarry Smith         II[c++] = i + j*mwidth + k*mwidth*nwidth;
425064c8009SBarry Smith 
426064c8009SBarry Smith         if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) {
427064c8009SBarry Smith           IIint[cint]  = i + j*mwidth + k*mwidth*nwidth;
428064c8009SBarry Smith           Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
429064c8009SBarry Smith         } else {
430064c8009SBarry Smith           IIsurf[csurf]  = i + j*mwidth + k*mwidth*nwidth;
431064c8009SBarry Smith           Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
432064c8009SBarry Smith         }
433064c8009SBarry Smith       }
434064c8009SBarry Smith     }
435064c8009SBarry Smith   }
4362c71b3e2SJacob Faibussowitsch   PetscCheckFalse(c != N,PETSC_COMM_SELF,PETSC_ERR_PLIB,"c != N");
4372c71b3e2SJacob Faibussowitsch   PetscCheckFalse(cint != Nint,PETSC_COMM_SELF,PETSC_ERR_PLIB,"cint != Nint");
4382c71b3e2SJacob Faibussowitsch   PetscCheckFalse(csurf != Nsurf,PETSC_COMM_SELF,PETSC_ERR_PLIB,"csurf != Nsurf");
439*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalToGlobalMapping(da,&ltg));
440*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISLocalToGlobalMappingApply(ltg,N,II,II));
441*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint));
442*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf));
443*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectGetComm((PetscObject)da,&comm));
444*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(comm,N,II,PETSC_COPY_VALUES,&is));
445*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,PETSC_COPY_VALUES,&isint));
446*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,PETSC_COPY_VALUES,&issurf));
447*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree3(II,Iint,Isurf));
448064c8009SBarry Smith 
449*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISSort(is));
450*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder));
451064c8009SBarry Smith   A    = *Aholder;
452*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(Aholder));
453064c8009SBarry Smith 
454*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii));
455*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais));
456*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi));
457064c8009SBarry Smith 
458064c8009SBarry Smith   /*
459064c8009SBarry Smith      Solve for the interpolation onto the interior Xint
460064c8009SBarry Smith   */
461*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatMatMult(Ais,Xsurf,MAT_INITIAL_MATRIX,PETSC_DETERMINE,&Xint_tmp));
462*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatScale(Xint_tmp,-1.0));
463064c8009SBarry Smith 
4648e722e36SBarry Smith   if (exotic->directSolve) {
465*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetFactor(Aii,MATSOLVERPETSC,MAT_FACTOR_LU,&iAii));
466*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatFactorInfoInitialize(&info));
467*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatGetOrdering(Aii,MATORDERINGND,&row,&col));
468*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatLUFactorSymbolic(iAii,Aii,row,col,&info));
469*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&row));
470*5f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&col));
471*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatLUFactorNumeric(iAii,Aii,&info));
472*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatMatSolve(iAii,Xint_tmp,Xint));
473*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&iAii));
474064c8009SBarry Smith   } else {
475064c8009SBarry Smith     Vec         b,x;
476064c8009SBarry Smith     PetscScalar *xint_tmp;
477064c8009SBarry Smith 
478*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseGetArray(Xint,&xint));
479*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,NULL,&x));
480*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseGetArray(Xint_tmp,&xint_tmp));
481*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCreateSeqWithArray(PETSC_COMM_SELF,1,Nint,NULL,&b));
482*5f80ce2aSJacob Faibussowitsch     CHKERRQ(KSPSetOperators(exotic->ksp,Aii,Aii));
483064c8009SBarry Smith     for (i=0; i<6; i++) {
484*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecPlaceArray(x,xint+i*Nint));
485*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecPlaceArray(b,xint_tmp+i*Nint));
486*5f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPSolve(exotic->ksp,b,x));
487*5f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPCheckSolve(exotic->ksp,pc,x));
488*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecResetArray(x));
489*5f80ce2aSJacob Faibussowitsch       CHKERRQ(VecResetArray(b));
490064c8009SBarry Smith     }
491*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseRestoreArray(Xint,&xint));
492*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDenseRestoreArray(Xint_tmp,&xint_tmp));
493*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(&x));
494*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(&b));
495064c8009SBarry Smith   }
496*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Xint_tmp));
497064c8009SBarry Smith 
498064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
499*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseGetArrayRead(Xint,&rxint));
500064c8009SBarry Smith   for (i=0; i<Nint; i++) {
501064c8009SBarry Smith     tmp = 0.0;
5021683a169SBarry Smith     for (j=0; j<6; j++) tmp += rxint[i+j*Nint];
5032fa5cd67SKarl Rupp 
5042c71b3e2SJacob Faibussowitsch     PetscCheckFalse(PetscAbsScalar(tmp-1.0) > 1.e-10,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong Xint interpolation at i %D value %g",i,(double)PetscAbsScalar(tmp));
505064c8009SBarry Smith   }
506*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseRestoreArrayRead(Xint,&rxint));
507*5f80ce2aSJacob Faibussowitsch   /* CHKERRQ(MatView(Xint,PETSC_VIEWER_STDOUT_WORLD)); */
508064c8009SBarry Smith #endif
509064c8009SBarry Smith 
510064c8009SBarry Smith   /*         total faces    */
511064c8009SBarry Smith   Ntotal =  mp*np*(pp+1) + mp*pp*(np+1) + np*pp*(mp+1);
512064c8009SBarry Smith 
513064c8009SBarry Smith   /*
514064c8009SBarry Smith       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
515064c8009SBarry Smith   */
516064c8009SBarry Smith   cnt = 0;
517064c8009SBarry Smith   { gl[cnt++] = mwidth+1;}
518064c8009SBarry Smith   {
519064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth+1;}
520064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;}
521064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth+mwidth*(n-jstart-1)+1;}
522064c8009SBarry Smith   }
523064c8009SBarry Smith   { gl[cnt++] = mwidth*nwidth*(p-kstart-1) + mwidth+1;}
524064c8009SBarry Smith 
525064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
526064c8009SBarry Smith   /* convert that to global numbering and get them on all processes */
527*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISLocalToGlobalMappingApply(ltg,6,gl,gl));
528064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
529*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(6*mp*np*pp,&globals));
530*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Allgather(gl,6,MPIU_INT,globals,6,MPIU_INT,PetscObjectComm((PetscObject)da)));
531064c8009SBarry Smith 
532064c8009SBarry Smith   /* Number the coarse grid points from 0 to Ntotal */
533*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetSize(Aglobal,&Nt,NULL));
534*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTableCreate(Ntotal/3,Nt+1,&ht));
535064c8009SBarry Smith   for (i=0; i<6*mp*np*pp; i++) {
536*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscTableAddCount(ht,globals[i]+1));
537064c8009SBarry Smith   }
538*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTableGetCount(ht,&cnt));
5392c71b3e2SJacob Faibussowitsch   PetscCheckFalse(cnt != Ntotal,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Hash table size %D not equal to total number coarse grid points %D",cnt,Ntotal);
540*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(globals));
541064c8009SBarry Smith   for (i=0; i<6; i++) {
542*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscTableFind(ht,gl[i]+1,&gl[i]));
543064c8009SBarry Smith     gl[i]--;
544064c8009SBarry Smith   }
545*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTableDestroy(&ht));
546064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
547064c8009SBarry Smith 
548064c8009SBarry Smith   /* construct global interpolation matrix */
549*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatGetLocalSize(Aglobal,&Ng,NULL));
550064c8009SBarry Smith   if (reuse == MAT_INITIAL_MATRIX) {
551*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatCreateAIJ(PetscObjectComm((PetscObject)da),Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,NULL,Nint,NULL,P));
552064c8009SBarry Smith   } else {
553*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatZeroEntries(*P));
554064c8009SBarry Smith   }
555*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE));
556*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseGetArrayRead(Xint,&rxint));
557*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetValues(*P,Nint,IIint,6,gl,rxint,INSERT_VALUES));
558*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseRestoreArrayRead(Xint,&rxint));
559*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseGetArrayRead(Xsurf,&rxint));
560*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetValues(*P,Nsurf,IIsurf,6,gl,rxint,INSERT_VALUES));
561*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDenseRestoreArrayRead(Xsurf,&rxint));
562*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY));
563*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY));
564*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(IIint,IIsurf));
565064c8009SBarry Smith 
566064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
567064c8009SBarry Smith   {
568064c8009SBarry Smith     Vec         x,y;
569064c8009SBarry Smith     PetscScalar *yy;
570*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCreateMPI(PetscObjectComm((PetscObject)da),Ng,PETSC_DETERMINE,&y));
571*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCreateMPI(PetscObjectComm((PetscObject)da),PETSC_DETERMINE,Ntotal,&x));
572*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecSet(x,1.0));
573*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatMult(*P,x,y));
574*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArray(y,&yy));
575064c8009SBarry Smith     for (i=0; i<Ng; i++) {
5762c71b3e2SJacob Faibussowitsch       PetscCheckFalse(PetscAbsScalar(yy[i]-1.0) > 1.e-10,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong p interpolation at i %D value %g",i,(double)PetscAbsScalar(yy[i]));
577064c8009SBarry Smith     }
578*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArray(y,&yy));
579*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(x));
580*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecDestroy(y));
581064c8009SBarry Smith   }
582064c8009SBarry Smith #endif
583064c8009SBarry Smith 
584*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Aii));
585*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Ais));
586*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Asi));
587*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&A));
588*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&is));
589*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&isint));
590*5f80ce2aSJacob Faibussowitsch   CHKERRQ(ISDestroy(&issurf));
591*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Xint));
592*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&Xsurf));
593064c8009SBarry Smith   PetscFunctionReturn(0);
594064c8009SBarry Smith }
595174b6946SBarry Smith 
5967233f9f0SBarry Smith /*@
5977233f9f0SBarry Smith    PCExoticSetType - Sets the type of coarse grid interpolation to use
5987233f9f0SBarry Smith 
5993f9fe445SBarry Smith    Logically Collective on PC
6007233f9f0SBarry Smith 
6017233f9f0SBarry Smith    Input Parameters:
6027233f9f0SBarry Smith +  pc - the preconditioner context
6037233f9f0SBarry Smith -  type - either PC_EXOTIC_FACE or PC_EXOTIC_WIREBASKET (defaults to face)
6047233f9f0SBarry Smith 
60595452b02SPatrick Sanan    Notes:
60695452b02SPatrick Sanan     The face based interpolation has 1 degree of freedom per face and ignores the
607563e08c6SBarry Smith      edge and vertex values completely in the coarse problem. For any seven point
608563e08c6SBarry Smith      stencil the interpolation of a constant on all faces into the interior is that constant.
609563e08c6SBarry Smith 
610563e08c6SBarry Smith      The wirebasket interpolation has 1 degree of freedom per vertex, per edge and
611563e08c6SBarry Smith      per face. A constant on the subdomain boundary is interpolated as that constant
612563e08c6SBarry Smith      in the interior of the domain.
613563e08c6SBarry Smith 
614563e08c6SBarry Smith      The coarse grid matrix is obtained via the Galerkin computation A_c = R A R^T, hence
615563e08c6SBarry Smith      if A is nonsingular A_c is also nonsingular.
616563e08c6SBarry Smith 
617563e08c6SBarry Smith      Both interpolations are suitable for only scalar problems.
618563e08c6SBarry Smith 
6197233f9f0SBarry Smith    Level: intermediate
6207233f9f0SBarry Smith 
6217233f9f0SBarry Smith .seealso: PCEXOTIC, PCExoticType()
6227233f9f0SBarry Smith @*/
6237087cfbeSBarry Smith PetscErrorCode  PCExoticSetType(PC pc,PCExoticType type)
6247233f9f0SBarry Smith {
6257233f9f0SBarry Smith   PetscFunctionBegin;
6260700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
627c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc,type,2);
628*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscTryMethod(pc,"PCExoticSetType_C",(PC,PCExoticType),(pc,type)));
6297233f9f0SBarry Smith   PetscFunctionReturn(0);
6307233f9f0SBarry Smith }
6317233f9f0SBarry Smith 
632f7a08781SBarry Smith static PetscErrorCode  PCExoticSetType_Exotic(PC pc,PCExoticType type)
6337233f9f0SBarry Smith {
634f3fbd535SBarry Smith   PC_MG     *mg  = (PC_MG*)pc->data;
63531567311SBarry Smith   PC_Exotic *ctx = (PC_Exotic*) mg->innerctx;
6367233f9f0SBarry Smith 
6377233f9f0SBarry Smith   PetscFunctionBegin;
6387233f9f0SBarry Smith   ctx->type = type;
6397233f9f0SBarry Smith   PetscFunctionReturn(0);
6407233f9f0SBarry Smith }
6417233f9f0SBarry Smith 
6427233f9f0SBarry Smith PetscErrorCode PCSetUp_Exotic(PC pc)
643174b6946SBarry Smith {
64496bdf778SBarry Smith   Mat            A;
645f3fbd535SBarry Smith   PC_MG          *mg   = (PC_MG*)pc->data;
64631567311SBarry Smith   PC_Exotic      *ex   = (PC_Exotic*) mg->innerctx;
64796bdf778SBarry Smith   MatReuse       reuse = (ex->P) ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
648174b6946SBarry Smith 
649174b6946SBarry Smith   PetscFunctionBegin;
6502c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!pc->dm,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Need to call PCSetDM() before using this PC");
651*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCGetOperators(pc,NULL,&A));
6527233f9f0SBarry Smith   if (ex->type == PC_EXOTIC_FACE) {
653*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMDAGetFaceInterpolation(pc,pc->dm,ex,A,reuse,&ex->P));
6547233f9f0SBarry Smith   } else if (ex->type == PC_EXOTIC_WIREBASKET) {
655*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMDAGetWireBasketInterpolation(pc,pc->dm,ex,A,reuse,&ex->P));
65698921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Unknown exotic coarse space %d",ex->type);
657*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCMGSetInterpolation(pc,1,ex->P));
658d0660788SBarry Smith   /* if PC has attached DM we must remove it or the PCMG will use it to compute incorrect sized vectors and interpolations */
659*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCSetDM(pc,NULL));
660*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCSetUp_MG(pc));
661174b6946SBarry Smith   PetscFunctionReturn(0);
662174b6946SBarry Smith }
663174b6946SBarry Smith 
6647233f9f0SBarry Smith PetscErrorCode PCDestroy_Exotic(PC pc)
665174b6946SBarry Smith {
666f3fbd535SBarry Smith   PC_MG          *mg  = (PC_MG*)pc->data;
66731567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
668174b6946SBarry Smith 
669174b6946SBarry Smith   PetscFunctionBegin;
670*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&ctx->P));
671*5f80ce2aSJacob Faibussowitsch   CHKERRQ(KSPDestroy(&ctx->ksp));
672*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(ctx));
673*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCDestroy_MG(pc));
674174b6946SBarry Smith   PetscFunctionReturn(0);
675174b6946SBarry Smith }
676174b6946SBarry Smith 
6777233f9f0SBarry Smith PetscErrorCode PCView_Exotic(PC pc,PetscViewer viewer)
6787233f9f0SBarry Smith {
679f3fbd535SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
680ace3abfcSBarry Smith   PetscBool      iascii;
68131567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
6827233f9f0SBarry Smith 
6837233f9f0SBarry Smith   PetscFunctionBegin;
684*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
6857233f9f0SBarry Smith   if (iascii) {
686*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerASCIIPrintf(viewer,"    Exotic type = %s\n",PCExoticTypes[ctx->type]));
6878e722e36SBarry Smith     if (ctx->directSolve) {
688*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPrintf(viewer,"      Using direct solver to construct interpolation\n"));
6898e722e36SBarry Smith     } else {
6908e722e36SBarry Smith       PetscViewer sviewer;
6918e722e36SBarry Smith       PetscMPIInt rank;
6928e722e36SBarry Smith 
693*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPrintf(viewer,"      Using iterative solver to construct interpolation\n"));
694*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPushTab(viewer));
695*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPushTab(viewer));  /* should not need to push this twice? */
696*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
697*5f80ce2aSJacob Faibussowitsch       CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc),&rank));
698dd400576SPatrick Sanan       if (rank == 0) {
699*5f80ce2aSJacob Faibussowitsch         CHKERRQ(KSPView(ctx->ksp,sviewer));
7008e722e36SBarry Smith       }
701*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer));
702*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPopTab(viewer));
703*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerASCIIPopTab(viewer));
7048e722e36SBarry Smith     }
7057233f9f0SBarry Smith   }
706*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCView_MG(pc,viewer));
7077233f9f0SBarry Smith   PetscFunctionReturn(0);
7087233f9f0SBarry Smith }
7097233f9f0SBarry Smith 
7104416b707SBarry Smith PetscErrorCode PCSetFromOptions_Exotic(PetscOptionItems *PetscOptionsObject,PC pc)
7117233f9f0SBarry Smith {
712ace3abfcSBarry Smith   PetscBool      flg;
713f3fbd535SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
7147233f9f0SBarry Smith   PCExoticType   mgctype;
71531567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
7167233f9f0SBarry Smith 
7177233f9f0SBarry Smith   PetscFunctionBegin;
718*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsHead(PetscOptionsObject,"Exotic coarse space options"));
719*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsEnum("-pc_exotic_type","face or wirebasket","PCExoticSetType",PCExoticTypes,(PetscEnum)ctx->type,(PetscEnum*)&mgctype,&flg));
7207233f9f0SBarry Smith   if (flg) {
721*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PCExoticSetType(pc,mgctype));
7227233f9f0SBarry Smith   }
723*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsBool("-pc_exotic_direct_solver","use direct solver to construct interpolation","None",ctx->directSolve,&ctx->directSolve,NULL));
7248e722e36SBarry Smith   if (!ctx->directSolve) {
7258e722e36SBarry Smith     if (!ctx->ksp) {
7268e722e36SBarry Smith       const char *prefix;
727*5f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPCreate(PETSC_COMM_SELF,&ctx->ksp));
728*5f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPSetErrorIfNotConverged(ctx->ksp,pc->erroriffailure));
729*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectIncrementTabLevel((PetscObject)ctx->ksp,(PetscObject)pc,1));
730*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscLogObjectParent((PetscObject)pc,(PetscObject)ctx->ksp));
731*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PCGetOptionsPrefix(pc,&prefix));
732*5f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPSetOptionsPrefix(ctx->ksp,prefix));
733*5f80ce2aSJacob Faibussowitsch       CHKERRQ(KSPAppendOptionsPrefix(ctx->ksp,"exotic_"));
7348e722e36SBarry Smith     }
735*5f80ce2aSJacob Faibussowitsch     CHKERRQ(KSPSetFromOptions(ctx->ksp));
7368e722e36SBarry Smith   }
737*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsTail());
7387233f9f0SBarry Smith   PetscFunctionReturn(0);
7397233f9f0SBarry Smith }
7407233f9f0SBarry Smith 
741174b6946SBarry Smith /*MC
7427233f9f0SBarry Smith      PCEXOTIC - Two level overlapping Schwarz preconditioner with exotic (non-standard) coarse grid spaces
743174b6946SBarry Smith 
7447233f9f0SBarry Smith      This uses the PCMG infrastructure restricted to two levels and the face and wirebasket based coarse
74524c3aa18SBarry Smith    grid spaces.
74624c3aa18SBarry Smith 
74795452b02SPatrick Sanan    Notes:
74895452b02SPatrick Sanan     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
74924c3aa18SBarry Smith 
75096a0c994SBarry Smith    References:
751606c0280SSatish Balay +  * - These coarse grid spaces originate in the work of Bramble, Pasciak  and Schatz, "The Construction
75296a0c994SBarry Smith    of Preconditioners for Elliptic Problems by Substructing IV", Mathematics of Computation, volume 53, 1989.
753606c0280SSatish Balay .  * - They were generalized slightly in "Domain Decomposition Method for Linear Elasticity", Ph. D. thesis, Barry Smith,
7544f02bc6aSBarry Smith    New York University, 1990.
755606c0280SSatish Balay .  * - They were then explored in great detail in Dryja, Smith, Widlund, "Schwarz Analysis
7563b65e785SBarry Smith    of Iterative Substructuring Methods for Elliptic Problems in Three Dimensions, SIAM Journal on Numerical
75796a0c994SBarry Smith    Analysis, volume 31. 1994. These were developed in the context of iterative substructuring preconditioners.
758606c0280SSatish Balay .  * - They were then ingeniously applied as coarse grid spaces for overlapping Schwarz methods by Dohrmann and Widlund.
7593b65e785SBarry Smith    They refer to them as GDSW (generalized Dryja, Smith, Widlund preconditioners). See, for example,
7603b65e785SBarry Smith    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Extending theory for domain decomposition algorithms to irregular subdomains. In Ulrich Langer, Marco
7613b65e785SBarry Smith    Discacciati, David Keyes, Olof Widlund, and Walter Zulehner, editors, Proceedings
7623b65e785SBarry Smith    of the 17th International Conference on Domain Decomposition Methods in
76396a0c994SBarry Smith    Science and Engineering, held in Strobl, Austria, 2006, number 60 in
76496a0c994SBarry Smith    Springer Verlag, Lecture Notes in Computational Science and Engineering, 2007.
765606c0280SSatish Balay .  * -  Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. A family of energy minimizing coarse spaces for overlapping Schwarz preconditioners. In Ulrich Langer,
7663b65e785SBarry Smith    Marco Discacciati, David Keyes, Olof Widlund, and Walter Zulehner, editors, Proceedings
7673b65e785SBarry Smith    of the 17th International Conference on Domain Decomposition Methods
76896a0c994SBarry Smith    in Science and Engineering, held in Strobl, Austria, 2006, number 60 in
76996a0c994SBarry Smith    Springer Verlag, Lecture Notes in Computational Science and Engineering, 2007
770606c0280SSatish Balay .  * - Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Domain decomposition
7713b65e785SBarry Smith    for less regular subdomains: Overlapping Schwarz in two dimensions. SIAM J.
77296a0c994SBarry Smith    Numer. Anal., 46(4), 2008.
773606c0280SSatish Balay -  * - Clark R. Dohrmann and Olof B. Widlund. An overlapping Schwarz
7743b65e785SBarry Smith    algorithm for almost incompressible elasticity. Technical Report
77596a0c994SBarry Smith    TR2008 912, Department of Computer Science, Courant Institute
7763b65e785SBarry Smith    of Mathematical Sciences, New York University, May 2008. URL:
7777233f9f0SBarry Smith 
7787233f9f0SBarry Smith    Options Database: The usual PCMG options are supported, such as -mg_levels_pc_type <type> -mg_coarse_pc_type <type>
7797233f9f0SBarry Smith       -pc_mg_type <type>
7807233f9f0SBarry Smith 
78125a35f6fSSatish Balay    Level: advanced
782174b6946SBarry Smith 
7836c699258SBarry Smith .seealso:  PCMG, PCSetDM(), PCExoticType, PCExoticSetType()
784174b6946SBarry Smith M*/
785174b6946SBarry Smith 
7868cc058d9SJed Brown PETSC_EXTERN PetscErrorCode PCCreate_Exotic(PC pc)
787174b6946SBarry Smith {
7887233f9f0SBarry Smith   PC_Exotic      *ex;
789f3fbd535SBarry Smith   PC_MG          *mg;
790174b6946SBarry Smith 
791174b6946SBarry Smith   PetscFunctionBegin;
792f91d8e95SBarry Smith   /* if type was previously mg; must manually destroy it because call to PCSetType(pc,PCMG) will not destroy it */
7932fa5cd67SKarl Rupp   if (pc->ops->destroy) {
794*5f80ce2aSJacob Faibussowitsch     CHKERRQ((*pc->ops->destroy)(pc));
7950a545947SLisandro Dalcin     pc->data = NULL;
7962fa5cd67SKarl Rupp   }
797*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(((PetscObject)pc)->type_name));
7980a545947SLisandro Dalcin   ((PetscObject)pc)->type_name = NULL;
799f91d8e95SBarry Smith 
800*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCSetType(pc,PCMG));
801*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCMGSetLevels(pc,2,NULL));
802*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PCMGSetGalerkin(pc,PC_MG_GALERKIN_PMAT));
803*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscNew(&ex)); \
8047233f9f0SBarry Smith   ex->type     = PC_EXOTIC_FACE;
805f3fbd535SBarry Smith   mg           = (PC_MG*) pc->data;
80631567311SBarry Smith   mg->innerctx = ex;
8077233f9f0SBarry Smith 
8087233f9f0SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_Exotic;
8097233f9f0SBarry Smith   pc->ops->view           = PCView_Exotic;
8107233f9f0SBarry Smith   pc->ops->destroy        = PCDestroy_Exotic;
8116c699258SBarry Smith   pc->ops->setup          = PCSetUp_Exotic;
8122fa5cd67SKarl Rupp 
813*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCExoticSetType_C",PCExoticSetType_Exotic));
814174b6946SBarry Smith   PetscFunctionReturn(0);
815174b6946SBarry Smith }
816