xref: /petsc/src/dm/impls/da/dainterp.c (revision 08401ef684002a709c6d3db98a0c9f54a8bcf1ec)
147c6ae99SBarry Smith 
247c6ae99SBarry Smith /*
3aa219208SBarry Smith   Code for interpolating between grids represented by DMDAs
447c6ae99SBarry Smith */
547c6ae99SBarry Smith 
6d52bd9f3SBarry Smith /*
7d52bd9f3SBarry 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
8d52bd9f3SBarry 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
92adb9dcfSBarry 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
102adb9dcfSBarry Smith    consider it cleaner, but old version is turned on since it handles periodic case.
11d52bd9f3SBarry Smith */
129314d695SBarry Smith #define NEWVERSION 0
1385afcc9aSBarry Smith 
14af0996ceSBarry Smith #include <petsc/private/dmdaimpl.h>    /*I   "petscdmda.h"   I*/
1547c6ae99SBarry Smith 
16fdc842d1SBarry Smith /*
17fdc842d1SBarry Smith    Since the interpolation uses MATMAIJ for dof > 0 we convert request for non-MATAIJ baseded matrices to MATAIJ.
18fdc842d1SBarry Smith    This is a bit of a hack, the reason for it is partially because -dm_mat_type defines the
19fdc842d1SBarry Smith    matrix type for both the operator matrices and the interpolation matrices so that users
20fdc842d1SBarry Smith    can select matrix types of base MATAIJ for accelerators
21fdc842d1SBarry Smith */
22fdc842d1SBarry Smith static PetscErrorCode ConvertToAIJ(MatType intype,MatType *outtype)
23fdc842d1SBarry Smith {
24fdc842d1SBarry Smith   PetscInt       i;
25fdc842d1SBarry Smith   char           const *types[3] = {MATAIJ,MATSEQAIJ,MATMPIAIJ};
26fdc842d1SBarry Smith   PetscBool      flg;
27fdc842d1SBarry Smith 
28fdc842d1SBarry Smith   PetscFunctionBegin;
2933a4d587SStefano Zampini   *outtype = MATAIJ;
30fdc842d1SBarry Smith   for (i=0; i<3; i++) {
319566063dSJacob Faibussowitsch     PetscCall(PetscStrbeginswith(intype,types[i],&flg));
32fdc842d1SBarry Smith     if (flg) {
33fdc842d1SBarry Smith       *outtype = intype;
34fdc842d1SBarry Smith       PetscFunctionReturn(0);
35fdc842d1SBarry Smith     }
36fdc842d1SBarry Smith   }
37fdc842d1SBarry Smith   PetscFunctionReturn(0);
38fdc842d1SBarry Smith }
39fdc842d1SBarry Smith 
40e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_1D_Q1(DM dac,DM daf,Mat *A)
4147c6ae99SBarry Smith {
428ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx;
438ea3bf28SBarry Smith   const PetscInt         *idx_f,*idx_c;
448ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
4547c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,mx,m_c,nc,ratio;
4647c6ae99SBarry Smith   PetscInt               i_c,i_start_c,i_start_ghost_c,cols[2],dof;
4785afcc9aSBarry Smith   PetscScalar            v[2],x;
4847c6ae99SBarry Smith   Mat                    mat;
49bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
50e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
51fdc842d1SBarry Smith   MatType                mattype;
5247c6ae99SBarry Smith 
5347c6ae99SBarry Smith   PetscFunctionBegin;
549566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,NULL,&Mx,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&bx,NULL,NULL,NULL));
559566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,NULL,&mx,NULL,NULL,NULL,NULL,NULL,&dof,NULL,NULL,NULL,NULL,NULL));
56bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
5747c6ae99SBarry Smith     ratio = mx/Mx;
58*08401ef6SPierre Jolivet     PetscCheck(ratio*Mx == mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
5947c6ae99SBarry Smith   } else {
6047c6ae99SBarry Smith     ratio = (mx-1)/(Mx-1);
612c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratio*(Mx-1) != mx-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
6247c6ae99SBarry Smith   }
6347c6ae99SBarry Smith 
649566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf,&i_start,NULL,NULL,&m_f,NULL,NULL));
659566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf,&i_start_ghost,NULL,NULL,&m_ghost,NULL,NULL));
669566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf,&ltog_f));
679566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f));
6847c6ae99SBarry Smith 
699566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac,&i_start_c,NULL,NULL,&m_c,NULL,NULL));
709566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac,&i_start_ghost_c,NULL,NULL,&m_ghost_c,NULL,NULL));
719566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac,&ltog_c));
729566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c));
7347c6ae99SBarry Smith 
7447c6ae99SBarry Smith   /* create interpolation matrix */
759566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dac),&mat));
76fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
77fdc842d1SBarry Smith   /*
78fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
79fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
80fdc842d1SBarry Smith    */
81fdc842d1SBarry Smith   if (dof > 1) {
829566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(mat,PETSC_TRUE));
83fdc842d1SBarry Smith   }
84fdc842d1SBarry Smith   #endif
859566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat,m_f,m_c,mx,Mx));
869566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype,&mattype));
879566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat,mattype));
889566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat,2,NULL));
899566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat,2,NULL,1,NULL));
9047c6ae99SBarry Smith 
9147c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
9285afcc9aSBarry Smith   if (!NEWVERSION) {
93b3bd94feSDave May 
9447c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
9547c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
96e3fbd1f4SBarry Smith       row = idx_f[i-i_start_ghost];
9747c6ae99SBarry Smith 
9847c6ae99SBarry Smith       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
99*08401ef6SPierre 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\
10047c6ae99SBarry Smith                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
10147c6ae99SBarry Smith 
10247c6ae99SBarry Smith       /*
10347c6ae99SBarry Smith        Only include those interpolation points that are truly
10447c6ae99SBarry Smith        nonzero. Note this is very important for final grid lines
10547c6ae99SBarry Smith        in x direction; since they have no right neighbor
10647c6ae99SBarry Smith        */
1076712e2f1SBarry Smith       x  = ((PetscReal)(i - i_c*ratio))/((PetscReal)ratio);
10847c6ae99SBarry Smith       nc = 0;
10947c6ae99SBarry Smith       /* one left and below; or we are right on it */
110e3fbd1f4SBarry Smith       col      = (i_c-i_start_ghost_c);
111e3fbd1f4SBarry Smith       cols[nc] = idx_c[col];
11247c6ae99SBarry Smith       v[nc++]  = -x + 1.0;
11347c6ae99SBarry Smith       /* one right? */
11447c6ae99SBarry Smith       if (i_c*ratio != i) {
115e3fbd1f4SBarry Smith         cols[nc] = idx_c[col+1];
11647c6ae99SBarry Smith         v[nc++]  = x;
11747c6ae99SBarry Smith       }
1189566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES));
11947c6ae99SBarry Smith     }
120b3bd94feSDave May 
121b3bd94feSDave May   } else {
122b3bd94feSDave May     PetscScalar *xi;
123b3bd94feSDave May     PetscInt    li,nxi,n;
124b3bd94feSDave May     PetscScalar Ni[2];
125b3bd94feSDave May 
126b3bd94feSDave May     /* compute local coordinate arrays */
127b3bd94feSDave May     nxi  = ratio + 1;
1289566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nxi,&xi));
129b3bd94feSDave May     for (li=0; li<nxi; li++) {
13052218ef2SJed Brown       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
131b3bd94feSDave May     }
132b3bd94feSDave May 
133b3bd94feSDave May     for (i=i_start; i<i_start+m_f; i++) {
134b3bd94feSDave May       /* convert to local "natural" numbering and then to PETSc global numbering */
135e3fbd1f4SBarry Smith       row = idx_f[(i-i_start_ghost)];
136b3bd94feSDave May 
137b3bd94feSDave May       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
138*08401ef6SPierre 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\
139b3bd94feSDave May                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
140b3bd94feSDave May 
141b3bd94feSDave May       /* remainders */
142b3bd94feSDave May       li = i - ratio * (i/ratio);
1438865f1eaSKarl Rupp       if (i==mx-1) li = nxi-1;
144b3bd94feSDave May 
145b3bd94feSDave May       /* corners */
146e3fbd1f4SBarry Smith       col     = (i_c-i_start_ghost_c);
147e3fbd1f4SBarry Smith       cols[0] = idx_c[col];
148b3bd94feSDave May       Ni[0]   = 1.0;
149b3bd94feSDave May       if ((li==0) || (li==nxi-1)) {
1509566063dSJacob Faibussowitsch         PetscCall(MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES));
151b3bd94feSDave May         continue;
152b3bd94feSDave May       }
153b3bd94feSDave May 
154b3bd94feSDave May       /* edges + interior */
155b3bd94feSDave May       /* remainders */
1568865f1eaSKarl Rupp       if (i==mx-1) i_c--;
157b3bd94feSDave May 
158e3fbd1f4SBarry Smith       col     = (i_c-i_start_ghost_c);
159e3fbd1f4SBarry Smith       cols[0] = idx_c[col]; /* one left and below; or we are right on it */
160e3fbd1f4SBarry Smith       cols[1] = idx_c[col+1];
161b3bd94feSDave May 
162b3bd94feSDave May       Ni[0] = 0.5*(1.0-xi[li]);
163b3bd94feSDave May       Ni[1] = 0.5*(1.0+xi[li]);
164b3bd94feSDave May       for (n=0; n<2; n++) {
1658865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[n])<1.0e-32) cols[n]=-1;
166b3bd94feSDave May       }
1679566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat,1,&row,2,cols,Ni,INSERT_VALUES));
168b3bd94feSDave May     }
1699566063dSJacob Faibussowitsch     PetscCall(PetscFree(xi));
170b3bd94feSDave May   }
1719566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f));
1729566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c));
1739566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
1749566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
1759566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat,dof,A));
1769566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
17747c6ae99SBarry Smith   PetscFunctionReturn(0);
17847c6ae99SBarry Smith }
17947c6ae99SBarry Smith 
180e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_1D_Q0(DM dac,DM daf,Mat *A)
18147c6ae99SBarry Smith {
1828ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx;
1838ea3bf28SBarry Smith   const PetscInt         *idx_f,*idx_c;
184e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
1858ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
18647c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,mx,m_c,nc,ratio;
18747c6ae99SBarry Smith   PetscInt               i_c,i_start_c,i_start_ghost_c,cols[2],dof;
18847c6ae99SBarry Smith   PetscScalar            v[2],x;
18947c6ae99SBarry Smith   Mat                    mat;
190bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
191fdc842d1SBarry Smith   MatType                mattype;
19247c6ae99SBarry Smith 
19347c6ae99SBarry Smith   PetscFunctionBegin;
1949566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,NULL,&Mx,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&bx,NULL,NULL,NULL));
1959566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,NULL,&mx,NULL,NULL,NULL,NULL,NULL,&dof,NULL,NULL,NULL,NULL,NULL));
196bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
1977a8be351SBarry Smith     PetscCheck(Mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
19847c6ae99SBarry Smith     ratio = mx/Mx;
199*08401ef6SPierre Jolivet     PetscCheck(ratio*Mx == mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
20047c6ae99SBarry Smith   } else {
201*08401ef6SPierre Jolivet     PetscCheck(Mx >= 2,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be greater than 1",Mx);
20247c6ae99SBarry Smith     ratio = (mx-1)/(Mx-1);
2032c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratio*(Mx-1) != mx-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
20447c6ae99SBarry Smith   }
20547c6ae99SBarry Smith 
2069566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf,&i_start,NULL,NULL,&m_f,NULL,NULL));
2079566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf,&i_start_ghost,NULL,NULL,&m_ghost,NULL,NULL));
2089566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf,&ltog_f));
2099566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f));
21047c6ae99SBarry Smith 
2119566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac,&i_start_c,NULL,NULL,&m_c,NULL,NULL));
2129566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac,&i_start_ghost_c,NULL,NULL,&m_ghost_c,NULL,NULL));
2139566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac,&ltog_c));
2149566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c));
21547c6ae99SBarry Smith 
21647c6ae99SBarry Smith   /* create interpolation matrix */
2179566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dac),&mat));
218fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
219fdc842d1SBarry Smith   /*
220fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
221fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
222fdc842d1SBarry Smith    */
223fdc842d1SBarry Smith   if (dof > 1) {
2249566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(mat,PETSC_TRUE));
225fdc842d1SBarry Smith   }
226fdc842d1SBarry Smith   #endif
2279566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat,m_f,m_c,mx,Mx));
2289566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype,&mattype));
2299566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat,mattype));
2309566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat,2,NULL));
2319566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat,2,NULL,0,NULL));
23247c6ae99SBarry Smith 
23347c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
23447c6ae99SBarry Smith   for (i=i_start; i<i_start+m_f; i++) {
23547c6ae99SBarry Smith     /* convert to local "natural" numbering and then to PETSc global numbering */
236e3fbd1f4SBarry Smith     row = idx_f[(i-i_start_ghost)];
23747c6ae99SBarry Smith 
23847c6ae99SBarry Smith     i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
23947c6ae99SBarry Smith 
24047c6ae99SBarry Smith     /*
24147c6ae99SBarry Smith          Only include those interpolation points that are truly
24247c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
24347c6ae99SBarry Smith          in x direction; since they have no right neighbor
24447c6ae99SBarry Smith     */
2456712e2f1SBarry Smith     x  = ((PetscReal)(i - i_c*ratio))/((PetscReal)ratio);
24647c6ae99SBarry Smith     nc = 0;
24747c6ae99SBarry Smith     /* one left and below; or we are right on it */
248e3fbd1f4SBarry Smith     col      = (i_c-i_start_ghost_c);
249e3fbd1f4SBarry Smith     cols[nc] = idx_c[col];
25047c6ae99SBarry Smith     v[nc++]  = -x + 1.0;
25147c6ae99SBarry Smith     /* one right? */
25247c6ae99SBarry Smith     if (i_c*ratio != i) {
253e3fbd1f4SBarry Smith       cols[nc] = idx_c[col+1];
25447c6ae99SBarry Smith       v[nc++]  = x;
25547c6ae99SBarry Smith     }
2569566063dSJacob Faibussowitsch     PetscCall(MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES));
25747c6ae99SBarry Smith   }
2589566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f));
2599566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c));
2609566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
2619566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
2629566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat,dof,A));
2639566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
2649566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(5.0*m_f));
26547c6ae99SBarry Smith   PetscFunctionReturn(0);
26647c6ae99SBarry Smith }
26747c6ae99SBarry Smith 
268e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_2D_Q1(DM dac,DM daf,Mat *A)
26947c6ae99SBarry Smith {
27047c6ae99SBarry Smith   PetscErrorCode         ierr;
2718ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
2728ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
273e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
2748ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,*dnz,*onz;
27547c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
27647c6ae99SBarry 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;
27747c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
27847c6ae99SBarry Smith   PetscScalar            v[4],x,y;
27947c6ae99SBarry Smith   Mat                    mat;
280bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
281fdc842d1SBarry Smith   MatType                mattype;
28247c6ae99SBarry Smith 
28347c6ae99SBarry Smith   PetscFunctionBegin;
2849566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,NULL,&Mx,&My,NULL,NULL,NULL,NULL,NULL,NULL,&bx,&by,NULL,NULL));
2859566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,NULL,&mx,&my,NULL,NULL,NULL,NULL,&dof,NULL,NULL,NULL,NULL,NULL));
286bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
2877a8be351SBarry Smith     PetscCheck(Mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
28847c6ae99SBarry Smith     ratioi = mx/Mx;
289*08401ef6SPierre Jolivet     PetscCheck(ratioi*Mx == mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
29047c6ae99SBarry Smith   } else {
291*08401ef6SPierre Jolivet     PetscCheck(Mx >= 2,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be greater than 1",Mx);
29247c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
2932c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratioi*(Mx-1) != mx-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
29447c6ae99SBarry Smith   }
295bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
2967a8be351SBarry Smith     PetscCheck(My,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
29747c6ae99SBarry Smith     ratioj = my/My;
298*08401ef6SPierre Jolivet     PetscCheck(ratioj*My == my,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
29947c6ae99SBarry Smith   } else {
300*08401ef6SPierre Jolivet     PetscCheck(My >= 2,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be greater than 1",My);
30147c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
3022c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratioj*(My-1) != my-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
30347c6ae99SBarry Smith   }
30447c6ae99SBarry Smith 
3059566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf,&i_start,&j_start,NULL,&m_f,&n_f,NULL));
3069566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,NULL,&m_ghost,&n_ghost,NULL));
3079566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf,&ltog_f));
3089566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f));
30947c6ae99SBarry Smith 
3109566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac,&i_start_c,&j_start_c,NULL,&m_c,&n_c,NULL));
3119566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,NULL,&m_ghost_c,&n_ghost_c,NULL));
3129566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac,&ltog_c));
3139566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c));
31447c6ae99SBarry Smith 
31547c6ae99SBarry Smith   /*
316aa219208SBarry Smith    Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
31747c6ae99SBarry Smith    The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
31847c6ae99SBarry Smith    processors). It's effective length is hence 4 times its normal length, this is
31947c6ae99SBarry Smith    why the col_scale is multiplied by the interpolation matrix column sizes.
32047c6ae99SBarry Smith    sol_shift allows each set of 1/4 processors do its own interpolation using ITS
32147c6ae99SBarry Smith    copy of the coarse vector. A bit of a hack but you do better.
32247c6ae99SBarry Smith 
32347c6ae99SBarry Smith    In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
32447c6ae99SBarry Smith    */
3259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c));
3269566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f));
3279566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f));
32847c6ae99SBarry Smith   col_scale = size_f/size_c;
32947c6ae99SBarry Smith   col_shift = Mx*My*(rank_f/size_c);
33047c6ae99SBarry Smith 
3319566063dSJacob Faibussowitsch   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f,col_scale*m_c*n_c,dnz,onz);PetscCall(ierr);
33247c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
33347c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
33447c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
335e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
33647c6ae99SBarry Smith 
33747c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
33847c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
33947c6ae99SBarry Smith 
340*08401ef6SPierre 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\
34147c6ae99SBarry Smith                                           j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
342*08401ef6SPierre 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\
34347c6ae99SBarry Smith                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
34447c6ae99SBarry Smith 
34547c6ae99SBarry Smith       /*
34647c6ae99SBarry Smith        Only include those interpolation points that are truly
34747c6ae99SBarry Smith        nonzero. Note this is very important for final grid lines
34847c6ae99SBarry Smith        in x and y directions; since they have no right/top neighbors
34947c6ae99SBarry Smith        */
35047c6ae99SBarry Smith       nc = 0;
35147c6ae99SBarry Smith       /* one left and below; or we are right on it */
352e3fbd1f4SBarry Smith       col        = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
353e3fbd1f4SBarry Smith       cols[nc++] = col_shift + idx_c[col];
35447c6ae99SBarry Smith       /* one right and below */
355e3fbd1f4SBarry Smith       if (i_c*ratioi != i) cols[nc++] = col_shift + idx_c[col+1];
35647c6ae99SBarry Smith       /* one left and above */
357e3fbd1f4SBarry Smith       if (j_c*ratioj != j) cols[nc++] = col_shift + idx_c[col+m_ghost_c];
35847c6ae99SBarry Smith       /* one right and above */
359e3fbd1f4SBarry Smith       if (i_c*ratioi != i && j_c*ratioj != j) cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)];
3609566063dSJacob Faibussowitsch       PetscCall(MatPreallocateSet(row,nc,cols,dnz,onz));
36147c6ae99SBarry Smith     }
36247c6ae99SBarry Smith   }
3639566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)daf),&mat));
364fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
365fdc842d1SBarry Smith   /*
366fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
367fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
368fdc842d1SBarry Smith   */
369fdc842d1SBarry Smith   if (dof > 1) {
3709566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(mat,PETSC_TRUE));
371fdc842d1SBarry Smith   }
372fdc842d1SBarry Smith #endif
3739566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My));
3749566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype,&mattype));
3759566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat,mattype));
3769566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat,0,dnz));
3779566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat,0,dnz,0,onz));
3789566063dSJacob Faibussowitsch   ierr = MatPreallocateFinalize(dnz,onz);PetscCall(ierr);
37947c6ae99SBarry Smith 
38047c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
38185afcc9aSBarry Smith   if (!NEWVERSION) {
382b3bd94feSDave May 
38347c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
38447c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
38547c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
386e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
38747c6ae99SBarry Smith 
38847c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
38947c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
39047c6ae99SBarry Smith 
39147c6ae99SBarry Smith         /*
39247c6ae99SBarry Smith          Only include those interpolation points that are truly
39347c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
39447c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
39547c6ae99SBarry Smith          */
3966712e2f1SBarry Smith         x = ((PetscReal)(i - i_c*ratioi))/((PetscReal)ratioi);
3976712e2f1SBarry Smith         y = ((PetscReal)(j - j_c*ratioj))/((PetscReal)ratioj);
398b3bd94feSDave May 
39947c6ae99SBarry Smith         nc = 0;
40047c6ae99SBarry Smith         /* one left and below; or we are right on it */
401e3fbd1f4SBarry Smith         col      = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
402e3fbd1f4SBarry Smith         cols[nc] = col_shift + idx_c[col];
40347c6ae99SBarry Smith         v[nc++]  = x*y - x - y + 1.0;
40447c6ae99SBarry Smith         /* one right and below */
40547c6ae99SBarry Smith         if (i_c*ratioi != i) {
406e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+1];
40747c6ae99SBarry Smith           v[nc++]  = -x*y + x;
40847c6ae99SBarry Smith         }
40947c6ae99SBarry Smith         /* one left and above */
41047c6ae99SBarry Smith         if (j_c*ratioj != j) {
411e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+m_ghost_c];
41247c6ae99SBarry Smith           v[nc++]  = -x*y + y;
41347c6ae99SBarry Smith         }
41447c6ae99SBarry Smith         /* one right and above */
41547c6ae99SBarry Smith         if (j_c*ratioj != j && i_c*ratioi != i) {
416e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)];
41747c6ae99SBarry Smith           v[nc++]  = x*y;
41847c6ae99SBarry Smith         }
4199566063dSJacob Faibussowitsch         PetscCall(MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES));
42047c6ae99SBarry Smith       }
42147c6ae99SBarry Smith     }
422b3bd94feSDave May 
423b3bd94feSDave May   } else {
424b3bd94feSDave May     PetscScalar Ni[4];
425b3bd94feSDave May     PetscScalar *xi,*eta;
426b3bd94feSDave May     PetscInt    li,nxi,lj,neta;
427b3bd94feSDave May 
428b3bd94feSDave May     /* compute local coordinate arrays */
429b3bd94feSDave May     nxi  = ratioi + 1;
430b3bd94feSDave May     neta = ratioj + 1;
4319566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nxi,&xi));
4329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(neta,&eta));
433b3bd94feSDave May     for (li=0; li<nxi; li++) {
43452218ef2SJed Brown       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
435b3bd94feSDave May     }
436b3bd94feSDave May     for (lj=0; lj<neta; lj++) {
43752218ef2SJed Brown       eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
438b3bd94feSDave May     }
439b3bd94feSDave May 
440b3bd94feSDave May     /* loop over local fine grid nodes setting interpolation for those*/
441b3bd94feSDave May     for (j=j_start; j<j_start+n_f; j++) {
442b3bd94feSDave May       for (i=i_start; i<i_start+m_f; i++) {
443b3bd94feSDave May         /* convert to local "natural" numbering and then to PETSc global numbering */
444e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
445b3bd94feSDave May 
446b3bd94feSDave May         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
447b3bd94feSDave May         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
448b3bd94feSDave May 
449b3bd94feSDave May         /* remainders */
450b3bd94feSDave May         li = i - ratioi * (i/ratioi);
4518865f1eaSKarl Rupp         if (i==mx-1) li = nxi-1;
452b3bd94feSDave May         lj = j - ratioj * (j/ratioj);
4538865f1eaSKarl Rupp         if (j==my-1) lj = neta-1;
454b3bd94feSDave May 
455b3bd94feSDave May         /* corners */
456e3fbd1f4SBarry Smith         col     = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
457e3fbd1f4SBarry Smith         cols[0] = col_shift + idx_c[col]; /* left, below */
458b3bd94feSDave May         Ni[0]   = 1.0;
459b3bd94feSDave May         if ((li==0) || (li==nxi-1)) {
460b3bd94feSDave May           if ((lj==0) || (lj==neta-1)) {
4619566063dSJacob Faibussowitsch             PetscCall(MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES));
462b3bd94feSDave May             continue;
463b3bd94feSDave May           }
464b3bd94feSDave May         }
465b3bd94feSDave May 
466b3bd94feSDave May         /* edges + interior */
467b3bd94feSDave May         /* remainders */
4688865f1eaSKarl Rupp         if (i==mx-1) i_c--;
4698865f1eaSKarl Rupp         if (j==my-1) j_c--;
470b3bd94feSDave May 
471e3fbd1f4SBarry Smith         col     = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
472e3fbd1f4SBarry Smith         cols[0] = col_shift + idx_c[col]; /* left, below */
473e3fbd1f4SBarry Smith         cols[1] = col_shift + idx_c[col+1]; /* right, below */
474e3fbd1f4SBarry Smith         cols[2] = col_shift + idx_c[col+m_ghost_c]; /* left, above */
475e3fbd1f4SBarry Smith         cols[3] = col_shift + idx_c[col+(m_ghost_c+1)]; /* right, above */
476b3bd94feSDave May 
477b3bd94feSDave May         Ni[0] = 0.25*(1.0-xi[li])*(1.0-eta[lj]);
478b3bd94feSDave May         Ni[1] = 0.25*(1.0+xi[li])*(1.0-eta[lj]);
479b3bd94feSDave May         Ni[2] = 0.25*(1.0-xi[li])*(1.0+eta[lj]);
480b3bd94feSDave May         Ni[3] = 0.25*(1.0+xi[li])*(1.0+eta[lj]);
481b3bd94feSDave May 
482b3bd94feSDave May         nc = 0;
4838865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[0])<1.0e-32) cols[0]=-1;
4848865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[1])<1.0e-32) cols[1]=-1;
4858865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[2])<1.0e-32) cols[2]=-1;
4868865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[3])<1.0e-32) cols[3]=-1;
487b3bd94feSDave May 
4889566063dSJacob Faibussowitsch         PetscCall(MatSetValues(mat,1,&row,4,cols,Ni,INSERT_VALUES));
489b3bd94feSDave May       }
490b3bd94feSDave May     }
4919566063dSJacob Faibussowitsch     PetscCall(PetscFree(xi));
4929566063dSJacob Faibussowitsch     PetscCall(PetscFree(eta));
493b3bd94feSDave May   }
4949566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f));
4959566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c));
4969566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
4979566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
4989566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat,dof,A));
4999566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
50047c6ae99SBarry Smith   PetscFunctionReturn(0);
50147c6ae99SBarry Smith }
50247c6ae99SBarry Smith 
50347c6ae99SBarry Smith /*
50447c6ae99SBarry Smith        Contributed by Andrei Draganescu <aidraga@sandia.gov>
50547c6ae99SBarry Smith */
506e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_2D_Q0(DM dac,DM daf,Mat *A)
50747c6ae99SBarry Smith {
50847c6ae99SBarry Smith   PetscErrorCode         ierr;
5098ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
5108ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
511e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
5128ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,*dnz,*onz;
51347c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
51447c6ae99SBarry 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;
51547c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
51647c6ae99SBarry Smith   PetscScalar            v[4];
51747c6ae99SBarry Smith   Mat                    mat;
518bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
519fdc842d1SBarry Smith   MatType                mattype;
52047c6ae99SBarry Smith 
52147c6ae99SBarry Smith   PetscFunctionBegin;
5229566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,NULL,&Mx,&My,NULL,NULL,NULL,NULL,NULL,NULL,&bx,&by,NULL,NULL));
5239566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,NULL,&mx,&my,NULL,NULL,NULL,NULL,&dof,NULL,NULL,NULL,NULL,NULL));
5247a8be351SBarry Smith   PetscCheck(Mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
5257a8be351SBarry Smith   PetscCheck(My,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
52647c6ae99SBarry Smith   ratioi = mx/Mx;
52747c6ae99SBarry Smith   ratioj = my/My;
528*08401ef6SPierre Jolivet   PetscCheck(ratioi*Mx == mx,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
529*08401ef6SPierre Jolivet   PetscCheck(ratioj*My == my,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
530*08401ef6SPierre Jolivet   PetscCheck(ratioi == 2,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 2");
531*08401ef6SPierre Jolivet   PetscCheck(ratioj == 2,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 2");
53247c6ae99SBarry Smith 
5339566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf,&i_start,&j_start,NULL,&m_f,&n_f,NULL));
5349566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,NULL,&m_ghost,&n_ghost,NULL));
5359566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf,&ltog_f));
5369566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f));
53747c6ae99SBarry Smith 
5389566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac,&i_start_c,&j_start_c,NULL,&m_c,&n_c,NULL));
5399566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,NULL,&m_ghost_c,&n_ghost_c,NULL));
5409566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac,&ltog_c));
5419566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c));
54247c6ae99SBarry Smith 
54347c6ae99SBarry Smith   /*
544aa219208SBarry Smith      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
54547c6ae99SBarry Smith      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
54647c6ae99SBarry Smith      processors). It's effective length is hence 4 times its normal length, this is
54747c6ae99SBarry Smith      why the col_scale is multiplied by the interpolation matrix column sizes.
54847c6ae99SBarry Smith      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
54947c6ae99SBarry Smith      copy of the coarse vector. A bit of a hack but you do better.
55047c6ae99SBarry Smith 
55147c6ae99SBarry Smith      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
55247c6ae99SBarry Smith   */
5539566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c));
5549566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f));
5559566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f));
55647c6ae99SBarry Smith   col_scale = size_f/size_c;
55747c6ae99SBarry Smith   col_shift = Mx*My*(rank_f/size_c);
55847c6ae99SBarry Smith 
5599566063dSJacob Faibussowitsch   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f,col_scale*m_c*n_c,dnz,onz);PetscCall(ierr);
56047c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
56147c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
56247c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
563e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
56447c6ae99SBarry Smith 
56547c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
56647c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
56747c6ae99SBarry Smith 
568*08401ef6SPierre 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\
56947c6ae99SBarry Smith     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
570*08401ef6SPierre 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\
57147c6ae99SBarry Smith     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
57247c6ae99SBarry Smith 
57347c6ae99SBarry Smith       /*
57447c6ae99SBarry Smith          Only include those interpolation points that are truly
57547c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
57647c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
57747c6ae99SBarry Smith       */
57847c6ae99SBarry Smith       nc = 0;
57947c6ae99SBarry Smith       /* one left and below; or we are right on it */
580e3fbd1f4SBarry Smith       col        = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
581e3fbd1f4SBarry Smith       cols[nc++] = col_shift + idx_c[col];
5829566063dSJacob Faibussowitsch       PetscCall(MatPreallocateSet(row,nc,cols,dnz,onz));
58347c6ae99SBarry Smith     }
58447c6ae99SBarry Smith   }
5859566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)daf),&mat));
586fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
587fdc842d1SBarry Smith   /*
588fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
589fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
590fdc842d1SBarry Smith   */
591fdc842d1SBarry Smith   if (dof > 1) {
5929566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(mat,PETSC_TRUE));
593fdc842d1SBarry Smith   }
594fdc842d1SBarry Smith   #endif
5959566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My));
5969566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype,&mattype));
5979566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat,mattype));
5989566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat,0,dnz));
5999566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat,0,dnz,0,onz));
6009566063dSJacob Faibussowitsch   ierr = MatPreallocateFinalize(dnz,onz);PetscCall(ierr);
60147c6ae99SBarry Smith 
60247c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
60347c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
60447c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
60547c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
606e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
60747c6ae99SBarry Smith 
60847c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
60947c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
61047c6ae99SBarry Smith       nc  = 0;
61147c6ae99SBarry Smith       /* one left and below; or we are right on it */
612e3fbd1f4SBarry Smith       col      = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
613e3fbd1f4SBarry Smith       cols[nc] = col_shift + idx_c[col];
61447c6ae99SBarry Smith       v[nc++]  = 1.0;
61547c6ae99SBarry Smith 
6169566063dSJacob Faibussowitsch       PetscCall(MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES));
61747c6ae99SBarry Smith     }
61847c6ae99SBarry Smith   }
6199566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f));
6209566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c));
6219566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
6229566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
6239566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat,dof,A));
6249566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
6259566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(13.0*m_f*n_f));
62647c6ae99SBarry Smith   PetscFunctionReturn(0);
62747c6ae99SBarry Smith }
62847c6ae99SBarry Smith 
62947c6ae99SBarry Smith /*
63047c6ae99SBarry Smith        Contributed by Jianming Yang <jianming-yang@uiowa.edu>
63147c6ae99SBarry Smith */
632e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_3D_Q0(DM dac,DM daf,Mat *A)
63347c6ae99SBarry Smith {
63447c6ae99SBarry Smith   PetscErrorCode         ierr;
6358ea3bf28SBarry Smith   PetscInt               i,j,l,i_start,j_start,l_start,m_f,n_f,p_f,Mx,My,Mz,dof;
6368ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
637e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
6388ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,p_ghost,m_ghost_c,n_ghost_c,p_ghost_c,nc,*dnz,*onz;
63947c6ae99SBarry 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;
64047c6ae99SBarry 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;
64147c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
64247c6ae99SBarry Smith   PetscScalar            v[8];
64347c6ae99SBarry Smith   Mat                    mat;
644bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
645fdc842d1SBarry Smith   MatType                mattype;
64647c6ae99SBarry Smith 
64747c6ae99SBarry Smith   PetscFunctionBegin;
6489566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,NULL,&Mx,&My,&Mz,NULL,NULL,NULL,NULL,NULL,&bx,&by,&bz,NULL));
6497a8be351SBarry Smith   PetscCheck(Mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
6507a8be351SBarry Smith   PetscCheck(My,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
6517a8be351SBarry Smith   PetscCheck(Mz,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of z coarse grid points %D must be positive",Mz);
6529566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,NULL,&mx,&my,&mz,NULL,NULL,NULL,&dof,NULL,NULL,NULL,NULL,NULL));
65347c6ae99SBarry Smith   ratioi = mx/Mx;
65447c6ae99SBarry Smith   ratioj = my/My;
65547c6ae99SBarry Smith   ratiol = mz/Mz;
656*08401ef6SPierre Jolivet   PetscCheck(ratioi*Mx == mx,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
657*08401ef6SPierre Jolivet   PetscCheck(ratioj*My == my,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
658*08401ef6SPierre Jolivet   PetscCheck(ratiol*Mz == mz,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in z");
6592c71b3e2SJacob Faibussowitsch   PetscCheckFalse(ratioi != 2 && ratioi != 1,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 1 or 2");
6602c71b3e2SJacob Faibussowitsch   PetscCheckFalse(ratioj != 2 && ratioj != 1,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 1 or 2");
6612c71b3e2SJacob Faibussowitsch   PetscCheckFalse(ratiol != 2 && ratiol != 1,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in z must be 1 or 2");
66247c6ae99SBarry Smith 
6639566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f));
6649566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost));
6659566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf,&ltog_f));
6669566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f));
66747c6ae99SBarry Smith 
6689566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c));
6699566063dSJacob 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));
6709566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac,&ltog_c));
6719566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c));
672e3fbd1f4SBarry Smith 
67347c6ae99SBarry Smith   /*
674aa219208SBarry Smith      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
67547c6ae99SBarry Smith      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
67647c6ae99SBarry Smith      processors). It's effective length is hence 4 times its normal length, this is
67747c6ae99SBarry Smith      why the col_scale is multiplied by the interpolation matrix column sizes.
67847c6ae99SBarry Smith      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
67947c6ae99SBarry Smith      copy of the coarse vector. A bit of a hack but you do better.
68047c6ae99SBarry Smith 
68147c6ae99SBarry Smith      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
68247c6ae99SBarry Smith   */
6839566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c));
6849566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f));
6859566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f));
68647c6ae99SBarry Smith   col_scale = size_f/size_c;
68747c6ae99SBarry Smith   col_shift = Mx*My*Mz*(rank_f/size_c);
68847c6ae99SBarry Smith 
6899566063dSJacob Faibussowitsch   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f*p_f,col_scale*m_c*n_c*p_c,dnz,onz);PetscCall(ierr);
69047c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
69147c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
69247c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
69347c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
694e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
69547c6ae99SBarry Smith 
69647c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
69747c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
69847c6ae99SBarry Smith         l_c = (l/ratiol);
69947c6ae99SBarry Smith 
700*08401ef6SPierre 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\
70147c6ae99SBarry Smith     l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
702*08401ef6SPierre 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\
70347c6ae99SBarry Smith     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
704*08401ef6SPierre 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\
70547c6ae99SBarry Smith     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
70647c6ae99SBarry Smith 
70747c6ae99SBarry Smith         /*
70847c6ae99SBarry Smith            Only include those interpolation points that are truly
70947c6ae99SBarry Smith            nonzero. Note this is very important for final grid lines
71047c6ae99SBarry Smith            in x and y directions; since they have no right/top neighbors
71147c6ae99SBarry Smith         */
71247c6ae99SBarry Smith         nc = 0;
71347c6ae99SBarry Smith         /* one left and below; or we are right on it */
714e3fbd1f4SBarry 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));
715e3fbd1f4SBarry Smith         cols[nc++] = col_shift + idx_c[col];
7169566063dSJacob Faibussowitsch         PetscCall(MatPreallocateSet(row,nc,cols,dnz,onz));
71747c6ae99SBarry Smith       }
71847c6ae99SBarry Smith     }
71947c6ae99SBarry Smith   }
7209566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)daf),&mat));
721fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
722fdc842d1SBarry Smith   /*
723fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
724fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
725fdc842d1SBarry Smith   */
726fdc842d1SBarry Smith   if (dof > 1) {
7279566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(mat,PETSC_TRUE));
728fdc842d1SBarry Smith   }
729fdc842d1SBarry Smith   #endif
7309566063dSJacob 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));
7319566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype,&mattype));
7329566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat,mattype));
7339566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat,0,dnz));
7349566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat,0,dnz,0,onz));
7359566063dSJacob Faibussowitsch   ierr = MatPreallocateFinalize(dnz,onz);PetscCall(ierr);
73647c6ae99SBarry Smith 
73747c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
73847c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
73947c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
74047c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
74147c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
742e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
74347c6ae99SBarry Smith 
74447c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
74547c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
74647c6ae99SBarry Smith         l_c = (l/ratiol);
74747c6ae99SBarry Smith         nc  = 0;
74847c6ae99SBarry Smith         /* one left and below; or we are right on it */
749e3fbd1f4SBarry 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));
750e3fbd1f4SBarry Smith         cols[nc] = col_shift + idx_c[col];
75147c6ae99SBarry Smith         v[nc++]  = 1.0;
75247c6ae99SBarry Smith 
7539566063dSJacob Faibussowitsch         PetscCall(MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES));
75447c6ae99SBarry Smith       }
75547c6ae99SBarry Smith     }
75647c6ae99SBarry Smith   }
7579566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f));
7589566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c));
7599566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
7609566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
7619566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat,dof,A));
7629566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
7639566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(13.0*m_f*n_f*p_f));
76447c6ae99SBarry Smith   PetscFunctionReturn(0);
76547c6ae99SBarry Smith }
76647c6ae99SBarry Smith 
767e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_3D_Q1(DM dac,DM daf,Mat *A)
76847c6ae99SBarry Smith {
76947c6ae99SBarry Smith   PetscErrorCode         ierr;
7708ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof,l;
7718ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
772e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
7738ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,Mz,mz;
77447c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
77547c6ae99SBarry Smith   PetscInt               i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
77647c6ae99SBarry Smith   PetscInt               l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
77747c6ae99SBarry Smith   PetscInt               l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
77847c6ae99SBarry Smith   PetscScalar            v[8],x,y,z;
77947c6ae99SBarry Smith   Mat                    mat;
780bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
781fdc842d1SBarry Smith   MatType                mattype;
78247c6ae99SBarry Smith 
78347c6ae99SBarry Smith   PetscFunctionBegin;
7849566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,NULL,&Mx,&My,&Mz,NULL,NULL,NULL,NULL,NULL,&bx,&by,&bz,NULL));
7859566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,NULL,&mx,&my,&mz,NULL,NULL,NULL,&dof,NULL,NULL,NULL,NULL,NULL));
78647c6ae99SBarry Smith   if (mx == Mx) {
78747c6ae99SBarry Smith     ratioi = 1;
788bff4a2f0SMatthew G. Knepley   } else if (bx == DM_BOUNDARY_PERIODIC) {
7897a8be351SBarry Smith     PetscCheck(Mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
79047c6ae99SBarry Smith     ratioi = mx/Mx;
791*08401ef6SPierre Jolivet     PetscCheck(ratioi*Mx == mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
79247c6ae99SBarry Smith   } else {
793*08401ef6SPierre Jolivet     PetscCheck(Mx >= 2,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be greater than 1",Mx);
79447c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
7952c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratioi*(Mx-1) != mx-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
79647c6ae99SBarry Smith   }
79747c6ae99SBarry Smith   if (my == My) {
79847c6ae99SBarry Smith     ratioj = 1;
799bff4a2f0SMatthew G. Knepley   } else if (by == DM_BOUNDARY_PERIODIC) {
8007a8be351SBarry Smith     PetscCheck(My,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
80147c6ae99SBarry Smith     ratioj = my/My;
802*08401ef6SPierre Jolivet     PetscCheck(ratioj*My == my,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
80347c6ae99SBarry Smith   } else {
804*08401ef6SPierre Jolivet     PetscCheck(My >= 2,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be greater than 1",My);
80547c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
8062c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratioj*(My-1) != my-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
80747c6ae99SBarry Smith   }
80847c6ae99SBarry Smith   if (mz == Mz) {
80947c6ae99SBarry Smith     ratiok = 1;
810bff4a2f0SMatthew G. Knepley   } else if (bz == DM_BOUNDARY_PERIODIC) {
8117a8be351SBarry Smith     PetscCheck(Mz,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of z coarse grid points %D must be positive",Mz);
81247c6ae99SBarry Smith     ratiok = mz/Mz;
813*08401ef6SPierre Jolivet     PetscCheck(ratiok*Mz == mz,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mz/Mz  must be integer: mz %D Mz %D",mz,Mz);
81447c6ae99SBarry Smith   } else {
815*08401ef6SPierre Jolivet     PetscCheck(Mz >= 2,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of z coarse grid points %D must be greater than 1",Mz);
81647c6ae99SBarry Smith     ratiok = (mz-1)/(Mz-1);
8172c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratiok*(Mz-1) != mz-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %D Mz %D",mz,Mz);
81847c6ae99SBarry Smith   }
81947c6ae99SBarry Smith 
8209566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f));
8219566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost));
8229566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf,&ltog_f));
8239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f));
82447c6ae99SBarry Smith 
8259566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c));
8269566063dSJacob 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));
8279566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac,&ltog_c));
8289566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c));
82947c6ae99SBarry Smith 
83047c6ae99SBarry Smith   /* create interpolation matrix, determining exact preallocation */
8319566063dSJacob Faibussowitsch   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)dac),m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);PetscCall(ierr);
83247c6ae99SBarry Smith   /* loop over local fine grid nodes counting interpolating points */
83347c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
83447c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
83547c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
83647c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
837e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
83847c6ae99SBarry Smith         i_c = (i/ratioi);
83947c6ae99SBarry Smith         j_c = (j/ratioj);
84047c6ae99SBarry Smith         l_c = (l/ratiok);
841*08401ef6SPierre 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\
84247c6ae99SBarry Smith                                             l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
843*08401ef6SPierre 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\
84447c6ae99SBarry Smith                                             j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
845*08401ef6SPierre 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\
84647c6ae99SBarry Smith                                             i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
84747c6ae99SBarry Smith 
84847c6ae99SBarry Smith         /*
84947c6ae99SBarry Smith          Only include those interpolation points that are truly
85047c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
85147c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
85247c6ae99SBarry Smith          */
85347c6ae99SBarry Smith         nc         = 0;
854e3fbd1f4SBarry 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));
855e3fbd1f4SBarry Smith         cols[nc++] = idx_c[col];
85647c6ae99SBarry Smith         if (i_c*ratioi != i) {
857e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+1];
85847c6ae99SBarry Smith         }
85947c6ae99SBarry Smith         if (j_c*ratioj != j) {
860e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+m_ghost_c];
86147c6ae99SBarry Smith         }
86247c6ae99SBarry Smith         if (l_c*ratiok != l) {
863e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c];
86447c6ae99SBarry Smith         }
86547c6ae99SBarry Smith         if (j_c*ratioj != j && i_c*ratioi != i) {
866e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c+1)];
86747c6ae99SBarry Smith         }
86847c6ae99SBarry Smith         if (j_c*ratioj != j && l_c*ratiok != l) {
869e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)];
87047c6ae99SBarry Smith         }
87147c6ae99SBarry Smith         if (i_c*ratioi != i && l_c*ratiok != l) {
872e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)];
87347c6ae99SBarry Smith         }
87447c6ae99SBarry Smith         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
875e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)];
87647c6ae99SBarry Smith         }
8779566063dSJacob Faibussowitsch         PetscCall(MatPreallocateSet(row,nc,cols,dnz,onz));
87847c6ae99SBarry Smith       }
87947c6ae99SBarry Smith     }
88047c6ae99SBarry Smith   }
8819566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dac),&mat));
882fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
883fdc842d1SBarry Smith   /*
884fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
885fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
886fdc842d1SBarry Smith   */
887fdc842d1SBarry Smith   if (dof > 1) {
8889566063dSJacob Faibussowitsch     PetscCall(MatBindToCPU(mat,PETSC_TRUE));
889fdc842d1SBarry Smith   }
890fdc842d1SBarry Smith   #endif
8919566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz));
8929566063dSJacob Faibussowitsch   PetscCall(ConvertToAIJ(dac->mattype,&mattype));
8939566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat,mattype));
8949566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(mat,0,dnz));
8959566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(mat,0,dnz,0,onz));
8969566063dSJacob Faibussowitsch   ierr = MatPreallocateFinalize(dnz,onz);PetscCall(ierr);
89747c6ae99SBarry Smith 
89847c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
8992adb9dcfSBarry Smith   if (!NEWVERSION) {
900b3bd94feSDave May 
90147c6ae99SBarry Smith     for (l=l_start; l<l_start+p_f; l++) {
90247c6ae99SBarry Smith       for (j=j_start; j<j_start+n_f; j++) {
90347c6ae99SBarry Smith         for (i=i_start; i<i_start+m_f; i++) {
90447c6ae99SBarry Smith           /* convert to local "natural" numbering and then to PETSc global numbering */
905e3fbd1f4SBarry Smith           row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
90647c6ae99SBarry Smith 
90747c6ae99SBarry Smith           i_c = (i/ratioi);
90847c6ae99SBarry Smith           j_c = (j/ratioj);
90947c6ae99SBarry Smith           l_c = (l/ratiok);
91047c6ae99SBarry Smith 
91147c6ae99SBarry Smith           /*
91247c6ae99SBarry Smith            Only include those interpolation points that are truly
91347c6ae99SBarry Smith            nonzero. Note this is very important for final grid lines
91447c6ae99SBarry Smith            in x and y directions; since they have no right/top neighbors
91547c6ae99SBarry Smith            */
9166712e2f1SBarry Smith           x = ((PetscReal)(i - i_c*ratioi))/((PetscReal)ratioi);
9176712e2f1SBarry Smith           y = ((PetscReal)(j - j_c*ratioj))/((PetscReal)ratioj);
9186712e2f1SBarry Smith           z = ((PetscReal)(l - l_c*ratiok))/((PetscReal)ratiok);
919b3bd94feSDave May 
92047c6ae99SBarry Smith           nc = 0;
92147c6ae99SBarry Smith           /* one left and below; or we are right on it */
922e3fbd1f4SBarry 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));
92347c6ae99SBarry Smith 
924e3fbd1f4SBarry Smith           cols[nc] = idx_c[col];
92547c6ae99SBarry Smith           v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
92647c6ae99SBarry Smith 
92747c6ae99SBarry Smith           if (i_c*ratioi != i) {
928e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+1];
92947c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
93047c6ae99SBarry Smith           }
93147c6ae99SBarry Smith 
93247c6ae99SBarry Smith           if (j_c*ratioj != j) {
933e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+m_ghost_c];
93447c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
93547c6ae99SBarry Smith           }
93647c6ae99SBarry Smith 
93747c6ae99SBarry Smith           if (l_c*ratiok != l) {
938e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+m_ghost_c*n_ghost_c];
93947c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
94047c6ae99SBarry Smith           }
94147c6ae99SBarry Smith 
94247c6ae99SBarry Smith           if (j_c*ratioj != j && i_c*ratioi != i) {
943e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c+1)];
94447c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
94547c6ae99SBarry Smith           }
94647c6ae99SBarry Smith 
94747c6ae99SBarry Smith           if (j_c*ratioj != j && l_c*ratiok != l) {
948e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)];
94947c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
95047c6ae99SBarry Smith           }
95147c6ae99SBarry Smith 
95247c6ae99SBarry Smith           if (i_c*ratioi != i && l_c*ratiok != l) {
953e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+1)];
95447c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
95547c6ae99SBarry Smith           }
95647c6ae99SBarry Smith 
95747c6ae99SBarry Smith           if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
958e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)];
95947c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
96047c6ae99SBarry Smith           }
9619566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES));
96247c6ae99SBarry Smith         }
96347c6ae99SBarry Smith       }
96447c6ae99SBarry Smith     }
965b3bd94feSDave May 
966b3bd94feSDave May   } else {
967b3bd94feSDave May     PetscScalar *xi,*eta,*zeta;
968b3bd94feSDave May     PetscInt    li,nxi,lj,neta,lk,nzeta,n;
969b3bd94feSDave May     PetscScalar Ni[8];
970b3bd94feSDave May 
971b3bd94feSDave May     /* compute local coordinate arrays */
972b3bd94feSDave May     nxi   = ratioi + 1;
973b3bd94feSDave May     neta  = ratioj + 1;
974b3bd94feSDave May     nzeta = ratiok + 1;
9759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nxi,&xi));
9769566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(neta,&eta));
9779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nzeta,&zeta));
9788865f1eaSKarl Rupp     for (li=0; li<nxi; li++) xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
9798865f1eaSKarl Rupp     for (lj=0; lj<neta; lj++) eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
9808865f1eaSKarl Rupp     for (lk=0; lk<nzeta; lk++) zeta[lk] = -1.0 + (PetscScalar)lk*(2.0/(PetscScalar)(nzeta-1));
981b3bd94feSDave May 
982b3bd94feSDave May     for (l=l_start; l<l_start+p_f; l++) {
983b3bd94feSDave May       for (j=j_start; j<j_start+n_f; j++) {
984b3bd94feSDave May         for (i=i_start; i<i_start+m_f; i++) {
985b3bd94feSDave May           /* convert to local "natural" numbering and then to PETSc global numbering */
986e3fbd1f4SBarry Smith           row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
987b3bd94feSDave May 
988b3bd94feSDave May           i_c = (i/ratioi);
989b3bd94feSDave May           j_c = (j/ratioj);
990b3bd94feSDave May           l_c = (l/ratiok);
991b3bd94feSDave May 
992b3bd94feSDave May           /* remainders */
993b3bd94feSDave May           li = i - ratioi * (i/ratioi);
9948865f1eaSKarl Rupp           if (i==mx-1) li = nxi-1;
995b3bd94feSDave May           lj = j - ratioj * (j/ratioj);
9968865f1eaSKarl Rupp           if (j==my-1) lj = neta-1;
997b3bd94feSDave May           lk = l - ratiok * (l/ratiok);
9988865f1eaSKarl Rupp           if (l==mz-1) lk = nzeta-1;
999b3bd94feSDave May 
1000b3bd94feSDave May           /* corners */
1001e3fbd1f4SBarry 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));
1002e3fbd1f4SBarry Smith           cols[0] = idx_c[col];
1003b3bd94feSDave May           Ni[0]   = 1.0;
1004b3bd94feSDave May           if ((li==0) || (li==nxi-1)) {
1005b3bd94feSDave May             if ((lj==0) || (lj==neta-1)) {
1006b3bd94feSDave May               if ((lk==0) || (lk==nzeta-1)) {
10079566063dSJacob Faibussowitsch                 PetscCall(MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES));
1008b3bd94feSDave May                 continue;
1009b3bd94feSDave May               }
1010b3bd94feSDave May             }
1011b3bd94feSDave May           }
1012b3bd94feSDave May 
1013b3bd94feSDave May           /* edges + interior */
1014b3bd94feSDave May           /* remainders */
10158865f1eaSKarl Rupp           if (i==mx-1) i_c--;
10168865f1eaSKarl Rupp           if (j==my-1) j_c--;
10178865f1eaSKarl Rupp           if (l==mz-1) l_c--;
1018b3bd94feSDave May 
1019e3fbd1f4SBarry 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));
1020e3fbd1f4SBarry Smith           cols[0] = idx_c[col]; /* one left and below; or we are right on it */
1021e3fbd1f4SBarry Smith           cols[1] = idx_c[col+1]; /* one right and below */
1022e3fbd1f4SBarry Smith           cols[2] = idx_c[col+m_ghost_c];  /* one left and above */
1023e3fbd1f4SBarry Smith           cols[3] = idx_c[col+(m_ghost_c+1)]; /* one right and above */
1024b3bd94feSDave May 
1025e3fbd1f4SBarry Smith           cols[4] = idx_c[col+m_ghost_c*n_ghost_c]; /* one left and below and front; or we are right on it */
1026e3fbd1f4SBarry Smith           cols[5] = idx_c[col+(m_ghost_c*n_ghost_c+1)]; /* one right and below, and front */
1027e3fbd1f4SBarry Smith           cols[6] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)]; /* one left and above and front*/
1028e3fbd1f4SBarry Smith           cols[7] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)]; /* one right and above and front */
1029b3bd94feSDave May 
1030b3bd94feSDave May           Ni[0] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
1031b3bd94feSDave May           Ni[1] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
1032b3bd94feSDave May           Ni[2] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);
1033b3bd94feSDave May           Ni[3] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);
1034b3bd94feSDave May 
1035b3bd94feSDave May           Ni[4] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
1036b3bd94feSDave May           Ni[5] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
1037b3bd94feSDave May           Ni[6] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);
1038b3bd94feSDave May           Ni[7] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);
1039b3bd94feSDave May 
1040b3bd94feSDave May           for (n=0; n<8; n++) {
10418865f1eaSKarl Rupp             if (PetscAbsScalar(Ni[n])<1.0e-32) cols[n]=-1;
1042b3bd94feSDave May           }
10439566063dSJacob Faibussowitsch           PetscCall(MatSetValues(mat,1,&row,8,cols,Ni,INSERT_VALUES));
1044b3bd94feSDave May 
1045b3bd94feSDave May         }
1046b3bd94feSDave May       }
1047b3bd94feSDave May     }
10489566063dSJacob Faibussowitsch     PetscCall(PetscFree(xi));
10499566063dSJacob Faibussowitsch     PetscCall(PetscFree(eta));
10509566063dSJacob Faibussowitsch     PetscCall(PetscFree(zeta));
1051b3bd94feSDave May   }
10529566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f));
10539566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c));
10549566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY));
10559566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY));
105647c6ae99SBarry Smith 
10579566063dSJacob Faibussowitsch   PetscCall(MatCreateMAIJ(mat,dof,A));
10589566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&mat));
105947c6ae99SBarry Smith   PetscFunctionReturn(0);
106047c6ae99SBarry Smith }
106147c6ae99SBarry Smith 
1062e727c939SJed Brown PetscErrorCode  DMCreateInterpolation_DA(DM dac,DM daf,Mat *A,Vec *scale)
106347c6ae99SBarry Smith {
106447c6ae99SBarry Smith   PetscInt         dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1065bff4a2f0SMatthew G. Knepley   DMBoundaryType   bxc,byc,bzc,bxf,byf,bzf;
1066aa219208SBarry Smith   DMDAStencilType  stc,stf;
106747c6ae99SBarry Smith   DM_DA            *ddc = (DM_DA*)dac->data;
106847c6ae99SBarry Smith 
106947c6ae99SBarry Smith   PetscFunctionBegin;
107047c6ae99SBarry Smith   PetscValidHeaderSpecific(dac,DM_CLASSID,1);
107147c6ae99SBarry Smith   PetscValidHeaderSpecific(daf,DM_CLASSID,2);
107247c6ae99SBarry Smith   PetscValidPointer(A,3);
107347c6ae99SBarry Smith   if (scale) PetscValidPointer(scale,4);
107447c6ae99SBarry Smith 
10759566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc));
10769566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf));
1077*08401ef6SPierre Jolivet   PetscCheck(dimc == dimf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
1078*08401ef6SPierre Jolivet   PetscCheck(dofc == doff,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
1079*08401ef6SPierre Jolivet   PetscCheck(sc == sf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
10802c71b3e2SJacob Faibussowitsch   PetscCheckFalse(bxc != bxf || byc != byf || bzc != bzf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
1081*08401ef6SPierre Jolivet   PetscCheck(stc == stf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
10822c71b3e2SJacob Faibussowitsch   PetscCheckFalse(Mc < 2 && Mf > 1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
10832c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dimc > 1 && Nc < 2 && Nf > 1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
10842c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dimc > 2 && Pc < 2 && Pf > 1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");
108547c6ae99SBarry Smith 
1086aa219208SBarry Smith   if (ddc->interptype == DMDA_Q1) {
108747c6ae99SBarry Smith     if (dimc == 1) {
10889566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_1D_Q1(dac,daf,A));
108947c6ae99SBarry Smith     } else if (dimc == 2) {
10909566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_2D_Q1(dac,daf,A));
109147c6ae99SBarry Smith     } else if (dimc == 3) {
10929566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_3D_Q1(dac,daf,A));
109398921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
1094aa219208SBarry Smith   } else if (ddc->interptype == DMDA_Q0) {
109547c6ae99SBarry Smith     if (dimc == 1) {
10969566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_1D_Q0(dac,daf,A));
109747c6ae99SBarry Smith     } else if (dimc == 2) {
10989566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_2D_Q0(dac,daf,A));
109947c6ae99SBarry Smith     } else if (dimc == 3) {
11009566063dSJacob Faibussowitsch       PetscCall(DMCreateInterpolation_DA_3D_Q0(dac,daf,A));
110198921bdaSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
110247c6ae99SBarry Smith   }
110347c6ae99SBarry Smith   if (scale) {
11049566063dSJacob Faibussowitsch     PetscCall(DMCreateInterpolationScale((DM)dac,(DM)daf,*A,scale));
110547c6ae99SBarry Smith   }
110647c6ae99SBarry Smith   PetscFunctionReturn(0);
110747c6ae99SBarry Smith }
110847c6ae99SBarry Smith 
1109e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_1D(DM dac,DM daf,VecScatter *inject)
11100bb2b966SJungho Lee {
11118ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx,dof;
11128ea3bf28SBarry Smith   const PetscInt         *idx_f;
1113e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f;
11148ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
11150bb2b966SJungho Lee   PetscInt               row,i_start_ghost,mx,m_c,nc,ratioi;
11160bb2b966SJungho Lee   PetscInt               i_start_c,i_start_ghost_c;
11170bb2b966SJungho Lee   PetscInt               *cols;
1118bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
11190bb2b966SJungho Lee   Vec                    vecf,vecc;
11200bb2b966SJungho Lee   IS                     isf;
11210bb2b966SJungho Lee 
11220bb2b966SJungho Lee   PetscFunctionBegin;
11239566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,NULL,&Mx,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&bx,NULL,NULL,NULL));
11249566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,NULL,&mx,NULL,NULL,NULL,NULL,NULL,&dof,NULL,NULL,NULL,NULL,NULL));
1125bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
11260bb2b966SJungho Lee     ratioi = mx/Mx;
1127*08401ef6SPierre Jolivet     PetscCheck(ratioi*Mx == mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
11280bb2b966SJungho Lee   } else {
11290bb2b966SJungho Lee     ratioi = (mx-1)/(Mx-1);
11302c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratioi*(Mx-1) != mx-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
11310bb2b966SJungho Lee   }
11320bb2b966SJungho Lee 
11339566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf,&i_start,NULL,NULL,&m_f,NULL,NULL));
11349566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf,&i_start_ghost,NULL,NULL,&m_ghost,NULL,NULL));
11359566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf,&ltog_f));
11369566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f));
11370bb2b966SJungho Lee 
11389566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac,&i_start_c,NULL,NULL,&m_c,NULL,NULL));
11399566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac,&i_start_ghost_c,NULL,NULL,&m_ghost_c,NULL,NULL));
11400bb2b966SJungho Lee 
11410bb2b966SJungho Lee   /* loop over local fine grid nodes setting interpolation for those*/
11420bb2b966SJungho Lee   nc   = 0;
11439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m_f,&cols));
11440bb2b966SJungho Lee 
11450bb2b966SJungho Lee   for (i=i_start_c; i<i_start_c+m_c; i++) {
11460bb2b966SJungho Lee     PetscInt i_f = i*ratioi;
11470bb2b966SJungho Lee 
11482c71b3e2SJacob Faibussowitsch     PetscCheckFalse(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 %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
11498865f1eaSKarl Rupp 
1150e3fbd1f4SBarry Smith     row        = idx_f[(i_f-i_start_ghost)];
1151e3fbd1f4SBarry Smith     cols[nc++] = row;
11520bb2b966SJungho Lee   }
11530bb2b966SJungho Lee 
11549566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f));
11559566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf));
11569566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dac,&vecc));
11579566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(daf,&vecf));
11589566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(vecf,isf,vecc,NULL,inject));
11599566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dac,&vecc));
11609566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(daf,&vecf));
11619566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isf));
11620bb2b966SJungho Lee   PetscFunctionReturn(0);
11630bb2b966SJungho Lee }
11640bb2b966SJungho Lee 
1165e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_2D(DM dac,DM daf,VecScatter *inject)
116647c6ae99SBarry Smith {
11678ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
11688ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
1169e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
11708ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c;
117147c6ae99SBarry Smith   PetscInt               row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
1172076202ddSJed Brown   PetscInt               i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
117347c6ae99SBarry Smith   PetscInt               *cols;
1174bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
117547c6ae99SBarry Smith   Vec                    vecf,vecc;
117647c6ae99SBarry Smith   IS                     isf;
117747c6ae99SBarry Smith 
117847c6ae99SBarry Smith   PetscFunctionBegin;
11799566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,NULL,&Mx,&My,NULL,NULL,NULL,NULL,NULL,NULL,&bx,&by,NULL,NULL));
11809566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,NULL,&mx,&my,NULL,NULL,NULL,NULL,&dof,NULL,NULL,NULL,NULL,NULL));
1181bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
118247c6ae99SBarry Smith     ratioi = mx/Mx;
1183*08401ef6SPierre Jolivet     PetscCheck(ratioi*Mx == mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
118447c6ae99SBarry Smith   } else {
118547c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
11862c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratioi*(Mx-1) != mx-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
118747c6ae99SBarry Smith   }
1188bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
118947c6ae99SBarry Smith     ratioj = my/My;
1190*08401ef6SPierre Jolivet     PetscCheck(ratioj*My == my,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
119147c6ae99SBarry Smith   } else {
119247c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
11932c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratioj*(My-1) != my-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
119447c6ae99SBarry Smith   }
119547c6ae99SBarry Smith 
11969566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf,&i_start,&j_start,NULL,&m_f,&n_f,NULL));
11979566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,NULL,&m_ghost,&n_ghost,NULL));
11989566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf,&ltog_f));
11999566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f));
120047c6ae99SBarry Smith 
12019566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac,&i_start_c,&j_start_c,NULL,&m_c,&n_c,NULL));
12029566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,NULL,&m_ghost_c,&n_ghost_c,NULL));
12039566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac,&ltog_c));
12049566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c));
120547c6ae99SBarry Smith 
120647c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
120747c6ae99SBarry Smith   nc   = 0;
12089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_f*m_f,&cols));
1209076202ddSJed Brown   for (j=j_start_c; j<j_start_c+n_c; j++) {
1210076202ddSJed Brown     for (i=i_start_c; i<i_start_c+m_c; i++) {
1211076202ddSJed Brown       PetscInt i_f = i*ratioi,j_f = j*ratioj;
12122c71b3e2SJacob Faibussowitsch       PetscCheckFalse(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\
1213076202ddSJed Brown     j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
12142c71b3e2SJacob Faibussowitsch       PetscCheckFalse(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\
1215076202ddSJed Brown     i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1216e3fbd1f4SBarry Smith       row        = idx_f[(m_ghost*(j_f-j_start_ghost) + (i_f-i_start_ghost))];
1217e3fbd1f4SBarry Smith       cols[nc++] = row;
121847c6ae99SBarry Smith     }
121947c6ae99SBarry Smith   }
12209566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f));
12219566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c));
122247c6ae99SBarry Smith 
12239566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf));
12249566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dac,&vecc));
12259566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(daf,&vecf));
12269566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(vecf,isf,vecc,NULL,inject));
12279566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dac,&vecc));
12289566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(daf,&vecf));
12299566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isf));
123047c6ae99SBarry Smith   PetscFunctionReturn(0);
123147c6ae99SBarry Smith }
123247c6ae99SBarry Smith 
1233e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_3D(DM dac,DM daf,VecScatter *inject)
1234b1757049SJed Brown {
1235b1757049SJed Brown   PetscInt               i,j,k,i_start,j_start,k_start,m_f,n_f,p_f,Mx,My,Mz;
1236b1757049SJed Brown   PetscInt               m_ghost,n_ghost,p_ghost,m_ghost_c,n_ghost_c,p_ghost_c;
1237b1757049SJed Brown   PetscInt               i_start_ghost,j_start_ghost,k_start_ghost;
1238b1757049SJed Brown   PetscInt               mx,my,mz,ratioi,ratioj,ratiok;
1239b1757049SJed Brown   PetscInt               i_start_c,j_start_c,k_start_c;
1240b1757049SJed Brown   PetscInt               m_c,n_c,p_c;
1241b1757049SJed Brown   PetscInt               i_start_ghost_c,j_start_ghost_c,k_start_ghost_c;
1242b1757049SJed Brown   PetscInt               row,nc,dof;
12438ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
1244e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
1245b1757049SJed Brown   PetscInt               *cols;
1246bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
1247b1757049SJed Brown   Vec                    vecf,vecc;
1248b1757049SJed Brown   IS                     isf;
1249b1757049SJed Brown 
1250b1757049SJed Brown   PetscFunctionBegin;
12519566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,NULL,&Mx,&My,&Mz,NULL,NULL,NULL,NULL,NULL,&bx,&by,&bz,NULL));
12529566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,NULL,&mx,&my,&mz,NULL,NULL,NULL,&dof,NULL,NULL,NULL,NULL,NULL));
1253b1757049SJed Brown 
1254bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
1255b1757049SJed Brown     ratioi = mx/Mx;
1256*08401ef6SPierre Jolivet     PetscCheck(ratioi*Mx == mx,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
1257b1757049SJed Brown   } else {
1258b1757049SJed Brown     ratioi = (mx-1)/(Mx-1);
12592c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratioi*(Mx-1) != mx-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
1260b1757049SJed Brown   }
1261bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
1262b1757049SJed Brown     ratioj = my/My;
1263*08401ef6SPierre Jolivet     PetscCheck(ratioj*My == my,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
1264b1757049SJed Brown   } else {
1265b1757049SJed Brown     ratioj = (my-1)/(My-1);
12662c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratioj*(My-1) != my-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
1267b1757049SJed Brown   }
1268bff4a2f0SMatthew G. Knepley   if (bz == DM_BOUNDARY_PERIODIC) {
1269b1757049SJed Brown     ratiok = mz/Mz;
1270*08401ef6SPierre Jolivet     PetscCheck(ratiok*Mz == mz,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mz/Mz  must be integer: mz %D My %D",mz,Mz);
1271b1757049SJed Brown   } else {
1272b1757049SJed Brown     ratiok = (mz-1)/(Mz-1);
12732c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ratiok*(Mz-1) != mz-1,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %D Mz %D",mz,Mz);
1274b1757049SJed Brown   }
1275b1757049SJed Brown 
12769566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf,&i_start,&j_start,&k_start,&m_f,&n_f,&p_f));
12779566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&k_start_ghost,&m_ghost,&n_ghost,&p_ghost));
12789566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf,&ltog_f));
12799566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f));
1280b1757049SJed Brown 
12819566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac,&i_start_c,&j_start_c,&k_start_c,&m_c,&n_c,&p_c));
12829566063dSJacob 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));
12839566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac,&ltog_c));
12849566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c));
1285b1757049SJed Brown 
1286b1757049SJed Brown   /* loop over local fine grid nodes setting interpolation for those*/
1287b1757049SJed Brown   nc   = 0;
12889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n_f*m_f*p_f,&cols));
1289b1757049SJed Brown   for (k=k_start_c; k<k_start_c+p_c; k++) {
1290b1757049SJed Brown     for (j=j_start_c; j<j_start_c+n_c; j++) {
1291b1757049SJed Brown       for (i=i_start_c; i<i_start_c+m_c; i++) {
1292b1757049SJed Brown         PetscInt i_f = i*ratioi,j_f = j*ratioj,k_f = k*ratiok;
12932c71b3e2SJacob Faibussowitsch         PetscCheckFalse(k_f < k_start_ghost || k_f >= k_start_ghost+p_ghost,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA  "
1294b1757049SJed Brown                                                                           "k_c %D k_f %D fine ghost range [%D,%D]",k,k_f,k_start_ghost,k_start_ghost+p_ghost);
12952c71b3e2SJacob Faibussowitsch         PetscCheckFalse(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  "
1296b1757049SJed Brown                                                                           "j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
12972c71b3e2SJacob Faibussowitsch         PetscCheckFalse(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  "
1298b1757049SJed Brown                                                                           "i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1299e3fbd1f4SBarry 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))];
1300e3fbd1f4SBarry Smith         cols[nc++] = row;
1301b1757049SJed Brown       }
1302b1757049SJed Brown     }
1303b1757049SJed Brown   }
13049566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f));
13059566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c));
1306b1757049SJed Brown 
13079566063dSJacob Faibussowitsch   PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf));
13089566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dac,&vecc));
13099566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(daf,&vecf));
13109566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(vecf,isf,vecc,NULL,inject));
13119566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dac,&vecc));
13129566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(daf,&vecf));
13139566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&isf));
1314b1757049SJed Brown   PetscFunctionReturn(0);
1315b1757049SJed Brown }
1316b1757049SJed Brown 
13176dbf9973SLawrence Mitchell PetscErrorCode  DMCreateInjection_DA(DM dac,DM daf,Mat *mat)
131847c6ae99SBarry Smith {
131947c6ae99SBarry Smith   PetscInt        dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1320bff4a2f0SMatthew G. Knepley   DMBoundaryType  bxc,byc,bzc,bxf,byf,bzf;
1321aa219208SBarry Smith   DMDAStencilType stc,stf;
132260c16ac1SBarry Smith   VecScatter      inject = NULL;
132347c6ae99SBarry Smith 
132447c6ae99SBarry Smith   PetscFunctionBegin;
132547c6ae99SBarry Smith   PetscValidHeaderSpecific(dac,DM_CLASSID,1);
132647c6ae99SBarry Smith   PetscValidHeaderSpecific(daf,DM_CLASSID,2);
13276dbf9973SLawrence Mitchell   PetscValidPointer(mat,3);
132847c6ae99SBarry Smith 
13299566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc));
13309566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf));
1331*08401ef6SPierre Jolivet   PetscCheck(dimc == dimf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
1332*08401ef6SPierre Jolivet   PetscCheck(dofc == doff,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
1333*08401ef6SPierre Jolivet   PetscCheck(sc == sf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
13342c71b3e2SJacob Faibussowitsch   PetscCheckFalse(bxc != bxf || byc != byf || bzc != bzf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
1335*08401ef6SPierre Jolivet   PetscCheck(stc == stf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
1336*08401ef6SPierre Jolivet   PetscCheck(Mc >= 2,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
13372c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dimc > 1 && Nc < 2,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
13382c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dimc > 2 && Pc < 2,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");
133947c6ae99SBarry Smith 
13400bb2b966SJungho Lee   if (dimc == 1) {
13419566063dSJacob Faibussowitsch     PetscCall(DMCreateInjection_DA_1D(dac,daf,&inject));
13420bb2b966SJungho Lee   } else if (dimc == 2) {
13439566063dSJacob Faibussowitsch     PetscCall(DMCreateInjection_DA_2D(dac,daf,&inject));
1344b1757049SJed Brown   } else if (dimc == 3) {
13459566063dSJacob Faibussowitsch     PetscCall(DMCreateInjection_DA_3D(dac,daf,&inject));
134647c6ae99SBarry Smith   }
13479566063dSJacob Faibussowitsch   PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)inject), inject, mat));
13489566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&inject));
134947c6ae99SBarry Smith   PetscFunctionReturn(0);
135047c6ae99SBarry Smith }
135147c6ae99SBarry Smith 
135297779f9aSLisandro Dalcin /*@
135397779f9aSLisandro Dalcin    DMCreateAggregates - Deprecated, see DMDACreateAggregates.
13546c877ef6SSatish Balay 
13556c877ef6SSatish Balay    Level: intermediate
135697779f9aSLisandro Dalcin @*/
1357a5bc1bf3SBarry Smith PetscErrorCode DMCreateAggregates(DM dac,DM daf,Mat *mat)
135897779f9aSLisandro Dalcin {
1359a5bc1bf3SBarry Smith   return DMDACreateAggregates(dac,daf,mat);
136097779f9aSLisandro Dalcin }
136197779f9aSLisandro Dalcin 
136297779f9aSLisandro Dalcin /*@
136397779f9aSLisandro Dalcin    DMDACreateAggregates - Gets the aggregates that map between
136497779f9aSLisandro Dalcin    grids associated with two DMDAs.
136597779f9aSLisandro Dalcin 
136697779f9aSLisandro Dalcin    Collective on dmc
136797779f9aSLisandro Dalcin 
136897779f9aSLisandro Dalcin    Input Parameters:
136997779f9aSLisandro Dalcin +  dmc - the coarse grid DMDA
137097779f9aSLisandro Dalcin -  dmf - the fine grid DMDA
137197779f9aSLisandro Dalcin 
137297779f9aSLisandro Dalcin    Output Parameters:
137397779f9aSLisandro Dalcin .  rest - the restriction matrix (transpose of the projection matrix)
137497779f9aSLisandro Dalcin 
137597779f9aSLisandro Dalcin    Level: intermediate
137697779f9aSLisandro Dalcin 
137797779f9aSLisandro Dalcin    Note: This routine is not used by PETSc.
137897779f9aSLisandro Dalcin    It is not clear what its use case is and it may be removed in a future release.
137997779f9aSLisandro Dalcin    Users should contact petsc-maint@mcs.anl.gov if they plan to use it.
138097779f9aSLisandro Dalcin 
138197779f9aSLisandro Dalcin .seealso: DMRefine(), DMCreateInjection(), DMCreateInterpolation()
138297779f9aSLisandro Dalcin @*/
138397779f9aSLisandro Dalcin PetscErrorCode DMDACreateAggregates(DM dac,DM daf,Mat *rest)
138447c6ae99SBarry Smith {
138547c6ae99SBarry Smith   PetscErrorCode         ierr;
138647c6ae99SBarry Smith   PetscInt               dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc;
138747c6ae99SBarry Smith   PetscInt               dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1388bff4a2f0SMatthew G. Knepley   DMBoundaryType         bxc,byc,bzc,bxf,byf,bzf;
1389aa219208SBarry Smith   DMDAStencilType        stc,stf;
139047c6ae99SBarry Smith   PetscInt               i,j,l;
139147c6ae99SBarry Smith   PetscInt               i_start,j_start,l_start, m_f,n_f,p_f;
139247c6ae99SBarry Smith   PetscInt               i_start_ghost,j_start_ghost,l_start_ghost,m_ghost,n_ghost,p_ghost;
13938ea3bf28SBarry Smith   const PetscInt         *idx_f;
139447c6ae99SBarry Smith   PetscInt               i_c,j_c,l_c;
139547c6ae99SBarry Smith   PetscInt               i_start_c,j_start_c,l_start_c, m_c,n_c,p_c;
139647c6ae99SBarry Smith   PetscInt               i_start_ghost_c,j_start_ghost_c,l_start_ghost_c,m_ghost_c,n_ghost_c,p_ghost_c;
13978ea3bf28SBarry Smith   const PetscInt         *idx_c;
139847c6ae99SBarry Smith   PetscInt               d;
139947c6ae99SBarry Smith   PetscInt               a;
140047c6ae99SBarry Smith   PetscInt               max_agg_size;
140147c6ae99SBarry Smith   PetscInt               *fine_nodes;
140247c6ae99SBarry Smith   PetscScalar            *one_vec;
140347c6ae99SBarry Smith   PetscInt               fn_idx;
1404565245c5SBarry Smith   ISLocalToGlobalMapping ltogmf,ltogmc;
140547c6ae99SBarry Smith 
140647c6ae99SBarry Smith   PetscFunctionBegin;
140797779f9aSLisandro Dalcin   PetscValidHeaderSpecificType(dac,DM_CLASSID,1,DMDA);
140897779f9aSLisandro Dalcin   PetscValidHeaderSpecificType(daf,DM_CLASSID,2,DMDA);
140947c6ae99SBarry Smith   PetscValidPointer(rest,3);
141047c6ae99SBarry Smith 
14119566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc));
14129566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf));
1413*08401ef6SPierre Jolivet   PetscCheck(dimc == dimf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
1414*08401ef6SPierre Jolivet   PetscCheck(dofc == doff,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
1415*08401ef6SPierre Jolivet   PetscCheck(sc == sf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
14162c71b3e2SJacob Faibussowitsch   PetscCheckFalse(bxc != bxf || byc != byf || bzc != bzf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
1417*08401ef6SPierre Jolivet   PetscCheck(stc == stf,PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
141847c6ae99SBarry Smith 
1419*08401ef6SPierre Jolivet   PetscCheck(Mf >= Mc,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Mc %D, Mf %D", Mc, Mf);
1420*08401ef6SPierre Jolivet   PetscCheck(Nf >= Nc,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Nc %D, Nf %D", Nc, Nf);
1421*08401ef6SPierre Jolivet   PetscCheck(Pf >= Pc,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Pc %D, Pf %D", Pc, Pf);
142247c6ae99SBarry Smith 
142347c6ae99SBarry Smith   if (Pc < 0) Pc = 1;
142447c6ae99SBarry Smith   if (Pf < 0) Pf = 1;
142547c6ae99SBarry Smith   if (Nc < 0) Nc = 1;
142647c6ae99SBarry Smith   if (Nf < 0) Nf = 1;
142747c6ae99SBarry Smith 
14289566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f));
14299566063dSJacob Faibussowitsch   PetscCall(DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost));
1430565245c5SBarry Smith 
14319566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(daf,&ltogmf));
14329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(ltogmf,&idx_f));
143347c6ae99SBarry Smith 
14349566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c));
14359566063dSJacob 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));
1436565245c5SBarry Smith 
14379566063dSJacob Faibussowitsch   PetscCall(DMGetLocalToGlobalMapping(dac,&ltogmc));
14389566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetIndices(ltogmc,&idx_c));
143947c6ae99SBarry Smith 
144047c6ae99SBarry Smith   /*
144147c6ae99SBarry Smith      Basic idea is as follows. Here's a 2D example, suppose r_x, r_y are the ratios
144247c6ae99SBarry Smith      for dimension 1 and 2 respectively.
144347c6ae99SBarry Smith      Let (i,j) be a coarse grid node. All the fine grid nodes between r_x*i and r_x*(i+1)
144447c6ae99SBarry Smith      and r_y*j and r_y*(j+1) will be grouped into the same coarse grid agregate.
144547c6ae99SBarry Smith      Each specific dof on the fine grid is mapped to one dof on the coarse grid.
144647c6ae99SBarry Smith   */
144747c6ae99SBarry Smith 
144847c6ae99SBarry Smith   max_agg_size = (Mf/Mc+1)*(Nf/Nc+1)*(Pf/Pc+1);
144947c6ae99SBarry Smith 
145047c6ae99SBarry Smith   /* create the matrix that will contain the restriction operator */
1451ce94432eSBarry Smith   ierr = 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,
14529566063dSJacob Faibussowitsch                       max_agg_size, NULL, max_agg_size, NULL, rest);PetscCall(ierr);
145347c6ae99SBarry Smith 
145447c6ae99SBarry Smith   /* store nodes in the fine grid here */
14559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(max_agg_size, &one_vec,max_agg_size, &fine_nodes));
145647c6ae99SBarry Smith   for (i=0; i<max_agg_size; i++) one_vec[i] = 1.0;
145747c6ae99SBarry Smith 
145847c6ae99SBarry Smith   /* loop over all coarse nodes */
145947c6ae99SBarry Smith   for (l_c=l_start_c; l_c<l_start_c+p_c; l_c++) {
146047c6ae99SBarry Smith     for (j_c=j_start_c; j_c<j_start_c+n_c; j_c++) {
146147c6ae99SBarry Smith       for (i_c=i_start_c; i_c<i_start_c+m_c; i_c++) {
146247c6ae99SBarry Smith         for (d=0; d<dofc; d++) {
146347c6ae99SBarry Smith           /* convert to local "natural" numbering and then to PETSc global numbering */
146447c6ae99SBarry 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;
146547c6ae99SBarry Smith 
146647c6ae99SBarry Smith           fn_idx = 0;
146747c6ae99SBarry Smith           /* Corresponding fine points are all points (i_f, j_f, l_f) such that
146847c6ae99SBarry Smith              i_c*Mf/Mc <= i_f < (i_c+1)*Mf/Mc
146947c6ae99SBarry Smith              (same for other dimensions)
147047c6ae99SBarry Smith           */
147147c6ae99SBarry Smith           for (l=l_c*Pf/Pc; l<PetscMin((l_c+1)*Pf/Pc,Pf); l++) {
147247c6ae99SBarry Smith             for (j=j_c*Nf/Nc; j<PetscMin((j_c+1)*Nf/Nc,Nf); j++) {
147347c6ae99SBarry Smith               for (i=i_c*Mf/Mc; i<PetscMin((i_c+1)*Mf/Mc,Mf); i++) {
147447c6ae99SBarry 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;
147547c6ae99SBarry Smith                 fn_idx++;
147647c6ae99SBarry Smith               }
147747c6ae99SBarry Smith             }
147847c6ae99SBarry Smith           }
147947c6ae99SBarry Smith           /* add all these points to one aggregate */
14809566063dSJacob Faibussowitsch           PetscCall(MatSetValues(*rest, 1, &a, fn_idx, fine_nodes, one_vec, INSERT_VALUES));
148147c6ae99SBarry Smith         }
148247c6ae99SBarry Smith       }
148347c6ae99SBarry Smith     }
148447c6ae99SBarry Smith   }
14859566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogmf,&idx_f));
14869566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogmc,&idx_c));
14879566063dSJacob Faibussowitsch   PetscCall(PetscFree2(one_vec,fine_nodes));
14889566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*rest, MAT_FINAL_ASSEMBLY));
14899566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*rest, MAT_FINAL_ASSEMBLY));
149047c6ae99SBarry Smith   PetscFunctionReturn(0);
149147c6ae99SBarry Smith }
1492