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