xref: /petsc/src/ksp/pc/impls/wb/wb.c (revision f1580f4e3ce5d5b2393648fd039d0d41b440385d)
1174b6946SBarry Smith 
2c6db04a5SJed Brown #include <petscdmda.h>              /*I "petscdmda.h" I*/
3af0996ceSBarry Smith #include <petsc/private/pcmgimpl.h> /*I "petscksp.h" I*/
482c86c8fSBarry Smith #include <petscctable.h>
57233f9f0SBarry Smith 
68e722e36SBarry Smith typedef struct {
78e722e36SBarry Smith   PCExoticType type;
88e722e36SBarry Smith   Mat          P;           /* the constructed interpolation matrix */
9ace3abfcSBarry Smith   PetscBool    directSolve; /* use direct LU factorization to construct interpolation */
108e722e36SBarry Smith   KSP          ksp;
118e722e36SBarry Smith } PC_Exotic;
12174b6946SBarry Smith 
130a545947SLisandro Dalcin const char *const PCExoticTypes[] = {"face", "wirebasket", "PCExoticType", "PC_Exotic", NULL};
14064c8009SBarry Smith 
15064c8009SBarry Smith /*
16aa219208SBarry Smith       DMDAGetWireBasketInterpolation - Gets the interpolation for a wirebasket based coarse space
17064c8009SBarry Smith 
18064c8009SBarry Smith */
199371c9d4SSatish Balay PetscErrorCode DMDAGetWireBasketInterpolation(PC pc, DM da, PC_Exotic *exotic, Mat Aglobal, MatReuse reuse, Mat *P) {
20064c8009SBarry 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;
2128d20b34SBarry Smith   PetscInt               mwidth, nwidth, pwidth, cnt, mp, np, pp, Ntotal, gl[26], *globals, Ng, *IIint, *IIsurf, Nt;
22064c8009SBarry Smith   Mat                    Xint, Xsurf, Xint_tmp;
23064c8009SBarry Smith   IS                     isint, issurf, is, row, col;
24064c8009SBarry Smith   ISLocalToGlobalMapping ltg;
25064c8009SBarry Smith   MPI_Comm               comm;
26064c8009SBarry Smith   Mat                    A, Aii, Ais, Asi, *Aholder, iAii;
27064c8009SBarry Smith   MatFactorInfo          info;
28064c8009SBarry Smith   PetscScalar           *xsurf, *xint;
291683a169SBarry Smith   const PetscScalar     *rxint;
308e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
31064c8009SBarry Smith   PetscScalar tmp;
32064c8009SBarry Smith #endif
33064c8009SBarry Smith   PetscTable ht;
34064c8009SBarry Smith 
35064c8009SBarry Smith   PetscFunctionBegin;
369566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, &dim, NULL, NULL, NULL, &mp, &np, &pp, &dof, NULL, NULL, NULL, NULL, NULL));
3708401ef6SPierre Jolivet   PetscCheck(dof == 1, PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Only for single field problems");
3808401ef6SPierre Jolivet   PetscCheck(dim == 3, PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Only coded for 3d problems");
399566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, NULL, NULL, NULL, &m, &n, &p));
409566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(da, &istart, &jstart, &kstart, &mwidth, &nwidth, &pwidth));
41064c8009SBarry Smith   istart = istart ? -1 : 0;
42064c8009SBarry Smith   jstart = jstart ? -1 : 0;
43064c8009SBarry Smith   kstart = kstart ? -1 : 0;
44064c8009SBarry Smith 
45064c8009SBarry Smith   /*
46064c8009SBarry Smith     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
47064c8009SBarry Smith     to all the local degrees of freedom (this includes the vertices, edges and faces).
48064c8009SBarry Smith 
49064c8009SBarry Smith     Xint are the subset of the interpolation into the interior
50064c8009SBarry Smith 
51064c8009SBarry Smith     Xface are the interpolation onto faces but not into the interior
52064c8009SBarry Smith 
53064c8009SBarry Smith     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
54064c8009SBarry Smith                                       Xint
55064c8009SBarry Smith     Symbolically one could write P = (Xface) after interchanging the rows to match the natural ordering on the domain
56064c8009SBarry Smith                                       Xsurf
57064c8009SBarry Smith   */
58064c8009SBarry Smith   N     = (m - istart) * (n - jstart) * (p - kstart);
59064c8009SBarry Smith   Nint  = (m - 2 - istart) * (n - 2 - jstart) * (p - 2 - kstart);
60064c8009SBarry Smith   Nface = 2 * ((m - 2 - istart) * (n - 2 - jstart) + (m - 2 - istart) * (p - 2 - kstart) + (n - 2 - jstart) * (p - 2 - kstart));
61064c8009SBarry Smith   Nwire = 4 * ((m - 2 - istart) + (n - 2 - jstart) + (p - 2 - kstart)) + 8;
62064c8009SBarry Smith   Nsurf = Nface + Nwire;
639566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(MPI_COMM_SELF, Nint, 26, NULL, &Xint));
649566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(MPI_COMM_SELF, Nsurf, 26, NULL, &Xsurf));
659566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(Xsurf, &xsurf));
66064c8009SBarry Smith 
67064c8009SBarry Smith   /*
68064c8009SBarry Smith      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
69064c8009SBarry Smith      Xsurf will be all zero (thus making the coarse matrix singular).
70064c8009SBarry Smith   */
7108401ef6SPierre Jolivet   PetscCheck(m - istart >= 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of grid points per process in X direction must be at least 3");
7208401ef6SPierre Jolivet   PetscCheck(n - jstart >= 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of grid points per process in Y direction must be at least 3");
7308401ef6SPierre Jolivet   PetscCheck(p - kstart >= 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of grid points per process in Z direction must be at least 3");
74064c8009SBarry Smith 
75064c8009SBarry Smith   cnt = 0;
762fa5cd67SKarl Rupp 
772fa5cd67SKarl Rupp   xsurf[cnt++] = 1;
782fa5cd67SKarl Rupp   for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + Nsurf] = 1;
792fa5cd67SKarl Rupp   xsurf[cnt++ + 2 * Nsurf] = 1;
802fa5cd67SKarl Rupp 
812fa5cd67SKarl Rupp   for (j = 1; j < n - 1 - jstart; j++) {
822fa5cd67SKarl Rupp     xsurf[cnt++ + 3 * Nsurf] = 1;
832fa5cd67SKarl Rupp     for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + 4 * Nsurf] = 1;
842fa5cd67SKarl Rupp     xsurf[cnt++ + 5 * Nsurf] = 1;
85064c8009SBarry Smith   }
862fa5cd67SKarl Rupp 
872fa5cd67SKarl Rupp   xsurf[cnt++ + 6 * Nsurf] = 1;
882fa5cd67SKarl Rupp   for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + 7 * Nsurf] = 1;
892fa5cd67SKarl Rupp   xsurf[cnt++ + 8 * Nsurf] = 1;
902fa5cd67SKarl Rupp 
912fa5cd67SKarl Rupp   for (k = 1; k < p - 1 - kstart; k++) {
922fa5cd67SKarl Rupp     xsurf[cnt++ + 9 * Nsurf] = 1;
932fa5cd67SKarl Rupp     for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + 10 * Nsurf] = 1;
942fa5cd67SKarl Rupp     xsurf[cnt++ + 11 * Nsurf] = 1;
952fa5cd67SKarl Rupp 
962fa5cd67SKarl Rupp     for (j = 1; j < n - 1 - jstart; j++) {
972fa5cd67SKarl Rupp       xsurf[cnt++ + 12 * Nsurf] = 1;
982fa5cd67SKarl Rupp       /* these are the interior nodes */
992fa5cd67SKarl Rupp       xsurf[cnt++ + 13 * Nsurf] = 1;
1002fa5cd67SKarl Rupp     }
1012fa5cd67SKarl Rupp 
1022fa5cd67SKarl Rupp     xsurf[cnt++ + 14 * Nsurf] = 1;
1032fa5cd67SKarl Rupp     for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + 15 * Nsurf] = 1;
1042fa5cd67SKarl Rupp     xsurf[cnt++ + 16 * Nsurf] = 1;
1052fa5cd67SKarl Rupp   }
1062fa5cd67SKarl Rupp 
1072fa5cd67SKarl Rupp   xsurf[cnt++ + 17 * Nsurf] = 1;
1082fa5cd67SKarl Rupp   for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + 18 * Nsurf] = 1;
1092fa5cd67SKarl Rupp   xsurf[cnt++ + 19 * Nsurf] = 1;
1102fa5cd67SKarl Rupp 
1112fa5cd67SKarl Rupp   for (j = 1; j < n - 1 - jstart; j++) {
1122fa5cd67SKarl Rupp     xsurf[cnt++ + 20 * Nsurf] = 1;
1132fa5cd67SKarl Rupp     for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + 21 * Nsurf] = 1;
1142fa5cd67SKarl Rupp     xsurf[cnt++ + 22 * Nsurf] = 1;
1152fa5cd67SKarl Rupp   }
1162fa5cd67SKarl Rupp 
1172fa5cd67SKarl Rupp   xsurf[cnt++ + 23 * Nsurf] = 1;
1182fa5cd67SKarl Rupp   for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + 24 * Nsurf] = 1;
1192fa5cd67SKarl Rupp   xsurf[cnt++ + 25 * Nsurf] = 1;
1202fa5cd67SKarl Rupp 
1218e722e36SBarry Smith   /* interpolations only sum to 1 when using direct solver */
1228e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
123064c8009SBarry Smith   for (i = 0; i < Nsurf; i++) {
124064c8009SBarry Smith     tmp = 0.0;
1252fa5cd67SKarl Rupp     for (j = 0; j < 26; j++) tmp += xsurf[i + j * Nsurf];
12663a3b9bcSJacob Faibussowitsch     PetscCheck(PetscAbsScalar(tmp - 1.0) <= 1.e-10, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong Xsurf interpolation at i %" PetscInt_FMT " value %g", i, (double)PetscAbsScalar(tmp));
127064c8009SBarry Smith   }
128064c8009SBarry Smith #endif
1299566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(Xsurf, &xsurf));
1309566063dSJacob Faibussowitsch   /* PetscCall(MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD));*/
131064c8009SBarry Smith 
132064c8009SBarry Smith   /*
133064c8009SBarry Smith        I are the indices for all the needed vertices (in global numbering)
134064c8009SBarry Smith        Iint are the indices for the interior values, I surf for the surface values
1357dae84e0SHong Zhang             (This is just for the part of the global matrix obtained with MatCreateSubMatrix(), it
136aa219208SBarry Smith              is NOT the local DMDA ordering.)
137064c8009SBarry Smith        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
138064c8009SBarry Smith   */
139064c8009SBarry Smith #define Endpoint(a, start, b) (a == 0 || a == (b - 1 - start))
1409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(N, &II, Nint, &Iint, Nsurf, &Isurf));
1419566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(Nint, &IIint, Nsurf, &IIsurf));
142064c8009SBarry Smith   for (k = 0; k < p - kstart; k++) {
143064c8009SBarry Smith     for (j = 0; j < n - jstart; j++) {
144064c8009SBarry Smith       for (i = 0; i < m - istart; i++) {
145064c8009SBarry Smith         II[c++] = i + j * mwidth + k * mwidth * nwidth;
146064c8009SBarry Smith 
147064c8009SBarry Smith         if (!Endpoint(i, istart, m) && !Endpoint(j, jstart, n) && !Endpoint(k, kstart, p)) {
148064c8009SBarry Smith           IIint[cint]  = i + j * mwidth + k * mwidth * nwidth;
149064c8009SBarry Smith           Iint[cint++] = i + j * (m - istart) + k * (m - istart) * (n - jstart);
150064c8009SBarry Smith         } else {
151064c8009SBarry Smith           IIsurf[csurf]  = i + j * mwidth + k * mwidth * nwidth;
152064c8009SBarry Smith           Isurf[csurf++] = i + j * (m - istart) + k * (m - istart) * (n - jstart);
153064c8009SBarry Smith         }
154064c8009SBarry Smith       }
155064c8009SBarry Smith     }
156064c8009SBarry Smith   }
15708401ef6SPierre Jolivet   PetscCheck(c == N, PETSC_COMM_SELF, PETSC_ERR_PLIB, "c != N");
15808401ef6SPierre Jolivet   PetscCheck(cint == Nint, PETSC_COMM_SELF, PETSC_ERR_PLIB, "cint != Nint");
15908401ef6SPierre Jolivet   PetscCheck(csurf == Nsurf, PETSC_COMM_SELF, PETSC_ERR_PLIB, "csurf != Nsurf");
1609566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(da, &ltg));
1619566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(ltg, N, II, II));
1629566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(ltg, Nint, IIint, IIint));
1639566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(ltg, Nsurf, IIsurf, IIsurf));
1649566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)da, &comm));
1659566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, N, II, PETSC_COPY_VALUES, &is));
1669566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, Nint, Iint, PETSC_COPY_VALUES, &isint));
1679566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, Nsurf, Isurf, PETSC_COPY_VALUES, &issurf));
1689566063dSJacob Faibussowitsch   PetscCall(PetscFree3(II, Iint, Isurf));
169064c8009SBarry Smith 
1709566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(Aglobal, 1, &is, &is, MAT_INITIAL_MATRIX, &Aholder));
171064c8009SBarry Smith   A = *Aholder;
1729566063dSJacob Faibussowitsch   PetscCall(PetscFree(Aholder));
173064c8009SBarry Smith 
1749566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, isint, isint, MAT_INITIAL_MATRIX, &Aii));
1759566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, isint, issurf, MAT_INITIAL_MATRIX, &Ais));
1769566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, issurf, isint, MAT_INITIAL_MATRIX, &Asi));
177064c8009SBarry Smith 
178064c8009SBarry Smith   /*
179064c8009SBarry Smith      Solve for the interpolation onto the interior Xint
180064c8009SBarry Smith   */
1819566063dSJacob Faibussowitsch   PetscCall(MatMatMult(Ais, Xsurf, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &Xint_tmp));
1829566063dSJacob Faibussowitsch   PetscCall(MatScale(Xint_tmp, -1.0));
1838e722e36SBarry Smith   if (exotic->directSolve) {
1849566063dSJacob Faibussowitsch     PetscCall(MatGetFactor(Aii, MATSOLVERPETSC, MAT_FACTOR_LU, &iAii));
1859566063dSJacob Faibussowitsch     PetscCall(MatFactorInfoInitialize(&info));
1869566063dSJacob Faibussowitsch     PetscCall(MatGetOrdering(Aii, MATORDERINGND, &row, &col));
1879566063dSJacob Faibussowitsch     PetscCall(MatLUFactorSymbolic(iAii, Aii, row, col, &info));
1889566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&row));
1899566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&col));
1909566063dSJacob Faibussowitsch     PetscCall(MatLUFactorNumeric(iAii, Aii, &info));
1919566063dSJacob Faibussowitsch     PetscCall(MatMatSolve(iAii, Xint_tmp, Xint));
1929566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&iAii));
1938e722e36SBarry Smith   } else {
1948e722e36SBarry Smith     Vec          b, x;
1958e722e36SBarry Smith     PetscScalar *xint_tmp;
196064c8009SBarry Smith 
1979566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(Xint, &xint));
1989566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, Nint, NULL, &x));
1999566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(Xint_tmp, &xint_tmp));
2009566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, Nint, NULL, &b));
2019566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(exotic->ksp, Aii, Aii));
2028e722e36SBarry Smith     for (i = 0; i < 26; i++) {
2039566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(x, xint + i * Nint));
2049566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(b, xint_tmp + i * Nint));
2059566063dSJacob Faibussowitsch       PetscCall(KSPSolve(exotic->ksp, b, x));
2069566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(exotic->ksp, pc, x));
2079566063dSJacob Faibussowitsch       PetscCall(VecResetArray(x));
2089566063dSJacob Faibussowitsch       PetscCall(VecResetArray(b));
2098e722e36SBarry Smith     }
2109566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArray(Xint, &xint));
2119566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArray(Xint_tmp, &xint_tmp));
2129566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x));
2139566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&b));
2148e722e36SBarry Smith   }
2159566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Xint_tmp));
2168e722e36SBarry Smith 
2178e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
2189566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(Xint, &rxint));
219064c8009SBarry Smith   for (i = 0; i < Nint; i++) {
220064c8009SBarry Smith     tmp = 0.0;
2211683a169SBarry Smith     for (j = 0; j < 26; j++) tmp += rxint[i + j * Nint];
2222fa5cd67SKarl Rupp 
22363a3b9bcSJacob Faibussowitsch     PetscCheck(PetscAbsScalar(tmp - 1.0) <= 1.e-10, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong Xint interpolation at i %" PetscInt_FMT " value %g", i, (double)PetscAbsScalar(tmp));
224064c8009SBarry Smith   }
2259566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(Xint, &rxint));
2269566063dSJacob Faibussowitsch   /* PetscCall(MatView(Xint,PETSC_VIEWER_STDOUT_WORLD)); */
227064c8009SBarry Smith #endif
228064c8009SBarry Smith 
229064c8009SBarry Smith   /*         total vertices             total faces                                  total edges */
230064c8009SBarry 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);
231064c8009SBarry Smith 
232064c8009SBarry Smith   /*
233064c8009SBarry Smith       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
234064c8009SBarry Smith   */
235064c8009SBarry Smith   cnt = 0;
2362fa5cd67SKarl Rupp 
2379371c9d4SSatish Balay   gl[cnt++] = 0;
2389371c9d4SSatish Balay   { gl[cnt++] = 1; }
2399371c9d4SSatish Balay   gl[cnt++] = m - istart - 1;
240064c8009SBarry Smith   {
2419371c9d4SSatish Balay     gl[cnt++] = mwidth;
2429371c9d4SSatish Balay     { gl[cnt++] = mwidth + 1; }
2439371c9d4SSatish Balay     gl[cnt++] = mwidth + m - istart - 1;
244064c8009SBarry Smith   }
2459371c9d4SSatish Balay   gl[cnt++] = mwidth * (n - jstart - 1);
2469371c9d4SSatish Balay   { gl[cnt++] = mwidth * (n - jstart - 1) + 1; }
2479371c9d4SSatish Balay   gl[cnt++] = mwidth * (n - jstart - 1) + m - istart - 1;
2489371c9d4SSatish Balay   {
2499371c9d4SSatish Balay     gl[cnt++] = mwidth * nwidth;
2509371c9d4SSatish Balay     { gl[cnt++] = mwidth * nwidth + 1; }
2519371c9d4SSatish Balay     gl[cnt++] = mwidth * nwidth + m - istart - 1;
2529371c9d4SSatish Balay     {
2539371c9d4SSatish Balay       gl[cnt++] = mwidth * nwidth + mwidth; /* these are the interior nodes */
2549371c9d4SSatish Balay       gl[cnt++] = mwidth * nwidth + mwidth + m - istart - 1;
2559371c9d4SSatish Balay     }
2569371c9d4SSatish Balay     gl[cnt++] = mwidth * nwidth + mwidth * (n - jstart - 1);
2579371c9d4SSatish Balay     { gl[cnt++] = mwidth * nwidth + mwidth * (n - jstart - 1) + 1; }
2589371c9d4SSatish Balay     gl[cnt++] = mwidth * nwidth + mwidth * (n - jstart - 1) + m - istart - 1;
2599371c9d4SSatish Balay   }
2609371c9d4SSatish Balay   gl[cnt++] = mwidth * nwidth * (p - kstart - 1);
2619371c9d4SSatish Balay   { gl[cnt++] = mwidth * nwidth * (p - kstart - 1) + 1; }
2629371c9d4SSatish Balay   gl[cnt++] = mwidth * nwidth * (p - kstart - 1) + m - istart - 1;
2639371c9d4SSatish Balay   {
2649371c9d4SSatish Balay     gl[cnt++] = mwidth * nwidth * (p - kstart - 1) + mwidth;
2659371c9d4SSatish Balay     { gl[cnt++] = mwidth * nwidth * (p - kstart - 1) + mwidth + 1; }
2669371c9d4SSatish Balay     gl[cnt++] = mwidth * nwidth * (p - kstart - 1) + mwidth + m - istart - 1;
2679371c9d4SSatish Balay   }
2689371c9d4SSatish Balay   gl[cnt++] = mwidth * nwidth * (p - kstart - 1) + mwidth * (n - jstart - 1);
2699371c9d4SSatish Balay   { gl[cnt++] = mwidth * nwidth * (p - kstart - 1) + mwidth * (n - jstart - 1) + 1; }
2709371c9d4SSatish Balay   gl[cnt++] = mwidth * nwidth * (p - kstart - 1) + mwidth * (n - jstart - 1) + m - istart - 1;
271064c8009SBarry Smith 
272064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
273064c8009SBarry Smith   /* convert that to global numbering and get them on all processes */
2749566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(ltg, 26, gl, gl));
275064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
2769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(26 * mp * np * pp, &globals));
2779566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allgather(gl, 26, MPIU_INT, globals, 26, MPIU_INT, PetscObjectComm((PetscObject)da)));
278064c8009SBarry Smith 
279064c8009SBarry Smith   /* Number the coarse grid points from 0 to Ntotal */
2809566063dSJacob Faibussowitsch   PetscCall(MatGetSize(Aglobal, &Nt, NULL));
2819566063dSJacob Faibussowitsch   PetscCall(PetscTableCreate(Ntotal / 3, Nt + 1, &ht));
28248a46eb9SPierre Jolivet   for (i = 0; i < 26 * mp * np * pp; i++) PetscCall(PetscTableAddCount(ht, globals[i] + 1));
2839566063dSJacob Faibussowitsch   PetscCall(PetscTableGetCount(ht, &cnt));
28463a3b9bcSJacob Faibussowitsch   PetscCheck(cnt == Ntotal, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hash table size %" PetscInt_FMT " not equal to total number coarse grid points %" PetscInt_FMT, cnt, Ntotal);
2859566063dSJacob Faibussowitsch   PetscCall(PetscFree(globals));
286064c8009SBarry Smith   for (i = 0; i < 26; i++) {
2879566063dSJacob Faibussowitsch     PetscCall(PetscTableFind(ht, gl[i] + 1, &gl[i]));
288064c8009SBarry Smith     gl[i]--;
289064c8009SBarry Smith   }
2909566063dSJacob Faibussowitsch   PetscCall(PetscTableDestroy(&ht));
291064c8009SBarry Smith   /* PetscIntView(26,gl,PETSC_VIEWER_STDOUT_WORLD); */
292064c8009SBarry Smith 
293064c8009SBarry Smith   /* construct global interpolation matrix */
2949566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(Aglobal, &Ng, NULL));
295064c8009SBarry Smith   if (reuse == MAT_INITIAL_MATRIX) {
2969566063dSJacob Faibussowitsch     PetscCall(MatCreateAIJ(PetscObjectComm((PetscObject)da), Ng, PETSC_DECIDE, PETSC_DECIDE, Ntotal, Nint + Nsurf, NULL, Nint + Nsurf, NULL, P));
297064c8009SBarry Smith   } else {
2989566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(*P));
299064c8009SBarry Smith   }
3009566063dSJacob Faibussowitsch   PetscCall(MatSetOption(*P, MAT_ROW_ORIENTED, PETSC_FALSE));
3019566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(Xint, &rxint));
3029566063dSJacob Faibussowitsch   PetscCall(MatSetValues(*P, Nint, IIint, 26, gl, rxint, INSERT_VALUES));
3039566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(Xint, &rxint));
3049566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(Xsurf, &rxint));
3059566063dSJacob Faibussowitsch   PetscCall(MatSetValues(*P, Nsurf, IIsurf, 26, gl, rxint, INSERT_VALUES));
3069566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(Xsurf, &rxint));
3079566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY));
3089566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY));
3099566063dSJacob Faibussowitsch   PetscCall(PetscFree2(IIint, IIsurf));
310064c8009SBarry Smith 
3118e722e36SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
312064c8009SBarry Smith   {
313064c8009SBarry Smith     Vec          x, y;
314064c8009SBarry Smith     PetscScalar *yy;
3159566063dSJacob Faibussowitsch     PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)da), Ng, PETSC_DETERMINE, &y));
3169566063dSJacob Faibussowitsch     PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)da), PETSC_DETERMINE, Ntotal, &x));
3179566063dSJacob Faibussowitsch     PetscCall(VecSet(x, 1.0));
3189566063dSJacob Faibussowitsch     PetscCall(MatMult(*P, x, y));
3199566063dSJacob Faibussowitsch     PetscCall(VecGetArray(y, &yy));
320ad540459SPierre Jolivet     for (i = 0; i < Ng; i++) PetscCheck(PetscAbsScalar(yy[i] - 1.0) <= 1.e-10, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong p interpolation at i %" PetscInt_FMT " value %g", i, (double)PetscAbsScalar(yy[i]));
3219566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(y, &yy));
3229566063dSJacob Faibussowitsch     PetscCall(VecDestroy(x));
3239566063dSJacob Faibussowitsch     PetscCall(VecDestroy(y));
324064c8009SBarry Smith   }
325064c8009SBarry Smith #endif
326064c8009SBarry Smith 
3279566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Aii));
3289566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Ais));
3299566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Asi));
3309566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A));
3319566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is));
3329566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isint));
3339566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&issurf));
3349566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Xint));
3359566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Xsurf));
336064c8009SBarry Smith   PetscFunctionReturn(0);
337064c8009SBarry Smith }
338064c8009SBarry Smith 
339064c8009SBarry Smith /*
340aa219208SBarry Smith       DMDAGetFaceInterpolation - Gets the interpolation for a face based coarse space
341064c8009SBarry Smith 
342064c8009SBarry Smith */
3439371c9d4SSatish Balay PetscErrorCode DMDAGetFaceInterpolation(PC pc, DM da, PC_Exotic *exotic, Mat Aglobal, MatReuse reuse, Mat *P) {
344064c8009SBarry 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;
34528d20b34SBarry Smith   PetscInt               mwidth, nwidth, pwidth, cnt, mp, np, pp, Ntotal, gl[6], *globals, Ng, *IIint, *IIsurf, Nt;
346064c8009SBarry Smith   Mat                    Xint, Xsurf, Xint_tmp;
347064c8009SBarry Smith   IS                     isint, issurf, is, row, col;
348064c8009SBarry Smith   ISLocalToGlobalMapping ltg;
349064c8009SBarry Smith   MPI_Comm               comm;
350064c8009SBarry Smith   Mat                    A, Aii, Ais, Asi, *Aholder, iAii;
351064c8009SBarry Smith   MatFactorInfo          info;
352064c8009SBarry Smith   PetscScalar           *xsurf, *xint;
3531683a169SBarry Smith   const PetscScalar     *rxint;
354064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
355064c8009SBarry Smith   PetscScalar tmp;
356064c8009SBarry Smith #endif
357064c8009SBarry Smith   PetscTable ht;
358064c8009SBarry Smith 
359064c8009SBarry Smith   PetscFunctionBegin;
3609566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, &dim, NULL, NULL, NULL, &mp, &np, &pp, &dof, NULL, NULL, NULL, NULL, NULL));
36108401ef6SPierre Jolivet   PetscCheck(dof == 1, PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Only for single field problems");
36208401ef6SPierre Jolivet   PetscCheck(dim == 3, PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Only coded for 3d problems");
3639566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, NULL, NULL, NULL, &m, &n, &p));
3649566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(da, &istart, &jstart, &kstart, &mwidth, &nwidth, &pwidth));
365064c8009SBarry Smith   istart = istart ? -1 : 0;
366064c8009SBarry Smith   jstart = jstart ? -1 : 0;
367064c8009SBarry Smith   kstart = kstart ? -1 : 0;
368064c8009SBarry Smith 
369064c8009SBarry Smith   /*
370064c8009SBarry Smith     the columns of P are the interpolation of each coarse grid point (one for each vertex and edge)
371064c8009SBarry Smith     to all the local degrees of freedom (this includes the vertices, edges and faces).
372064c8009SBarry Smith 
373064c8009SBarry Smith     Xint are the subset of the interpolation into the interior
374064c8009SBarry Smith 
375064c8009SBarry Smith     Xface are the interpolation onto faces but not into the interior
376064c8009SBarry Smith 
377064c8009SBarry Smith     Xsurf are the interpolation onto the vertices and edges (the surfbasket)
378064c8009SBarry Smith                                       Xint
379064c8009SBarry Smith     Symbolically one could write P = (Xface) after interchanging the rows to match the natural ordering on the domain
380064c8009SBarry Smith                                       Xsurf
381064c8009SBarry Smith   */
382064c8009SBarry Smith   N     = (m - istart) * (n - jstart) * (p - kstart);
383064c8009SBarry Smith   Nint  = (m - 2 - istart) * (n - 2 - jstart) * (p - 2 - kstart);
384064c8009SBarry Smith   Nface = 2 * ((m - 2 - istart) * (n - 2 - jstart) + (m - 2 - istart) * (p - 2 - kstart) + (n - 2 - jstart) * (p - 2 - kstart));
385064c8009SBarry Smith   Nwire = 4 * ((m - 2 - istart) + (n - 2 - jstart) + (p - 2 - kstart)) + 8;
386064c8009SBarry Smith   Nsurf = Nface + Nwire;
3879566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(MPI_COMM_SELF, Nint, 6, NULL, &Xint));
3889566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqDense(MPI_COMM_SELF, Nsurf, 6, NULL, &Xsurf));
3899566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(Xsurf, &xsurf));
390064c8009SBarry Smith 
391064c8009SBarry Smith   /*
392064c8009SBarry Smith      Require that all 12 edges and 6 faces have at least one grid point. Otherwise some of the columns of
393064c8009SBarry Smith      Xsurf will be all zero (thus making the coarse matrix singular).
394064c8009SBarry Smith   */
39508401ef6SPierre Jolivet   PetscCheck(m - istart >= 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of grid points per process in X direction must be at least 3");
39608401ef6SPierre Jolivet   PetscCheck(n - jstart >= 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of grid points per process in Y direction must be at least 3");
39708401ef6SPierre Jolivet   PetscCheck(p - kstart >= 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Number of grid points per process in Z direction must be at least 3");
398064c8009SBarry Smith 
399064c8009SBarry Smith   cnt = 0;
4002fa5cd67SKarl Rupp   for (j = 1; j < n - 1 - jstart; j++) {
4012fa5cd67SKarl Rupp     for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + 0 * Nsurf] = 1;
402064c8009SBarry Smith   }
4032fa5cd67SKarl Rupp 
4042fa5cd67SKarl Rupp   for (k = 1; k < p - 1 - kstart; k++) {
4052fa5cd67SKarl Rupp     for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + 1 * Nsurf] = 1;
4062fa5cd67SKarl Rupp     for (j = 1; j < n - 1 - jstart; j++) {
4072fa5cd67SKarl Rupp       xsurf[cnt++ + 2 * Nsurf] = 1;
4082fa5cd67SKarl Rupp       /* these are the interior nodes */
4092fa5cd67SKarl Rupp       xsurf[cnt++ + 3 * Nsurf] = 1;
4102fa5cd67SKarl Rupp     }
4112fa5cd67SKarl Rupp     for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + 4 * Nsurf] = 1;
4122fa5cd67SKarl Rupp   }
4132fa5cd67SKarl Rupp   for (j = 1; j < n - 1 - jstart; j++) {
4142fa5cd67SKarl Rupp     for (i = 1; i < m - istart - 1; i++) xsurf[cnt++ + 5 * Nsurf] = 1;
4152fa5cd67SKarl Rupp   }
416064c8009SBarry Smith 
417064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
418064c8009SBarry Smith   for (i = 0; i < Nsurf; i++) {
419064c8009SBarry Smith     tmp = 0.0;
4202fa5cd67SKarl Rupp     for (j = 0; j < 6; j++) tmp += xsurf[i + j * Nsurf];
4212fa5cd67SKarl Rupp 
42263a3b9bcSJacob Faibussowitsch     PetscCheck(PetscAbsScalar(tmp - 1.0) <= 1.e-10, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong Xsurf interpolation at i %" PetscInt_FMT " value %g", i, (double)PetscAbsScalar(tmp));
423064c8009SBarry Smith   }
424064c8009SBarry Smith #endif
4259566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(Xsurf, &xsurf));
4269566063dSJacob Faibussowitsch   /* PetscCall(MatView(Xsurf,PETSC_VIEWER_STDOUT_WORLD));*/
427064c8009SBarry Smith 
428064c8009SBarry Smith   /*
429064c8009SBarry Smith        I are the indices for all the needed vertices (in global numbering)
430064c8009SBarry Smith        Iint are the indices for the interior values, I surf for the surface values
4317dae84e0SHong Zhang             (This is just for the part of the global matrix obtained with MatCreateSubMatrix(), it
432aa219208SBarry Smith              is NOT the local DMDA ordering.)
433064c8009SBarry Smith        IIint and IIsurf are the same as the Iint, Isurf except they are in the global numbering
434064c8009SBarry Smith   */
435064c8009SBarry Smith #define Endpoint(a, start, b) (a == 0 || a == (b - 1 - start))
4369566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(N, &II, Nint, &Iint, Nsurf, &Isurf));
4379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(Nint, &IIint, Nsurf, &IIsurf));
438064c8009SBarry Smith   for (k = 0; k < p - kstart; k++) {
439064c8009SBarry Smith     for (j = 0; j < n - jstart; j++) {
440064c8009SBarry Smith       for (i = 0; i < m - istart; i++) {
441064c8009SBarry Smith         II[c++] = i + j * mwidth + k * mwidth * nwidth;
442064c8009SBarry Smith 
443064c8009SBarry Smith         if (!Endpoint(i, istart, m) && !Endpoint(j, jstart, n) && !Endpoint(k, kstart, p)) {
444064c8009SBarry Smith           IIint[cint]  = i + j * mwidth + k * mwidth * nwidth;
445064c8009SBarry Smith           Iint[cint++] = i + j * (m - istart) + k * (m - istart) * (n - jstart);
446064c8009SBarry Smith         } else {
447064c8009SBarry Smith           IIsurf[csurf]  = i + j * mwidth + k * mwidth * nwidth;
448064c8009SBarry Smith           Isurf[csurf++] = i + j * (m - istart) + k * (m - istart) * (n - jstart);
449064c8009SBarry Smith         }
450064c8009SBarry Smith       }
451064c8009SBarry Smith     }
452064c8009SBarry Smith   }
45308401ef6SPierre Jolivet   PetscCheck(c == N, PETSC_COMM_SELF, PETSC_ERR_PLIB, "c != N");
45408401ef6SPierre Jolivet   PetscCheck(cint == Nint, PETSC_COMM_SELF, PETSC_ERR_PLIB, "cint != Nint");
45508401ef6SPierre Jolivet   PetscCheck(csurf == Nsurf, PETSC_COMM_SELF, PETSC_ERR_PLIB, "csurf != Nsurf");
4569566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(da, &ltg));
4579566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(ltg, N, II, II));
4589566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(ltg, Nint, IIint, IIint));
4599566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(ltg, Nsurf, IIsurf, IIsurf));
4609566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)da, &comm));
4619566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(comm, N, II, PETSC_COPY_VALUES, &is));
4629566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, Nint, Iint, PETSC_COPY_VALUES, &isint));
4639566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, Nsurf, Isurf, PETSC_COPY_VALUES, &issurf));
4649566063dSJacob Faibussowitsch   PetscCall(PetscFree3(II, Iint, Isurf));
465064c8009SBarry Smith 
4669566063dSJacob Faibussowitsch   PetscCall(ISSort(is));
4679566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(Aglobal, 1, &is, &is, MAT_INITIAL_MATRIX, &Aholder));
468064c8009SBarry Smith   A = *Aholder;
4699566063dSJacob Faibussowitsch   PetscCall(PetscFree(Aholder));
470064c8009SBarry Smith 
4719566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, isint, isint, MAT_INITIAL_MATRIX, &Aii));
4729566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, isint, issurf, MAT_INITIAL_MATRIX, &Ais));
4739566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrix(A, issurf, isint, MAT_INITIAL_MATRIX, &Asi));
474064c8009SBarry Smith 
475064c8009SBarry Smith   /*
476064c8009SBarry Smith      Solve for the interpolation onto the interior Xint
477064c8009SBarry Smith   */
4789566063dSJacob Faibussowitsch   PetscCall(MatMatMult(Ais, Xsurf, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &Xint_tmp));
4799566063dSJacob Faibussowitsch   PetscCall(MatScale(Xint_tmp, -1.0));
480064c8009SBarry Smith 
4818e722e36SBarry Smith   if (exotic->directSolve) {
4829566063dSJacob Faibussowitsch     PetscCall(MatGetFactor(Aii, MATSOLVERPETSC, MAT_FACTOR_LU, &iAii));
4839566063dSJacob Faibussowitsch     PetscCall(MatFactorInfoInitialize(&info));
4849566063dSJacob Faibussowitsch     PetscCall(MatGetOrdering(Aii, MATORDERINGND, &row, &col));
4859566063dSJacob Faibussowitsch     PetscCall(MatLUFactorSymbolic(iAii, Aii, row, col, &info));
4869566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&row));
4879566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&col));
4889566063dSJacob Faibussowitsch     PetscCall(MatLUFactorNumeric(iAii, Aii, &info));
4899566063dSJacob Faibussowitsch     PetscCall(MatMatSolve(iAii, Xint_tmp, Xint));
4909566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&iAii));
491064c8009SBarry Smith   } else {
492064c8009SBarry Smith     Vec          b, x;
493064c8009SBarry Smith     PetscScalar *xint_tmp;
494064c8009SBarry Smith 
4959566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(Xint, &xint));
4969566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, Nint, NULL, &x));
4979566063dSJacob Faibussowitsch     PetscCall(MatDenseGetArray(Xint_tmp, &xint_tmp));
4989566063dSJacob Faibussowitsch     PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, Nint, NULL, &b));
4999566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(exotic->ksp, Aii, Aii));
500064c8009SBarry Smith     for (i = 0; i < 6; i++) {
5019566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(x, xint + i * Nint));
5029566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(b, xint_tmp + i * Nint));
5039566063dSJacob Faibussowitsch       PetscCall(KSPSolve(exotic->ksp, b, x));
5049566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(exotic->ksp, pc, x));
5059566063dSJacob Faibussowitsch       PetscCall(VecResetArray(x));
5069566063dSJacob Faibussowitsch       PetscCall(VecResetArray(b));
507064c8009SBarry Smith     }
5089566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArray(Xint, &xint));
5099566063dSJacob Faibussowitsch     PetscCall(MatDenseRestoreArray(Xint_tmp, &xint_tmp));
5109566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&x));
5119566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&b));
512064c8009SBarry Smith   }
5139566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Xint_tmp));
514064c8009SBarry Smith 
515064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
5169566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(Xint, &rxint));
517064c8009SBarry Smith   for (i = 0; i < Nint; i++) {
518064c8009SBarry Smith     tmp = 0.0;
5191683a169SBarry Smith     for (j = 0; j < 6; j++) tmp += rxint[i + j * Nint];
5202fa5cd67SKarl Rupp 
52163a3b9bcSJacob Faibussowitsch     PetscCheck(PetscAbsScalar(tmp - 1.0) <= 1.e-10, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong Xint interpolation at i %" PetscInt_FMT " value %g", i, (double)PetscAbsScalar(tmp));
522064c8009SBarry Smith   }
5239566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(Xint, &rxint));
5249566063dSJacob Faibussowitsch   /* PetscCall(MatView(Xint,PETSC_VIEWER_STDOUT_WORLD)); */
525064c8009SBarry Smith #endif
526064c8009SBarry Smith 
527064c8009SBarry Smith   /*         total faces    */
528064c8009SBarry Smith   Ntotal = mp * np * (pp + 1) + mp * pp * (np + 1) + np * pp * (mp + 1);
529064c8009SBarry Smith 
530064c8009SBarry Smith   /*
531064c8009SBarry Smith       For each vertex, edge, face on process (in the same orderings as used above) determine its local number including ghost points
532064c8009SBarry Smith   */
533064c8009SBarry Smith   cnt = 0;
534064c8009SBarry Smith   { gl[cnt++] = mwidth + 1; }
5359371c9d4SSatish Balay   {{gl[cnt++] = mwidth * nwidth + 1;
5369371c9d4SSatish Balay }
537064c8009SBarry Smith {
5389371c9d4SSatish Balay   gl[cnt++] = mwidth * nwidth + mwidth; /* these are the interior nodes */
5399371c9d4SSatish Balay   gl[cnt++] = mwidth * nwidth + mwidth + m - istart - 1;
5409371c9d4SSatish Balay }
541064c8009SBarry Smith { gl[cnt++] = mwidth * nwidth + mwidth * (n - jstart - 1) + 1; }
542064c8009SBarry Smith }
543064c8009SBarry Smith { gl[cnt++] = mwidth * nwidth * (p - kstart - 1) + mwidth + 1; }
544064c8009SBarry Smith 
545064c8009SBarry Smith /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
546064c8009SBarry Smith /* convert that to global numbering and get them on all processes */
5479566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingApply(ltg, 6, gl, gl));
548064c8009SBarry Smith /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
5499566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(6 * mp * np * pp, &globals));
5509566063dSJacob Faibussowitsch PetscCallMPI(MPI_Allgather(gl, 6, MPIU_INT, globals, 6, MPIU_INT, PetscObjectComm((PetscObject)da)));
551064c8009SBarry Smith 
552064c8009SBarry Smith /* Number the coarse grid points from 0 to Ntotal */
5539566063dSJacob Faibussowitsch PetscCall(MatGetSize(Aglobal, &Nt, NULL));
5549566063dSJacob Faibussowitsch PetscCall(PetscTableCreate(Ntotal / 3, Nt + 1, &ht));
55548a46eb9SPierre Jolivet for (i = 0; i < 6 * mp * np * pp; i++) PetscCall(PetscTableAddCount(ht, globals[i] + 1));
5569566063dSJacob Faibussowitsch PetscCall(PetscTableGetCount(ht, &cnt));
55763a3b9bcSJacob Faibussowitsch PetscCheck(cnt == Ntotal, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hash table size %" PetscInt_FMT " not equal to total number coarse grid points %" PetscInt_FMT, cnt, Ntotal);
5589566063dSJacob Faibussowitsch PetscCall(PetscFree(globals));
559064c8009SBarry Smith for (i = 0; i < 6; i++) {
5609566063dSJacob Faibussowitsch   PetscCall(PetscTableFind(ht, gl[i] + 1, &gl[i]));
561064c8009SBarry Smith   gl[i]--;
562064c8009SBarry Smith }
5639566063dSJacob Faibussowitsch PetscCall(PetscTableDestroy(&ht));
564064c8009SBarry Smith /* PetscIntView(6,gl,PETSC_VIEWER_STDOUT_WORLD); */
565064c8009SBarry Smith 
566064c8009SBarry Smith /* construct global interpolation matrix */
5679566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(Aglobal, &Ng, NULL));
568064c8009SBarry Smith if (reuse == MAT_INITIAL_MATRIX) {
5699566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(PetscObjectComm((PetscObject)da), Ng, PETSC_DECIDE, PETSC_DECIDE, Ntotal, Nint + Nsurf, NULL, Nint, NULL, P));
570064c8009SBarry Smith } else {
5719566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(*P));
572064c8009SBarry Smith }
5739566063dSJacob Faibussowitsch PetscCall(MatSetOption(*P, MAT_ROW_ORIENTED, PETSC_FALSE));
5749566063dSJacob Faibussowitsch PetscCall(MatDenseGetArrayRead(Xint, &rxint));
5759566063dSJacob Faibussowitsch PetscCall(MatSetValues(*P, Nint, IIint, 6, gl, rxint, INSERT_VALUES));
5769566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArrayRead(Xint, &rxint));
5779566063dSJacob Faibussowitsch PetscCall(MatDenseGetArrayRead(Xsurf, &rxint));
5789566063dSJacob Faibussowitsch PetscCall(MatSetValues(*P, Nsurf, IIsurf, 6, gl, rxint, INSERT_VALUES));
5799566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArrayRead(Xsurf, &rxint));
5809566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY));
5819566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY));
5829566063dSJacob Faibussowitsch PetscCall(PetscFree2(IIint, IIsurf));
583064c8009SBarry Smith 
584064c8009SBarry Smith #if defined(PETSC_USE_DEBUG_foo)
585064c8009SBarry Smith {
586064c8009SBarry Smith   Vec          x, y;
587064c8009SBarry Smith   PetscScalar *yy;
5889566063dSJacob Faibussowitsch   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)da), Ng, PETSC_DETERMINE, &y));
5899566063dSJacob Faibussowitsch   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)da), PETSC_DETERMINE, Ntotal, &x));
5909566063dSJacob Faibussowitsch   PetscCall(VecSet(x, 1.0));
5919566063dSJacob Faibussowitsch   PetscCall(MatMult(*P, x, y));
5929566063dSJacob Faibussowitsch   PetscCall(VecGetArray(y, &yy));
593ad540459SPierre Jolivet   for (i = 0; i < Ng; i++) PetscCheck(PetscAbsScalar(yy[i] - 1.0) <= 1.e-10, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong p interpolation at i %" PetscInt_FMT " value %g", i, (double)PetscAbsScalar(yy[i]));
5949566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(y, &yy));
5959566063dSJacob Faibussowitsch   PetscCall(VecDestroy(x));
5969566063dSJacob Faibussowitsch   PetscCall(VecDestroy(y));
597064c8009SBarry Smith }
598064c8009SBarry Smith #endif
599064c8009SBarry Smith 
6009566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Aii));
6019566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Ais));
6029566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Asi));
6039566063dSJacob Faibussowitsch PetscCall(MatDestroy(&A));
6049566063dSJacob Faibussowitsch PetscCall(ISDestroy(&is));
6059566063dSJacob Faibussowitsch PetscCall(ISDestroy(&isint));
6069566063dSJacob Faibussowitsch PetscCall(ISDestroy(&issurf));
6079566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Xint));
6089566063dSJacob Faibussowitsch PetscCall(MatDestroy(&Xsurf));
609064c8009SBarry Smith PetscFunctionReturn(0);
610064c8009SBarry Smith }
611174b6946SBarry Smith 
6127233f9f0SBarry Smith /*@
6137233f9f0SBarry Smith    PCExoticSetType - Sets the type of coarse grid interpolation to use
6147233f9f0SBarry Smith 
615*f1580f4eSBarry Smith    Logically Collective on pc
6167233f9f0SBarry Smith 
6177233f9f0SBarry Smith    Input Parameters:
6187233f9f0SBarry Smith +  pc - the preconditioner context
6197233f9f0SBarry Smith -  type - either PC_EXOTIC_FACE or PC_EXOTIC_WIREBASKET (defaults to face)
6207233f9f0SBarry Smith 
62195452b02SPatrick Sanan    Notes:
62295452b02SPatrick Sanan     The face based interpolation has 1 degree of freedom per face and ignores the
623563e08c6SBarry Smith      edge and vertex values completely in the coarse problem. For any seven point
624563e08c6SBarry Smith      stencil the interpolation of a constant on all faces into the interior is that constant.
625563e08c6SBarry Smith 
626563e08c6SBarry Smith      The wirebasket interpolation has 1 degree of freedom per vertex, per edge and
627563e08c6SBarry Smith      per face. A constant on the subdomain boundary is interpolated as that constant
628563e08c6SBarry Smith      in the interior of the domain.
629563e08c6SBarry Smith 
630563e08c6SBarry Smith      The coarse grid matrix is obtained via the Galerkin computation A_c = R A R^T, hence
631563e08c6SBarry Smith      if A is nonsingular A_c is also nonsingular.
632563e08c6SBarry Smith 
633563e08c6SBarry Smith      Both interpolations are suitable for only scalar problems.
634563e08c6SBarry Smith 
6357233f9f0SBarry Smith    Level: intermediate
6367233f9f0SBarry Smith 
637db781477SPatrick Sanan .seealso: `PCEXOTIC`, `PCExoticType()`
6387233f9f0SBarry Smith @*/
6399371c9d4SSatish Balay PetscErrorCode PCExoticSetType(PC pc, PCExoticType type) {
6407233f9f0SBarry Smith   PetscFunctionBegin;
6410700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
642c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc, type, 2);
643cac4c232SBarry Smith   PetscTryMethod(pc, "PCExoticSetType_C", (PC, PCExoticType), (pc, type));
6447233f9f0SBarry Smith   PetscFunctionReturn(0);
6457233f9f0SBarry Smith }
6467233f9f0SBarry Smith 
6479371c9d4SSatish Balay static PetscErrorCode PCExoticSetType_Exotic(PC pc, PCExoticType type) {
648f3fbd535SBarry Smith   PC_MG     *mg  = (PC_MG *)pc->data;
64931567311SBarry Smith   PC_Exotic *ctx = (PC_Exotic *)mg->innerctx;
6507233f9f0SBarry Smith 
6517233f9f0SBarry Smith   PetscFunctionBegin;
6527233f9f0SBarry Smith   ctx->type = type;
6537233f9f0SBarry Smith   PetscFunctionReturn(0);
6547233f9f0SBarry Smith }
6557233f9f0SBarry Smith 
6569371c9d4SSatish Balay PetscErrorCode PCSetUp_Exotic(PC pc) {
65796bdf778SBarry Smith   Mat        A;
658f3fbd535SBarry Smith   PC_MG     *mg    = (PC_MG *)pc->data;
65931567311SBarry Smith   PC_Exotic *ex    = (PC_Exotic *)mg->innerctx;
66096bdf778SBarry Smith   MatReuse   reuse = (ex->P) ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
661174b6946SBarry Smith 
662174b6946SBarry Smith   PetscFunctionBegin;
66328b400f6SJacob Faibussowitsch   PetscCheck(pc->dm, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Need to call PCSetDM() before using this PC");
6649566063dSJacob Faibussowitsch   PetscCall(PCGetOperators(pc, NULL, &A));
6657233f9f0SBarry Smith   if (ex->type == PC_EXOTIC_FACE) {
6669566063dSJacob Faibussowitsch     PetscCall(DMDAGetFaceInterpolation(pc, pc->dm, ex, A, reuse, &ex->P));
6677233f9f0SBarry Smith   } else if (ex->type == PC_EXOTIC_WIREBASKET) {
6689566063dSJacob Faibussowitsch     PetscCall(DMDAGetWireBasketInterpolation(pc, pc->dm, ex, A, reuse, &ex->P));
66998921bdaSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unknown exotic coarse space %d", ex->type);
6709566063dSJacob Faibussowitsch   PetscCall(PCMGSetInterpolation(pc, 1, ex->P));
671d0660788SBarry Smith   /* if PC has attached DM we must remove it or the PCMG will use it to compute incorrect sized vectors and interpolations */
6729566063dSJacob Faibussowitsch   PetscCall(PCSetDM(pc, NULL));
6739566063dSJacob Faibussowitsch   PetscCall(PCSetUp_MG(pc));
674174b6946SBarry Smith   PetscFunctionReturn(0);
675174b6946SBarry Smith }
676174b6946SBarry Smith 
6779371c9d4SSatish Balay PetscErrorCode PCDestroy_Exotic(PC pc) {
678f3fbd535SBarry Smith   PC_MG     *mg  = (PC_MG *)pc->data;
67931567311SBarry Smith   PC_Exotic *ctx = (PC_Exotic *)mg->innerctx;
680174b6946SBarry Smith 
681174b6946SBarry Smith   PetscFunctionBegin;
6829566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ctx->P));
6839566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&ctx->ksp));
6849566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx));
6852e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCExoticSetType_C", NULL));
6869566063dSJacob Faibussowitsch   PetscCall(PCDestroy_MG(pc));
687174b6946SBarry Smith   PetscFunctionReturn(0);
688174b6946SBarry Smith }
689174b6946SBarry Smith 
6909371c9d4SSatish Balay PetscErrorCode PCView_Exotic(PC pc, PetscViewer viewer) {
691f3fbd535SBarry Smith   PC_MG     *mg = (PC_MG *)pc->data;
692ace3abfcSBarry Smith   PetscBool  iascii;
69331567311SBarry Smith   PC_Exotic *ctx = (PC_Exotic *)mg->innerctx;
6947233f9f0SBarry Smith 
6957233f9f0SBarry Smith   PetscFunctionBegin;
6969566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
6977233f9f0SBarry Smith   if (iascii) {
6989566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "    Exotic type = %s\n", PCExoticTypes[ctx->type]));
6998e722e36SBarry Smith     if (ctx->directSolve) {
7009566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "      Using direct solver to construct interpolation\n"));
7018e722e36SBarry Smith     } else {
7028e722e36SBarry Smith       PetscViewer sviewer;
7038e722e36SBarry Smith       PetscMPIInt rank;
7048e722e36SBarry Smith 
7059566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "      Using iterative solver to construct interpolation\n"));
7069566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
7079566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer)); /* should not need to push this twice? */
7089566063dSJacob Faibussowitsch       PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
7099566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank));
71048a46eb9SPierre Jolivet       if (rank == 0) PetscCall(KSPView(ctx->ksp, sviewer));
7119566063dSJacob Faibussowitsch       PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
7129566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
7139566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
7148e722e36SBarry Smith     }
7157233f9f0SBarry Smith   }
7169566063dSJacob Faibussowitsch   PetscCall(PCView_MG(pc, viewer));
7177233f9f0SBarry Smith   PetscFunctionReturn(0);
7187233f9f0SBarry Smith }
7197233f9f0SBarry Smith 
7209371c9d4SSatish Balay PetscErrorCode PCSetFromOptions_Exotic(PC pc, PetscOptionItems *PetscOptionsObject) {
721ace3abfcSBarry Smith   PetscBool    flg;
722f3fbd535SBarry Smith   PC_MG       *mg = (PC_MG *)pc->data;
7237233f9f0SBarry Smith   PCExoticType mgctype;
72431567311SBarry Smith   PC_Exotic   *ctx = (PC_Exotic *)mg->innerctx;
7257233f9f0SBarry Smith 
7267233f9f0SBarry Smith   PetscFunctionBegin;
727d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Exotic coarse space options");
7289566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_exotic_type", "face or wirebasket", "PCExoticSetType", PCExoticTypes, (PetscEnum)ctx->type, (PetscEnum *)&mgctype, &flg));
7291baa6e33SBarry Smith   if (flg) PetscCall(PCExoticSetType(pc, mgctype));
7309566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_exotic_direct_solver", "use direct solver to construct interpolation", "None", ctx->directSolve, &ctx->directSolve, NULL));
7318e722e36SBarry Smith   if (!ctx->directSolve) {
7328e722e36SBarry Smith     if (!ctx->ksp) {
7338e722e36SBarry Smith       const char *prefix;
7349566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PETSC_COMM_SELF, &ctx->ksp));
7359566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(ctx->ksp, pc->erroriffailure));
7369566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)ctx->ksp, (PetscObject)pc, 1));
7379566063dSJacob Faibussowitsch       PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)ctx->ksp));
7389566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc, &prefix));
7399566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(ctx->ksp, prefix));
7409566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(ctx->ksp, "exotic_"));
7418e722e36SBarry Smith     }
7429566063dSJacob Faibussowitsch     PetscCall(KSPSetFromOptions(ctx->ksp));
7438e722e36SBarry Smith   }
744d0609cedSBarry Smith   PetscOptionsHeadEnd();
7457233f9f0SBarry Smith   PetscFunctionReturn(0);
7467233f9f0SBarry Smith }
7477233f9f0SBarry Smith 
748174b6946SBarry Smith /*MC
7497233f9f0SBarry Smith      PCEXOTIC - Two level overlapping Schwarz preconditioner with exotic (non-standard) coarse grid spaces
750174b6946SBarry Smith 
751*f1580f4eSBarry Smith      This uses the `PCMG` infrastructure restricted to two levels and the face and wirebasket based coarse
75224c3aa18SBarry Smith    grid spaces.
75324c3aa18SBarry Smith 
754*f1580f4eSBarry Smith    Level: advanced
755*f1580f4eSBarry Smith 
75695452b02SPatrick Sanan    Notes:
757*f1580f4eSBarry Smith    Must be used with `DMDA`
758*f1580f4eSBarry Smith 
759*f1580f4eSBarry Smith    By default this uses `KSPGMRES` on the fine grid smoother so this should be used with `KSPFGMRES` or the smoother changed to not use `KSPGMRES`
76024c3aa18SBarry Smith 
76196a0c994SBarry Smith    References:
762606c0280SSatish Balay +  * - These coarse grid spaces originate in the work of Bramble, Pasciak  and Schatz, "The Construction
76396a0c994SBarry Smith    of Preconditioners for Elliptic Problems by Substructing IV", Mathematics of Computation, volume 53, 1989.
764606c0280SSatish Balay .  * - They were generalized slightly in "Domain Decomposition Method for Linear Elasticity", Ph. D. thesis, Barry Smith,
7654f02bc6aSBarry Smith    New York University, 1990.
766606c0280SSatish Balay .  * - They were then explored in great detail in Dryja, Smith, Widlund, "Schwarz Analysis
7673b65e785SBarry Smith    of Iterative Substructuring Methods for Elliptic Problems in Three Dimensions, SIAM Journal on Numerical
76896a0c994SBarry Smith    Analysis, volume 31. 1994. These were developed in the context of iterative substructuring preconditioners.
769606c0280SSatish Balay .  * - They were then ingeniously applied as coarse grid spaces for overlapping Schwarz methods by Dohrmann and Widlund.
7703b65e785SBarry Smith    They refer to them as GDSW (generalized Dryja, Smith, Widlund preconditioners). See, for example,
7713b65e785SBarry Smith    Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Extending theory for domain decomposition algorithms to irregular subdomains. In Ulrich Langer, Marco
7723b65e785SBarry Smith    Discacciati, David Keyes, Olof Widlund, and Walter Zulehner, editors, Proceedings
7733b65e785SBarry Smith    of the 17th International Conference on Domain Decomposition Methods in
77496a0c994SBarry Smith    Science and Engineering, held in Strobl, Austria, 2006, number 60 in
77596a0c994SBarry Smith    Springer Verlag, Lecture Notes in Computational Science and Engineering, 2007.
776606c0280SSatish Balay .  * -  Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. A family of energy minimizing coarse spaces for overlapping Schwarz preconditioners. In Ulrich Langer,
7773b65e785SBarry Smith    Marco Discacciati, David Keyes, Olof Widlund, and Walter Zulehner, editors, Proceedings
7783b65e785SBarry Smith    of the 17th International Conference on Domain Decomposition Methods
77996a0c994SBarry Smith    in Science and Engineering, held in Strobl, Austria, 2006, number 60 in
78096a0c994SBarry Smith    Springer Verlag, Lecture Notes in Computational Science and Engineering, 2007
781606c0280SSatish Balay .  * - Clark R. Dohrmann, Axel Klawonn, and Olof B. Widlund. Domain decomposition
7823b65e785SBarry Smith    for less regular subdomains: Overlapping Schwarz in two dimensions. SIAM J.
78396a0c994SBarry Smith    Numer. Anal., 46(4), 2008.
784606c0280SSatish Balay -  * - Clark R. Dohrmann and Olof B. Widlund. An overlapping Schwarz
7853b65e785SBarry Smith    algorithm for almost incompressible elasticity. Technical Report
78696a0c994SBarry Smith    TR2008 912, Department of Computer Science, Courant Institute
7873b65e785SBarry Smith    of Mathematical Sciences, New York University, May 2008. URL:
7887233f9f0SBarry Smith 
789*f1580f4eSBarry Smith    The usual `PCMG` options are supported, such as -mg_levels_pc_type <type> -mg_coarse_pc_type <type> and  -pc_mg_type <type>
790174b6946SBarry Smith 
791db781477SPatrick Sanan .seealso: `PCMG`, `PCSetDM()`, `PCExoticType`, `PCExoticSetType()`
792174b6946SBarry Smith M*/
793174b6946SBarry Smith 
7949371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCCreate_Exotic(PC pc) {
7957233f9f0SBarry Smith   PC_Exotic *ex;
796f3fbd535SBarry Smith   PC_MG     *mg;
797174b6946SBarry Smith 
798174b6946SBarry Smith   PetscFunctionBegin;
799f91d8e95SBarry Smith   /* if type was previously mg; must manually destroy it because call to PCSetType(pc,PCMG) will not destroy it */
800dbbe0bcdSBarry Smith   PetscTryTypeMethod(pc, destroy);
8010a545947SLisandro Dalcin   pc->data = NULL;
802dbbe0bcdSBarry Smith 
8039566063dSJacob Faibussowitsch   PetscCall(PetscFree(((PetscObject)pc)->type_name));
8040a545947SLisandro Dalcin   ((PetscObject)pc)->type_name = NULL;
805f91d8e95SBarry Smith 
8069566063dSJacob Faibussowitsch   PetscCall(PCSetType(pc, PCMG));
8079566063dSJacob Faibussowitsch   PetscCall(PCMGSetLevels(pc, 2, NULL));
8089566063dSJacob Faibussowitsch   PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_PMAT));
8099371c9d4SSatish Balay   PetscCall(PetscNew(&ex));
8107233f9f0SBarry Smith   ex->type     = PC_EXOTIC_FACE;
811f3fbd535SBarry Smith   mg           = (PC_MG *)pc->data;
81231567311SBarry Smith   mg->innerctx = ex;
8137233f9f0SBarry Smith 
8147233f9f0SBarry Smith   pc->ops->setfromoptions = PCSetFromOptions_Exotic;
8157233f9f0SBarry Smith   pc->ops->view           = PCView_Exotic;
8167233f9f0SBarry Smith   pc->ops->destroy        = PCDestroy_Exotic;
8176c699258SBarry Smith   pc->ops->setup          = PCSetUp_Exotic;
8182fa5cd67SKarl Rupp 
8199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCExoticSetType_C", PCExoticSetType_Exotic));
820174b6946SBarry Smith   PetscFunctionReturn(0);
821174b6946SBarry Smith }
822