xref: /petsc/src/dm/impls/da/dainterp.c (revision 12b4a53753ecbae42c98ba33876a303b79054923)
147c6ae99SBarry Smith /*
2aa219208SBarry Smith   Code for interpolating between grids represented by DMDAs
347c6ae99SBarry Smith */
447c6ae99SBarry Smith 
5d52bd9f3SBarry Smith /*
6d52bd9f3SBarry Smith    For linear elements there are two branches of code to compute the interpolation. They should compute the same results but may not. The "new version" does
7d52bd9f3SBarry Smith    not work for periodic domains, the old does. Change NEWVERSION to 1 to compile in the new version. Eventually when we are sure the two produce identical results
82adb9dcfSBarry Smith    we will remove/merge the new version. Based on current tests, these both produce the same results. We are leaving NEWVERSION for now in the code since some
92adb9dcfSBarry Smith    consider it cleaner, but old version is turned on since it handles periodic case.
10d52bd9f3SBarry Smith */
119314d695SBarry Smith #define NEWVERSION 0
1285afcc9aSBarry Smith 
13af0996ceSBarry Smith #include <petsc/private/dmdaimpl.h> /*I   "petscdmda.h"   I*/
1447c6ae99SBarry Smith 
15fdc842d1SBarry Smith /*
16fdc842d1SBarry Smith    Since the interpolation uses MATMAIJ for dof > 0 we convert request for non-MATAIJ baseded matrices to MATAIJ.
17fdc842d1SBarry Smith    This is a bit of a hack, the reason for it is partially because -dm_mat_type defines the
18fdc842d1SBarry Smith    matrix type for both the operator matrices and the interpolation matrices so that users
19fdc842d1SBarry Smith    can select matrix types of base MATAIJ for accelerators
20fdc842d1SBarry Smith */
21d71ae5a4SJacob Faibussowitsch static PetscErrorCode ConvertToAIJ(MatType intype, MatType *outtype)
22d71ae5a4SJacob Faibussowitsch {
23fdc842d1SBarry Smith   PetscInt    i;
24fdc842d1SBarry Smith   char const *types[3] = {MATAIJ, MATSEQAIJ, MATMPIAIJ};
25fdc842d1SBarry Smith   PetscBool   flg;
26fdc842d1SBarry Smith 
27fdc842d1SBarry Smith   PetscFunctionBegin;
2833a4d587SStefano Zampini   *outtype = MATAIJ;
29fdc842d1SBarry Smith   for (i = 0; i < 3; i++) {
309566063dSJacob Faibussowitsch     PetscCall(PetscStrbeginswith(intype, types[i], &flg));
31fdc842d1SBarry Smith     if (flg) {
32fdc842d1SBarry Smith       *outtype = intype;
333ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
34fdc842d1SBarry Smith     }
35fdc842d1SBarry Smith   }
363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37fdc842d1SBarry Smith }
38fdc842d1SBarry Smith 
3966976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateInterpolation_DA_1D_Q1(DM dac, DM daf, Mat *A)
40d71ae5a4SJacob Faibussowitsch {
418ea3bf28SBarry Smith   PetscInt               i, i_start, m_f, Mx;
428ea3bf28SBarry Smith   const PetscInt        *idx_f, *idx_c;
438ea3bf28SBarry Smith   PetscInt               m_ghost, m_ghost_c;
4447c6ae99SBarry Smith   PetscInt               row, col, i_start_ghost, mx, m_c, nc, ratio;
4547c6ae99SBarry Smith   PetscInt               i_c, i_start_c, i_start_ghost_c, cols[2], dof;
4685afcc9aSBarry Smith   PetscScalar            v[2], x;
4747c6ae99SBarry Smith   Mat                    mat;
48bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
49e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f, ltog_c;
50fdc842d1SBarry Smith   MatType                mattype;
5147c6ae99SBarry Smith 
5247c6ae99SBarry Smith   PetscFunctionBegin;
539566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, NULL, &Mx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &bx, NULL, NULL, NULL));
549566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, NULL, &mx, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
55bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
5647c6ae99SBarry Smith     ratio = mx / Mx;
5763a3b9bcSJacob Faibussowitsch     PetscCheck(ratio * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx  must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
5847c6ae99SBarry Smith   } else {
5947c6ae99SBarry Smith     ratio = (mx - 1) / (Mx - 1);
601dca8a05SBarry Smith     PetscCheck(ratio * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
6147c6ae99SBarry Smith   }
6247c6ae99SBarry Smith 
639566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf, &i_start, NULL, NULL, &m_f, NULL, NULL));
649566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, NULL, NULL, &m_ghost, NULL, NULL));
659566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf, &ltog_f));
669566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
6747c6ae99SBarry Smith 
689566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac, &i_start_c, NULL, NULL, &m_c, NULL, NULL));
699566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, NULL, NULL, &m_ghost_c, NULL, NULL));
709566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac, &ltog_c));
719566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
7247c6ae99SBarry Smith 
7347c6ae99SBarry Smith   /* create interpolation matrix */
749566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dac), &mat));
75fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
76fdc842d1SBarry Smith   /*
77fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
78fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
79fdc842d1SBarry Smith    */
8048a46eb9SPierre Jolivet   if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
81fdc842d1SBarry Smith #endif
829566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat, m_f, m_c, mx, Mx));
839566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype, &mattype));
849566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat, mattype));
859566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat, 2, NULL));
869566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat, 2, NULL, 1, NULL));
8747c6ae99SBarry Smith 
8847c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
8985afcc9aSBarry Smith   if (!NEWVERSION) {
9047c6ae99SBarry Smith     for (i = i_start; i < i_start + m_f; i++) {
9147c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
92e3fbd1f4SBarry Smith       row = idx_f[i - i_start_ghost];
9347c6ae99SBarry Smith 
9447c6ae99SBarry Smith       i_c = (i / ratio); /* coarse grid node to left of fine grid node */
9508401ef6SPierre Jolivet       PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
969371c9d4SSatish Balay                                           i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT,
979371c9d4SSatish Balay                  i_start, i_c, i_start_ghost_c);
9847c6ae99SBarry Smith 
9947c6ae99SBarry Smith       /*
10047c6ae99SBarry Smith        Only include those interpolation points that are truly
10147c6ae99SBarry Smith        nonzero. Note this is very important for final grid lines
10247c6ae99SBarry Smith        in x direction; since they have no right neighbor
10347c6ae99SBarry Smith        */
1046712e2f1SBarry Smith       x  = ((PetscReal)(i - i_c * ratio)) / ((PetscReal)ratio);
10547c6ae99SBarry Smith       nc = 0;
10647c6ae99SBarry Smith       /* one left and below; or we are right on it */
107e3fbd1f4SBarry Smith       col      = (i_c - i_start_ghost_c);
108e3fbd1f4SBarry Smith       cols[nc] = idx_c[col];
10947c6ae99SBarry Smith       v[nc++]  = -x + 1.0;
11047c6ae99SBarry Smith       /* one right? */
11147c6ae99SBarry Smith       if (i_c * ratio != i) {
112e3fbd1f4SBarry Smith         cols[nc] = idx_c[col + 1];
11347c6ae99SBarry Smith         v[nc++]  = x;
11447c6ae99SBarry Smith       }
1159566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
11647c6ae99SBarry Smith     }
117b3bd94feSDave May 
118b3bd94feSDave May   } else {
119b3bd94feSDave May     PetscScalar *xi;
120b3bd94feSDave May     PetscInt     li, nxi, n;
121b3bd94feSDave May     PetscScalar  Ni[2];
122b3bd94feSDave May 
123b3bd94feSDave May     /* compute local coordinate arrays */
124b3bd94feSDave May     nxi = ratio + 1;
1259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nxi, &xi));
126ad540459SPierre Jolivet     for (li = 0; li < nxi; li++) xi[li] = -1.0 + (PetscScalar)li * (2.0 / (PetscScalar)(nxi - 1));
127b3bd94feSDave May 
128b3bd94feSDave May     for (i = i_start; i < i_start + m_f; i++) {
129b3bd94feSDave May       /* convert to local "natural" numbering and then to PETSc global numbering */
130e3fbd1f4SBarry Smith       row = idx_f[(i - i_start_ghost)];
131b3bd94feSDave May 
132b3bd94feSDave May       i_c = (i / ratio); /* coarse grid node to left of fine grid node */
13308401ef6SPierre Jolivet       PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
1349371c9d4SSatish Balay                                           i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT,
1359371c9d4SSatish Balay                  i_start, i_c, i_start_ghost_c);
136b3bd94feSDave May 
137b3bd94feSDave May       /* remainders */
138b3bd94feSDave May       li = i - ratio * (i / ratio);
1398865f1eaSKarl Rupp       if (i == mx - 1) li = nxi - 1;
140b3bd94feSDave May 
141b3bd94feSDave May       /* corners */
142e3fbd1f4SBarry Smith       col     = (i_c - i_start_ghost_c);
143e3fbd1f4SBarry Smith       cols[0] = idx_c[col];
144b3bd94feSDave May       Ni[0]   = 1.0;
145b3bd94feSDave May       if ((li == 0) || (li == nxi - 1)) {
1469566063dSJacob Faibussowitsch         PetscCall(MatSetValue(mat, row, cols[0], Ni[0], INSERT_VALUES));
147b3bd94feSDave May         continue;
148b3bd94feSDave May       }
149b3bd94feSDave May 
150b3bd94feSDave May       /* edges + interior */
151b3bd94feSDave May       /* remainders */
1528865f1eaSKarl Rupp       if (i == mx - 1) i_c--;
153b3bd94feSDave May 
154e3fbd1f4SBarry Smith       col     = (i_c - i_start_ghost_c);
155e3fbd1f4SBarry Smith       cols[0] = idx_c[col]; /* one left and below; or we are right on it */
156e3fbd1f4SBarry Smith       cols[1] = idx_c[col + 1];
157b3bd94feSDave May 
158b3bd94feSDave May       Ni[0] = 0.5 * (1.0 - xi[li]);
159b3bd94feSDave May       Ni[1] = 0.5 * (1.0 + xi[li]);
160b3bd94feSDave May       for (n = 0; n < 2; n++) {
1618865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[n]) < 1.0e-32) cols[n] = -1;
162b3bd94feSDave May       }
1639566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, 1, &row, 2, cols, Ni, INSERT_VALUES));
164b3bd94feSDave May     }
1659566063dSJacob Faibussowitsch     PetscCall(PetscFree(xi));
166b3bd94feSDave May   }
1679566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
1689566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
1699566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
1709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
1719566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat, dof, A));
1729566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
1733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17447c6ae99SBarry Smith }
17547c6ae99SBarry Smith 
17666976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateInterpolation_DA_1D_Q0(DM dac, DM daf, Mat *A)
177d71ae5a4SJacob Faibussowitsch {
1788ea3bf28SBarry Smith   PetscInt               i, i_start, m_f, Mx;
1798ea3bf28SBarry Smith   const PetscInt        *idx_f, *idx_c;
180e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f, ltog_c;
1818ea3bf28SBarry Smith   PetscInt               m_ghost, m_ghost_c;
18247c6ae99SBarry Smith   PetscInt               row, col, i_start_ghost, mx, m_c, nc, ratio;
18347c6ae99SBarry Smith   PetscInt               i_c, i_start_c, i_start_ghost_c, cols[2], dof;
18447c6ae99SBarry Smith   PetscScalar            v[2], x;
18547c6ae99SBarry Smith   Mat                    mat;
186bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
187fdc842d1SBarry Smith   MatType                mattype;
18847c6ae99SBarry Smith 
18947c6ae99SBarry Smith   PetscFunctionBegin;
1909566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, NULL, &Mx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &bx, NULL, NULL, NULL));
1919566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, NULL, &mx, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
192bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
19363a3b9bcSJacob Faibussowitsch     PetscCheck(Mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be positive", Mx);
19447c6ae99SBarry Smith     ratio = mx / Mx;
19563a3b9bcSJacob Faibussowitsch     PetscCheck(ratio * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx  must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
19647c6ae99SBarry Smith   } else {
19763a3b9bcSJacob Faibussowitsch     PetscCheck(Mx >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be greater than 1", Mx);
19847c6ae99SBarry Smith     ratio = (mx - 1) / (Mx - 1);
1991dca8a05SBarry Smith     PetscCheck(ratio * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
20047c6ae99SBarry Smith   }
20147c6ae99SBarry Smith 
2029566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf, &i_start, NULL, NULL, &m_f, NULL, NULL));
2039566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, NULL, NULL, &m_ghost, NULL, NULL));
2049566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf, &ltog_f));
2059566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
20647c6ae99SBarry Smith 
2079566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac, &i_start_c, NULL, NULL, &m_c, NULL, NULL));
2089566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, NULL, NULL, &m_ghost_c, NULL, NULL));
2099566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac, &ltog_c));
2109566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
21147c6ae99SBarry Smith 
21247c6ae99SBarry Smith   /* create interpolation matrix */
2139566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dac), &mat));
214fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
215fdc842d1SBarry Smith   /*
216fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
217fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
218fdc842d1SBarry Smith    */
21948a46eb9SPierre Jolivet   if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
220fdc842d1SBarry Smith #endif
2219566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat, m_f, m_c, mx, Mx));
2229566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype, &mattype));
2239566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat, mattype));
2249566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat, 2, NULL));
2259566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat, 2, NULL, 0, NULL));
22647c6ae99SBarry Smith 
22747c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
22847c6ae99SBarry Smith   for (i = i_start; i < i_start + m_f; i++) {
22947c6ae99SBarry Smith     /* convert to local "natural" numbering and then to PETSc global numbering */
230e3fbd1f4SBarry Smith     row = idx_f[(i - i_start_ghost)];
23147c6ae99SBarry Smith 
23247c6ae99SBarry Smith     i_c = (i / ratio); /* coarse grid node to left of fine grid node */
23347c6ae99SBarry Smith 
23447c6ae99SBarry Smith     /*
23547c6ae99SBarry Smith          Only include those interpolation points that are truly
23647c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
23747c6ae99SBarry Smith          in x direction; since they have no right neighbor
23847c6ae99SBarry Smith     */
2396712e2f1SBarry Smith     x  = ((PetscReal)(i - i_c * ratio)) / ((PetscReal)ratio);
24047c6ae99SBarry Smith     nc = 0;
24147c6ae99SBarry Smith     /* one left and below; or we are right on it */
242e3fbd1f4SBarry Smith     col      = (i_c - i_start_ghost_c);
243e3fbd1f4SBarry Smith     cols[nc] = idx_c[col];
24447c6ae99SBarry Smith     v[nc++]  = -x + 1.0;
24547c6ae99SBarry Smith     /* one right? */
24647c6ae99SBarry Smith     if (i_c * ratio != i) {
247e3fbd1f4SBarry Smith       cols[nc] = idx_c[col + 1];
24847c6ae99SBarry Smith       v[nc++]  = x;
24947c6ae99SBarry Smith     }
2509566063dSJacob Faibussowitsch     PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
25147c6ae99SBarry Smith   }
2529566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
2539566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
2549566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
2559566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
2569566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat, dof, A));
2579566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
2589566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(5.0 * m_f));
2593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26047c6ae99SBarry Smith }
26147c6ae99SBarry Smith 
26266976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateInterpolation_DA_2D_Q1(DM dac, DM daf, Mat *A)
263d71ae5a4SJacob Faibussowitsch {
2648ea3bf28SBarry Smith   PetscInt               i, j, i_start, j_start, m_f, n_f, Mx, My, dof;
2658ea3bf28SBarry Smith   const PetscInt        *idx_c, *idx_f;
266e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f, ltog_c;
2678ea3bf28SBarry Smith   PetscInt               m_ghost, n_ghost, m_ghost_c, n_ghost_c, *dnz, *onz;
26847c6ae99SBarry Smith   PetscInt               row, col, i_start_ghost, j_start_ghost, cols[4], mx, m_c, my, nc, ratioi, ratioj;
26947c6ae99SBarry Smith   PetscInt               i_c, j_c, i_start_c, j_start_c, n_c, i_start_ghost_c, j_start_ghost_c, col_shift, col_scale;
27047c6ae99SBarry Smith   PetscMPIInt            size_c, size_f, rank_f;
27147c6ae99SBarry Smith   PetscScalar            v[4], x, y;
27247c6ae99SBarry Smith   Mat                    mat;
273bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx, by;
274fdc842d1SBarry Smith   MatType                mattype;
27547c6ae99SBarry Smith 
27647c6ae99SBarry Smith   PetscFunctionBegin;
2779566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, NULL, NULL, NULL, NULL, NULL, NULL, &bx, &by, NULL, NULL));
2789566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
279bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
28063a3b9bcSJacob Faibussowitsch     PetscCheck(Mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be positive", Mx);
28147c6ae99SBarry Smith     ratioi = mx / Mx;
28263a3b9bcSJacob Faibussowitsch     PetscCheck(ratioi * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx  must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
28347c6ae99SBarry Smith   } else {
28463a3b9bcSJacob Faibussowitsch     PetscCheck(Mx >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be greater than 1", Mx);
28547c6ae99SBarry Smith     ratioi = (mx - 1) / (Mx - 1);
2861dca8a05SBarry Smith     PetscCheck(ratioi * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
28747c6ae99SBarry Smith   }
288bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
28963a3b9bcSJacob Faibussowitsch     PetscCheck(My, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be positive", My);
29047c6ae99SBarry Smith     ratioj = my / My;
29163a3b9bcSJacob Faibussowitsch     PetscCheck(ratioj * My == my, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: my/My  must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
29247c6ae99SBarry Smith   } else {
29363a3b9bcSJacob Faibussowitsch     PetscCheck(My >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be greater than 1", My);
29447c6ae99SBarry Smith     ratioj = (my - 1) / (My - 1);
2951dca8a05SBarry Smith     PetscCheck(ratioj * (My - 1) == my - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (my - 1)/(My - 1) must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
29647c6ae99SBarry Smith   }
29747c6ae99SBarry Smith 
2989566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf, &i_start, &j_start, NULL, &m_f, &n_f, NULL));
2999566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, NULL, &m_ghost, &n_ghost, NULL));
3009566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf, &ltog_f));
3019566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
30247c6ae99SBarry Smith 
3039566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, NULL, &m_c, &n_c, NULL));
3049566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, NULL, &m_ghost_c, &n_ghost_c, NULL));
3059566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac, &ltog_c));
3069566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
30747c6ae99SBarry Smith 
30847c6ae99SBarry Smith   /*
309aa219208SBarry Smith    Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
31047c6ae99SBarry Smith    The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
31147c6ae99SBarry Smith    processors). It's effective length is hence 4 times its normal length, this is
31247c6ae99SBarry Smith    why the col_scale is multiplied by the interpolation matrix column sizes.
31347c6ae99SBarry Smith    sol_shift allows each set of 1/4 processors do its own interpolation using ITS
31447c6ae99SBarry Smith    copy of the coarse vector. A bit of a hack but you do better.
31547c6ae99SBarry Smith 
31647c6ae99SBarry Smith    In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
31747c6ae99SBarry Smith    */
3189566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dac), &size_c));
3199566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)daf), &size_f));
3209566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)daf), &rank_f));
32147c6ae99SBarry Smith   col_scale = size_f / size_c;
32247c6ae99SBarry Smith   col_shift = Mx * My * (rank_f / size_c);
32347c6ae99SBarry Smith 
324d0609cedSBarry Smith   MatPreallocateBegin(PetscObjectComm((PetscObject)daf), m_f * n_f, col_scale * m_c * n_c, dnz, onz);
32547c6ae99SBarry Smith   for (j = j_start; j < j_start + n_f; j++) {
32647c6ae99SBarry Smith     for (i = i_start; i < i_start + m_f; i++) {
32747c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
328e3fbd1f4SBarry Smith       row = idx_f[(m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
32947c6ae99SBarry Smith 
33047c6ae99SBarry Smith       i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
33147c6ae99SBarry Smith       j_c = (j / ratioj); /* coarse grid node below fine grid node */
33247c6ae99SBarry Smith 
33308401ef6SPierre Jolivet       PetscCheck(j_c >= j_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
3349371c9d4SSatish Balay                                           j_start %" PetscInt_FMT " j_c %" PetscInt_FMT " j_start_ghost_c %" PetscInt_FMT,
3359371c9d4SSatish Balay                  j_start, j_c, j_start_ghost_c);
33608401ef6SPierre Jolivet       PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
3379371c9d4SSatish Balay                                           i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT,
3389371c9d4SSatish Balay                  i_start, i_c, i_start_ghost_c);
33947c6ae99SBarry Smith 
34047c6ae99SBarry Smith       /*
34147c6ae99SBarry Smith        Only include those interpolation points that are truly
34247c6ae99SBarry Smith        nonzero. Note this is very important for final grid lines
34347c6ae99SBarry Smith        in x and y directions; since they have no right/top neighbors
34447c6ae99SBarry Smith        */
34547c6ae99SBarry Smith       nc = 0;
34647c6ae99SBarry Smith       /* one left and below; or we are right on it */
347e3fbd1f4SBarry Smith       col        = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
348e3fbd1f4SBarry Smith       cols[nc++] = col_shift + idx_c[col];
34947c6ae99SBarry Smith       /* one right and below */
350e3fbd1f4SBarry Smith       if (i_c * ratioi != i) cols[nc++] = col_shift + idx_c[col + 1];
35147c6ae99SBarry Smith       /* one left and above */
352e3fbd1f4SBarry Smith       if (j_c * ratioj != j) cols[nc++] = col_shift + idx_c[col + m_ghost_c];
35347c6ae99SBarry Smith       /* one right and above */
354e3fbd1f4SBarry Smith       if (i_c * ratioi != i && j_c * ratioj != j) cols[nc++] = col_shift + idx_c[col + (m_ghost_c + 1)];
3559566063dSJacob Faibussowitsch       PetscCall(MatPreallocateSet(row, nc, cols, dnz, onz));
35647c6ae99SBarry Smith     }
35747c6ae99SBarry Smith   }
3589566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)daf), &mat));
359fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
360fdc842d1SBarry Smith   /*
361fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
362fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
363fdc842d1SBarry Smith   */
36448a46eb9SPierre Jolivet   if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
365fdc842d1SBarry Smith #endif
3669566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat, m_f * n_f, col_scale * m_c * n_c, mx * my, col_scale * Mx * My));
3679566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype, &mattype));
3689566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat, mattype));
3699566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat, 0, dnz));
3709566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat, 0, dnz, 0, onz));
371d0609cedSBarry Smith   MatPreallocateEnd(dnz, onz);
37247c6ae99SBarry Smith 
37347c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
37485afcc9aSBarry Smith   if (!NEWVERSION) {
37547c6ae99SBarry Smith     for (j = j_start; j < j_start + n_f; j++) {
37647c6ae99SBarry Smith       for (i = i_start; i < i_start + m_f; i++) {
37747c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
378e3fbd1f4SBarry Smith         row = idx_f[(m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
37947c6ae99SBarry Smith 
38047c6ae99SBarry Smith         i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
38147c6ae99SBarry Smith         j_c = (j / ratioj); /* coarse grid node below fine grid node */
38247c6ae99SBarry Smith 
38347c6ae99SBarry Smith         /*
38447c6ae99SBarry Smith          Only include those interpolation points that are truly
38547c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
38647c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
38747c6ae99SBarry Smith          */
3886712e2f1SBarry Smith         x = ((PetscReal)(i - i_c * ratioi)) / ((PetscReal)ratioi);
3896712e2f1SBarry Smith         y = ((PetscReal)(j - j_c * ratioj)) / ((PetscReal)ratioj);
390b3bd94feSDave May 
39147c6ae99SBarry Smith         nc = 0;
39247c6ae99SBarry Smith         /* one left and below; or we are right on it */
393e3fbd1f4SBarry Smith         col      = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
394e3fbd1f4SBarry Smith         cols[nc] = col_shift + idx_c[col];
39547c6ae99SBarry Smith         v[nc++]  = x * y - x - y + 1.0;
39647c6ae99SBarry Smith         /* one right and below */
39747c6ae99SBarry Smith         if (i_c * ratioi != i) {
398e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col + 1];
39947c6ae99SBarry Smith           v[nc++]  = -x * y + x;
40047c6ae99SBarry Smith         }
40147c6ae99SBarry Smith         /* one left and above */
40247c6ae99SBarry Smith         if (j_c * ratioj != j) {
403e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col + m_ghost_c];
40447c6ae99SBarry Smith           v[nc++]  = -x * y + y;
40547c6ae99SBarry Smith         }
40647c6ae99SBarry Smith         /* one right and above */
40747c6ae99SBarry Smith         if (j_c * ratioj != j && i_c * ratioi != i) {
408e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col + (m_ghost_c + 1)];
40947c6ae99SBarry Smith           v[nc++]  = x * y;
41047c6ae99SBarry Smith         }
4119566063dSJacob Faibussowitsch         PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
41247c6ae99SBarry Smith       }
41347c6ae99SBarry Smith     }
414b3bd94feSDave May 
415b3bd94feSDave May   } else {
416b3bd94feSDave May     PetscScalar  Ni[4];
417b3bd94feSDave May     PetscScalar *xi, *eta;
418b3bd94feSDave May     PetscInt     li, nxi, lj, neta;
419b3bd94feSDave May 
420b3bd94feSDave May     /* compute local coordinate arrays */
421b3bd94feSDave May     nxi  = ratioi + 1;
422b3bd94feSDave May     neta = ratioj + 1;
4239566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nxi, &xi));
4249566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(neta, &eta));
425ad540459SPierre Jolivet     for (li = 0; li < nxi; li++) xi[li] = -1.0 + (PetscScalar)li * (2.0 / (PetscScalar)(nxi - 1));
426ad540459SPierre Jolivet     for (lj = 0; lj < neta; lj++) eta[lj] = -1.0 + (PetscScalar)lj * (2.0 / (PetscScalar)(neta - 1));
427b3bd94feSDave May 
428b3bd94feSDave May     /* loop over local fine grid nodes setting interpolation for those*/
429b3bd94feSDave May     for (j = j_start; j < j_start + n_f; j++) {
430b3bd94feSDave May       for (i = i_start; i < i_start + m_f; i++) {
431b3bd94feSDave May         /* convert to local "natural" numbering and then to PETSc global numbering */
432e3fbd1f4SBarry Smith         row = idx_f[(m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
433b3bd94feSDave May 
434b3bd94feSDave May         i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
435b3bd94feSDave May         j_c = (j / ratioj); /* coarse grid node below fine grid node */
436b3bd94feSDave May 
437b3bd94feSDave May         /* remainders */
438b3bd94feSDave May         li = i - ratioi * (i / ratioi);
4398865f1eaSKarl Rupp         if (i == mx - 1) li = nxi - 1;
440b3bd94feSDave May         lj = j - ratioj * (j / ratioj);
4418865f1eaSKarl Rupp         if (j == my - 1) lj = neta - 1;
442b3bd94feSDave May 
443b3bd94feSDave May         /* corners */
444e3fbd1f4SBarry Smith         col     = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
445e3fbd1f4SBarry Smith         cols[0] = col_shift + idx_c[col]; /* left, below */
446b3bd94feSDave May         Ni[0]   = 1.0;
447b3bd94feSDave May         if ((li == 0) || (li == nxi - 1)) {
448b3bd94feSDave May           if ((lj == 0) || (lj == neta - 1)) {
4499566063dSJacob Faibussowitsch             PetscCall(MatSetValue(mat, row, cols[0], Ni[0], INSERT_VALUES));
450b3bd94feSDave May             continue;
451b3bd94feSDave May           }
452b3bd94feSDave May         }
453b3bd94feSDave May 
454b3bd94feSDave May         /* edges + interior */
455b3bd94feSDave May         /* remainders */
4568865f1eaSKarl Rupp         if (i == mx - 1) i_c--;
4578865f1eaSKarl Rupp         if (j == my - 1) j_c--;
458b3bd94feSDave May 
459e3fbd1f4SBarry Smith         col     = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
460e3fbd1f4SBarry Smith         cols[0] = col_shift + idx_c[col];                   /* left, below */
461e3fbd1f4SBarry Smith         cols[1] = col_shift + idx_c[col + 1];               /* right, below */
462e3fbd1f4SBarry Smith         cols[2] = col_shift + idx_c[col + m_ghost_c];       /* left, above */
463e3fbd1f4SBarry Smith         cols[3] = col_shift + idx_c[col + (m_ghost_c + 1)]; /* right, above */
464b3bd94feSDave May 
465b3bd94feSDave May         Ni[0] = 0.25 * (1.0 - xi[li]) * (1.0 - eta[lj]);
466b3bd94feSDave May         Ni[1] = 0.25 * (1.0 + xi[li]) * (1.0 - eta[lj]);
467b3bd94feSDave May         Ni[2] = 0.25 * (1.0 - xi[li]) * (1.0 + eta[lj]);
468b3bd94feSDave May         Ni[3] = 0.25 * (1.0 + xi[li]) * (1.0 + eta[lj]);
469b3bd94feSDave May 
470b3bd94feSDave May         nc = 0;
4718865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[0]) < 1.0e-32) cols[0] = -1;
4728865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[1]) < 1.0e-32) cols[1] = -1;
4738865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[2]) < 1.0e-32) cols[2] = -1;
4748865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[3]) < 1.0e-32) cols[3] = -1;
475b3bd94feSDave May 
4769566063dSJacob Faibussowitsch         PetscCall(MatSetValues(mat, 1, &row, 4, cols, Ni, INSERT_VALUES));
477b3bd94feSDave May       }
478b3bd94feSDave May     }
4799566063dSJacob Faibussowitsch     PetscCall(PetscFree(xi));
4809566063dSJacob Faibussowitsch     PetscCall(PetscFree(eta));
481b3bd94feSDave May   }
4829566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
4839566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
4849566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
4859566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
4869566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat, dof, A));
4879566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
4883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48947c6ae99SBarry Smith }
49047c6ae99SBarry Smith 
49147c6ae99SBarry Smith /*
49247c6ae99SBarry Smith        Contributed by Andrei Draganescu <aidraga@sandia.gov>
49347c6ae99SBarry Smith */
49466976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateInterpolation_DA_2D_Q0(DM dac, DM daf, Mat *A)
495d71ae5a4SJacob Faibussowitsch {
4968ea3bf28SBarry Smith   PetscInt               i, j, i_start, j_start, m_f, n_f, Mx, My, dof;
4978ea3bf28SBarry Smith   const PetscInt        *idx_c, *idx_f;
498e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f, ltog_c;
4998ea3bf28SBarry Smith   PetscInt               m_ghost, n_ghost, m_ghost_c, n_ghost_c, *dnz, *onz;
50047c6ae99SBarry Smith   PetscInt               row, col, i_start_ghost, j_start_ghost, cols[4], mx, m_c, my, nc, ratioi, ratioj;
50147c6ae99SBarry Smith   PetscInt               i_c, j_c, i_start_c, j_start_c, n_c, i_start_ghost_c, j_start_ghost_c, col_shift, col_scale;
50247c6ae99SBarry Smith   PetscMPIInt            size_c, size_f, rank_f;
50347c6ae99SBarry Smith   PetscScalar            v[4];
50447c6ae99SBarry Smith   Mat                    mat;
505bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx, by;
506fdc842d1SBarry Smith   MatType                mattype;
50747c6ae99SBarry Smith 
50847c6ae99SBarry Smith   PetscFunctionBegin;
5099566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, NULL, NULL, NULL, NULL, NULL, NULL, &bx, &by, NULL, NULL));
5109566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
51163a3b9bcSJacob Faibussowitsch   PetscCheck(Mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be positive", Mx);
51263a3b9bcSJacob Faibussowitsch   PetscCheck(My, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be positive", My);
51347c6ae99SBarry Smith   ratioi = mx / Mx;
51447c6ae99SBarry Smith   ratioj = my / My;
51508401ef6SPierre Jolivet   PetscCheck(ratioi * Mx == mx, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Fine grid points must be multiple of coarse grid points in x");
51608401ef6SPierre Jolivet   PetscCheck(ratioj * My == my, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Fine grid points must be multiple of coarse grid points in y");
51708401ef6SPierre Jolivet   PetscCheck(ratioi == 2, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Coarsening factor in x must be 2");
51808401ef6SPierre Jolivet   PetscCheck(ratioj == 2, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Coarsening factor in y must be 2");
51947c6ae99SBarry Smith 
5209566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf, &i_start, &j_start, NULL, &m_f, &n_f, NULL));
5219566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, NULL, &m_ghost, &n_ghost, NULL));
5229566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf, &ltog_f));
5239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
52447c6ae99SBarry Smith 
5259566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, NULL, &m_c, &n_c, NULL));
5269566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, NULL, &m_ghost_c, &n_ghost_c, NULL));
5279566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac, &ltog_c));
5289566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
52947c6ae99SBarry Smith 
53047c6ae99SBarry Smith   /*
531aa219208SBarry Smith      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
53247c6ae99SBarry Smith      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
53347c6ae99SBarry Smith      processors). It's effective length is hence 4 times its normal length, this is
53447c6ae99SBarry Smith      why the col_scale is multiplied by the interpolation matrix column sizes.
53547c6ae99SBarry Smith      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
53647c6ae99SBarry Smith      copy of the coarse vector. A bit of a hack but you do better.
53747c6ae99SBarry Smith 
53847c6ae99SBarry Smith      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
53947c6ae99SBarry Smith   */
5409566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dac), &size_c));
5419566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)daf), &size_f));
5429566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)daf), &rank_f));
54347c6ae99SBarry Smith   col_scale = size_f / size_c;
54447c6ae99SBarry Smith   col_shift = Mx * My * (rank_f / size_c);
54547c6ae99SBarry Smith 
546d0609cedSBarry Smith   MatPreallocateBegin(PetscObjectComm((PetscObject)daf), m_f * n_f, col_scale * m_c * n_c, dnz, onz);
54747c6ae99SBarry Smith   for (j = j_start; j < j_start + n_f; j++) {
54847c6ae99SBarry Smith     for (i = i_start; i < i_start + m_f; i++) {
54947c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
550e3fbd1f4SBarry Smith       row = idx_f[(m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
55147c6ae99SBarry Smith 
55247c6ae99SBarry Smith       i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
55347c6ae99SBarry Smith       j_c = (j / ratioj); /* coarse grid node below fine grid node */
55447c6ae99SBarry Smith 
55508401ef6SPierre Jolivet       PetscCheck(j_c >= j_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
5569371c9d4SSatish Balay     j_start %" PetscInt_FMT " j_c %" PetscInt_FMT " j_start_ghost_c %" PetscInt_FMT,
5579371c9d4SSatish Balay                  j_start, j_c, j_start_ghost_c);
55808401ef6SPierre Jolivet       PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
5599371c9d4SSatish Balay     i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT,
5609371c9d4SSatish Balay                  i_start, i_c, i_start_ghost_c);
56147c6ae99SBarry Smith 
56247c6ae99SBarry Smith       /*
56347c6ae99SBarry Smith          Only include those interpolation points that are truly
56447c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
56547c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
56647c6ae99SBarry Smith       */
56747c6ae99SBarry Smith       nc = 0;
56847c6ae99SBarry Smith       /* one left and below; or we are right on it */
569e3fbd1f4SBarry Smith       col        = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
570e3fbd1f4SBarry Smith       cols[nc++] = col_shift + idx_c[col];
5719566063dSJacob Faibussowitsch       PetscCall(MatPreallocateSet(row, nc, cols, dnz, onz));
57247c6ae99SBarry Smith     }
57347c6ae99SBarry Smith   }
5749566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)daf), &mat));
575fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
576fdc842d1SBarry Smith   /*
577fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
578fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
579fdc842d1SBarry Smith   */
58048a46eb9SPierre Jolivet   if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
581fdc842d1SBarry Smith #endif
5829566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat, m_f * n_f, col_scale * m_c * n_c, mx * my, col_scale * Mx * My));
5839566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype, &mattype));
5849566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat, mattype));
5859566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat, 0, dnz));
5869566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat, 0, dnz, 0, onz));
587d0609cedSBarry Smith   MatPreallocateEnd(dnz, onz);
58847c6ae99SBarry Smith 
58947c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
59047c6ae99SBarry Smith   for (j = j_start; j < j_start + n_f; j++) {
59147c6ae99SBarry Smith     for (i = i_start; i < i_start + m_f; i++) {
59247c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
593e3fbd1f4SBarry Smith       row = idx_f[(m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
59447c6ae99SBarry Smith 
59547c6ae99SBarry Smith       i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
59647c6ae99SBarry Smith       j_c = (j / ratioj); /* coarse grid node below fine grid node */
59747c6ae99SBarry Smith       nc  = 0;
59847c6ae99SBarry Smith       /* one left and below; or we are right on it */
599e3fbd1f4SBarry Smith       col      = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
600e3fbd1f4SBarry Smith       cols[nc] = col_shift + idx_c[col];
60147c6ae99SBarry Smith       v[nc++]  = 1.0;
60247c6ae99SBarry Smith 
6039566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
60447c6ae99SBarry Smith     }
60547c6ae99SBarry Smith   }
6069566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
6079566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
6089566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
6099566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
6109566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat, dof, A));
6119566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
6129566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(13.0 * m_f * n_f));
6133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
61447c6ae99SBarry Smith }
61547c6ae99SBarry Smith 
61647c6ae99SBarry Smith /*
61747c6ae99SBarry Smith        Contributed by Jianming Yang <jianming-yang@uiowa.edu>
61847c6ae99SBarry Smith */
61966976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateInterpolation_DA_3D_Q0(DM dac, DM daf, Mat *A)
620d71ae5a4SJacob Faibussowitsch {
6218ea3bf28SBarry Smith   PetscInt               i, j, l, i_start, j_start, l_start, m_f, n_f, p_f, Mx, My, Mz, dof;
6228ea3bf28SBarry Smith   const PetscInt        *idx_c, *idx_f;
623e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f, ltog_c;
6248ea3bf28SBarry Smith   PetscInt               m_ghost, n_ghost, p_ghost, m_ghost_c, n_ghost_c, p_ghost_c, nc, *dnz, *onz;
62547c6ae99SBarry Smith   PetscInt               row, col, i_start_ghost, j_start_ghost, l_start_ghost, cols[8], mx, m_c, my, n_c, mz, p_c, ratioi, ratioj, ratiol;
62647c6ae99SBarry Smith   PetscInt               i_c, j_c, l_c, i_start_c, j_start_c, l_start_c, i_start_ghost_c, j_start_ghost_c, l_start_ghost_c, col_shift, col_scale;
62747c6ae99SBarry Smith   PetscMPIInt            size_c, size_f, rank_f;
62847c6ae99SBarry Smith   PetscScalar            v[8];
62947c6ae99SBarry Smith   Mat                    mat;
630bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx, by, bz;
631fdc842d1SBarry Smith   MatType                mattype;
63247c6ae99SBarry Smith 
63347c6ae99SBarry Smith   PetscFunctionBegin;
6349566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, &Mz, NULL, NULL, NULL, NULL, NULL, &bx, &by, &bz, NULL));
63563a3b9bcSJacob Faibussowitsch   PetscCheck(Mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be positive", Mx);
63663a3b9bcSJacob Faibussowitsch   PetscCheck(My, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be positive", My);
63763a3b9bcSJacob Faibussowitsch   PetscCheck(Mz, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of z coarse grid points %" PetscInt_FMT " must be positive", Mz);
6389566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, &mz, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
63947c6ae99SBarry Smith   ratioi = mx / Mx;
64047c6ae99SBarry Smith   ratioj = my / My;
64147c6ae99SBarry Smith   ratiol = mz / Mz;
64208401ef6SPierre Jolivet   PetscCheck(ratioi * Mx == mx, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Fine grid points must be multiple of coarse grid points in x");
64308401ef6SPierre Jolivet   PetscCheck(ratioj * My == my, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Fine grid points must be multiple of coarse grid points in y");
64408401ef6SPierre Jolivet   PetscCheck(ratiol * Mz == mz, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Fine grid points must be multiple of coarse grid points in z");
6451dca8a05SBarry Smith   PetscCheck(ratioi == 2 || ratioi == 1, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Coarsening factor in x must be 1 or 2");
6461dca8a05SBarry Smith   PetscCheck(ratioj == 2 || ratioj == 1, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Coarsening factor in y must be 1 or 2");
6471dca8a05SBarry Smith   PetscCheck(ratiol == 2 || ratiol == 1, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Coarsening factor in z must be 1 or 2");
64847c6ae99SBarry Smith 
6499566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf, &i_start, &j_start, &l_start, &m_f, &n_f, &p_f));
6509566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, &l_start_ghost, &m_ghost, &n_ghost, &p_ghost));
6519566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf, &ltog_f));
6529566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
65347c6ae99SBarry Smith 
6549566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, &l_start_c, &m_c, &n_c, &p_c));
6559566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, &l_start_ghost_c, &m_ghost_c, &n_ghost_c, &p_ghost_c));
6569566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac, &ltog_c));
6579566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
658e3fbd1f4SBarry Smith 
65947c6ae99SBarry Smith   /*
660aa219208SBarry Smith      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
66147c6ae99SBarry Smith      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
66247c6ae99SBarry Smith      processors). It's effective length is hence 4 times its normal length, this is
66347c6ae99SBarry Smith      why the col_scale is multiplied by the interpolation matrix column sizes.
66447c6ae99SBarry Smith      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
66547c6ae99SBarry Smith      copy of the coarse vector. A bit of a hack but you do better.
66647c6ae99SBarry Smith 
66747c6ae99SBarry Smith      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
66847c6ae99SBarry Smith   */
6699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dac), &size_c));
6709566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)daf), &size_f));
6719566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)daf), &rank_f));
67247c6ae99SBarry Smith   col_scale = size_f / size_c;
67347c6ae99SBarry Smith   col_shift = Mx * My * Mz * (rank_f / size_c);
67447c6ae99SBarry Smith 
675d0609cedSBarry Smith   MatPreallocateBegin(PetscObjectComm((PetscObject)daf), m_f * n_f * p_f, col_scale * m_c * n_c * p_c, dnz, onz);
67647c6ae99SBarry Smith   for (l = l_start; l < l_start + p_f; l++) {
67747c6ae99SBarry Smith     for (j = j_start; j < j_start + n_f; j++) {
67847c6ae99SBarry Smith       for (i = i_start; i < i_start + m_f; i++) {
67947c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
680e3fbd1f4SBarry Smith         row = idx_f[(m_ghost * n_ghost * (l - l_start_ghost) + m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
68147c6ae99SBarry Smith 
68247c6ae99SBarry Smith         i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
68347c6ae99SBarry Smith         j_c = (j / ratioj); /* coarse grid node below fine grid node */
68447c6ae99SBarry Smith         l_c = (l / ratiol);
68547c6ae99SBarry Smith 
68608401ef6SPierre Jolivet         PetscCheck(l_c >= l_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
6879371c9d4SSatish Balay     l_start %" PetscInt_FMT " l_c %" PetscInt_FMT " l_start_ghost_c %" PetscInt_FMT,
6889371c9d4SSatish Balay                    l_start, l_c, l_start_ghost_c);
68908401ef6SPierre Jolivet         PetscCheck(j_c >= j_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
6909371c9d4SSatish Balay     j_start %" PetscInt_FMT " j_c %" PetscInt_FMT " j_start_ghost_c %" PetscInt_FMT,
6919371c9d4SSatish Balay                    j_start, j_c, j_start_ghost_c);
69208401ef6SPierre Jolivet         PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
6939371c9d4SSatish Balay     i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT,
6949371c9d4SSatish Balay                    i_start, i_c, i_start_ghost_c);
69547c6ae99SBarry Smith 
69647c6ae99SBarry Smith         /*
69747c6ae99SBarry Smith            Only include those interpolation points that are truly
69847c6ae99SBarry Smith            nonzero. Note this is very important for final grid lines
69947c6ae99SBarry Smith            in x and y directions; since they have no right/top neighbors
70047c6ae99SBarry Smith         */
70147c6ae99SBarry Smith         nc = 0;
70247c6ae99SBarry Smith         /* one left and below; or we are right on it */
703e3fbd1f4SBarry Smith         col        = (m_ghost_c * n_ghost_c * (l_c - l_start_ghost_c) + m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
704e3fbd1f4SBarry Smith         cols[nc++] = col_shift + idx_c[col];
7059566063dSJacob Faibussowitsch         PetscCall(MatPreallocateSet(row, nc, cols, dnz, onz));
70647c6ae99SBarry Smith       }
70747c6ae99SBarry Smith     }
70847c6ae99SBarry Smith   }
7099566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)daf), &mat));
710fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
711fdc842d1SBarry Smith   /*
712fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
713fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
714fdc842d1SBarry Smith   */
71548a46eb9SPierre Jolivet   if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
716fdc842d1SBarry Smith #endif
7179566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat, m_f * n_f * p_f, col_scale * m_c * n_c * p_c, mx * my * mz, col_scale * Mx * My * Mz));
7189566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype, &mattype));
7199566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat, mattype));
7209566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat, 0, dnz));
7219566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat, 0, dnz, 0, onz));
722d0609cedSBarry Smith   MatPreallocateEnd(dnz, onz);
72347c6ae99SBarry Smith 
72447c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
72547c6ae99SBarry Smith   for (l = l_start; l < l_start + p_f; l++) {
72647c6ae99SBarry Smith     for (j = j_start; j < j_start + n_f; j++) {
72747c6ae99SBarry Smith       for (i = i_start; i < i_start + m_f; i++) {
72847c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
729e3fbd1f4SBarry Smith         row = idx_f[(m_ghost * n_ghost * (l - l_start_ghost) + m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
73047c6ae99SBarry Smith 
73147c6ae99SBarry Smith         i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
73247c6ae99SBarry Smith         j_c = (j / ratioj); /* coarse grid node below fine grid node */
73347c6ae99SBarry Smith         l_c = (l / ratiol);
73447c6ae99SBarry Smith         nc  = 0;
73547c6ae99SBarry Smith         /* one left and below; or we are right on it */
736e3fbd1f4SBarry Smith         col      = (m_ghost_c * n_ghost_c * (l_c - l_start_ghost_c) + m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
737e3fbd1f4SBarry Smith         cols[nc] = col_shift + idx_c[col];
73847c6ae99SBarry Smith         v[nc++]  = 1.0;
73947c6ae99SBarry Smith 
7409566063dSJacob Faibussowitsch         PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
74147c6ae99SBarry Smith       }
74247c6ae99SBarry Smith     }
74347c6ae99SBarry Smith   }
7449566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
7459566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
7469566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
7479566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
7489566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat, dof, A));
7499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
7509566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(13.0 * m_f * n_f * p_f));
7513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
75247c6ae99SBarry Smith }
75347c6ae99SBarry Smith 
75466976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateInterpolation_DA_3D_Q1(DM dac, DM daf, Mat *A)
755d71ae5a4SJacob Faibussowitsch {
7568ea3bf28SBarry Smith   PetscInt               i, j, i_start, j_start, m_f, n_f, Mx, My, dof, l;
7578ea3bf28SBarry Smith   const PetscInt        *idx_c, *idx_f;
758e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f, ltog_c;
7598ea3bf28SBarry Smith   PetscInt               m_ghost, n_ghost, m_ghost_c, n_ghost_c, Mz, mz;
76047c6ae99SBarry Smith   PetscInt               row, col, i_start_ghost, j_start_ghost, cols[8], mx, m_c, my, nc, ratioi, ratioj, ratiok;
76147c6ae99SBarry Smith   PetscInt               i_c, j_c, i_start_c, j_start_c, n_c, i_start_ghost_c, j_start_ghost_c;
76247c6ae99SBarry Smith   PetscInt               l_start, p_f, l_start_ghost, p_ghost, l_start_c, p_c;
76347c6ae99SBarry Smith   PetscInt               l_start_ghost_c, p_ghost_c, l_c, *dnz, *onz;
76447c6ae99SBarry Smith   PetscScalar            v[8], x, y, z;
76547c6ae99SBarry Smith   Mat                    mat;
766bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx, by, bz;
767fdc842d1SBarry Smith   MatType                mattype;
76847c6ae99SBarry Smith 
76947c6ae99SBarry Smith   PetscFunctionBegin;
7709566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, &Mz, NULL, NULL, NULL, NULL, NULL, &bx, &by, &bz, NULL));
7719566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, &mz, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
77247c6ae99SBarry Smith   if (mx == Mx) {
77347c6ae99SBarry Smith     ratioi = 1;
774bff4a2f0SMatthew G. Knepley   } else if (bx == DM_BOUNDARY_PERIODIC) {
77563a3b9bcSJacob Faibussowitsch     PetscCheck(Mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be positive", Mx);
77647c6ae99SBarry Smith     ratioi = mx / Mx;
77763a3b9bcSJacob Faibussowitsch     PetscCheck(ratioi * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx  must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
77847c6ae99SBarry Smith   } else {
77963a3b9bcSJacob Faibussowitsch     PetscCheck(Mx >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be greater than 1", Mx);
78047c6ae99SBarry Smith     ratioi = (mx - 1) / (Mx - 1);
7811dca8a05SBarry Smith     PetscCheck(ratioi * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
78247c6ae99SBarry Smith   }
78347c6ae99SBarry Smith   if (my == My) {
78447c6ae99SBarry Smith     ratioj = 1;
785bff4a2f0SMatthew G. Knepley   } else if (by == DM_BOUNDARY_PERIODIC) {
78663a3b9bcSJacob Faibussowitsch     PetscCheck(My, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be positive", My);
78747c6ae99SBarry Smith     ratioj = my / My;
78863a3b9bcSJacob Faibussowitsch     PetscCheck(ratioj * My == my, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: my/My  must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
78947c6ae99SBarry Smith   } else {
79063a3b9bcSJacob Faibussowitsch     PetscCheck(My >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be greater than 1", My);
79147c6ae99SBarry Smith     ratioj = (my - 1) / (My - 1);
7921dca8a05SBarry Smith     PetscCheck(ratioj * (My - 1) == my - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (my - 1)/(My - 1) must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
79347c6ae99SBarry Smith   }
79447c6ae99SBarry Smith   if (mz == Mz) {
79547c6ae99SBarry Smith     ratiok = 1;
796bff4a2f0SMatthew G. Knepley   } else if (bz == DM_BOUNDARY_PERIODIC) {
79763a3b9bcSJacob Faibussowitsch     PetscCheck(Mz, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of z coarse grid points %" PetscInt_FMT " must be positive", Mz);
79847c6ae99SBarry Smith     ratiok = mz / Mz;
79963a3b9bcSJacob Faibussowitsch     PetscCheck(ratiok * Mz == mz, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mz/Mz  must be integer: mz %" PetscInt_FMT " Mz %" PetscInt_FMT, mz, Mz);
80047c6ae99SBarry Smith   } else {
80163a3b9bcSJacob Faibussowitsch     PetscCheck(Mz >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of z coarse grid points %" PetscInt_FMT " must be greater than 1", Mz);
80247c6ae99SBarry Smith     ratiok = (mz - 1) / (Mz - 1);
8031dca8a05SBarry Smith     PetscCheck(ratiok * (Mz - 1) == mz - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %" PetscInt_FMT " Mz %" PetscInt_FMT, mz, Mz);
80447c6ae99SBarry Smith   }
80547c6ae99SBarry Smith 
8069566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf, &i_start, &j_start, &l_start, &m_f, &n_f, &p_f));
8079566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, &l_start_ghost, &m_ghost, &n_ghost, &p_ghost));
8089566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf, &ltog_f));
8099566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
81047c6ae99SBarry Smith 
8119566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, &l_start_c, &m_c, &n_c, &p_c));
8129566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, &l_start_ghost_c, &m_ghost_c, &n_ghost_c, &p_ghost_c));
8139566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac, &ltog_c));
8149566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
81547c6ae99SBarry Smith 
81647c6ae99SBarry Smith   /* create interpolation matrix, determining exact preallocation */
817d0609cedSBarry Smith   MatPreallocateBegin(PetscObjectComm((PetscObject)dac), m_f * n_f * p_f, m_c * n_c * p_c, dnz, onz);
81847c6ae99SBarry Smith   /* loop over local fine grid nodes counting interpolating points */
81947c6ae99SBarry Smith   for (l = l_start; l < l_start + p_f; l++) {
82047c6ae99SBarry Smith     for (j = j_start; j < j_start + n_f; j++) {
82147c6ae99SBarry Smith       for (i = i_start; i < i_start + m_f; i++) {
82247c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
823e3fbd1f4SBarry Smith         row = idx_f[(m_ghost * n_ghost * (l - l_start_ghost) + m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
82447c6ae99SBarry Smith         i_c = (i / ratioi);
82547c6ae99SBarry Smith         j_c = (j / ratioj);
82647c6ae99SBarry Smith         l_c = (l / ratiok);
82708401ef6SPierre Jolivet         PetscCheck(l_c >= l_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
8289371c9d4SSatish Balay                                             l_start %" PetscInt_FMT " l_c %" PetscInt_FMT " l_start_ghost_c %" PetscInt_FMT,
8299371c9d4SSatish Balay                    l_start, l_c, l_start_ghost_c);
83008401ef6SPierre Jolivet         PetscCheck(j_c >= j_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
8319371c9d4SSatish Balay                                             j_start %" PetscInt_FMT " j_c %" PetscInt_FMT " j_start_ghost_c %" PetscInt_FMT,
8329371c9d4SSatish Balay                    j_start, j_c, j_start_ghost_c);
83308401ef6SPierre Jolivet         PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
8349371c9d4SSatish Balay                                             i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT,
8359371c9d4SSatish Balay                    i_start, i_c, i_start_ghost_c);
83647c6ae99SBarry Smith 
83747c6ae99SBarry Smith         /*
83847c6ae99SBarry Smith          Only include those interpolation points that are truly
83947c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
84047c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
84147c6ae99SBarry Smith          */
84247c6ae99SBarry Smith         nc         = 0;
843e3fbd1f4SBarry Smith         col        = (m_ghost_c * n_ghost_c * (l_c - l_start_ghost_c) + m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
844e3fbd1f4SBarry Smith         cols[nc++] = idx_c[col];
845ad540459SPierre Jolivet         if (i_c * ratioi != i) cols[nc++] = idx_c[col + 1];
846ad540459SPierre Jolivet         if (j_c * ratioj != j) cols[nc++] = idx_c[col + m_ghost_c];
847ad540459SPierre Jolivet         if (l_c * ratiok != l) cols[nc++] = idx_c[col + m_ghost_c * n_ghost_c];
848ad540459SPierre Jolivet         if (j_c * ratioj != j && i_c * ratioi != i) cols[nc++] = idx_c[col + (m_ghost_c + 1)];
849ad540459SPierre Jolivet         if (j_c * ratioj != j && l_c * ratiok != l) cols[nc++] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c)];
850ad540459SPierre Jolivet         if (i_c * ratioi != i && l_c * ratiok != l) cols[nc++] = idx_c[col + (m_ghost_c * n_ghost_c + 1)];
851ad540459SPierre Jolivet         if (i_c * ratioi != i && l_c * ratiok != l && j_c * ratioj != j) cols[nc++] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c + 1)];
8529566063dSJacob Faibussowitsch         PetscCall(MatPreallocateSet(row, nc, cols, dnz, onz));
85347c6ae99SBarry Smith       }
85447c6ae99SBarry Smith     }
85547c6ae99SBarry Smith   }
8569566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dac), &mat));
857fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
858fdc842d1SBarry Smith   /*
859fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
860fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
861fdc842d1SBarry Smith   */
86248a46eb9SPierre Jolivet   if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
863fdc842d1SBarry Smith #endif
8649566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat, m_f * n_f * p_f, m_c * n_c * p_c, mx * my * mz, Mx * My * Mz));
8659566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype, &mattype));
8669566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat, mattype));
8679566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat, 0, dnz));
8689566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat, 0, dnz, 0, onz));
869d0609cedSBarry Smith   MatPreallocateEnd(dnz, onz);
87047c6ae99SBarry Smith 
87147c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
8722adb9dcfSBarry Smith   if (!NEWVERSION) {
87347c6ae99SBarry Smith     for (l = l_start; l < l_start + p_f; l++) {
87447c6ae99SBarry Smith       for (j = j_start; j < j_start + n_f; j++) {
87547c6ae99SBarry Smith         for (i = i_start; i < i_start + m_f; i++) {
87647c6ae99SBarry Smith           /* convert to local "natural" numbering and then to PETSc global numbering */
877e3fbd1f4SBarry Smith           row = idx_f[(m_ghost * n_ghost * (l - l_start_ghost) + m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
87847c6ae99SBarry Smith 
87947c6ae99SBarry Smith           i_c = (i / ratioi);
88047c6ae99SBarry Smith           j_c = (j / ratioj);
88147c6ae99SBarry Smith           l_c = (l / ratiok);
88247c6ae99SBarry Smith 
88347c6ae99SBarry Smith           /*
88447c6ae99SBarry Smith            Only include those interpolation points that are truly
88547c6ae99SBarry Smith            nonzero. Note this is very important for final grid lines
88647c6ae99SBarry Smith            in x and y directions; since they have no right/top neighbors
88747c6ae99SBarry Smith            */
8886712e2f1SBarry Smith           x = ((PetscReal)(i - i_c * ratioi)) / ((PetscReal)ratioi);
8896712e2f1SBarry Smith           y = ((PetscReal)(j - j_c * ratioj)) / ((PetscReal)ratioj);
8906712e2f1SBarry Smith           z = ((PetscReal)(l - l_c * ratiok)) / ((PetscReal)ratiok);
891b3bd94feSDave May 
89247c6ae99SBarry Smith           nc = 0;
89347c6ae99SBarry Smith           /* one left and below; or we are right on it */
894e3fbd1f4SBarry Smith           col = (m_ghost_c * n_ghost_c * (l_c - l_start_ghost_c) + m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
89547c6ae99SBarry Smith 
896e3fbd1f4SBarry Smith           cols[nc] = idx_c[col];
89747c6ae99SBarry Smith           v[nc++]  = .125 * (1. - (2.0 * x - 1.)) * (1. - (2.0 * y - 1.)) * (1. - (2.0 * z - 1.));
89847c6ae99SBarry Smith 
89947c6ae99SBarry Smith           if (i_c * ratioi != i) {
900e3fbd1f4SBarry Smith             cols[nc] = idx_c[col + 1];
90147c6ae99SBarry Smith             v[nc++]  = .125 * (1. + (2.0 * x - 1.)) * (1. - (2.0 * y - 1.)) * (1. - (2.0 * z - 1.));
90247c6ae99SBarry Smith           }
90347c6ae99SBarry Smith 
90447c6ae99SBarry Smith           if (j_c * ratioj != j) {
905e3fbd1f4SBarry Smith             cols[nc] = idx_c[col + m_ghost_c];
90647c6ae99SBarry Smith             v[nc++]  = .125 * (1. - (2.0 * x - 1.)) * (1. + (2.0 * y - 1.)) * (1. - (2.0 * z - 1.));
90747c6ae99SBarry Smith           }
90847c6ae99SBarry Smith 
90947c6ae99SBarry Smith           if (l_c * ratiok != l) {
910e3fbd1f4SBarry Smith             cols[nc] = idx_c[col + m_ghost_c * n_ghost_c];
91147c6ae99SBarry Smith             v[nc++]  = .125 * (1. - (2.0 * x - 1.)) * (1. - (2.0 * y - 1.)) * (1. + (2.0 * z - 1.));
91247c6ae99SBarry Smith           }
91347c6ae99SBarry Smith 
91447c6ae99SBarry Smith           if (j_c * ratioj != j && i_c * ratioi != i) {
915e3fbd1f4SBarry Smith             cols[nc] = idx_c[col + (m_ghost_c + 1)];
91647c6ae99SBarry Smith             v[nc++]  = .125 * (1. + (2.0 * x - 1.)) * (1. + (2.0 * y - 1.)) * (1. - (2.0 * z - 1.));
91747c6ae99SBarry Smith           }
91847c6ae99SBarry Smith 
91947c6ae99SBarry Smith           if (j_c * ratioj != j && l_c * ratiok != l) {
920e3fbd1f4SBarry Smith             cols[nc] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c)];
92147c6ae99SBarry Smith             v[nc++]  = .125 * (1. - (2.0 * x - 1.)) * (1. + (2.0 * y - 1.)) * (1. + (2.0 * z - 1.));
92247c6ae99SBarry Smith           }
92347c6ae99SBarry Smith 
92447c6ae99SBarry Smith           if (i_c * ratioi != i && l_c * ratiok != l) {
925e3fbd1f4SBarry Smith             cols[nc] = idx_c[col + (m_ghost_c * n_ghost_c + 1)];
92647c6ae99SBarry Smith             v[nc++]  = .125 * (1. + (2.0 * x - 1.)) * (1. - (2.0 * y - 1.)) * (1. + (2.0 * z - 1.));
92747c6ae99SBarry Smith           }
92847c6ae99SBarry Smith 
92947c6ae99SBarry Smith           if (i_c * ratioi != i && l_c * ratiok != l && j_c * ratioj != j) {
930e3fbd1f4SBarry Smith             cols[nc] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c + 1)];
93147c6ae99SBarry Smith             v[nc++]  = .125 * (1. + (2.0 * x - 1.)) * (1. + (2.0 * y - 1.)) * (1. + (2.0 * z - 1.));
93247c6ae99SBarry Smith           }
9339566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
93447c6ae99SBarry Smith         }
93547c6ae99SBarry Smith       }
93647c6ae99SBarry Smith     }
937b3bd94feSDave May 
938b3bd94feSDave May   } else {
939b3bd94feSDave May     PetscScalar *xi, *eta, *zeta;
940b3bd94feSDave May     PetscInt     li, nxi, lj, neta, lk, nzeta, n;
941b3bd94feSDave May     PetscScalar  Ni[8];
942b3bd94feSDave May 
943b3bd94feSDave May     /* compute local coordinate arrays */
944b3bd94feSDave May     nxi   = ratioi + 1;
945b3bd94feSDave May     neta  = ratioj + 1;
946b3bd94feSDave May     nzeta = ratiok + 1;
9479566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nxi, &xi));
9489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(neta, &eta));
9499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nzeta, &zeta));
9508865f1eaSKarl Rupp     for (li = 0; li < nxi; li++) xi[li] = -1.0 + (PetscScalar)li * (2.0 / (PetscScalar)(nxi - 1));
9518865f1eaSKarl Rupp     for (lj = 0; lj < neta; lj++) eta[lj] = -1.0 + (PetscScalar)lj * (2.0 / (PetscScalar)(neta - 1));
9528865f1eaSKarl Rupp     for (lk = 0; lk < nzeta; lk++) zeta[lk] = -1.0 + (PetscScalar)lk * (2.0 / (PetscScalar)(nzeta - 1));
953b3bd94feSDave May 
954b3bd94feSDave May     for (l = l_start; l < l_start + p_f; l++) {
955b3bd94feSDave May       for (j = j_start; j < j_start + n_f; j++) {
956b3bd94feSDave May         for (i = i_start; i < i_start + m_f; i++) {
957b3bd94feSDave May           /* convert to local "natural" numbering and then to PETSc global numbering */
958e3fbd1f4SBarry Smith           row = idx_f[(m_ghost * n_ghost * (l - l_start_ghost) + m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
959b3bd94feSDave May 
960b3bd94feSDave May           i_c = (i / ratioi);
961b3bd94feSDave May           j_c = (j / ratioj);
962b3bd94feSDave May           l_c = (l / ratiok);
963b3bd94feSDave May 
964b3bd94feSDave May           /* remainders */
965b3bd94feSDave May           li = i - ratioi * (i / ratioi);
9668865f1eaSKarl Rupp           if (i == mx - 1) li = nxi - 1;
967b3bd94feSDave May           lj = j - ratioj * (j / ratioj);
9688865f1eaSKarl Rupp           if (j == my - 1) lj = neta - 1;
969b3bd94feSDave May           lk = l - ratiok * (l / ratiok);
9708865f1eaSKarl Rupp           if (l == mz - 1) lk = nzeta - 1;
971b3bd94feSDave May 
972b3bd94feSDave May           /* corners */
973e3fbd1f4SBarry Smith           col     = (m_ghost_c * n_ghost_c * (l_c - l_start_ghost_c) + m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
974e3fbd1f4SBarry Smith           cols[0] = idx_c[col];
975b3bd94feSDave May           Ni[0]   = 1.0;
976b3bd94feSDave May           if ((li == 0) || (li == nxi - 1)) {
977b3bd94feSDave May             if ((lj == 0) || (lj == neta - 1)) {
978b3bd94feSDave May               if ((lk == 0) || (lk == nzeta - 1)) {
9799566063dSJacob Faibussowitsch                 PetscCall(MatSetValue(mat, row, cols[0], Ni[0], INSERT_VALUES));
980b3bd94feSDave May                 continue;
981b3bd94feSDave May               }
982b3bd94feSDave May             }
983b3bd94feSDave May           }
984b3bd94feSDave May 
985b3bd94feSDave May           /* edges + interior */
986b3bd94feSDave May           /* remainders */
9878865f1eaSKarl Rupp           if (i == mx - 1) i_c--;
9888865f1eaSKarl Rupp           if (j == my - 1) j_c--;
9898865f1eaSKarl Rupp           if (l == mz - 1) l_c--;
990b3bd94feSDave May 
991e3fbd1f4SBarry Smith           col     = (m_ghost_c * n_ghost_c * (l_c - l_start_ghost_c) + m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
992e3fbd1f4SBarry Smith           cols[0] = idx_c[col];                   /* one left and below; or we are right on it */
993e3fbd1f4SBarry Smith           cols[1] = idx_c[col + 1];               /* one right and below */
994e3fbd1f4SBarry Smith           cols[2] = idx_c[col + m_ghost_c];       /* one left and above */
995e3fbd1f4SBarry Smith           cols[3] = idx_c[col + (m_ghost_c + 1)]; /* one right and above */
996b3bd94feSDave May 
997e3fbd1f4SBarry Smith           cols[4] = idx_c[col + m_ghost_c * n_ghost_c];                   /* one left and below and front; or we are right on it */
998e3fbd1f4SBarry Smith           cols[5] = idx_c[col + (m_ghost_c * n_ghost_c + 1)];             /* one right and below, and front */
999e3fbd1f4SBarry Smith           cols[6] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c)];     /* one left and above and front*/
1000e3fbd1f4SBarry Smith           cols[7] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c + 1)]; /* one right and above and front */
1001b3bd94feSDave May 
1002b3bd94feSDave May           Ni[0] = 0.125 * (1.0 - xi[li]) * (1.0 - eta[lj]) * (1.0 - zeta[lk]);
1003b3bd94feSDave May           Ni[1] = 0.125 * (1.0 + xi[li]) * (1.0 - eta[lj]) * (1.0 - zeta[lk]);
1004b3bd94feSDave May           Ni[2] = 0.125 * (1.0 - xi[li]) * (1.0 + eta[lj]) * (1.0 - zeta[lk]);
1005b3bd94feSDave May           Ni[3] = 0.125 * (1.0 + xi[li]) * (1.0 + eta[lj]) * (1.0 - zeta[lk]);
1006b3bd94feSDave May 
1007b3bd94feSDave May           Ni[4] = 0.125 * (1.0 - xi[li]) * (1.0 - eta[lj]) * (1.0 + zeta[lk]);
1008b3bd94feSDave May           Ni[5] = 0.125 * (1.0 + xi[li]) * (1.0 - eta[lj]) * (1.0 + zeta[lk]);
1009b3bd94feSDave May           Ni[6] = 0.125 * (1.0 - xi[li]) * (1.0 + eta[lj]) * (1.0 + zeta[lk]);
1010b3bd94feSDave May           Ni[7] = 0.125 * (1.0 + xi[li]) * (1.0 + eta[lj]) * (1.0 + zeta[lk]);
1011b3bd94feSDave May 
1012b3bd94feSDave May           for (n = 0; n < 8; n++) {
10138865f1eaSKarl Rupp             if (PetscAbsScalar(Ni[n]) < 1.0e-32) cols[n] = -1;
1014b3bd94feSDave May           }
10159566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat, 1, &row, 8, cols, Ni, INSERT_VALUES));
1016b3bd94feSDave May         }
1017b3bd94feSDave May       }
1018b3bd94feSDave May     }
10199566063dSJacob Faibussowitsch     PetscCall(PetscFree(xi));
10209566063dSJacob Faibussowitsch     PetscCall(PetscFree(eta));
10219566063dSJacob Faibussowitsch     PetscCall(PetscFree(zeta));
1022b3bd94feSDave May   }
10239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
10249566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
10259566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
10269566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
102747c6ae99SBarry Smith 
10289566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat, dof, A));
10299566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
10303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
103147c6ae99SBarry Smith }
103247c6ae99SBarry Smith 
1033d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInterpolation_DA(DM dac, DM daf, Mat *A, Vec *scale)
1034d71ae5a4SJacob Faibussowitsch {
103547c6ae99SBarry Smith   PetscInt        dimc, Mc, Nc, Pc, mc, nc, pc, dofc, sc, dimf, Mf, Nf, Pf, mf, nf, pf, doff, sf;
1036bff4a2f0SMatthew G. Knepley   DMBoundaryType  bxc, byc, bzc, bxf, byf, bzf;
1037aa219208SBarry Smith   DMDAStencilType stc, stf;
103847c6ae99SBarry Smith   DM_DA          *ddc = (DM_DA *)dac->data;
103947c6ae99SBarry Smith 
104047c6ae99SBarry Smith   PetscFunctionBegin;
104147c6ae99SBarry Smith   PetscValidHeaderSpecific(dac, DM_CLASSID, 1);
104247c6ae99SBarry Smith   PetscValidHeaderSpecific(daf, DM_CLASSID, 2);
10434f572ea9SToby Isaac   PetscAssertPointer(A, 3);
10444f572ea9SToby Isaac   if (scale) PetscAssertPointer(scale, 4);
104547c6ae99SBarry Smith 
10469566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, &dimc, &Mc, &Nc, &Pc, &mc, &nc, &pc, &dofc, &sc, &bxc, &byc, &bzc, &stc));
10479566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, &dimf, &Mf, &Nf, &Pf, &mf, &nf, &pf, &doff, &sf, &bxf, &byf, &bzf, &stf));
104863a3b9bcSJacob Faibussowitsch   PetscCheck(dimc == dimf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Dimensions of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dimc, dimf);
104963a3b9bcSJacob Faibussowitsch   PetscCheck(dofc == doff, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "DOF of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dofc, doff);
105063a3b9bcSJacob Faibussowitsch   PetscCheck(sc == sf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil width of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, sc, sf);
10511dca8a05SBarry Smith   PetscCheck(bxc == bxf && byc == byf && bzc == bzf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Boundary type different in two DMDAs");
105208401ef6SPierre Jolivet   PetscCheck(stc == stf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil type different in two DMDAs");
10531dca8a05SBarry Smith   PetscCheck(Mc >= 2 || Mf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in x direction");
10541dca8a05SBarry Smith   PetscCheck(dimc <= 1 || Nc >= 2 || Nf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in y direction");
10551dca8a05SBarry Smith   PetscCheck(dimc <= 2 || Pc >= 2 || Pf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in z direction");
105647c6ae99SBarry Smith 
1057aa219208SBarry Smith   if (ddc->interptype == DMDA_Q1) {
105847c6ae99SBarry Smith     if (dimc == 1) {
10599566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_1D_Q1(dac, daf, A));
106047c6ae99SBarry Smith     } else if (dimc == 2) {
10619566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_2D_Q1(dac, daf, A));
106247c6ae99SBarry Smith     } else if (dimc == 3) {
10639566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_3D_Q1(dac, daf, A));
106463a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)daf), PETSC_ERR_SUP, "No support for this DMDA dimension %" PetscInt_FMT " for interpolation type %d", dimc, (int)ddc->interptype);
1065aa219208SBarry Smith   } else if (ddc->interptype == DMDA_Q0) {
106647c6ae99SBarry Smith     if (dimc == 1) {
10679566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_1D_Q0(dac, daf, A));
106847c6ae99SBarry Smith     } else if (dimc == 2) {
10699566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_2D_Q0(dac, daf, A));
107047c6ae99SBarry Smith     } else if (dimc == 3) {
10719566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_3D_Q0(dac, daf, A));
107263a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)daf), PETSC_ERR_SUP, "No support for this DMDA dimension %" PetscInt_FMT " for interpolation type %d", dimc, (int)ddc->interptype);
107347c6ae99SBarry Smith   }
10741baa6e33SBarry Smith   if (scale) PetscCall(DMCreateInterpolationScale((DM)dac, (DM)daf, *A, scale));
10753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
107647c6ae99SBarry Smith }
107747c6ae99SBarry Smith 
107866976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateInjection_DA_1D(DM dac, DM daf, VecScatter *inject)
1079d71ae5a4SJacob Faibussowitsch {
10808ea3bf28SBarry Smith   PetscInt               i, i_start, m_f, Mx, dof;
10818ea3bf28SBarry Smith   const PetscInt        *idx_f;
1082e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f;
10838ea3bf28SBarry Smith   PetscInt               m_ghost, m_ghost_c;
10840bb2b966SJungho Lee   PetscInt               row, i_start_ghost, mx, m_c, nc, ratioi;
10850bb2b966SJungho Lee   PetscInt               i_start_c, i_start_ghost_c;
10860bb2b966SJungho Lee   PetscInt              *cols;
1087bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
10880bb2b966SJungho Lee   Vec                    vecf, vecc;
10890bb2b966SJungho Lee   IS                     isf;
10900bb2b966SJungho Lee 
10910bb2b966SJungho Lee   PetscFunctionBegin;
10929566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, NULL, &Mx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &bx, NULL, NULL, NULL));
10939566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, NULL, &mx, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
1094bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
10950bb2b966SJungho Lee     ratioi = mx / Mx;
109663a3b9bcSJacob Faibussowitsch     PetscCheck(ratioi * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx  must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
10970bb2b966SJungho Lee   } else {
10980bb2b966SJungho Lee     ratioi = (mx - 1) / (Mx - 1);
10991dca8a05SBarry Smith     PetscCheck(ratioi * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
11000bb2b966SJungho Lee   }
11010bb2b966SJungho Lee 
11029566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf, &i_start, NULL, NULL, &m_f, NULL, NULL));
11039566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, NULL, NULL, &m_ghost, NULL, NULL));
11049566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf, &ltog_f));
11059566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
11060bb2b966SJungho Lee 
11079566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac, &i_start_c, NULL, NULL, &m_c, NULL, NULL));
11089566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, NULL, NULL, &m_ghost_c, NULL, NULL));
11090bb2b966SJungho Lee 
11100bb2b966SJungho Lee   /* loop over local fine grid nodes setting interpolation for those*/
11110bb2b966SJungho Lee   nc = 0;
11129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m_f, &cols));
11130bb2b966SJungho Lee 
11140bb2b966SJungho Lee   for (i = i_start_c; i < i_start_c + m_c; i++) {
11150bb2b966SJungho Lee     PetscInt i_f = i * ratioi;
11160bb2b966SJungho Lee 
11171dca8a05SBarry Smith     PetscCheck(i_f >= i_start_ghost && i_f < i_start_ghost + m_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\ni_c %" PetscInt_FMT " i_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]", i, i_f, i_start_ghost, i_start_ghost + m_ghost);
11188865f1eaSKarl Rupp 
1119e3fbd1f4SBarry Smith     row        = idx_f[(i_f - i_start_ghost)];
1120e3fbd1f4SBarry Smith     cols[nc++] = row;
11210bb2b966SJungho Lee   }
11220bb2b966SJungho Lee 
11239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
11249566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)daf), dof, nc, cols, PETSC_OWN_POINTER, &isf));
11259566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dac, &vecc));
11269566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(daf, &vecf));
11279566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(vecf, isf, vecc, NULL, inject));
11289566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dac, &vecc));
11299566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(daf, &vecf));
11309566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isf));
11313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11320bb2b966SJungho Lee }
11330bb2b966SJungho Lee 
113466976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateInjection_DA_2D(DM dac, DM daf, VecScatter *inject)
1135d71ae5a4SJacob Faibussowitsch {
11368ea3bf28SBarry Smith   PetscInt               i, j, i_start, j_start, m_f, n_f, Mx, My, dof;
11378ea3bf28SBarry Smith   const PetscInt        *idx_c, *idx_f;
1138e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f, ltog_c;
11398ea3bf28SBarry Smith   PetscInt               m_ghost, n_ghost, m_ghost_c, n_ghost_c;
114047c6ae99SBarry Smith   PetscInt               row, i_start_ghost, j_start_ghost, mx, m_c, my, nc, ratioi, ratioj;
1141076202ddSJed Brown   PetscInt               i_start_c, j_start_c, n_c, i_start_ghost_c, j_start_ghost_c;
114247c6ae99SBarry Smith   PetscInt              *cols;
1143bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx, by;
114447c6ae99SBarry Smith   Vec                    vecf, vecc;
114547c6ae99SBarry Smith   IS                     isf;
114647c6ae99SBarry Smith 
114747c6ae99SBarry Smith   PetscFunctionBegin;
11489566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, NULL, NULL, NULL, NULL, NULL, NULL, &bx, &by, NULL, NULL));
11499566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
1150bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
115147c6ae99SBarry Smith     ratioi = mx / Mx;
115263a3b9bcSJacob Faibussowitsch     PetscCheck(ratioi * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx  must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
115347c6ae99SBarry Smith   } else {
115447c6ae99SBarry Smith     ratioi = (mx - 1) / (Mx - 1);
11551dca8a05SBarry Smith     PetscCheck(ratioi * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
115647c6ae99SBarry Smith   }
1157bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
115847c6ae99SBarry Smith     ratioj = my / My;
115963a3b9bcSJacob Faibussowitsch     PetscCheck(ratioj * My == my, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: my/My  must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
116047c6ae99SBarry Smith   } else {
116147c6ae99SBarry Smith     ratioj = (my - 1) / (My - 1);
11621dca8a05SBarry Smith     PetscCheck(ratioj * (My - 1) == my - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (my - 1)/(My - 1) must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
116347c6ae99SBarry Smith   }
116447c6ae99SBarry Smith 
11659566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf, &i_start, &j_start, NULL, &m_f, &n_f, NULL));
11669566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, NULL, &m_ghost, &n_ghost, NULL));
11679566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf, &ltog_f));
11689566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
116947c6ae99SBarry Smith 
11709566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, NULL, &m_c, &n_c, NULL));
11719566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, NULL, &m_ghost_c, &n_ghost_c, NULL));
11729566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac, &ltog_c));
11739566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
117447c6ae99SBarry Smith 
117547c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
117647c6ae99SBarry Smith   nc = 0;
11779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_f * m_f, &cols));
1178076202ddSJed Brown   for (j = j_start_c; j < j_start_c + n_c; j++) {
1179076202ddSJed Brown     for (i = i_start_c; i < i_start_c + m_c; i++) {
1180076202ddSJed Brown       PetscInt i_f = i * ratioi, j_f = j * ratioj;
11811dca8a05SBarry Smith       PetscCheck(j_f >= j_start_ghost && j_f < j_start_ghost + n_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
11829371c9d4SSatish Balay     j_c %" PetscInt_FMT " j_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]",
11839371c9d4SSatish Balay                  j, j_f, j_start_ghost, j_start_ghost + n_ghost);
11841dca8a05SBarry Smith       PetscCheck(i_f >= i_start_ghost && i_f < i_start_ghost + m_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA\n\
11859371c9d4SSatish Balay     i_c %" PetscInt_FMT " i_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]",
11869371c9d4SSatish Balay                  i, i_f, i_start_ghost, i_start_ghost + m_ghost);
1187e3fbd1f4SBarry Smith       row        = idx_f[(m_ghost * (j_f - j_start_ghost) + (i_f - i_start_ghost))];
1188e3fbd1f4SBarry Smith       cols[nc++] = row;
118947c6ae99SBarry Smith     }
119047c6ae99SBarry Smith   }
11919566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
11929566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
119347c6ae99SBarry Smith 
11949566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)daf), dof, nc, cols, PETSC_OWN_POINTER, &isf));
11959566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dac, &vecc));
11969566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(daf, &vecf));
11979566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(vecf, isf, vecc, NULL, inject));
11989566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dac, &vecc));
11999566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(daf, &vecf));
12009566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isf));
12013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
120247c6ae99SBarry Smith }
120347c6ae99SBarry Smith 
120466976f2fSJacob Faibussowitsch static PetscErrorCode DMCreateInjection_DA_3D(DM dac, DM daf, VecScatter *inject)
1205d71ae5a4SJacob Faibussowitsch {
1206b1757049SJed Brown   PetscInt               i, j, k, i_start, j_start, k_start, m_f, n_f, p_f, Mx, My, Mz;
1207b1757049SJed Brown   PetscInt               m_ghost, n_ghost, p_ghost, m_ghost_c, n_ghost_c, p_ghost_c;
1208b1757049SJed Brown   PetscInt               i_start_ghost, j_start_ghost, k_start_ghost;
1209b1757049SJed Brown   PetscInt               mx, my, mz, ratioi, ratioj, ratiok;
1210b1757049SJed Brown   PetscInt               i_start_c, j_start_c, k_start_c;
1211b1757049SJed Brown   PetscInt               m_c, n_c, p_c;
1212b1757049SJed Brown   PetscInt               i_start_ghost_c, j_start_ghost_c, k_start_ghost_c;
1213b1757049SJed Brown   PetscInt               row, nc, dof;
12148ea3bf28SBarry Smith   const PetscInt        *idx_c, *idx_f;
1215e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f, ltog_c;
1216b1757049SJed Brown   PetscInt              *cols;
1217bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx, by, bz;
1218b1757049SJed Brown   Vec                    vecf, vecc;
1219b1757049SJed Brown   IS                     isf;
1220b1757049SJed Brown 
1221b1757049SJed Brown   PetscFunctionBegin;
12229566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, &Mz, NULL, NULL, NULL, NULL, NULL, &bx, &by, &bz, NULL));
12239566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, &mz, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
1224b1757049SJed Brown 
1225bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
1226b1757049SJed Brown     ratioi = mx / Mx;
122763a3b9bcSJacob Faibussowitsch     PetscCheck(ratioi * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx  must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
1228b1757049SJed Brown   } else {
1229b1757049SJed Brown     ratioi = (mx - 1) / (Mx - 1);
12301dca8a05SBarry Smith     PetscCheck(ratioi * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
1231b1757049SJed Brown   }
1232bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
1233b1757049SJed Brown     ratioj = my / My;
123463a3b9bcSJacob Faibussowitsch     PetscCheck(ratioj * My == my, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: my/My  must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
1235b1757049SJed Brown   } else {
1236b1757049SJed Brown     ratioj = (my - 1) / (My - 1);
12371dca8a05SBarry Smith     PetscCheck(ratioj * (My - 1) == my - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (my - 1)/(My - 1) must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
1238b1757049SJed Brown   }
1239bff4a2f0SMatthew G. Knepley   if (bz == DM_BOUNDARY_PERIODIC) {
1240b1757049SJed Brown     ratiok = mz / Mz;
124163a3b9bcSJacob Faibussowitsch     PetscCheck(ratiok * Mz == mz, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mz/Mz  must be integer: mz %" PetscInt_FMT " My %" PetscInt_FMT, mz, Mz);
1242b1757049SJed Brown   } else {
1243b1757049SJed Brown     ratiok = (mz - 1) / (Mz - 1);
12441dca8a05SBarry Smith     PetscCheck(ratiok * (Mz - 1) == mz - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %" PetscInt_FMT " Mz %" PetscInt_FMT, mz, Mz);
1245b1757049SJed Brown   }
1246b1757049SJed Brown 
12479566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf, &i_start, &j_start, &k_start, &m_f, &n_f, &p_f));
12489566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, &k_start_ghost, &m_ghost, &n_ghost, &p_ghost));
12499566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf, &ltog_f));
12509566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
1251b1757049SJed Brown 
12529566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, &k_start_c, &m_c, &n_c, &p_c));
12539566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, &k_start_ghost_c, &m_ghost_c, &n_ghost_c, &p_ghost_c));
12549566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac, &ltog_c));
12559566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
1256b1757049SJed Brown 
1257b1757049SJed Brown   /* loop over local fine grid nodes setting interpolation for those*/
1258b1757049SJed Brown   nc = 0;
12599566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_f * m_f * p_f, &cols));
1260b1757049SJed Brown   for (k = k_start_c; k < k_start_c + p_c; k++) {
1261b1757049SJed Brown     for (j = j_start_c; j < j_start_c + n_c; j++) {
1262b1757049SJed Brown       for (i = i_start_c; i < i_start_c + m_c; i++) {
1263b1757049SJed Brown         PetscInt i_f = i * ratioi, j_f = j * ratioj, k_f = k * ratiok;
12649371c9d4SSatish Balay         PetscCheck(k_f >= k_start_ghost && k_f < k_start_ghost + p_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP,
12659371c9d4SSatish Balay                    "Processor's coarse DMDA must lie over fine DMDA  "
12669371c9d4SSatish Balay                    "k_c %" PetscInt_FMT " k_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]",
12679371c9d4SSatish Balay                    k, k_f, k_start_ghost, k_start_ghost + p_ghost);
12689371c9d4SSatish Balay         PetscCheck(j_f >= j_start_ghost && j_f < j_start_ghost + n_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP,
12699371c9d4SSatish Balay                    "Processor's coarse DMDA must lie over fine DMDA  "
12709371c9d4SSatish Balay                    "j_c %" PetscInt_FMT " j_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]",
12719371c9d4SSatish Balay                    j, j_f, j_start_ghost, j_start_ghost + n_ghost);
12729371c9d4SSatish Balay         PetscCheck(i_f >= i_start_ghost && i_f < i_start_ghost + m_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP,
12739371c9d4SSatish Balay                    "Processor's coarse DMDA must lie over fine DMDA  "
12749371c9d4SSatish Balay                    "i_c %" PetscInt_FMT " i_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]",
12759371c9d4SSatish Balay                    i, i_f, i_start_ghost, i_start_ghost + m_ghost);
1276e3fbd1f4SBarry Smith         row        = idx_f[(m_ghost * n_ghost * (k_f - k_start_ghost) + m_ghost * (j_f - j_start_ghost) + (i_f - i_start_ghost))];
1277e3fbd1f4SBarry Smith         cols[nc++] = row;
1278b1757049SJed Brown       }
1279b1757049SJed Brown     }
1280b1757049SJed Brown   }
12819566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
12829566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
1283b1757049SJed Brown 
12849566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)daf), dof, nc, cols, PETSC_OWN_POINTER, &isf));
12859566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dac, &vecc));
12869566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(daf, &vecf));
12879566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(vecf, isf, vecc, NULL, inject));
12889566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dac, &vecc));
12899566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(daf, &vecf));
12909566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isf));
12913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1292b1757049SJed Brown }
1293b1757049SJed Brown 
1294d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateInjection_DA(DM dac, DM daf, Mat *mat)
1295d71ae5a4SJacob Faibussowitsch {
129647c6ae99SBarry Smith   PetscInt        dimc, Mc, Nc, Pc, mc, nc, pc, dofc, sc, dimf, Mf, Nf, Pf, mf, nf, pf, doff, sf;
1297bff4a2f0SMatthew G. Knepley   DMBoundaryType  bxc, byc, bzc, bxf, byf, bzf;
1298aa219208SBarry Smith   DMDAStencilType stc, stf;
129960c16ac1SBarry Smith   VecScatter      inject = NULL;
130047c6ae99SBarry Smith 
130147c6ae99SBarry Smith   PetscFunctionBegin;
130247c6ae99SBarry Smith   PetscValidHeaderSpecific(dac, DM_CLASSID, 1);
130347c6ae99SBarry Smith   PetscValidHeaderSpecific(daf, DM_CLASSID, 2);
13044f572ea9SToby Isaac   PetscAssertPointer(mat, 3);
130547c6ae99SBarry Smith 
13069566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, &dimc, &Mc, &Nc, &Pc, &mc, &nc, &pc, &dofc, &sc, &bxc, &byc, &bzc, &stc));
13079566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, &dimf, &Mf, &Nf, &Pf, &mf, &nf, &pf, &doff, &sf, &bxf, &byf, &bzf, &stf));
130863a3b9bcSJacob Faibussowitsch   PetscCheck(dimc == dimf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Dimensions of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dimc, dimf);
130963a3b9bcSJacob Faibussowitsch   PetscCheck(dofc == doff, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "DOF of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dofc, doff);
131063a3b9bcSJacob Faibussowitsch   PetscCheck(sc == sf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil width of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, sc, sf);
13111dca8a05SBarry Smith   PetscCheck(bxc == bxf && byc == byf && bzc == bzf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Boundary type different in two DMDAs");
131208401ef6SPierre Jolivet   PetscCheck(stc == stf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil type different in two DMDAs");
131308401ef6SPierre Jolivet   PetscCheck(Mc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in x direction");
13141dca8a05SBarry Smith   PetscCheck(dimc <= 1 || Nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in y direction");
13151dca8a05SBarry Smith   PetscCheck(dimc <= 2 || Pc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in z direction");
131647c6ae99SBarry Smith 
13170bb2b966SJungho Lee   if (dimc == 1) {
13189566063dSJacob Faibussowitsch     PetscCall(DMCreateInjection_DA_1D(dac, daf, &inject));
13190bb2b966SJungho Lee   } else if (dimc == 2) {
13209566063dSJacob Faibussowitsch     PetscCall(DMCreateInjection_DA_2D(dac, daf, &inject));
1321b1757049SJed Brown   } else if (dimc == 3) {
13229566063dSJacob Faibussowitsch     PetscCall(DMCreateInjection_DA_3D(dac, daf, &inject));
132347c6ae99SBarry Smith   }
13249566063dSJacob Faibussowitsch   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)inject), inject, mat));
13259566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&inject));
13263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
132747c6ae99SBarry Smith }
132847c6ae99SBarry Smith 
1329a4e35b19SJacob Faibussowitsch // PetscClangLinter pragma ignore: -fdoc-*
133097779f9aSLisandro Dalcin /*@
133197779f9aSLisandro Dalcin   DMCreateAggregates - Deprecated, see DMDACreateAggregates.
13326c877ef6SSatish Balay 
13336c877ef6SSatish Balay   Level: intermediate
133497779f9aSLisandro Dalcin @*/
1335d71ae5a4SJacob Faibussowitsch PetscErrorCode DMCreateAggregates(DM dac, DM daf, Mat *mat)
1336d71ae5a4SJacob Faibussowitsch {
1337a5bc1bf3SBarry Smith   return DMDACreateAggregates(dac, daf, mat);
133897779f9aSLisandro Dalcin }
133997779f9aSLisandro Dalcin 
134097779f9aSLisandro Dalcin /*@
134197779f9aSLisandro Dalcin   DMDACreateAggregates - Gets the aggregates that map between
1342dce8aebaSBarry Smith   grids associated with two `DMDA`
134397779f9aSLisandro Dalcin 
134420f4b53cSBarry Smith   Collective
134597779f9aSLisandro Dalcin 
134697779f9aSLisandro Dalcin   Input Parameters:
134760225df5SJacob Faibussowitsch + dac - the coarse grid `DMDA`
134860225df5SJacob Faibussowitsch - daf - the fine grid `DMDA`
134997779f9aSLisandro Dalcin 
13502fe279fdSBarry Smith   Output Parameter:
135197779f9aSLisandro Dalcin . rest - the restriction matrix (transpose of the projection matrix)
135297779f9aSLisandro Dalcin 
135397779f9aSLisandro Dalcin   Level: intermediate
135497779f9aSLisandro Dalcin 
1355dce8aebaSBarry Smith   Note:
1356dce8aebaSBarry Smith   This routine is not used by PETSc.
135797779f9aSLisandro Dalcin   It is not clear what its use case is and it may be removed in a future release.
135897779f9aSLisandro Dalcin   Users should contact petsc-maint@mcs.anl.gov if they plan to use it.
135997779f9aSLisandro Dalcin 
1360*12b4a537SBarry Smith .seealso: [](sec_struct), `DMRefine()`, `DMCreateInjection()`, `DMCreateInterpolation()`
136197779f9aSLisandro Dalcin @*/
1362d71ae5a4SJacob Faibussowitsch PetscErrorCode DMDACreateAggregates(DM dac, DM daf, Mat *rest)
1363d71ae5a4SJacob Faibussowitsch {
136447c6ae99SBarry Smith   PetscInt               dimc, Mc, Nc, Pc, mc, nc, pc, dofc, sc;
136547c6ae99SBarry Smith   PetscInt               dimf, Mf, Nf, Pf, mf, nf, pf, doff, sf;
1366bff4a2f0SMatthew G. Knepley   DMBoundaryType         bxc, byc, bzc, bxf, byf, bzf;
1367aa219208SBarry Smith   DMDAStencilType        stc, stf;
136847c6ae99SBarry Smith   PetscInt               i, j, l;
136947c6ae99SBarry Smith   PetscInt               i_start, j_start, l_start, m_f, n_f, p_f;
137047c6ae99SBarry Smith   PetscInt               i_start_ghost, j_start_ghost, l_start_ghost, m_ghost, n_ghost, p_ghost;
13718ea3bf28SBarry Smith   const PetscInt        *idx_f;
137247c6ae99SBarry Smith   PetscInt               i_c, j_c, l_c;
137347c6ae99SBarry Smith   PetscInt               i_start_c, j_start_c, l_start_c, m_c, n_c, p_c;
137447c6ae99SBarry Smith   PetscInt               i_start_ghost_c, j_start_ghost_c, l_start_ghost_c, m_ghost_c, n_ghost_c, p_ghost_c;
13758ea3bf28SBarry Smith   const PetscInt        *idx_c;
137647c6ae99SBarry Smith   PetscInt               d;
137747c6ae99SBarry Smith   PetscInt               a;
137847c6ae99SBarry Smith   PetscInt               max_agg_size;
137947c6ae99SBarry Smith   PetscInt              *fine_nodes;
138047c6ae99SBarry Smith   PetscScalar           *one_vec;
138147c6ae99SBarry Smith   PetscInt               fn_idx;
1382565245c5SBarry Smith   ISLocalToGlobalMapping ltogmf, ltogmc;
138347c6ae99SBarry Smith 
138447c6ae99SBarry Smith   PetscFunctionBegin;
138597779f9aSLisandro Dalcin   PetscValidHeaderSpecificType(dac, DM_CLASSID, 1, DMDA);
138697779f9aSLisandro Dalcin   PetscValidHeaderSpecificType(daf, DM_CLASSID, 2, DMDA);
13874f572ea9SToby Isaac   PetscAssertPointer(rest, 3);
138847c6ae99SBarry Smith 
13899566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac, &dimc, &Mc, &Nc, &Pc, &mc, &nc, &pc, &dofc, &sc, &bxc, &byc, &bzc, &stc));
13909566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf, &dimf, &Mf, &Nf, &Pf, &mf, &nf, &pf, &doff, &sf, &bxf, &byf, &bzf, &stf));
139163a3b9bcSJacob Faibussowitsch   PetscCheck(dimc == dimf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Dimensions of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dimc, dimf);
139263a3b9bcSJacob Faibussowitsch   PetscCheck(dofc == doff, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "DOF of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dofc, doff);
139363a3b9bcSJacob Faibussowitsch   PetscCheck(sc == sf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil width of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, sc, sf);
13941dca8a05SBarry Smith   PetscCheck(bxc == bxf && byc == byf && bzc == bzf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Boundary type different in two DMDAs");
139508401ef6SPierre Jolivet   PetscCheck(stc == stf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil type different in two DMDAs");
139647c6ae99SBarry Smith 
139763a3b9bcSJacob Faibussowitsch   PetscCheck(Mf >= Mc, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Coarse grid has more points than fine grid, Mc %" PetscInt_FMT ", Mf %" PetscInt_FMT, Mc, Mf);
139863a3b9bcSJacob Faibussowitsch   PetscCheck(Nf >= Nc, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Coarse grid has more points than fine grid, Nc %" PetscInt_FMT ", Nf %" PetscInt_FMT, Nc, Nf);
139963a3b9bcSJacob Faibussowitsch   PetscCheck(Pf >= Pc, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Coarse grid has more points than fine grid, Pc %" PetscInt_FMT ", Pf %" PetscInt_FMT, Pc, Pf);
140047c6ae99SBarry Smith 
140147c6ae99SBarry Smith   if (Pc < 0) Pc = 1;
140247c6ae99SBarry Smith   if (Pf < 0) Pf = 1;
140347c6ae99SBarry Smith   if (Nc < 0) Nc = 1;
140447c6ae99SBarry Smith   if (Nf < 0) Nf = 1;
140547c6ae99SBarry Smith 
14069566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf, &i_start, &j_start, &l_start, &m_f, &n_f, &p_f));
14079566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, &l_start_ghost, &m_ghost, &n_ghost, &p_ghost));
1408565245c5SBarry Smith 
14099566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf, &ltogmf));
14109566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(ltogmf, &idx_f));
141147c6ae99SBarry Smith 
14129566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, &l_start_c, &m_c, &n_c, &p_c));
14139566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, &l_start_ghost_c, &m_ghost_c, &n_ghost_c, &p_ghost_c));
1414565245c5SBarry Smith 
14159566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac, &ltogmc));
14169566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(ltogmc, &idx_c));
141747c6ae99SBarry Smith 
141847c6ae99SBarry Smith   /*
141947c6ae99SBarry Smith      Basic idea is as follows. Here's a 2D example, suppose r_x, r_y are the ratios
142047c6ae99SBarry Smith      for dimension 1 and 2 respectively.
142147c6ae99SBarry Smith      Let (i,j) be a coarse grid node. All the fine grid nodes between r_x*i and r_x*(i+1)
1422da81f932SPierre Jolivet      and r_y*j and r_y*(j+1) will be grouped into the same coarse grid aggregate.
142347c6ae99SBarry Smith      Each specific dof on the fine grid is mapped to one dof on the coarse grid.
142447c6ae99SBarry Smith   */
142547c6ae99SBarry Smith 
142647c6ae99SBarry Smith   max_agg_size = (Mf / Mc + 1) * (Nf / Nc + 1) * (Pf / Pc + 1);
142747c6ae99SBarry Smith 
142847c6ae99SBarry Smith   /* create the matrix that will contain the restriction operator */
14299371c9d4SSatish Balay   PetscCall(MatCreateAIJ(PetscObjectComm((PetscObject)daf), m_c * n_c * p_c * dofc, m_f * n_f * p_f * doff, Mc * Nc * Pc * dofc, Mf * Nf * Pf * doff, max_agg_size, NULL, max_agg_size, NULL, rest));
143047c6ae99SBarry Smith 
143147c6ae99SBarry Smith   /* store nodes in the fine grid here */
14329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(max_agg_size, &one_vec, max_agg_size, &fine_nodes));
143347c6ae99SBarry Smith   for (i = 0; i < max_agg_size; i++) one_vec[i] = 1.0;
143447c6ae99SBarry Smith 
143547c6ae99SBarry Smith   /* loop over all coarse nodes */
143647c6ae99SBarry Smith   for (l_c = l_start_c; l_c < l_start_c + p_c; l_c++) {
143747c6ae99SBarry Smith     for (j_c = j_start_c; j_c < j_start_c + n_c; j_c++) {
143847c6ae99SBarry Smith       for (i_c = i_start_c; i_c < i_start_c + m_c; i_c++) {
143947c6ae99SBarry Smith         for (d = 0; d < dofc; d++) {
144047c6ae99SBarry Smith           /* convert to local "natural" numbering and then to PETSc global numbering */
144147c6ae99SBarry Smith           a = idx_c[dofc * (m_ghost_c * n_ghost_c * (l_c - l_start_ghost_c) + m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c))] + d;
144247c6ae99SBarry Smith 
144347c6ae99SBarry Smith           fn_idx = 0;
144447c6ae99SBarry Smith           /* Corresponding fine points are all points (i_f, j_f, l_f) such that
144547c6ae99SBarry Smith              i_c*Mf/Mc <= i_f < (i_c+1)*Mf/Mc
144647c6ae99SBarry Smith              (same for other dimensions)
144747c6ae99SBarry Smith           */
144847c6ae99SBarry Smith           for (l = l_c * Pf / Pc; l < PetscMin((l_c + 1) * Pf / Pc, Pf); l++) {
144947c6ae99SBarry Smith             for (j = j_c * Nf / Nc; j < PetscMin((j_c + 1) * Nf / Nc, Nf); j++) {
145047c6ae99SBarry Smith               for (i = i_c * Mf / Mc; i < PetscMin((i_c + 1) * Mf / Mc, Mf); i++) {
145147c6ae99SBarry Smith                 fine_nodes[fn_idx] = idx_f[doff * (m_ghost * n_ghost * (l - l_start_ghost) + m_ghost * (j - j_start_ghost) + (i - i_start_ghost))] + d;
145247c6ae99SBarry Smith                 fn_idx++;
145347c6ae99SBarry Smith               }
145447c6ae99SBarry Smith             }
145547c6ae99SBarry Smith           }
145647c6ae99SBarry Smith           /* add all these points to one aggregate */
14579566063dSJacob Faibussowitsch           PetscCall(MatSetValues(*rest, 1, &a, fn_idx, fine_nodes, one_vec, INSERT_VALUES));
145847c6ae99SBarry Smith         }
145947c6ae99SBarry Smith       }
146047c6ae99SBarry Smith     }
146147c6ae99SBarry Smith   }
14629566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogmf, &idx_f));
14639566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogmc, &idx_c));
14649566063dSJacob Faibussowitsch   PetscCall(PetscFree2(one_vec, fine_nodes));
14659566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*rest, MAT_FINAL_ASSEMBLY));
14669566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*rest, MAT_FINAL_ASSEMBLY));
14673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
146847c6ae99SBarry Smith }
1469