xref: /petsc/src/ksp/pc/impls/wb/wb.c (revision 0700a8246d308f50502909ba325e6169d3ee27eb)
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 
98e722e36SBarry Smith typedef struct {
108e722e36SBarry Smith   PCExoticType type;
118e722e36SBarry Smith   Mat          P;            /* the constructed interpolation matrix */
128e722e36SBarry Smith   PetscTruth   directSolve;  /* use direct LU factorization to construct interpolation */
138e722e36SBarry Smith   KSP          ksp;
148e722e36SBarry Smith } PC_Exotic;
15174b6946SBarry Smith 
168e722e36SBarry Smith const char *PCExoticTypes[] = {"face","wirebasket","PCExoticType","PC_Exotic",0};
17064c8009SBarry Smith 
18064c8009SBarry Smith 
19064c8009SBarry Smith #undef __FUNCT__
20064c8009SBarry Smith #define __FUNCT__ "DAGetWireBasketInterpolation"
21064c8009SBarry Smith /*
22064c8009SBarry Smith       DAGetWireBasketInterpolation - Gets the interpolation for a wirebasket based coarse space
23064c8009SBarry Smith 
24064c8009SBarry Smith */
256c699258SBarry Smith PetscErrorCode DAGetWireBasketInterpolation(DA da,PC_Exotic *exotic,Mat Aglobal,MatReuse reuse,Mat *P)
26064c8009SBarry Smith {
27064c8009SBarry Smith   PetscErrorCode         ierr;
28064c8009SBarry 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;
29064c8009SBarry Smith   PetscInt               mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[26],*globals,Ng,*IIint,*IIsurf;
30064c8009SBarry Smith   Mat                    Xint, Xsurf,Xint_tmp;
31064c8009SBarry Smith   IS                     isint,issurf,is,row,col;
32064c8009SBarry Smith   ISLocalToGlobalMapping ltg;
33064c8009SBarry Smith   MPI_Comm               comm;
34064c8009SBarry Smith   Mat                    A,Aii,Ais,Asi,*Aholder,iAii;
35064c8009SBarry Smith   MatFactorInfo          info;
36064c8009SBarry Smith   PetscScalar            *xsurf,*xint;
378e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
38064c8009SBarry Smith   PetscScalar            tmp;
39064c8009SBarry Smith #endif
40064c8009SBarry Smith   PetscTable             ht;
41064c8009SBarry Smith 
42064c8009SBarry Smith   PetscFunctionBegin;
43064c8009SBarry Smith   ierr = DAGetInfo(da,&dim,0,0,0,&mp,&np,&pp,&dof,0,0,0);CHKERRQ(ierr);
44064c8009SBarry Smith   if (dof != 1) SETERRQ(PETSC_ERR_SUP,"Only for single field problems");
45064c8009SBarry Smith   if (dim != 3) SETERRQ(PETSC_ERR_SUP,"Only coded for 3d problems");
46064c8009SBarry Smith   ierr = DAGetCorners(da,0,0,0,&m,&n,&p);CHKERRQ(ierr);
47064c8009SBarry Smith   ierr = DAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth);CHKERRQ(ierr);
48064c8009SBarry Smith   istart = istart ? -1 : 0;
49064c8009SBarry Smith   jstart = jstart ? -1 : 0;
50064c8009SBarry Smith   kstart = kstart ? -1 : 0;
51064c8009SBarry Smith 
52064c8009SBarry Smith   /*
53064c8009SBarry Smith     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
54064c8009SBarry Smith     to all the local degrees of freedom (this includes the vertices, edges and faces).
55064c8009SBarry Smith 
56064c8009SBarry Smith     Xint are the subset of the interpolation into the interior
57064c8009SBarry Smith 
58064c8009SBarry Smith     Xface are the interpolation onto faces but not into the interior
59064c8009SBarry Smith 
60064c8009SBarry Smith     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
61064c8009SBarry Smith                                         Xint
62064c8009SBarry Smith     Symbolically one could write P = (  Xface  ) after interchanging the rows to match the natural ordering on the domain
63064c8009SBarry Smith                                         Xsurf
64064c8009SBarry Smith   */
65064c8009SBarry Smith   N     = (m - istart)*(n - jstart)*(p - kstart);
66064c8009SBarry Smith   Nint  = (m-2-istart)*(n-2-jstart)*(p-2-kstart);
67064c8009SBarry Smith   Nface = 2*( (m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart) );
68064c8009SBarry Smith   Nwire = 4*( (m-2-istart) + (n-2-jstart) + (p-2-kstart) ) + 8;
69064c8009SBarry Smith   Nsurf = Nface + Nwire;
70064c8009SBarry Smith   ierr = MatCreateSeqDense(MPI_COMM_SELF,Nint,26,PETSC_NULL,&Xint);CHKERRQ(ierr);
71064c8009SBarry Smith   ierr = MatCreateSeqDense(MPI_COMM_SELF,Nsurf,26,PETSC_NULL,&Xsurf);CHKERRQ(ierr);
72064c8009SBarry Smith   ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
73064c8009SBarry Smith 
74064c8009SBarry Smith   /*
75064c8009SBarry Smith      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
76064c8009SBarry Smith      Xsurf will be all zero (thus making the coarse matrix singular).
77064c8009SBarry Smith   */
78064c8009SBarry Smith   if (m-istart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in X direction must be at least 3");
79064c8009SBarry Smith   if (n-jstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Y direction must be at least 3");
80064c8009SBarry Smith   if (p-kstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Z direction must be at least 3");
81064c8009SBarry Smith 
82064c8009SBarry Smith   cnt = 0;
83064c8009SBarry Smith   xsurf[cnt++] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + Nsurf] = 1;} xsurf[cnt++ + 2*Nsurf] = 1;
84064c8009SBarry 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;}
85064c8009SBarry Smith   xsurf[cnt++ + 6*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 7*Nsurf] = 1;} xsurf[cnt++ + 8*Nsurf] = 1;
86064c8009SBarry Smith   for (k=1;k<p-1-kstart;k++) {
87064c8009SBarry Smith     xsurf[cnt++ + 9*Nsurf] = 1;  for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 10*Nsurf] = 1;}  xsurf[cnt++ + 11*Nsurf] = 1;
88064c8009SBarry Smith     for (j=1;j<n-1-jstart;j++) { xsurf[cnt++ + 12*Nsurf] = 1; /* these are the interior nodes */ xsurf[cnt++ + 13*Nsurf] = 1;}
89064c8009SBarry Smith     xsurf[cnt++ + 14*Nsurf] = 1;  for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 15*Nsurf] = 1;} xsurf[cnt++ + 16*Nsurf] = 1;
90064c8009SBarry Smith   }
91064c8009SBarry Smith   xsurf[cnt++ + 17*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 18*Nsurf] = 1;} xsurf[cnt++ + 19*Nsurf] = 1;
92064c8009SBarry 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;}
93064c8009SBarry Smith   xsurf[cnt++ + 23*Nsurf] = 1; for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 24*Nsurf] = 1;} xsurf[cnt++ + 25*Nsurf] = 1;
94064c8009SBarry Smith 
958e722e36SBarry Smith   /* interpolations only sum to 1 when using direct solver */
968e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
97064c8009SBarry Smith   for (i=0; i<Nsurf; i++) {
98064c8009SBarry Smith     tmp = 0.0;
99064c8009SBarry Smith     for (j=0; j<26; j++) {
100064c8009SBarry Smith       tmp += xsurf[i+j*Nsurf];
101064c8009SBarry Smith     }
102064c8009SBarry Smith     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xsurf interpolation at i %D value %G",i,PetscAbsScalar(tmp));
103064c8009SBarry Smith   }
104064c8009SBarry Smith #endif
105064c8009SBarry Smith   ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
106064c8009SBarry Smith   /* ierr = MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);*/
107064c8009SBarry Smith 
108064c8009SBarry Smith 
109064c8009SBarry Smith   /*
110064c8009SBarry Smith        I are the indices for all the needed vertices (in global numbering)
111064c8009SBarry Smith        Iint are the indices for the interior values, I surf for the surface values
112064c8009SBarry Smith             (This is just for the part of the global matrix obtained with MatGetSubMatrix(), it
113064c8009SBarry Smith              is NOT the local DA ordering.)
114064c8009SBarry Smith        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
115064c8009SBarry Smith   */
116064c8009SBarry Smith #define Endpoint(a,start,b) (a == 0 || a == (b-1-start))
117064c8009SBarry Smith   ierr = PetscMalloc3(N,PetscInt,&II,Nint,PetscInt,&Iint,Nsurf,PetscInt,&Isurf);CHKERRQ(ierr);
118064c8009SBarry Smith   ierr = PetscMalloc2(Nint,PetscInt,&IIint,Nsurf,PetscInt,&IIsurf);CHKERRQ(ierr);
119064c8009SBarry Smith   for (k=0; k<p-kstart; k++) {
120064c8009SBarry Smith     for (j=0; j<n-jstart; j++) {
121064c8009SBarry Smith       for (i=0; i<m-istart; i++) {
122064c8009SBarry Smith         II[c++] = i + j*mwidth + k*mwidth*nwidth;
123064c8009SBarry Smith 
124064c8009SBarry Smith         if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) {
125064c8009SBarry Smith           IIint[cint]  = i + j*mwidth + k*mwidth*nwidth;
126064c8009SBarry Smith           Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
127064c8009SBarry Smith         } else {
128064c8009SBarry Smith           IIsurf[csurf]  = i + j*mwidth + k*mwidth*nwidth;
129064c8009SBarry Smith           Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
130064c8009SBarry Smith         }
131064c8009SBarry Smith       }
132064c8009SBarry Smith     }
133064c8009SBarry Smith   }
134064c8009SBarry Smith   if (c != N) SETERRQ(PETSC_ERR_PLIB,"c != N");
135064c8009SBarry Smith   if (cint != Nint) SETERRQ(PETSC_ERR_PLIB,"cint != Nint");
136064c8009SBarry Smith   if (csurf != Nsurf) SETERRQ(PETSC_ERR_PLIB,"csurf != Nsurf");
137064c8009SBarry Smith   ierr = DAGetISLocalToGlobalMapping(da,&ltg);CHKERRQ(ierr);
138064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,N,II,II);CHKERRQ(ierr);
139064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint);CHKERRQ(ierr);
140064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf);CHKERRQ(ierr);
141064c8009SBarry Smith   ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr);
142064c8009SBarry Smith   ierr = ISCreateGeneral(comm,N,II,&is);CHKERRQ(ierr);
143064c8009SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,&isint);CHKERRQ(ierr);
144064c8009SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,&issurf);CHKERRQ(ierr);
145064c8009SBarry Smith   ierr = PetscFree3(II,Iint,Isurf);CHKERRQ(ierr);
146064c8009SBarry Smith 
147064c8009SBarry Smith   ierr = MatGetSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder);CHKERRQ(ierr);
148064c8009SBarry Smith   A    = *Aholder;
149064c8009SBarry Smith   ierr = PetscFree(Aholder);CHKERRQ(ierr);
150064c8009SBarry Smith 
151064c8009SBarry Smith   ierr = MatGetSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii);CHKERRQ(ierr);
152064c8009SBarry Smith   ierr = MatGetSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais);CHKERRQ(ierr);
153064c8009SBarry Smith   ierr = MatGetSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi);CHKERRQ(ierr);
154064c8009SBarry Smith 
155064c8009SBarry Smith   /*
156064c8009SBarry Smith      Solve for the interpolation onto the interior Xint
157064c8009SBarry Smith   */
1588e722e36SBarry Smith   ierr = MatDuplicate(Xint,MAT_DO_NOT_COPY_VALUES,&Xint_tmp);CHKERRQ(ierr);
1598e722e36SBarry Smith   ierr = MatMatMult(Ais,Xsurf,MAT_REUSE_MATRIX,PETSC_DETERMINE,&Xint_tmp);CHKERRQ(ierr);
1608e722e36SBarry Smith   ierr = MatScale(Xint_tmp,-1.0);CHKERRQ(ierr);
1618e722e36SBarry Smith   if (exotic->directSolve) {
162064c8009SBarry Smith     ierr = MatGetFactor(Aii,MAT_SOLVER_PETSC,MAT_FACTOR_LU,&iAii);CHKERRQ(ierr);
163064c8009SBarry Smith     ierr = MatFactorInfoInitialize(&info);CHKERRQ(ierr);
164064c8009SBarry Smith     ierr = MatGetOrdering(Aii,MATORDERING_ND,&row,&col);CHKERRQ(ierr);
165064c8009SBarry Smith     ierr = MatLUFactorSymbolic(iAii,Aii,row,col,&info);CHKERRQ(ierr);
166064c8009SBarry Smith     ierr = ISDestroy(row);CHKERRQ(ierr);
167064c8009SBarry Smith     ierr = ISDestroy(col);CHKERRQ(ierr);
168064c8009SBarry Smith     ierr = MatLUFactorNumeric(iAii,Aii,&info);CHKERRQ(ierr);
169064c8009SBarry Smith     ierr = MatMatSolve(iAii,Xint_tmp,Xint);CHKERRQ(ierr);
170064c8009SBarry Smith     ierr = MatDestroy(iAii);CHKERRQ(ierr);
1718e722e36SBarry Smith   } else {
1728e722e36SBarry Smith     Vec         b,x;
1738e722e36SBarry Smith     PetscScalar *xint_tmp;
174064c8009SBarry Smith 
1758e722e36SBarry Smith     ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr);
1768e722e36SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,Nint,0,&x);CHKERRQ(ierr);
1778e722e36SBarry Smith     ierr = MatGetArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
1788e722e36SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,Nint,0,&b);CHKERRQ(ierr);
1798e722e36SBarry Smith     ierr = KSPSetOperators(exotic->ksp,Aii,Aii,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
1808e722e36SBarry Smith     for (i=0; i<26; i++) {
1818e722e36SBarry Smith       ierr = VecPlaceArray(x,xint+i*Nint);CHKERRQ(ierr);
1828e722e36SBarry Smith       ierr = VecPlaceArray(b,xint_tmp+i*Nint);CHKERRQ(ierr);
1838e722e36SBarry Smith       ierr = KSPSolve(exotic->ksp,b,x);CHKERRQ(ierr);
1848e722e36SBarry Smith       ierr = VecResetArray(x);CHKERRQ(ierr);
1858e722e36SBarry Smith       ierr = VecResetArray(b);CHKERRQ(ierr);
1868e722e36SBarry Smith     }
1878e722e36SBarry Smith     ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr);
1888e722e36SBarry Smith     ierr = MatRestoreArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
1898e722e36SBarry Smith     ierr = VecDestroy(x);CHKERRQ(ierr);
1908e722e36SBarry Smith     ierr = VecDestroy(b);CHKERRQ(ierr);
1918e722e36SBarry Smith   }
1928e722e36SBarry Smith   ierr = MatDestroy(Xint_tmp);CHKERRQ(ierr);
1938e722e36SBarry Smith 
1948e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
195064c8009SBarry Smith   ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr);
196064c8009SBarry Smith   for (i=0; i<Nint; i++) {
197064c8009SBarry Smith     tmp = 0.0;
198064c8009SBarry Smith     for (j=0; j<26; j++) {
199064c8009SBarry Smith       tmp += xint[i+j*Nint];
200064c8009SBarry Smith     }
201064c8009SBarry Smith     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xint interpolation at i %D value %G",i,PetscAbsScalar(tmp));
202064c8009SBarry Smith   }
203064c8009SBarry Smith   ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr);
204064c8009SBarry Smith   /* ierr =MatView(Xint,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); */
205064c8009SBarry Smith #endif
206064c8009SBarry Smith 
207064c8009SBarry Smith 
208064c8009SBarry Smith   /*         total vertices             total faces                                  total edges */
209064c8009SBarry 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);
210064c8009SBarry Smith 
211064c8009SBarry Smith   /*
212064c8009SBarry Smith       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
213064c8009SBarry Smith   */
214064c8009SBarry Smith   cnt = 0;
215064c8009SBarry Smith   gl[cnt++] = 0;  { gl[cnt++] = 1;} gl[cnt++] = m-istart-1;
216064c8009SBarry Smith   { gl[cnt++] = mwidth;  { gl[cnt++] = mwidth+1;} gl[cnt++] = mwidth + m-istart-1;}
217064c8009SBarry Smith   gl[cnt++] = mwidth*(n-jstart-1);  { gl[cnt++] = mwidth*(n-jstart-1)+1;} gl[cnt++] = mwidth*(n-jstart-1) + m-istart-1;
218064c8009SBarry Smith   {
219064c8009SBarry Smith     gl[cnt++] = mwidth*nwidth;  { gl[cnt++] = mwidth*nwidth+1;}  gl[cnt++] = mwidth*nwidth+ m-istart-1;
220064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;}
221064c8009SBarry 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;
222064c8009SBarry Smith   }
223064c8009SBarry 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;
224064c8009SBarry 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;}
225064c8009SBarry 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;
226064c8009SBarry Smith 
227064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
228064c8009SBarry Smith   /* convert that to global numbering and get them on all processes */
229064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,26,gl,gl);CHKERRQ(ierr);
230064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
231064c8009SBarry Smith   ierr = PetscMalloc(26*mp*np*pp*sizeof(PetscInt),&globals);CHKERRQ(ierr);
232064c8009SBarry Smith   ierr = MPI_Allgather(gl,26,MPIU_INT,globals,26,MPIU_INT,((PetscObject)da)->comm);CHKERRQ(ierr);
233064c8009SBarry Smith 
234064c8009SBarry Smith   /* Number the coarse grid points from 0 to Ntotal */
235064c8009SBarry Smith   ierr = PetscTableCreate(Ntotal/3,&ht);CHKERRQ(ierr);
236064c8009SBarry Smith   for (i=0; i<26*mp*np*pp; i++){
237064c8009SBarry Smith     ierr = PetscTableAddCount(ht,globals[i]+1);CHKERRQ(ierr);
238064c8009SBarry Smith   }
239064c8009SBarry Smith   ierr = PetscTableGetCount(ht,&cnt);CHKERRQ(ierr);
240064c8009SBarry Smith   if (cnt != Ntotal) SETERRQ2(PETSC_ERR_PLIB,"Hash table size %D not equal to total number coarse grid points %D",cnt,Ntotal);
241064c8009SBarry Smith   ierr = PetscFree(globals);CHKERRQ(ierr);
242064c8009SBarry Smith   for (i=0; i<26; i++) {
243064c8009SBarry Smith     ierr = PetscTableFind(ht,gl[i]+1,&gl[i]);CHKERRQ(ierr);
244064c8009SBarry Smith     gl[i]--;
245064c8009SBarry Smith   }
246064c8009SBarry Smith   ierr = PetscTableDestroy(ht);CHKERRQ(ierr);
247064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
248064c8009SBarry Smith 
249064c8009SBarry Smith   /* construct global interpolation matrix */
250064c8009SBarry Smith   ierr = MatGetLocalSize(Aglobal,&Ng,PETSC_NULL);CHKERRQ(ierr);
251064c8009SBarry Smith   if (reuse == MAT_INITIAL_MATRIX) {
252064c8009SBarry Smith     ierr = MatCreateMPIAIJ(((PetscObject)da)->comm,Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,PETSC_NULL,Nint+Nsurf,PETSC_NULL,P);CHKERRQ(ierr);
253064c8009SBarry Smith   } else {
254064c8009SBarry Smith     ierr = MatZeroEntries(*P);CHKERRQ(ierr);
255064c8009SBarry Smith   }
256064c8009SBarry Smith   ierr = MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
257064c8009SBarry Smith   ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr);
258064c8009SBarry Smith   ierr = MatSetValues(*P,Nint,IIint,26,gl,xint,INSERT_VALUES);CHKERRQ(ierr);
259064c8009SBarry Smith   ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr);
260064c8009SBarry Smith   ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
261064c8009SBarry Smith   ierr = MatSetValues(*P,Nsurf,IIsurf,26,gl,xsurf,INSERT_VALUES);CHKERRQ(ierr);
262064c8009SBarry Smith   ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
263064c8009SBarry Smith   ierr = MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
264064c8009SBarry Smith   ierr = MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
265064c8009SBarry Smith   ierr = PetscFree2(IIint,IIsurf);CHKERRQ(ierr);
266064c8009SBarry Smith 
2678e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
268064c8009SBarry Smith   {
269064c8009SBarry Smith     Vec         x,y;
270064c8009SBarry Smith     PetscScalar *yy;
271064c8009SBarry Smith     ierr = VecCreateMPI(((PetscObject)da)->comm,Ng,PETSC_DETERMINE,&y);CHKERRQ(ierr);
272064c8009SBarry Smith     ierr = VecCreateMPI(((PetscObject)da)->comm,PETSC_DETERMINE,Ntotal,&x);CHKERRQ(ierr);
273064c8009SBarry Smith     ierr = VecSet(x,1.0);CHKERRQ(ierr);
274064c8009SBarry Smith     ierr = MatMult(*P,x,y);CHKERRQ(ierr);
275064c8009SBarry Smith     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
276064c8009SBarry Smith     for (i=0; i<Ng; i++) {
277064c8009SBarry 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]));
278064c8009SBarry Smith     }
279064c8009SBarry Smith     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
280064c8009SBarry Smith     ierr = VecDestroy(x);CHKERRQ(ierr);
281064c8009SBarry Smith     ierr = VecDestroy(y);CHKERRQ(ierr);
282064c8009SBarry Smith   }
283064c8009SBarry Smith #endif
284064c8009SBarry Smith 
285064c8009SBarry Smith   ierr = MatDestroy(Aii);CHKERRQ(ierr);
286064c8009SBarry Smith   ierr = MatDestroy(Ais);CHKERRQ(ierr);
287064c8009SBarry Smith   ierr = MatDestroy(Asi);CHKERRQ(ierr);
288064c8009SBarry Smith   ierr = MatDestroy(A);CHKERRQ(ierr);
289064c8009SBarry Smith   ierr = ISDestroy(is);CHKERRQ(ierr);
290064c8009SBarry Smith   ierr = ISDestroy(isint);CHKERRQ(ierr);
291064c8009SBarry Smith   ierr = ISDestroy(issurf);CHKERRQ(ierr);
292064c8009SBarry Smith   ierr = MatDestroy(Xint);CHKERRQ(ierr);
293064c8009SBarry Smith   ierr = MatDestroy(Xsurf);CHKERRQ(ierr);
294064c8009SBarry Smith   PetscFunctionReturn(0);
295064c8009SBarry Smith }
296064c8009SBarry Smith 
297064c8009SBarry Smith #undef __FUNCT__
298064c8009SBarry Smith #define __FUNCT__ "DAGetFaceInterpolation"
299064c8009SBarry Smith /*
300064c8009SBarry Smith       DAGetFaceInterpolation - Gets the interpolation for a face based coarse space
301064c8009SBarry Smith 
302064c8009SBarry Smith */
3036c699258SBarry Smith PetscErrorCode DAGetFaceInterpolation(DA da,PC_Exotic *exotic,Mat Aglobal,MatReuse reuse,Mat *P)
304064c8009SBarry Smith {
305064c8009SBarry Smith   PetscErrorCode         ierr;
306064c8009SBarry 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;
307064c8009SBarry Smith   PetscInt               mwidth,nwidth,pwidth,cnt,mp,np,pp,Ntotal,gl[6],*globals,Ng,*IIint,*IIsurf;
308064c8009SBarry Smith   Mat                    Xint, Xsurf,Xint_tmp;
309064c8009SBarry Smith   IS                     isint,issurf,is,row,col;
310064c8009SBarry Smith   ISLocalToGlobalMapping ltg;
311064c8009SBarry Smith   MPI_Comm               comm;
312064c8009SBarry Smith   Mat                    A,Aii,Ais,Asi,*Aholder,iAii;
313064c8009SBarry Smith   MatFactorInfo          info;
314064c8009SBarry Smith   PetscScalar            *xsurf,*xint;
315064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
316064c8009SBarry Smith   PetscScalar            tmp;
317064c8009SBarry Smith #endif
318064c8009SBarry Smith   PetscTable             ht;
319064c8009SBarry Smith 
320064c8009SBarry Smith   PetscFunctionBegin;
321064c8009SBarry Smith   ierr = DAGetInfo(da,&dim,0,0,0,&mp,&np,&pp,&dof,0,0,0);CHKERRQ(ierr);
322064c8009SBarry Smith   if (dof != 1) SETERRQ(PETSC_ERR_SUP,"Only for single field problems");
323064c8009SBarry Smith   if (dim != 3) SETERRQ(PETSC_ERR_SUP,"Only coded for 3d problems");
324064c8009SBarry Smith   ierr = DAGetCorners(da,0,0,0,&m,&n,&p);CHKERRQ(ierr);
325064c8009SBarry Smith   ierr = DAGetGhostCorners(da,&istart,&jstart,&kstart,&mwidth,&nwidth,&pwidth);CHKERRQ(ierr);
326064c8009SBarry Smith   istart = istart ? -1 : 0;
327064c8009SBarry Smith   jstart = jstart ? -1 : 0;
328064c8009SBarry Smith   kstart = kstart ? -1 : 0;
329064c8009SBarry Smith 
330064c8009SBarry Smith   /*
331064c8009SBarry Smith     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
332064c8009SBarry Smith     to all the local degrees of freedom (this includes the vertices, edges and faces).
333064c8009SBarry Smith 
334064c8009SBarry Smith     Xint are the subset of the interpolation into the interior
335064c8009SBarry Smith 
336064c8009SBarry Smith     Xface are the interpolation onto faces but not into the interior
337064c8009SBarry Smith 
338064c8009SBarry Smith     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
339064c8009SBarry Smith                                         Xint
340064c8009SBarry Smith     Symbolically one could write P = (  Xface  ) after interchanging the rows to match the natural ordering on the domain
341064c8009SBarry Smith                                         Xsurf
342064c8009SBarry Smith   */
343064c8009SBarry Smith   N     = (m - istart)*(n - jstart)*(p - kstart);
344064c8009SBarry Smith   Nint  = (m-2-istart)*(n-2-jstart)*(p-2-kstart);
345064c8009SBarry Smith   Nface = 2*( (m-2-istart)*(n-2-jstart) + (m-2-istart)*(p-2-kstart) + (n-2-jstart)*(p-2-kstart) );
346064c8009SBarry Smith   Nwire = 4*( (m-2-istart) + (n-2-jstart) + (p-2-kstart) ) + 8;
347064c8009SBarry Smith   Nsurf = Nface + Nwire;
348064c8009SBarry Smith   ierr = MatCreateSeqDense(MPI_COMM_SELF,Nint,6,PETSC_NULL,&Xint);CHKERRQ(ierr);
349064c8009SBarry Smith   ierr = MatCreateSeqDense(MPI_COMM_SELF,Nsurf,6,PETSC_NULL,&Xsurf);CHKERRQ(ierr);
350064c8009SBarry Smith   ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
351064c8009SBarry Smith 
352064c8009SBarry Smith   /*
353064c8009SBarry Smith      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
354064c8009SBarry Smith      Xsurf will be all zero (thus making the coarse matrix singular).
355064c8009SBarry Smith   */
356064c8009SBarry Smith   if (m-istart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in X direction must be at least 3");
357064c8009SBarry Smith   if (n-jstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Y direction must be at least 3");
358064c8009SBarry Smith   if (p-kstart < 3) SETERRQ(PETSC_ERR_SUP,"Number of grid points per process in Z direction must be at least 3");
359064c8009SBarry Smith 
360064c8009SBarry Smith   cnt = 0;
361064c8009SBarry Smith   for (j=1;j<n-1-jstart;j++) {  for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 0*Nsurf] = 1;} }
362064c8009SBarry Smith    for (k=1;k<p-1-kstart;k++) {
363064c8009SBarry Smith     for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 1*Nsurf] = 1;}
364064c8009SBarry Smith     for (j=1;j<n-1-jstart;j++) { xsurf[cnt++ + 2*Nsurf] = 1; /* these are the interior nodes */ xsurf[cnt++ + 3*Nsurf] = 1;}
365064c8009SBarry Smith     for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 4*Nsurf] = 1;}
366064c8009SBarry Smith   }
367064c8009SBarry Smith   for (j=1;j<n-1-jstart;j++) {for (i=1; i<m-istart-1; i++) { xsurf[cnt++ + 5*Nsurf] = 1;} }
368064c8009SBarry Smith 
369064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
370064c8009SBarry Smith   for (i=0; i<Nsurf; i++) {
371064c8009SBarry Smith     tmp = 0.0;
372064c8009SBarry Smith     for (j=0; j<6; j++) {
373064c8009SBarry Smith       tmp += xsurf[i+j*Nsurf];
374064c8009SBarry Smith     }
375064c8009SBarry Smith     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xsurf interpolation at i %D value %G",i,PetscAbsScalar(tmp));
376064c8009SBarry Smith   }
377064c8009SBarry Smith #endif
378064c8009SBarry Smith   ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
379064c8009SBarry Smith   /* ierr = MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);*/
380064c8009SBarry Smith 
381064c8009SBarry Smith 
382064c8009SBarry Smith   /*
383064c8009SBarry Smith        I are the indices for all the needed vertices (in global numbering)
384064c8009SBarry Smith        Iint are the indices for the interior values, I surf for the surface values
385064c8009SBarry Smith             (This is just for the part of the global matrix obtained with MatGetSubMatrix(), it
386064c8009SBarry Smith              is NOT the local DA ordering.)
387064c8009SBarry Smith        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
388064c8009SBarry Smith   */
389064c8009SBarry Smith #define Endpoint(a,start,b) (a == 0 || a == (b-1-start))
390064c8009SBarry Smith   ierr = PetscMalloc3(N,PetscInt,&II,Nint,PetscInt,&Iint,Nsurf,PetscInt,&Isurf);CHKERRQ(ierr);
391064c8009SBarry Smith   ierr = PetscMalloc2(Nint,PetscInt,&IIint,Nsurf,PetscInt,&IIsurf);CHKERRQ(ierr);
392064c8009SBarry Smith   for (k=0; k<p-kstart; k++) {
393064c8009SBarry Smith     for (j=0; j<n-jstart; j++) {
394064c8009SBarry Smith       for (i=0; i<m-istart; i++) {
395064c8009SBarry Smith         II[c++] = i + j*mwidth + k*mwidth*nwidth;
396064c8009SBarry Smith 
397064c8009SBarry Smith         if (!Endpoint(i,istart,m) && !Endpoint(j,jstart,n) && !Endpoint(k,kstart,p)) {
398064c8009SBarry Smith           IIint[cint]  = i + j*mwidth + k*mwidth*nwidth;
399064c8009SBarry Smith           Iint[cint++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
400064c8009SBarry Smith         } else {
401064c8009SBarry Smith           IIsurf[csurf]  = i + j*mwidth + k*mwidth*nwidth;
402064c8009SBarry Smith           Isurf[csurf++] = i + j*(m-istart) + k*(m-istart)*(n-jstart);
403064c8009SBarry Smith         }
404064c8009SBarry Smith       }
405064c8009SBarry Smith     }
406064c8009SBarry Smith   }
407064c8009SBarry Smith   if (c != N) SETERRQ(PETSC_ERR_PLIB,"c != N");
408064c8009SBarry Smith   if (cint != Nint) SETERRQ(PETSC_ERR_PLIB,"cint != Nint");
409064c8009SBarry Smith   if (csurf != Nsurf) SETERRQ(PETSC_ERR_PLIB,"csurf != Nsurf");
410064c8009SBarry Smith   ierr = DAGetISLocalToGlobalMapping(da,&ltg);CHKERRQ(ierr);
411064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,N,II,II);CHKERRQ(ierr);
412064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nint,IIint,IIint);CHKERRQ(ierr);
413064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,Nsurf,IIsurf,IIsurf);CHKERRQ(ierr);
414064c8009SBarry Smith   ierr = PetscObjectGetComm((PetscObject)da,&comm);CHKERRQ(ierr);
415064c8009SBarry Smith   ierr = ISCreateGeneral(comm,N,II,&is);CHKERRQ(ierr);
416064c8009SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nint,Iint,&isint);CHKERRQ(ierr);
417064c8009SBarry Smith   ierr = ISCreateGeneral(PETSC_COMM_SELF,Nsurf,Isurf,&issurf);CHKERRQ(ierr);
418064c8009SBarry Smith   ierr = PetscFree3(II,Iint,Isurf);CHKERRQ(ierr);
419064c8009SBarry Smith 
420064c8009SBarry Smith   ierr = MatGetSubMatrices(Aglobal,1,&is,&is,MAT_INITIAL_MATRIX,&Aholder);CHKERRQ(ierr);
421064c8009SBarry Smith   A    = *Aholder;
422064c8009SBarry Smith   ierr = PetscFree(Aholder);CHKERRQ(ierr);
423064c8009SBarry Smith 
424064c8009SBarry Smith   ierr = MatGetSubMatrix(A,isint,isint,MAT_INITIAL_MATRIX,&Aii);CHKERRQ(ierr);
425064c8009SBarry Smith   ierr = MatGetSubMatrix(A,isint,issurf,MAT_INITIAL_MATRIX,&Ais);CHKERRQ(ierr);
426064c8009SBarry Smith   ierr = MatGetSubMatrix(A,issurf,isint,MAT_INITIAL_MATRIX,&Asi);CHKERRQ(ierr);
427064c8009SBarry Smith 
428064c8009SBarry Smith   /*
429064c8009SBarry Smith      Solve for the interpolation onto the interior Xint
430064c8009SBarry Smith   */
431064c8009SBarry Smith   ierr = MatDuplicate(Xint,MAT_DO_NOT_COPY_VALUES,&Xint_tmp);CHKERRQ(ierr);
432064c8009SBarry Smith   ierr = MatMatMult(Ais,Xsurf,MAT_REUSE_MATRIX,PETSC_DETERMINE,&Xint_tmp);CHKERRQ(ierr);
433064c8009SBarry Smith   ierr = MatScale(Xint_tmp,-1.0);CHKERRQ(ierr);
434064c8009SBarry Smith 
4358e722e36SBarry Smith   if (exotic->directSolve) {
436064c8009SBarry Smith     ierr = MatGetFactor(Aii,MAT_SOLVER_PETSC,MAT_FACTOR_LU,&iAii);CHKERRQ(ierr);
437064c8009SBarry Smith     ierr = MatFactorInfoInitialize(&info);CHKERRQ(ierr);
438064c8009SBarry Smith     ierr = MatGetOrdering(Aii,MATORDERING_ND,&row,&col);CHKERRQ(ierr);
439064c8009SBarry Smith     ierr = MatLUFactorSymbolic(iAii,Aii,row,col,&info);CHKERRQ(ierr);
440064c8009SBarry Smith     ierr = ISDestroy(row);CHKERRQ(ierr);
441064c8009SBarry Smith     ierr = ISDestroy(col);CHKERRQ(ierr);
442064c8009SBarry Smith     ierr = MatLUFactorNumeric(iAii,Aii,&info);CHKERRQ(ierr);
443064c8009SBarry Smith     ierr = MatMatSolve(iAii,Xint_tmp,Xint);CHKERRQ(ierr);
444064c8009SBarry Smith     ierr = MatDestroy(iAii);CHKERRQ(ierr);
445064c8009SBarry Smith   } else {
446064c8009SBarry Smith     Vec         b,x;
447064c8009SBarry Smith     PetscScalar *xint_tmp;
448064c8009SBarry Smith 
449064c8009SBarry Smith     ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr);
450064c8009SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,Nint,0,&x);CHKERRQ(ierr);
451064c8009SBarry Smith     ierr = MatGetArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
452064c8009SBarry Smith     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,Nint,0,&b);CHKERRQ(ierr);
4538e722e36SBarry Smith     ierr = KSPSetOperators(exotic->ksp,Aii,Aii,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
454064c8009SBarry Smith     for (i=0; i<6; i++) {
455064c8009SBarry Smith       ierr = VecPlaceArray(x,xint+i*Nint);CHKERRQ(ierr);
456064c8009SBarry Smith       ierr = VecPlaceArray(b,xint_tmp+i*Nint);CHKERRQ(ierr);
4578e722e36SBarry Smith       ierr = KSPSolve(exotic->ksp,b,x);CHKERRQ(ierr);
458064c8009SBarry Smith       ierr = VecResetArray(x);CHKERRQ(ierr);
459064c8009SBarry Smith       ierr = VecResetArray(b);CHKERRQ(ierr);
460064c8009SBarry Smith     }
461064c8009SBarry Smith     ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr);
462064c8009SBarry Smith     ierr = MatRestoreArray(Xint_tmp,&xint_tmp);CHKERRQ(ierr);
463064c8009SBarry Smith     ierr = VecDestroy(x);CHKERRQ(ierr);
464064c8009SBarry Smith     ierr = VecDestroy(b);CHKERRQ(ierr);
465064c8009SBarry Smith   }
466064c8009SBarry Smith   ierr = MatDestroy(Xint_tmp);CHKERRQ(ierr);
467064c8009SBarry Smith 
468064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
469064c8009SBarry Smith   ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr);
470064c8009SBarry Smith   for (i=0; i<Nint; i++) {
471064c8009SBarry Smith     tmp = 0.0;
472064c8009SBarry Smith     for (j=0; j<6; j++) {
473064c8009SBarry Smith       tmp += xint[i+j*Nint];
474064c8009SBarry Smith     }
475064c8009SBarry Smith     if (PetscAbsScalar(tmp-1.0) > 1.e-10) SETERRQ2(PETSC_ERR_PLIB,"Wrong Xint interpolation at i %D value %G",i,PetscAbsScalar(tmp));
476064c8009SBarry Smith   }
477064c8009SBarry Smith   ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr);
478064c8009SBarry Smith   /* ierr =MatView(Xint,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); */
479064c8009SBarry Smith #endif
480064c8009SBarry Smith 
481064c8009SBarry Smith 
482064c8009SBarry Smith   /*         total faces    */
483064c8009SBarry Smith   Ntotal =  mp*np*(pp+1) + mp*pp*(np+1) + np*pp*(mp+1);
484064c8009SBarry Smith 
485064c8009SBarry Smith   /*
486064c8009SBarry Smith       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
487064c8009SBarry Smith   */
488064c8009SBarry Smith   cnt = 0;
489064c8009SBarry Smith   { gl[cnt++] = mwidth+1;}
490064c8009SBarry Smith   {
491064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth+1;}
492064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth + mwidth; /* these are the interior nodes */ gl[cnt++] = mwidth*nwidth + mwidth+m-istart-1;}
493064c8009SBarry Smith     { gl[cnt++] = mwidth*nwidth+mwidth*(n-jstart-1)+1;}
494064c8009SBarry Smith   }
495064c8009SBarry Smith   { gl[cnt++] = mwidth*nwidth*(p-kstart-1) + mwidth+1;}
496064c8009SBarry Smith 
497064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
498064c8009SBarry Smith   /* convert that to global numbering and get them on all processes */
499064c8009SBarry Smith   ierr = ISLocalToGlobalMappingApply(ltg,6,gl,gl);CHKERRQ(ierr);
500064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
501064c8009SBarry Smith   ierr = PetscMalloc(6*mp*np*pp*sizeof(PetscInt),&globals);CHKERRQ(ierr);
502064c8009SBarry Smith   ierr = MPI_Allgather(gl,6,MPIU_INT,globals,6,MPIU_INT,((PetscObject)da)->comm);CHKERRQ(ierr);
503064c8009SBarry Smith 
504064c8009SBarry Smith   /* Number the coarse grid points from 0 to Ntotal */
505064c8009SBarry Smith   ierr = PetscTableCreate(Ntotal/3,&ht);CHKERRQ(ierr);
506064c8009SBarry Smith   for (i=0; i<6*mp*np*pp; i++){
507064c8009SBarry Smith     ierr = PetscTableAddCount(ht,globals[i]+1);CHKERRQ(ierr);
508064c8009SBarry Smith   }
509064c8009SBarry Smith   ierr = PetscTableGetCount(ht,&cnt);CHKERRQ(ierr);
510064c8009SBarry Smith   if (cnt != Ntotal) SETERRQ2(PETSC_ERR_PLIB,"Hash table size %D not equal to total number coarse grid points %D",cnt,Ntotal);
511064c8009SBarry Smith   ierr = PetscFree(globals);CHKERRQ(ierr);
512064c8009SBarry Smith   for (i=0; i<6; i++) {
513064c8009SBarry Smith     ierr = PetscTableFind(ht,gl[i]+1,&gl[i]);CHKERRQ(ierr);
514064c8009SBarry Smith     gl[i]--;
515064c8009SBarry Smith   }
516064c8009SBarry Smith   ierr = PetscTableDestroy(ht);CHKERRQ(ierr);
517064c8009SBarry Smith   /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
518064c8009SBarry Smith 
519064c8009SBarry Smith   /* construct global interpolation matrix */
520064c8009SBarry Smith   ierr = MatGetLocalSize(Aglobal,&Ng,PETSC_NULL);CHKERRQ(ierr);
521064c8009SBarry Smith   if (reuse == MAT_INITIAL_MATRIX) {
522064c8009SBarry Smith     ierr = MatCreateMPIAIJ(((PetscObject)da)->comm,Ng,PETSC_DECIDE,PETSC_DECIDE,Ntotal,Nint+Nsurf,PETSC_NULL,Nint,PETSC_NULL,P);CHKERRQ(ierr);
523064c8009SBarry Smith   } else {
524064c8009SBarry Smith     ierr = MatZeroEntries(*P);CHKERRQ(ierr);
525064c8009SBarry Smith   }
526064c8009SBarry Smith   ierr = MatSetOption(*P,MAT_ROW_ORIENTED,PETSC_FALSE);CHKERRQ(ierr);
527064c8009SBarry Smith   ierr = MatGetArray(Xint,&xint);CHKERRQ(ierr);
528064c8009SBarry Smith   ierr = MatSetValues(*P,Nint,IIint,6,gl,xint,INSERT_VALUES);CHKERRQ(ierr);
529064c8009SBarry Smith   ierr = MatRestoreArray(Xint,&xint);CHKERRQ(ierr);
530064c8009SBarry Smith   ierr = MatGetArray(Xsurf,&xsurf);CHKERRQ(ierr);
531064c8009SBarry Smith   ierr = MatSetValues(*P,Nsurf,IIsurf,6,gl,xsurf,INSERT_VALUES);CHKERRQ(ierr);
532064c8009SBarry Smith   ierr = MatRestoreArray(Xsurf,&xsurf);CHKERRQ(ierr);
533064c8009SBarry Smith   ierr = MatAssemblyBegin(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
534064c8009SBarry Smith   ierr = MatAssemblyEnd(*P,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
535064c8009SBarry Smith   ierr = PetscFree2(IIint,IIsurf);CHKERRQ(ierr);
536064c8009SBarry Smith 
537064c8009SBarry Smith 
538064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
539064c8009SBarry Smith   {
540064c8009SBarry Smith     Vec         x,y;
541064c8009SBarry Smith     PetscScalar *yy;
542064c8009SBarry Smith     ierr = VecCreateMPI(((PetscObject)da)->comm,Ng,PETSC_DETERMINE,&y);CHKERRQ(ierr);
543064c8009SBarry Smith     ierr = VecCreateMPI(((PetscObject)da)->comm,PETSC_DETERMINE,Ntotal,&x);CHKERRQ(ierr);
544064c8009SBarry Smith     ierr = VecSet(x,1.0);CHKERRQ(ierr);
545064c8009SBarry Smith     ierr = MatMult(*P,x,y);CHKERRQ(ierr);
546064c8009SBarry Smith     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
547064c8009SBarry Smith     for (i=0; i<Ng; i++) {
548064c8009SBarry 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]));
549064c8009SBarry Smith     }
550064c8009SBarry Smith     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
551064c8009SBarry Smith     ierr = VecDestroy(x);CHKERRQ(ierr);
552064c8009SBarry Smith     ierr = VecDestroy(y);CHKERRQ(ierr);
553064c8009SBarry Smith   }
554064c8009SBarry Smith #endif
555064c8009SBarry Smith 
556064c8009SBarry Smith   ierr = MatDestroy(Aii);CHKERRQ(ierr);
557064c8009SBarry Smith   ierr = MatDestroy(Ais);CHKERRQ(ierr);
558064c8009SBarry Smith   ierr = MatDestroy(Asi);CHKERRQ(ierr);
559064c8009SBarry Smith   ierr = MatDestroy(A);CHKERRQ(ierr);
560064c8009SBarry Smith   ierr = ISDestroy(is);CHKERRQ(ierr);
561064c8009SBarry Smith   ierr = ISDestroy(isint);CHKERRQ(ierr);
562064c8009SBarry Smith   ierr = ISDestroy(issurf);CHKERRQ(ierr);
563064c8009SBarry Smith   ierr = MatDestroy(Xint);CHKERRQ(ierr);
564064c8009SBarry Smith   ierr = MatDestroy(Xsurf);CHKERRQ(ierr);
565064c8009SBarry Smith   PetscFunctionReturn(0);
566064c8009SBarry Smith }
567174b6946SBarry Smith 
5687233f9f0SBarry Smith 
569174b6946SBarry Smith #undef __FUNCT__
5707233f9f0SBarry Smith #define __FUNCT__ "PCExoticSetType"
5717233f9f0SBarry Smith /*@
5727233f9f0SBarry Smith    PCExoticSetType - Sets the type of coarse grid interpolation to use
5737233f9f0SBarry Smith 
5747233f9f0SBarry Smith    Collective on PC
5757233f9f0SBarry Smith 
5767233f9f0SBarry Smith    Input Parameters:
5777233f9f0SBarry Smith +  pc - the preconditioner context
5787233f9f0SBarry Smith -  type - either PC_EXOTIC_FACE or PC_EXOTIC_WIREBASKET (defaults to face)
5797233f9f0SBarry Smith 
580563e08c6SBarry Smith    Notes: The face based interpolation has 1 degree of freedom per face and ignores the
581563e08c6SBarry Smith      edge and vertex values completely in the coarse problem. For any seven point
582563e08c6SBarry Smith      stencil the interpolation of a constant on all faces into the interior is that constant.
583563e08c6SBarry Smith 
584563e08c6SBarry Smith      The wirebasket interpolation has 1 degree of freedom per vertex, per edge and
585563e08c6SBarry Smith      per face. A constant on the subdomain boundary is interpolated as that constant
586563e08c6SBarry Smith      in the interior of the domain.
587563e08c6SBarry Smith 
588563e08c6SBarry Smith      The coarse grid matrix is obtained via the Galerkin computation A_c = R A R^T, hence
589563e08c6SBarry Smith      if A is nonsingular A_c is also nonsingular.
590563e08c6SBarry Smith 
591563e08c6SBarry Smith      Both interpolations are suitable for only scalar problems.
592563e08c6SBarry Smith 
5937233f9f0SBarry Smith    Level: intermediate
5947233f9f0SBarry Smith 
5957233f9f0SBarry Smith 
5967233f9f0SBarry Smith .seealso: PCEXOTIC, PCExoticType()
5977233f9f0SBarry Smith @*/
5987233f9f0SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCExoticSetType(PC pc,PCExoticType type)
5997233f9f0SBarry Smith {
6007233f9f0SBarry Smith   PetscErrorCode ierr,(*f)(PC,PCExoticType);
6017233f9f0SBarry Smith 
6027233f9f0SBarry Smith   PetscFunctionBegin;
603*0700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
6047233f9f0SBarry Smith   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCExoticSetType_C",(void (**)(void))&f);CHKERRQ(ierr);
6057233f9f0SBarry Smith   if (f) {
6067233f9f0SBarry Smith     ierr = (*f)(pc,type);CHKERRQ(ierr);
6077233f9f0SBarry Smith   }
6087233f9f0SBarry Smith   PetscFunctionReturn(0);
6097233f9f0SBarry Smith }
6107233f9f0SBarry Smith 
6117233f9f0SBarry Smith #undef __FUNCT__
6127233f9f0SBarry Smith #define __FUNCT__ "PCExoticSetType_Exotic"
6137233f9f0SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCExoticSetType_Exotic(PC pc,PCExoticType type)
6147233f9f0SBarry Smith {
615f3fbd535SBarry Smith   PC_MG     *mg = (PC_MG*)pc->data;
61631567311SBarry Smith   PC_Exotic *ctx = (PC_Exotic*) mg->innerctx;
6177233f9f0SBarry Smith 
6187233f9f0SBarry Smith   PetscFunctionBegin;
6197233f9f0SBarry Smith   ctx->type = type;
6207233f9f0SBarry Smith   PetscFunctionReturn(0);
6217233f9f0SBarry Smith }
6227233f9f0SBarry Smith 
6237233f9f0SBarry Smith #undef __FUNCT__
6247233f9f0SBarry Smith #define __FUNCT__ "PCSetUp_Exotic"
6257233f9f0SBarry Smith PetscErrorCode PCSetUp_Exotic(PC pc)
626174b6946SBarry Smith {
627174b6946SBarry Smith   PetscErrorCode ierr;
62896bdf778SBarry Smith   Mat            A;
629f3fbd535SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
63031567311SBarry Smith   PC_Exotic      *ex = (PC_Exotic*) mg->innerctx;
63196bdf778SBarry Smith   MatReuse       reuse = (ex->P) ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
632174b6946SBarry Smith 
633174b6946SBarry Smith   PetscFunctionBegin;
6346c699258SBarry Smith   if (!pc->dm) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Need to call PCSetDM() before using this PC");
635174b6946SBarry Smith   ierr = PCGetOperators(pc,PETSC_NULL,&A,PETSC_NULL);CHKERRQ(ierr);
6367233f9f0SBarry Smith   if (ex->type == PC_EXOTIC_FACE) {
6376c699258SBarry Smith     ierr = DAGetFaceInterpolation((DA)pc->dm,ex,A,reuse,&ex->P);CHKERRQ(ierr);
6387233f9f0SBarry Smith   } else if (ex->type == PC_EXOTIC_WIREBASKET) {
6396c699258SBarry Smith     ierr = DAGetWireBasketInterpolation((DA)pc->dm,ex,A,reuse,&ex->P);CHKERRQ(ierr);
6407233f9f0SBarry Smith   } else SETERRQ1(PETSC_ERR_PLIB,"Unknown exotic coarse space %d",ex->type);
64196bdf778SBarry Smith   ierr = PCMGSetInterpolation(pc,1,ex->P);CHKERRQ(ierr);
6427233f9f0SBarry Smith   ierr = PCSetUp_MG(pc);CHKERRQ(ierr);
643174b6946SBarry Smith   PetscFunctionReturn(0);
644174b6946SBarry Smith }
645174b6946SBarry Smith 
646174b6946SBarry Smith #undef __FUNCT__
6477233f9f0SBarry Smith #define __FUNCT__ "PCDestroy_Exotic"
6487233f9f0SBarry Smith PetscErrorCode PCDestroy_Exotic(PC pc)
649174b6946SBarry Smith {
650174b6946SBarry Smith   PetscErrorCode ierr;
651f3fbd535SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
65231567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
653174b6946SBarry Smith 
654174b6946SBarry Smith   PetscFunctionBegin;
65596bdf778SBarry Smith   if (ctx->P) {ierr = MatDestroy(ctx->P);CHKERRQ(ierr);}
6568e722e36SBarry Smith   if (ctx->ksp) {ierr = KSPDestroy(ctx->ksp);CHKERRQ(ierr);}
6577233f9f0SBarry Smith   ierr = PetscFree(ctx);CHKERRQ(ierr);
6587233f9f0SBarry Smith   ierr = PCDestroy_MG(pc);CHKERRQ(ierr);
659174b6946SBarry Smith   PetscFunctionReturn(0);
660174b6946SBarry Smith }
661174b6946SBarry Smith 
662174b6946SBarry Smith #undef __FUNCT__
6637233f9f0SBarry Smith #define __FUNCT__ "PCView_Exotic"
6647233f9f0SBarry Smith PetscErrorCode PCView_Exotic(PC pc,PetscViewer viewer)
6657233f9f0SBarry Smith {
666f3fbd535SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
6677233f9f0SBarry Smith   PetscErrorCode ierr;
6687233f9f0SBarry Smith   PetscTruth     iascii;
66931567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
6707233f9f0SBarry Smith 
6717233f9f0SBarry Smith   PetscFunctionBegin;
6727233f9f0SBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
6737233f9f0SBarry Smith   if (iascii) {
6747233f9f0SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"    Exotic type = %s\n",PCExoticTypes[ctx->type]);CHKERRQ(ierr);
6758e722e36SBarry Smith     if (ctx->directSolve) {
6768e722e36SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"      Using direct solver to construct interpolation\n");CHKERRQ(ierr);
6778e722e36SBarry Smith     } else {
6788e722e36SBarry Smith       PetscViewer sviewer;
6798e722e36SBarry Smith       PetscMPIInt rank;
6808e722e36SBarry Smith 
6818e722e36SBarry Smith       ierr = PetscViewerASCIIPrintf(viewer,"      Using iterative solver to construct interpolation\n");CHKERRQ(ierr);
6828e722e36SBarry Smith       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
6838e722e36SBarry Smith       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);  /* should not need to push this twice? */
6848e722e36SBarry Smith       ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr);
6858e722e36SBarry Smith       ierr = MPI_Comm_rank(((PetscObject)pc)->comm,&rank);CHKERRQ(ierr);
6868e722e36SBarry Smith       if (!rank) {
6878e722e36SBarry Smith 	ierr = KSPView(ctx->ksp,sviewer);CHKERRQ(ierr);
6888e722e36SBarry Smith       }
6898e722e36SBarry Smith       ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr);
6908e722e36SBarry Smith       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
6918e722e36SBarry Smith       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
6928e722e36SBarry Smith     }
6937233f9f0SBarry Smith   }
6947233f9f0SBarry Smith   ierr = PCView_MG(pc,viewer);CHKERRQ(ierr);
6957233f9f0SBarry Smith   PetscFunctionReturn(0);
6967233f9f0SBarry Smith }
6977233f9f0SBarry Smith 
6987233f9f0SBarry Smith #undef __FUNCT__
6997233f9f0SBarry Smith #define __FUNCT__ "PCSetFromOptions_Exotic"
7007233f9f0SBarry Smith PetscErrorCode PCSetFromOptions_Exotic(PC pc)
7017233f9f0SBarry Smith {
7027233f9f0SBarry Smith   PetscErrorCode ierr;
7037233f9f0SBarry Smith   PetscTruth     flg;
704f3fbd535SBarry Smith   PC_MG          *mg = (PC_MG*)pc->data;
7057233f9f0SBarry Smith   PCExoticType   mgctype;
70631567311SBarry Smith   PC_Exotic      *ctx = (PC_Exotic*) mg->innerctx;
7077233f9f0SBarry Smith 
7087233f9f0SBarry Smith   PetscFunctionBegin;
7097233f9f0SBarry Smith   ierr = PetscOptionsHead("Exotic coarse space options");CHKERRQ(ierr);
7107233f9f0SBarry Smith     ierr = PetscOptionsEnum("-pc_exotic_type","face or wirebasket","PCExoticSetType",PCExoticTypes,(PetscEnum)ctx->type,(PetscEnum*)&mgctype,&flg);CHKERRQ(ierr);
7117233f9f0SBarry Smith     if (flg) {
7127233f9f0SBarry Smith       ierr = PCExoticSetType(pc,mgctype);CHKERRQ(ierr);
7137233f9f0SBarry Smith     }
7148e722e36SBarry Smith     ierr = PetscOptionsTruth("-pc_exotic_direct_solver","use direct solver to construct interpolation","None",ctx->directSolve,&ctx->directSolve,PETSC_NULL);CHKERRQ(ierr);
7158e722e36SBarry Smith     if (!ctx->directSolve) {
7168e722e36SBarry Smith       if (!ctx->ksp) {
7178e722e36SBarry Smith         const char *prefix;
7188e722e36SBarry Smith         ierr = KSPCreate(PETSC_COMM_SELF,&ctx->ksp);CHKERRQ(ierr);
7198e722e36SBarry Smith         ierr = PetscObjectIncrementTabLevel((PetscObject)ctx->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
7208e722e36SBarry Smith         ierr = PetscLogObjectParent(pc,ctx->ksp);CHKERRQ(ierr);
7218e722e36SBarry Smith         ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
7228e722e36SBarry Smith         ierr = KSPSetOptionsPrefix(ctx->ksp,prefix);CHKERRQ(ierr);
7238e722e36SBarry Smith         ierr = KSPAppendOptionsPrefix(ctx->ksp,"exotic_");CHKERRQ(ierr);
7248e722e36SBarry Smith       }
7258e722e36SBarry Smith       ierr = KSPSetFromOptions(ctx->ksp);CHKERRQ(ierr);
7268e722e36SBarry Smith     }
7277233f9f0SBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
7287233f9f0SBarry Smith   PetscFunctionReturn(0);
7297233f9f0SBarry Smith }
7307233f9f0SBarry Smith 
731174b6946SBarry Smith 
732174b6946SBarry Smith /*MC
7337233f9f0SBarry Smith      PCEXOTIC - Two level overlapping Schwarz preconditioner with exotic (non-standard) coarse grid spaces
734174b6946SBarry Smith 
7357233f9f0SBarry Smith      This uses the PCMG infrastructure restricted to two levels and the face and wirebasket based coarse
7363b65e785SBarry Smith    grid spaces. These coarse grid spaces originate in the work of Bramble, Pasciak  and Schatz, "The Construction
7373b65e785SBarry Smith    of Preconditioners for Elliptic Problems by Substructing IV", Mathematics of Computation, volume 53 pages 1--24, 1989.
7383b65e785SBarry Smith    They were generalized slightly in "Domain Decomposition Method for Linear Elasticity", Ph. D. thesis, Barry Smith,
7393b65e785SBarry Smith    New York University, 1990. They were then explored in great detail in Dryja, Smith, Widlund, "Schwarz Analysis
7403b65e785SBarry Smith    of Iterative Substructuring Methods for Elliptic Problems in Three Dimensions, SIAM Journal on Numerical
7413b65e785SBarry Smith    Analysis, volume 31. pages 1662-1694, 1994. These were developed in the context of iterative substructuring preconditioners.
7423b65e785SBarry Smith    They were then ingeniously applied as coarse grid spaces for overlapping Schwarz methods by Dohrmann and Widlund.
7433b65e785SBarry Smith    They refer to them as GDSW (generalized Dryja, Smith, Widlund preconditioners). See, for example,
7443b65e785SBarry Smith    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Extending theory for domain decomposition algorithms to irregular subdomains. In Ulrich Langer, Marco
7453b65e785SBarry Smith    Discacciati, David Keyes, Olof Widlund, and Walter Zulehner, editors, Proceedings
7463b65e785SBarry Smith    of the 17th International Conference on Domain Decomposition Methods in
7473b65e785SBarry Smith    Science and Engineering, held in Strobl, Austria, July 3-7, 2006, number 60 in
7483b65e785SBarry Smith    Springer-Verlag, Lecture Notes in Computational Science and Engineering, pages 255-261, 2007.
7493b65e785SBarry Smith    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. A family of energy min-
7503b65e785SBarry Smith    imizing coarse spaces for overlapping Schwarz preconditioners. In Ulrich Langer,
7513b65e785SBarry Smith    Marco Discacciati, David Keyes, OlofWidlund, andWalter Zulehner, editors, Proceedings
7523b65e785SBarry Smith    of the 17th International Conference on Domain Decomposition Methods
7533b65e785SBarry Smith    in Science and Engineering, held in Strobl, Austria, July 3-7, 2006, number 60 in
7543b65e785SBarry Smith    Springer-Verlag, Lecture Notes in Computational Science and Engineering, pages 247-254, 2007
7553b65e785SBarry Smith    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Domain decomposition
7563b65e785SBarry Smith    for less regular subdomains: Overlapping Schwarz in two dimensions. SIAM J.
7573b65e785SBarry Smith    Numer. Anal., 46(4):2153-2168, 2008.
7583b65e785SBarry Smith    Clark R. Dohrmann and Olof B. Widlund. An overlapping Schwarz
7593b65e785SBarry Smith    algorithm for almost incompressible elasticity. Technical Report
7603b65e785SBarry Smith    TR2008-912, Department of Computer Science, Courant Institute
7613b65e785SBarry Smith    of Mathematical Sciences, New York University, May 2008. URL:
7623b65e785SBarry Smith    http://cs.nyu.edu/csweb/Research/TechReports/TR2008-912/TR2008-912.pdf
7637233f9f0SBarry Smith 
7647233f9f0SBarry Smith    Options Database: The usual PCMG options are supported, such as -mg_levels_pc_type <type> -mg_coarse_pc_type <type>
7657233f9f0SBarry Smith       -pc_mg_type <type>
7667233f9f0SBarry Smith 
76725a35f6fSSatish Balay    Level: advanced
768174b6946SBarry Smith 
7696c699258SBarry Smith .seealso:  PCMG, PCSetDM(), PCExoticType, PCExoticSetType()
770174b6946SBarry Smith M*/
771174b6946SBarry Smith 
772174b6946SBarry Smith EXTERN_C_BEGIN
773174b6946SBarry Smith #undef __FUNCT__
7747233f9f0SBarry Smith #define __FUNCT__ "PCCreate_Exotic"
7757233f9f0SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_Exotic(PC pc)
776174b6946SBarry Smith {
777174b6946SBarry Smith   PetscErrorCode ierr;
7787233f9f0SBarry Smith   PC_Exotic      *ex;
779f3fbd535SBarry Smith   PC_MG          *mg;
780174b6946SBarry Smith 
781174b6946SBarry Smith   PetscFunctionBegin;
782f91d8e95SBarry Smith   /* if type was previously mg; must manually destroy it because call to PCSetType(pc,PCMG) will not destroy it */
783f91d8e95SBarry Smith   if (pc->ops->destroy) { ierr =  (*pc->ops->destroy)(pc);CHKERRQ(ierr); pc->data = 0;}
784f91d8e95SBarry Smith   ierr = PetscStrfree(((PetscObject)pc)->type_name);CHKERRQ(ierr);
785f91d8e95SBarry Smith   ((PetscObject)pc)->type_name = 0;
786f91d8e95SBarry Smith 
787174b6946SBarry Smith   ierr = PCSetType(pc,PCMG);CHKERRQ(ierr);
788174b6946SBarry Smith   ierr = PCMGSetLevels(pc,2,PETSC_NULL);CHKERRQ(ierr);
789174b6946SBarry Smith   ierr = PCMGSetGalerkin(pc);CHKERRQ(ierr);
79096bdf778SBarry Smith   ierr = PetscNew(PC_Exotic,&ex);CHKERRQ(ierr);\
7917233f9f0SBarry Smith   ex->type = PC_EXOTIC_FACE;
792f3fbd535SBarry Smith   mg = (PC_MG*) pc->data;
79331567311SBarry Smith   mg->innerctx = ex;
7947233f9f0SBarry Smith 
7957233f9f0SBarry Smith 
7967233f9f0SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_Exotic;
7977233f9f0SBarry Smith   pc->ops->view           = PCView_Exotic;
7987233f9f0SBarry Smith   pc->ops->destroy        = PCDestroy_Exotic;
7996c699258SBarry Smith   pc->ops->setup          = PCSetUp_Exotic;
8007233f9f0SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCExoticSetType_C","PCExoticSetType_Exotic",PCExoticSetType_Exotic);CHKERRQ(ierr);
801174b6946SBarry Smith   PetscFunctionReturn(0);
802174b6946SBarry Smith }
803174b6946SBarry Smith EXTERN_C_END
804