xref: /petsc/src/dm/impls/da/dainterp.c (revision a5bc1bf344cccdca9c53fc2bcd040c7b504fff0e)
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   PetscErrorCode ierr;
25fdc842d1SBarry Smith   PetscInt       i;
26fdc842d1SBarry Smith   char           const *types[3] = {MATAIJ,MATSEQAIJ,MATMPIAIJ};
27fdc842d1SBarry Smith   PetscBool      flg;
28fdc842d1SBarry Smith 
29fdc842d1SBarry Smith   PetscFunctionBegin;
3033a4d587SStefano Zampini   *outtype = MATAIJ;
31fdc842d1SBarry Smith   for (i=0; i<3; i++) {
32fdc842d1SBarry Smith     ierr = PetscStrbeginswith(intype,types[i],&flg);CHKERRQ(ierr);
33fdc842d1SBarry Smith     if (flg) {
34fdc842d1SBarry Smith       *outtype = intype;
35fdc842d1SBarry Smith       PetscFunctionReturn(0);
36fdc842d1SBarry Smith     }
37fdc842d1SBarry Smith   }
38fdc842d1SBarry Smith   PetscFunctionReturn(0);
39fdc842d1SBarry Smith }
40fdc842d1SBarry Smith 
41e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_1D_Q1(DM dac,DM daf,Mat *A)
4247c6ae99SBarry Smith {
4347c6ae99SBarry Smith   PetscErrorCode         ierr;
448ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx;
458ea3bf28SBarry Smith   const PetscInt         *idx_f,*idx_c;
468ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
4747c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,mx,m_c,nc,ratio;
4847c6ae99SBarry Smith   PetscInt               i_c,i_start_c,i_start_ghost_c,cols[2],dof;
4985afcc9aSBarry Smith   PetscScalar            v[2],x;
5047c6ae99SBarry Smith   Mat                    mat;
51bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
52e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
53fdc842d1SBarry Smith   MatType                mattype;
5447c6ae99SBarry Smith 
5547c6ae99SBarry Smith   PetscFunctionBegin;
561321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);CHKERRQ(ierr);
571321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
58bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
5947c6ae99SBarry Smith     ratio = mx/Mx;
6047c6ae99SBarry Smith     if (ratio*Mx != mx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
6147c6ae99SBarry Smith   } else {
6247c6ae99SBarry Smith     ratio = (mx-1)/(Mx-1);
6347c6ae99SBarry Smith     if (ratio*(Mx-1) != mx-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
6447c6ae99SBarry Smith   }
6547c6ae99SBarry Smith 
66aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);CHKERRQ(ierr);
67aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);CHKERRQ(ierr);
6845b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
6945b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
7047c6ae99SBarry Smith 
71aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);CHKERRQ(ierr);
72aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);CHKERRQ(ierr);
7345b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
7445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
7547c6ae99SBarry Smith 
7647c6ae99SBarry Smith   /* create interpolation matrix */
77ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)dac),&mat);CHKERRQ(ierr);
78fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
79fdc842d1SBarry Smith   /*
80fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
81fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
82fdc842d1SBarry Smith    */
83fdc842d1SBarry Smith   if (dof > 1) {
84b470e4b4SRichard Tran Mills     ierr = MatBindToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
85fdc842d1SBarry Smith   }
86fdc842d1SBarry Smith   #endif
8747c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f,m_c,mx,Mx);CHKERRQ(ierr);
88fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
89fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
900298fd71SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,2,NULL);CHKERRQ(ierr);
910298fd71SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,2,NULL,1,NULL);CHKERRQ(ierr);
9247c6ae99SBarry Smith 
9347c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
9485afcc9aSBarry Smith   if (!NEWVERSION) {
95b3bd94feSDave May 
9647c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
9747c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
98e3fbd1f4SBarry Smith       row = idx_f[i-i_start_ghost];
9947c6ae99SBarry Smith 
10047c6ae99SBarry Smith       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
101aa219208SBarry Smith       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
10247c6ae99SBarry Smith                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
10347c6ae99SBarry Smith 
10447c6ae99SBarry Smith       /*
10547c6ae99SBarry Smith        Only include those interpolation points that are truly
10647c6ae99SBarry Smith        nonzero. Note this is very important for final grid lines
10747c6ae99SBarry Smith        in x direction; since they have no right neighbor
10847c6ae99SBarry Smith        */
1096712e2f1SBarry Smith       x  = ((PetscReal)(i - i_c*ratio))/((PetscReal)ratio);
11047c6ae99SBarry Smith       nc = 0;
11147c6ae99SBarry Smith       /* one left and below; or we are right on it */
112e3fbd1f4SBarry Smith       col      = (i_c-i_start_ghost_c);
113e3fbd1f4SBarry Smith       cols[nc] = idx_c[col];
11447c6ae99SBarry Smith       v[nc++]  = -x + 1.0;
11547c6ae99SBarry Smith       /* one right? */
11647c6ae99SBarry Smith       if (i_c*ratio != i) {
117e3fbd1f4SBarry Smith         cols[nc] = idx_c[col+1];
11847c6ae99SBarry Smith         v[nc++]  = x;
11947c6ae99SBarry Smith       }
12047c6ae99SBarry Smith       ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
12147c6ae99SBarry Smith     }
122b3bd94feSDave May 
123b3bd94feSDave May   } else {
124b3bd94feSDave May     PetscScalar *xi;
125b3bd94feSDave May     PetscInt    li,nxi,n;
126b3bd94feSDave May     PetscScalar Ni[2];
127b3bd94feSDave May 
128b3bd94feSDave May     /* compute local coordinate arrays */
129b3bd94feSDave May     nxi  = ratio + 1;
130854ce69bSBarry Smith     ierr = PetscMalloc1(nxi,&xi);CHKERRQ(ierr);
131b3bd94feSDave May     for (li=0; li<nxi; li++) {
13252218ef2SJed Brown       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
133b3bd94feSDave May     }
134b3bd94feSDave May 
135b3bd94feSDave May     for (i=i_start; i<i_start+m_f; i++) {
136b3bd94feSDave May       /* convert to local "natural" numbering and then to PETSc global numbering */
137e3fbd1f4SBarry Smith       row = idx_f[(i-i_start_ghost)];
138b3bd94feSDave May 
139b3bd94feSDave May       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
140b3bd94feSDave May       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
141b3bd94feSDave May                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
142b3bd94feSDave May 
143b3bd94feSDave May       /* remainders */
144b3bd94feSDave May       li = i - ratio * (i/ratio);
1458865f1eaSKarl Rupp       if (i==mx-1) li = nxi-1;
146b3bd94feSDave May 
147b3bd94feSDave May       /* corners */
148e3fbd1f4SBarry Smith       col     = (i_c-i_start_ghost_c);
149e3fbd1f4SBarry Smith       cols[0] = idx_c[col];
150b3bd94feSDave May       Ni[0]   = 1.0;
151b3bd94feSDave May       if ((li==0) || (li==nxi-1)) {
152b3bd94feSDave May         ierr = MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);CHKERRQ(ierr);
153b3bd94feSDave May         continue;
154b3bd94feSDave May       }
155b3bd94feSDave May 
156b3bd94feSDave May       /* edges + interior */
157b3bd94feSDave May       /* remainders */
1588865f1eaSKarl Rupp       if (i==mx-1) i_c--;
159b3bd94feSDave May 
160e3fbd1f4SBarry Smith       col     = (i_c-i_start_ghost_c);
161e3fbd1f4SBarry Smith       cols[0] = idx_c[col]; /* one left and below; or we are right on it */
162e3fbd1f4SBarry Smith       cols[1] = idx_c[col+1];
163b3bd94feSDave May 
164b3bd94feSDave May       Ni[0] = 0.5*(1.0-xi[li]);
165b3bd94feSDave May       Ni[1] = 0.5*(1.0+xi[li]);
166b3bd94feSDave May       for (n=0; n<2; n++) {
1678865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[n])<1.0e-32) cols[n]=-1;
168b3bd94feSDave May       }
169b3bd94feSDave May       ierr = MatSetValues(mat,1,&row,2,cols,Ni,INSERT_VALUES);CHKERRQ(ierr);
170b3bd94feSDave May     }
171b3bd94feSDave May     ierr = PetscFree(xi);CHKERRQ(ierr);
172b3bd94feSDave May   }
17345b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
17445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
17547c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
17647c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
17747c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
178fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
17947c6ae99SBarry Smith   PetscFunctionReturn(0);
18047c6ae99SBarry Smith }
18147c6ae99SBarry Smith 
182e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_1D_Q0(DM dac,DM daf,Mat *A)
18347c6ae99SBarry Smith {
18447c6ae99SBarry Smith   PetscErrorCode         ierr;
1858ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx;
1868ea3bf28SBarry Smith   const PetscInt         *idx_f,*idx_c;
187e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
1888ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
18947c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,mx,m_c,nc,ratio;
19047c6ae99SBarry Smith   PetscInt               i_c,i_start_c,i_start_ghost_c,cols[2],dof;
19147c6ae99SBarry Smith   PetscScalar            v[2],x;
19247c6ae99SBarry Smith   Mat                    mat;
193bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
194fdc842d1SBarry Smith   MatType                mattype;
19547c6ae99SBarry Smith 
19647c6ae99SBarry Smith   PetscFunctionBegin;
1971321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);CHKERRQ(ierr);
1981321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
199bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
2003a586487SStefano Zampini     if (!Mx) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
20147c6ae99SBarry Smith     ratio = mx/Mx;
20247c6ae99SBarry Smith     if (ratio*Mx != mx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
20347c6ae99SBarry Smith   } else {
2043a586487SStefano Zampini     if (Mx < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be greater than 1",Mx);
20547c6ae99SBarry Smith     ratio = (mx-1)/(Mx-1);
20647c6ae99SBarry Smith     if (ratio*(Mx-1) != mx-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
20747c6ae99SBarry Smith   }
20847c6ae99SBarry Smith 
209aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);CHKERRQ(ierr);
210aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);CHKERRQ(ierr);
21145b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
21245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
21347c6ae99SBarry Smith 
214aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);CHKERRQ(ierr);
215aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);CHKERRQ(ierr);
21645b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
21745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
21847c6ae99SBarry Smith 
21947c6ae99SBarry Smith   /* create interpolation matrix */
220ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)dac),&mat);CHKERRQ(ierr);
221fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
222fdc842d1SBarry Smith   /*
223fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
224fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
225fdc842d1SBarry Smith    */
226fdc842d1SBarry Smith   if (dof > 1) {
227b470e4b4SRichard Tran Mills     ierr = MatBindToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
228fdc842d1SBarry Smith   }
229fdc842d1SBarry Smith   #endif
23047c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f,m_c,mx,Mx);CHKERRQ(ierr);
231fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
232fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
2330298fd71SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,2,NULL);CHKERRQ(ierr);
2340298fd71SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,2,NULL,0,NULL);CHKERRQ(ierr);
23547c6ae99SBarry Smith 
23647c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
23747c6ae99SBarry Smith   for (i=i_start; i<i_start+m_f; i++) {
23847c6ae99SBarry Smith     /* convert to local "natural" numbering and then to PETSc global numbering */
239e3fbd1f4SBarry Smith     row = idx_f[(i-i_start_ghost)];
24047c6ae99SBarry Smith 
24147c6ae99SBarry Smith     i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
24247c6ae99SBarry Smith 
24347c6ae99SBarry Smith     /*
24447c6ae99SBarry Smith          Only include those interpolation points that are truly
24547c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
24647c6ae99SBarry Smith          in x direction; since they have no right neighbor
24747c6ae99SBarry Smith     */
2486712e2f1SBarry Smith     x  = ((PetscReal)(i - i_c*ratio))/((PetscReal)ratio);
24947c6ae99SBarry Smith     nc = 0;
25047c6ae99SBarry Smith     /* one left and below; or we are right on it */
251e3fbd1f4SBarry Smith     col      = (i_c-i_start_ghost_c);
252e3fbd1f4SBarry Smith     cols[nc] = idx_c[col];
25347c6ae99SBarry Smith     v[nc++]  = -x + 1.0;
25447c6ae99SBarry Smith     /* one right? */
25547c6ae99SBarry Smith     if (i_c*ratio != i) {
256e3fbd1f4SBarry Smith       cols[nc] = idx_c[col+1];
25747c6ae99SBarry Smith       v[nc++]  = x;
25847c6ae99SBarry Smith     }
25947c6ae99SBarry Smith     ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
26047c6ae99SBarry Smith   }
26145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
26245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
26347c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
26447c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
26547c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
266fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
26747c6ae99SBarry Smith   ierr = PetscLogFlops(5.0*m_f);CHKERRQ(ierr);
26847c6ae99SBarry Smith   PetscFunctionReturn(0);
26947c6ae99SBarry Smith }
27047c6ae99SBarry Smith 
271e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_2D_Q1(DM dac,DM daf,Mat *A)
27247c6ae99SBarry Smith {
27347c6ae99SBarry Smith   PetscErrorCode         ierr;
2748ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
2758ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
276e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
2778ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,*dnz,*onz;
27847c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
27947c6ae99SBarry 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;
28047c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
28147c6ae99SBarry Smith   PetscScalar            v[4],x,y;
28247c6ae99SBarry Smith   Mat                    mat;
283bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
284fdc842d1SBarry Smith   MatType                mattype;
28547c6ae99SBarry Smith 
28647c6ae99SBarry Smith   PetscFunctionBegin;
2871321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);CHKERRQ(ierr);
2881321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
289bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
2903a586487SStefano Zampini     if (!Mx) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
29147c6ae99SBarry Smith     ratioi = mx/Mx;
29247c6ae99SBarry Smith     if (ratioi*Mx != mx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
29347c6ae99SBarry Smith   } else {
2943a586487SStefano Zampini     if (Mx < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be greater than 1",Mx);
29547c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
29647c6ae99SBarry Smith     if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
29747c6ae99SBarry Smith   }
298bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
2993a586487SStefano Zampini     if (!My) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
30047c6ae99SBarry Smith     ratioj = my/My;
30147c6ae99SBarry Smith     if (ratioj*My != my) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
30247c6ae99SBarry Smith   } else {
3033a586487SStefano Zampini     if (My < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be greater than 1",My);
30447c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
30547c6ae99SBarry Smith     if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
30647c6ae99SBarry Smith   }
30747c6ae99SBarry Smith 
308aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);CHKERRQ(ierr);
309aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);CHKERRQ(ierr);
31045b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
31145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
31247c6ae99SBarry Smith 
313aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);CHKERRQ(ierr);
314aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);CHKERRQ(ierr);
31545b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
31645b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
31747c6ae99SBarry Smith 
31847c6ae99SBarry Smith   /*
319aa219208SBarry Smith    Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
32047c6ae99SBarry Smith    The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
32147c6ae99SBarry Smith    processors). It's effective length is hence 4 times its normal length, this is
32247c6ae99SBarry Smith    why the col_scale is multiplied by the interpolation matrix column sizes.
32347c6ae99SBarry Smith    sol_shift allows each set of 1/4 processors do its own interpolation using ITS
32447c6ae99SBarry Smith    copy of the coarse vector. A bit of a hack but you do better.
32547c6ae99SBarry Smith 
32647c6ae99SBarry Smith    In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
32747c6ae99SBarry Smith    */
328ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);CHKERRQ(ierr);
329ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);CHKERRQ(ierr);
330ce94432eSBarry Smith   ierr      = MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);CHKERRQ(ierr);
33147c6ae99SBarry Smith   col_scale = size_f/size_c;
33247c6ae99SBarry Smith   col_shift = Mx*My*(rank_f/size_c);
33347c6ae99SBarry Smith 
334ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f,col_scale*m_c*n_c,dnz,onz);CHKERRQ(ierr);
33547c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
33647c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
33747c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
338e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
33947c6ae99SBarry Smith 
34047c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
34147c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
34247c6ae99SBarry Smith 
343aa219208SBarry Smith       if (j_c < j_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
34447c6ae99SBarry Smith                                           j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
345aa219208SBarry Smith       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
34647c6ae99SBarry Smith                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
34747c6ae99SBarry Smith 
34847c6ae99SBarry Smith       /*
34947c6ae99SBarry Smith        Only include those interpolation points that are truly
35047c6ae99SBarry Smith        nonzero. Note this is very important for final grid lines
35147c6ae99SBarry Smith        in x and y directions; since they have no right/top neighbors
35247c6ae99SBarry Smith        */
35347c6ae99SBarry Smith       nc = 0;
35447c6ae99SBarry Smith       /* one left and below; or we are right on it */
355e3fbd1f4SBarry Smith       col        = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
356e3fbd1f4SBarry Smith       cols[nc++] = col_shift + idx_c[col];
35747c6ae99SBarry Smith       /* one right and below */
358e3fbd1f4SBarry Smith       if (i_c*ratioi != i) cols[nc++] = col_shift + idx_c[col+1];
35947c6ae99SBarry Smith       /* one left and above */
360e3fbd1f4SBarry Smith       if (j_c*ratioj != j) cols[nc++] = col_shift + idx_c[col+m_ghost_c];
36147c6ae99SBarry Smith       /* one right and above */
362e3fbd1f4SBarry Smith       if (i_c*ratioi != i && j_c*ratioj != j) cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)];
36347c6ae99SBarry Smith       ierr = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
36447c6ae99SBarry Smith     }
36547c6ae99SBarry Smith   }
366ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)daf),&mat);CHKERRQ(ierr);
367fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
368fdc842d1SBarry Smith   /*
369fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
370fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
371fdc842d1SBarry Smith   */
372fdc842d1SBarry Smith   if (dof > 1) {
373b470e4b4SRichard Tran Mills     ierr = MatBindToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
374fdc842d1SBarry Smith   }
375fdc842d1SBarry Smith #endif
37647c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);CHKERRQ(ierr);
377fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
378fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
37947c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
38047c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
38147c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
38247c6ae99SBarry Smith 
38347c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
38485afcc9aSBarry Smith   if (!NEWVERSION) {
385b3bd94feSDave May 
38647c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
38747c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
38847c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
389e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
39047c6ae99SBarry Smith 
39147c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
39247c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
39347c6ae99SBarry Smith 
39447c6ae99SBarry Smith         /*
39547c6ae99SBarry Smith          Only include those interpolation points that are truly
39647c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
39747c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
39847c6ae99SBarry Smith          */
3996712e2f1SBarry Smith         x = ((PetscReal)(i - i_c*ratioi))/((PetscReal)ratioi);
4006712e2f1SBarry Smith         y = ((PetscReal)(j - j_c*ratioj))/((PetscReal)ratioj);
401b3bd94feSDave May 
40247c6ae99SBarry Smith         nc = 0;
40347c6ae99SBarry Smith         /* one left and below; or we are right on it */
404e3fbd1f4SBarry Smith         col      = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
405e3fbd1f4SBarry Smith         cols[nc] = col_shift + idx_c[col];
40647c6ae99SBarry Smith         v[nc++]  = x*y - x - y + 1.0;
40747c6ae99SBarry Smith         /* one right and below */
40847c6ae99SBarry Smith         if (i_c*ratioi != i) {
409e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+1];
41047c6ae99SBarry Smith           v[nc++]  = -x*y + x;
41147c6ae99SBarry Smith         }
41247c6ae99SBarry Smith         /* one left and above */
41347c6ae99SBarry Smith         if (j_c*ratioj != j) {
414e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+m_ghost_c];
41547c6ae99SBarry Smith           v[nc++]  = -x*y + y;
41647c6ae99SBarry Smith         }
41747c6ae99SBarry Smith         /* one right and above */
41847c6ae99SBarry Smith         if (j_c*ratioj != j && i_c*ratioi != i) {
419e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)];
42047c6ae99SBarry Smith           v[nc++]  = x*y;
42147c6ae99SBarry Smith         }
42247c6ae99SBarry Smith         ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
42347c6ae99SBarry Smith       }
42447c6ae99SBarry Smith     }
425b3bd94feSDave May 
426b3bd94feSDave May   } else {
427b3bd94feSDave May     PetscScalar Ni[4];
428b3bd94feSDave May     PetscScalar *xi,*eta;
429b3bd94feSDave May     PetscInt    li,nxi,lj,neta;
430b3bd94feSDave May 
431b3bd94feSDave May     /* compute local coordinate arrays */
432b3bd94feSDave May     nxi  = ratioi + 1;
433b3bd94feSDave May     neta = ratioj + 1;
434854ce69bSBarry Smith     ierr = PetscMalloc1(nxi,&xi);CHKERRQ(ierr);
435854ce69bSBarry Smith     ierr = PetscMalloc1(neta,&eta);CHKERRQ(ierr);
436b3bd94feSDave May     for (li=0; li<nxi; li++) {
43752218ef2SJed Brown       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
438b3bd94feSDave May     }
439b3bd94feSDave May     for (lj=0; lj<neta; lj++) {
44052218ef2SJed Brown       eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
441b3bd94feSDave May     }
442b3bd94feSDave May 
443b3bd94feSDave May     /* loop over local fine grid nodes setting interpolation for those*/
444b3bd94feSDave May     for (j=j_start; j<j_start+n_f; j++) {
445b3bd94feSDave May       for (i=i_start; i<i_start+m_f; i++) {
446b3bd94feSDave May         /* convert to local "natural" numbering and then to PETSc global numbering */
447e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
448b3bd94feSDave May 
449b3bd94feSDave May         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
450b3bd94feSDave May         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
451b3bd94feSDave May 
452b3bd94feSDave May         /* remainders */
453b3bd94feSDave May         li = i - ratioi * (i/ratioi);
4548865f1eaSKarl Rupp         if (i==mx-1) li = nxi-1;
455b3bd94feSDave May         lj = j - ratioj * (j/ratioj);
4568865f1eaSKarl Rupp         if (j==my-1) lj = neta-1;
457b3bd94feSDave May 
458b3bd94feSDave May         /* corners */
459e3fbd1f4SBarry Smith         col     = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
460e3fbd1f4SBarry Smith         cols[0] = col_shift + idx_c[col]; /* left, below */
461b3bd94feSDave May         Ni[0]   = 1.0;
462b3bd94feSDave May         if ((li==0) || (li==nxi-1)) {
463b3bd94feSDave May           if ((lj==0) || (lj==neta-1)) {
464b3bd94feSDave May             ierr = MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);CHKERRQ(ierr);
465b3bd94feSDave May             continue;
466b3bd94feSDave May           }
467b3bd94feSDave May         }
468b3bd94feSDave May 
469b3bd94feSDave May         /* edges + interior */
470b3bd94feSDave May         /* remainders */
4718865f1eaSKarl Rupp         if (i==mx-1) i_c--;
4728865f1eaSKarl Rupp         if (j==my-1) j_c--;
473b3bd94feSDave May 
474e3fbd1f4SBarry Smith         col     = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
475e3fbd1f4SBarry Smith         cols[0] = col_shift + idx_c[col]; /* left, below */
476e3fbd1f4SBarry Smith         cols[1] = col_shift + idx_c[col+1]; /* right, below */
477e3fbd1f4SBarry Smith         cols[2] = col_shift + idx_c[col+m_ghost_c]; /* left, above */
478e3fbd1f4SBarry Smith         cols[3] = col_shift + idx_c[col+(m_ghost_c+1)]; /* right, above */
479b3bd94feSDave May 
480b3bd94feSDave May         Ni[0] = 0.25*(1.0-xi[li])*(1.0-eta[lj]);
481b3bd94feSDave May         Ni[1] = 0.25*(1.0+xi[li])*(1.0-eta[lj]);
482b3bd94feSDave May         Ni[2] = 0.25*(1.0-xi[li])*(1.0+eta[lj]);
483b3bd94feSDave May         Ni[3] = 0.25*(1.0+xi[li])*(1.0+eta[lj]);
484b3bd94feSDave May 
485b3bd94feSDave May         nc = 0;
4868865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[0])<1.0e-32) cols[0]=-1;
4878865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[1])<1.0e-32) cols[1]=-1;
4888865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[2])<1.0e-32) cols[2]=-1;
4898865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[3])<1.0e-32) cols[3]=-1;
490b3bd94feSDave May 
491b3bd94feSDave May         ierr = MatSetValues(mat,1,&row,4,cols,Ni,INSERT_VALUES);CHKERRQ(ierr);
492b3bd94feSDave May       }
493b3bd94feSDave May     }
494b3bd94feSDave May     ierr = PetscFree(xi);CHKERRQ(ierr);
495b3bd94feSDave May     ierr = PetscFree(eta);CHKERRQ(ierr);
496b3bd94feSDave May   }
49745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
49845b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
49947c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
50047c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
50147c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
502fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
50347c6ae99SBarry Smith   PetscFunctionReturn(0);
50447c6ae99SBarry Smith }
50547c6ae99SBarry Smith 
50647c6ae99SBarry Smith /*
50747c6ae99SBarry Smith        Contributed by Andrei Draganescu <aidraga@sandia.gov>
50847c6ae99SBarry Smith */
509e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_2D_Q0(DM dac,DM daf,Mat *A)
51047c6ae99SBarry Smith {
51147c6ae99SBarry Smith   PetscErrorCode         ierr;
5128ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
5138ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
514e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
5158ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,*dnz,*onz;
51647c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
51747c6ae99SBarry 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;
51847c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
51947c6ae99SBarry Smith   PetscScalar            v[4];
52047c6ae99SBarry Smith   Mat                    mat;
521bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
522fdc842d1SBarry Smith   MatType                mattype;
52347c6ae99SBarry Smith 
52447c6ae99SBarry Smith   PetscFunctionBegin;
5251321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);CHKERRQ(ierr);
5261321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
5273a586487SStefano Zampini   if (!Mx) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
5283a586487SStefano Zampini   if (!My) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
52947c6ae99SBarry Smith   ratioi = mx/Mx;
53047c6ae99SBarry Smith   ratioj = my/My;
531ce94432eSBarry Smith   if (ratioi*Mx != mx) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
532ce94432eSBarry Smith   if (ratioj*My != my) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
533ce94432eSBarry Smith   if (ratioi != 2) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 2");
534ce94432eSBarry Smith   if (ratioj != 2) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 2");
53547c6ae99SBarry Smith 
536aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);CHKERRQ(ierr);
537aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);CHKERRQ(ierr);
53845b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
53945b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
54047c6ae99SBarry Smith 
541aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);CHKERRQ(ierr);
542aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);CHKERRQ(ierr);
54345b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
54445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
54547c6ae99SBarry Smith 
54647c6ae99SBarry Smith   /*
547aa219208SBarry Smith      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
54847c6ae99SBarry Smith      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
54947c6ae99SBarry Smith      processors). It's effective length is hence 4 times its normal length, this is
55047c6ae99SBarry Smith      why the col_scale is multiplied by the interpolation matrix column sizes.
55147c6ae99SBarry Smith      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
55247c6ae99SBarry Smith      copy of the coarse vector. A bit of a hack but you do better.
55347c6ae99SBarry Smith 
55447c6ae99SBarry Smith      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
55547c6ae99SBarry Smith   */
556ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);CHKERRQ(ierr);
557ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);CHKERRQ(ierr);
558ce94432eSBarry Smith   ierr      = MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);CHKERRQ(ierr);
55947c6ae99SBarry Smith   col_scale = size_f/size_c;
56047c6ae99SBarry Smith   col_shift = Mx*My*(rank_f/size_c);
56147c6ae99SBarry Smith 
562ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f,col_scale*m_c*n_c,dnz,onz);CHKERRQ(ierr);
56347c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
56447c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
56547c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
566e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
56747c6ae99SBarry Smith 
56847c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
56947c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
57047c6ae99SBarry Smith 
571aa219208SBarry Smith       if (j_c < j_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
57247c6ae99SBarry Smith     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
573aa219208SBarry Smith       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
57447c6ae99SBarry Smith     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
57547c6ae99SBarry Smith 
57647c6ae99SBarry Smith       /*
57747c6ae99SBarry Smith          Only include those interpolation points that are truly
57847c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
57947c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
58047c6ae99SBarry Smith       */
58147c6ae99SBarry Smith       nc = 0;
58247c6ae99SBarry Smith       /* one left and below; or we are right on it */
583e3fbd1f4SBarry Smith       col        = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
584e3fbd1f4SBarry Smith       cols[nc++] = col_shift + idx_c[col];
58547c6ae99SBarry Smith       ierr       = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
58647c6ae99SBarry Smith     }
58747c6ae99SBarry Smith   }
588ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)daf),&mat);CHKERRQ(ierr);
589fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
590fdc842d1SBarry Smith   /*
591fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
592fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
593fdc842d1SBarry Smith   */
594fdc842d1SBarry Smith   if (dof > 1) {
595b470e4b4SRichard Tran Mills     ierr = MatBindToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
596fdc842d1SBarry Smith   }
597fdc842d1SBarry Smith   #endif
59847c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);CHKERRQ(ierr);
599fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
600fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
60147c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
60247c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
60347c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
60447c6ae99SBarry Smith 
60547c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
60647c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
60747c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
60847c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
609e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
61047c6ae99SBarry Smith 
61147c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
61247c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
61347c6ae99SBarry Smith       nc  = 0;
61447c6ae99SBarry Smith       /* one left and below; or we are right on it */
615e3fbd1f4SBarry Smith       col      = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
616e3fbd1f4SBarry Smith       cols[nc] = col_shift + idx_c[col];
61747c6ae99SBarry Smith       v[nc++]  = 1.0;
61847c6ae99SBarry Smith 
61947c6ae99SBarry Smith       ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
62047c6ae99SBarry Smith     }
62147c6ae99SBarry Smith   }
62245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
62345b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
62447c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
62547c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
62647c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
627fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
62847c6ae99SBarry Smith   ierr = PetscLogFlops(13.0*m_f*n_f);CHKERRQ(ierr);
62947c6ae99SBarry Smith   PetscFunctionReturn(0);
63047c6ae99SBarry Smith }
63147c6ae99SBarry Smith 
63247c6ae99SBarry Smith /*
63347c6ae99SBarry Smith        Contributed by Jianming Yang <jianming-yang@uiowa.edu>
63447c6ae99SBarry Smith */
635e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_3D_Q0(DM dac,DM daf,Mat *A)
63647c6ae99SBarry Smith {
63747c6ae99SBarry Smith   PetscErrorCode         ierr;
6388ea3bf28SBarry Smith   PetscInt               i,j,l,i_start,j_start,l_start,m_f,n_f,p_f,Mx,My,Mz,dof;
6398ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
640e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
6418ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,p_ghost,m_ghost_c,n_ghost_c,p_ghost_c,nc,*dnz,*onz;
64247c6ae99SBarry 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;
64347c6ae99SBarry 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;
64447c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
64547c6ae99SBarry Smith   PetscScalar            v[8];
64647c6ae99SBarry Smith   Mat                    mat;
647bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
648fdc842d1SBarry Smith   MatType                mattype;
64947c6ae99SBarry Smith 
65047c6ae99SBarry Smith   PetscFunctionBegin;
6511321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);CHKERRQ(ierr);
6523a586487SStefano Zampini   if (!Mx) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
6533a586487SStefano Zampini   if (!My) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
6543a586487SStefano Zampini   if (!Mz) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of z coarse grid points %D must be positive",Mz);
6551321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
65647c6ae99SBarry Smith   ratioi = mx/Mx;
65747c6ae99SBarry Smith   ratioj = my/My;
65847c6ae99SBarry Smith   ratiol = mz/Mz;
659ce94432eSBarry Smith   if (ratioi*Mx != mx) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
660ce94432eSBarry Smith   if (ratioj*My != my) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
661ce94432eSBarry Smith   if (ratiol*Mz != mz) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in z");
662ce94432eSBarry Smith   if (ratioi != 2 && ratioi != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 1 or 2");
663ce94432eSBarry Smith   if (ratioj != 2 && ratioj != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 1 or 2");
664ce94432eSBarry Smith   if (ratiol != 2 && ratiol != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in z must be 1 or 2");
66547c6ae99SBarry Smith 
666aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
667aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
66845b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
66945b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
67047c6ae99SBarry Smith 
671aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
672aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);CHKERRQ(ierr);
67345b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
67445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
675e3fbd1f4SBarry Smith 
67647c6ae99SBarry Smith   /*
677aa219208SBarry Smith      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
67847c6ae99SBarry Smith      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
67947c6ae99SBarry Smith      processors). It's effective length is hence 4 times its normal length, this is
68047c6ae99SBarry Smith      why the col_scale is multiplied by the interpolation matrix column sizes.
68147c6ae99SBarry Smith      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
68247c6ae99SBarry Smith      copy of the coarse vector. A bit of a hack but you do better.
68347c6ae99SBarry Smith 
68447c6ae99SBarry Smith      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
68547c6ae99SBarry Smith   */
686ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);CHKERRQ(ierr);
687ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);CHKERRQ(ierr);
688ce94432eSBarry Smith   ierr      = MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);CHKERRQ(ierr);
68947c6ae99SBarry Smith   col_scale = size_f/size_c;
69047c6ae99SBarry Smith   col_shift = Mx*My*Mz*(rank_f/size_c);
69147c6ae99SBarry Smith 
692ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f*p_f,col_scale*m_c*n_c*p_c,dnz,onz);CHKERRQ(ierr);
69347c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
69447c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
69547c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
69647c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
697e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
69847c6ae99SBarry Smith 
69947c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
70047c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
70147c6ae99SBarry Smith         l_c = (l/ratiol);
70247c6ae99SBarry Smith 
703aa219208SBarry Smith         if (l_c < l_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
70447c6ae99SBarry Smith     l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
705aa219208SBarry Smith         if (j_c < j_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
70647c6ae99SBarry Smith     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
707aa219208SBarry Smith         if (i_c < i_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
70847c6ae99SBarry Smith     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
70947c6ae99SBarry Smith 
71047c6ae99SBarry Smith         /*
71147c6ae99SBarry Smith            Only include those interpolation points that are truly
71247c6ae99SBarry Smith            nonzero. Note this is very important for final grid lines
71347c6ae99SBarry Smith            in x and y directions; since they have no right/top neighbors
71447c6ae99SBarry Smith         */
71547c6ae99SBarry Smith         nc = 0;
71647c6ae99SBarry Smith         /* one left and below; or we are right on it */
717e3fbd1f4SBarry 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));
718e3fbd1f4SBarry Smith         cols[nc++] = col_shift + idx_c[col];
71947c6ae99SBarry Smith         ierr       = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
72047c6ae99SBarry Smith       }
72147c6ae99SBarry Smith     }
72247c6ae99SBarry Smith   }
723ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)daf),&mat);CHKERRQ(ierr);
724fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
725fdc842d1SBarry Smith   /*
726fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
727fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
728fdc842d1SBarry Smith   */
729fdc842d1SBarry Smith   if (dof > 1) {
730b470e4b4SRichard Tran Mills     ierr = MatBindToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
731fdc842d1SBarry Smith   }
732fdc842d1SBarry Smith   #endif
73347c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f*n_f*p_f,col_scale*m_c*n_c*p_c,mx*my*mz,col_scale*Mx*My*Mz);CHKERRQ(ierr);
734fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
735fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
73647c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
73747c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
73847c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
73947c6ae99SBarry Smith 
74047c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
74147c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
74247c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
74347c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
74447c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
745e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
74647c6ae99SBarry Smith 
74747c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
74847c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
74947c6ae99SBarry Smith         l_c = (l/ratiol);
75047c6ae99SBarry Smith         nc  = 0;
75147c6ae99SBarry Smith         /* one left and below; or we are right on it */
752e3fbd1f4SBarry 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));
753e3fbd1f4SBarry Smith         cols[nc] = col_shift + idx_c[col];
75447c6ae99SBarry Smith         v[nc++]  = 1.0;
75547c6ae99SBarry Smith 
75647c6ae99SBarry Smith         ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
75747c6ae99SBarry Smith       }
75847c6ae99SBarry Smith     }
75947c6ae99SBarry Smith   }
76045b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
76145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
76247c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
76347c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
76447c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
765fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
76647c6ae99SBarry Smith   ierr = PetscLogFlops(13.0*m_f*n_f*p_f);CHKERRQ(ierr);
76747c6ae99SBarry Smith   PetscFunctionReturn(0);
76847c6ae99SBarry Smith }
76947c6ae99SBarry Smith 
770e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_3D_Q1(DM dac,DM daf,Mat *A)
77147c6ae99SBarry Smith {
77247c6ae99SBarry Smith   PetscErrorCode         ierr;
7738ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof,l;
7748ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
775e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
7768ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,Mz,mz;
77747c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
77847c6ae99SBarry Smith   PetscInt               i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
77947c6ae99SBarry Smith   PetscInt               l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
78047c6ae99SBarry Smith   PetscInt               l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
78147c6ae99SBarry Smith   PetscScalar            v[8],x,y,z;
78247c6ae99SBarry Smith   Mat                    mat;
783bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
784fdc842d1SBarry Smith   MatType                mattype;
78547c6ae99SBarry Smith 
78647c6ae99SBarry Smith   PetscFunctionBegin;
7871321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);CHKERRQ(ierr);
7881321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
78947c6ae99SBarry Smith   if (mx == Mx) {
79047c6ae99SBarry Smith     ratioi = 1;
791bff4a2f0SMatthew G. Knepley   } else if (bx == DM_BOUNDARY_PERIODIC) {
7923a586487SStefano Zampini     if (!Mx) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
79347c6ae99SBarry Smith     ratioi = mx/Mx;
79447c6ae99SBarry Smith     if (ratioi*Mx != mx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
79547c6ae99SBarry Smith   } else {
7963a586487SStefano Zampini     if (Mx < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be greater than 1",Mx);
79747c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
79847c6ae99SBarry Smith     if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
79947c6ae99SBarry Smith   }
80047c6ae99SBarry Smith   if (my == My) {
80147c6ae99SBarry Smith     ratioj = 1;
802bff4a2f0SMatthew G. Knepley   } else if (by == DM_BOUNDARY_PERIODIC) {
8033a586487SStefano Zampini     if (!My) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
80447c6ae99SBarry Smith     ratioj = my/My;
80547c6ae99SBarry Smith     if (ratioj*My != my) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
80647c6ae99SBarry Smith   } else {
8073a586487SStefano Zampini     if (My < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be greater than 1",My);
80847c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
80947c6ae99SBarry Smith     if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
81047c6ae99SBarry Smith   }
81147c6ae99SBarry Smith   if (mz == Mz) {
81247c6ae99SBarry Smith     ratiok = 1;
813bff4a2f0SMatthew G. Knepley   } else if (bz == DM_BOUNDARY_PERIODIC) {
8143a586487SStefano Zampini     if (!Mz) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of z coarse grid points %D must be positive",Mz);
81547c6ae99SBarry Smith     ratiok = mz/Mz;
81647c6ae99SBarry Smith     if (ratiok*Mz != mz) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mz/Mz  must be integer: mz %D Mz %D",mz,Mz);
81747c6ae99SBarry Smith   } else {
8183a586487SStefano Zampini     if (Mz < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of z coarse grid points %D must be greater than 1",Mz);
81947c6ae99SBarry Smith     ratiok = (mz-1)/(Mz-1);
82047c6ae99SBarry Smith     if (ratiok*(Mz-1) != mz-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %D Mz %D",mz,Mz);
82147c6ae99SBarry Smith   }
82247c6ae99SBarry Smith 
823aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
824aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
82545b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
82645b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
82747c6ae99SBarry Smith 
828aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
829aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);CHKERRQ(ierr);
83045b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
83145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
83247c6ae99SBarry Smith 
83347c6ae99SBarry Smith   /* create interpolation matrix, determining exact preallocation */
834ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)dac),m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);CHKERRQ(ierr);
83547c6ae99SBarry Smith   /* loop over local fine grid nodes counting interpolating points */
83647c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
83747c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
83847c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
83947c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
840e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
84147c6ae99SBarry Smith         i_c = (i/ratioi);
84247c6ae99SBarry Smith         j_c = (j/ratioj);
84347c6ae99SBarry Smith         l_c = (l/ratiok);
844aa219208SBarry Smith         if (l_c < l_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
84547c6ae99SBarry Smith                                             l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
846aa219208SBarry Smith         if (j_c < j_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
84747c6ae99SBarry Smith                                             j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
848aa219208SBarry Smith         if (i_c < i_start_ghost_c) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
84947c6ae99SBarry Smith                                             i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
85047c6ae99SBarry Smith 
85147c6ae99SBarry Smith         /*
85247c6ae99SBarry Smith          Only include those interpolation points that are truly
85347c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
85447c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
85547c6ae99SBarry Smith          */
85647c6ae99SBarry Smith         nc         = 0;
857e3fbd1f4SBarry 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));
858e3fbd1f4SBarry Smith         cols[nc++] = idx_c[col];
85947c6ae99SBarry Smith         if (i_c*ratioi != i) {
860e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+1];
86147c6ae99SBarry Smith         }
86247c6ae99SBarry Smith         if (j_c*ratioj != j) {
863e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+m_ghost_c];
86447c6ae99SBarry Smith         }
86547c6ae99SBarry Smith         if (l_c*ratiok != l) {
866e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c];
86747c6ae99SBarry Smith         }
86847c6ae99SBarry Smith         if (j_c*ratioj != j && i_c*ratioi != i) {
869e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c+1)];
87047c6ae99SBarry Smith         }
87147c6ae99SBarry Smith         if (j_c*ratioj != j && l_c*ratiok != l) {
872e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)];
87347c6ae99SBarry Smith         }
87447c6ae99SBarry Smith         if (i_c*ratioi != i && l_c*ratiok != l) {
875e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)];
87647c6ae99SBarry Smith         }
87747c6ae99SBarry Smith         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
878e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)];
87947c6ae99SBarry Smith         }
88047c6ae99SBarry Smith         ierr = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
88147c6ae99SBarry Smith       }
88247c6ae99SBarry Smith     }
88347c6ae99SBarry Smith   }
884ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)dac),&mat);CHKERRQ(ierr);
885fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
886fdc842d1SBarry Smith   /*
887fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
888fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
889fdc842d1SBarry Smith   */
890fdc842d1SBarry Smith   if (dof > 1) {
891b470e4b4SRichard Tran Mills     ierr = MatBindToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
892fdc842d1SBarry Smith   }
893fdc842d1SBarry Smith   #endif
89447c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz);CHKERRQ(ierr);
895fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
896fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
89747c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
89847c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
89947c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
90047c6ae99SBarry Smith 
90147c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
9022adb9dcfSBarry Smith   if (!NEWVERSION) {
903b3bd94feSDave May 
90447c6ae99SBarry Smith     for (l=l_start; l<l_start+p_f; l++) {
90547c6ae99SBarry Smith       for (j=j_start; j<j_start+n_f; j++) {
90647c6ae99SBarry Smith         for (i=i_start; i<i_start+m_f; i++) {
90747c6ae99SBarry Smith           /* convert to local "natural" numbering and then to PETSc global numbering */
908e3fbd1f4SBarry Smith           row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
90947c6ae99SBarry Smith 
91047c6ae99SBarry Smith           i_c = (i/ratioi);
91147c6ae99SBarry Smith           j_c = (j/ratioj);
91247c6ae99SBarry Smith           l_c = (l/ratiok);
91347c6ae99SBarry Smith 
91447c6ae99SBarry Smith           /*
91547c6ae99SBarry Smith            Only include those interpolation points that are truly
91647c6ae99SBarry Smith            nonzero. Note this is very important for final grid lines
91747c6ae99SBarry Smith            in x and y directions; since they have no right/top neighbors
91847c6ae99SBarry Smith            */
9196712e2f1SBarry Smith           x = ((PetscReal)(i - i_c*ratioi))/((PetscReal)ratioi);
9206712e2f1SBarry Smith           y = ((PetscReal)(j - j_c*ratioj))/((PetscReal)ratioj);
9216712e2f1SBarry Smith           z = ((PetscReal)(l - l_c*ratiok))/((PetscReal)ratiok);
922b3bd94feSDave May 
92347c6ae99SBarry Smith           nc = 0;
92447c6ae99SBarry Smith           /* one left and below; or we are right on it */
925e3fbd1f4SBarry 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));
92647c6ae99SBarry Smith 
927e3fbd1f4SBarry Smith           cols[nc] = idx_c[col];
92847c6ae99SBarry Smith           v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
92947c6ae99SBarry Smith 
93047c6ae99SBarry Smith           if (i_c*ratioi != i) {
931e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+1];
93247c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
93347c6ae99SBarry Smith           }
93447c6ae99SBarry Smith 
93547c6ae99SBarry Smith           if (j_c*ratioj != j) {
936e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+m_ghost_c];
93747c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
93847c6ae99SBarry Smith           }
93947c6ae99SBarry Smith 
94047c6ae99SBarry Smith           if (l_c*ratiok != l) {
941e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+m_ghost_c*n_ghost_c];
94247c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
94347c6ae99SBarry Smith           }
94447c6ae99SBarry Smith 
94547c6ae99SBarry Smith           if (j_c*ratioj != j && i_c*ratioi != i) {
946e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c+1)];
94747c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
94847c6ae99SBarry Smith           }
94947c6ae99SBarry Smith 
95047c6ae99SBarry Smith           if (j_c*ratioj != j && l_c*ratiok != l) {
951e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)];
95247c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
95347c6ae99SBarry Smith           }
95447c6ae99SBarry Smith 
95547c6ae99SBarry Smith           if (i_c*ratioi != i && l_c*ratiok != l) {
956e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+1)];
95747c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
95847c6ae99SBarry Smith           }
95947c6ae99SBarry Smith 
96047c6ae99SBarry Smith           if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
961e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)];
96247c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
96347c6ae99SBarry Smith           }
96447c6ae99SBarry Smith           ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
96547c6ae99SBarry Smith         }
96647c6ae99SBarry Smith       }
96747c6ae99SBarry Smith     }
968b3bd94feSDave May 
969b3bd94feSDave May   } else {
970b3bd94feSDave May     PetscScalar *xi,*eta,*zeta;
971b3bd94feSDave May     PetscInt    li,nxi,lj,neta,lk,nzeta,n;
972b3bd94feSDave May     PetscScalar Ni[8];
973b3bd94feSDave May 
974b3bd94feSDave May     /* compute local coordinate arrays */
975b3bd94feSDave May     nxi   = ratioi + 1;
976b3bd94feSDave May     neta  = ratioj + 1;
977b3bd94feSDave May     nzeta = ratiok + 1;
978854ce69bSBarry Smith     ierr  = PetscMalloc1(nxi,&xi);CHKERRQ(ierr);
979854ce69bSBarry Smith     ierr  = PetscMalloc1(neta,&eta);CHKERRQ(ierr);
980854ce69bSBarry Smith     ierr  = PetscMalloc1(nzeta,&zeta);CHKERRQ(ierr);
9818865f1eaSKarl Rupp     for (li=0; li<nxi; li++) xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
9828865f1eaSKarl Rupp     for (lj=0; lj<neta; lj++) eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
9838865f1eaSKarl Rupp     for (lk=0; lk<nzeta; lk++) zeta[lk] = -1.0 + (PetscScalar)lk*(2.0/(PetscScalar)(nzeta-1));
984b3bd94feSDave May 
985b3bd94feSDave May     for (l=l_start; l<l_start+p_f; l++) {
986b3bd94feSDave May       for (j=j_start; j<j_start+n_f; j++) {
987b3bd94feSDave May         for (i=i_start; i<i_start+m_f; i++) {
988b3bd94feSDave May           /* convert to local "natural" numbering and then to PETSc global numbering */
989e3fbd1f4SBarry Smith           row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
990b3bd94feSDave May 
991b3bd94feSDave May           i_c = (i/ratioi);
992b3bd94feSDave May           j_c = (j/ratioj);
993b3bd94feSDave May           l_c = (l/ratiok);
994b3bd94feSDave May 
995b3bd94feSDave May           /* remainders */
996b3bd94feSDave May           li = i - ratioi * (i/ratioi);
9978865f1eaSKarl Rupp           if (i==mx-1) li = nxi-1;
998b3bd94feSDave May           lj = j - ratioj * (j/ratioj);
9998865f1eaSKarl Rupp           if (j==my-1) lj = neta-1;
1000b3bd94feSDave May           lk = l - ratiok * (l/ratiok);
10018865f1eaSKarl Rupp           if (l==mz-1) lk = nzeta-1;
1002b3bd94feSDave May 
1003b3bd94feSDave May           /* corners */
1004e3fbd1f4SBarry 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));
1005e3fbd1f4SBarry Smith           cols[0] = idx_c[col];
1006b3bd94feSDave May           Ni[0]   = 1.0;
1007b3bd94feSDave May           if ((li==0) || (li==nxi-1)) {
1008b3bd94feSDave May             if ((lj==0) || (lj==neta-1)) {
1009b3bd94feSDave May               if ((lk==0) || (lk==nzeta-1)) {
1010b3bd94feSDave May                 ierr = MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);CHKERRQ(ierr);
1011b3bd94feSDave May                 continue;
1012b3bd94feSDave May               }
1013b3bd94feSDave May             }
1014b3bd94feSDave May           }
1015b3bd94feSDave May 
1016b3bd94feSDave May           /* edges + interior */
1017b3bd94feSDave May           /* remainders */
10188865f1eaSKarl Rupp           if (i==mx-1) i_c--;
10198865f1eaSKarl Rupp           if (j==my-1) j_c--;
10208865f1eaSKarl Rupp           if (l==mz-1) l_c--;
1021b3bd94feSDave May 
1022e3fbd1f4SBarry 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));
1023e3fbd1f4SBarry Smith           cols[0] = idx_c[col]; /* one left and below; or we are right on it */
1024e3fbd1f4SBarry Smith           cols[1] = idx_c[col+1]; /* one right and below */
1025e3fbd1f4SBarry Smith           cols[2] = idx_c[col+m_ghost_c];  /* one left and above */
1026e3fbd1f4SBarry Smith           cols[3] = idx_c[col+(m_ghost_c+1)]; /* one right and above */
1027b3bd94feSDave May 
1028e3fbd1f4SBarry Smith           cols[4] = idx_c[col+m_ghost_c*n_ghost_c]; /* one left and below and front; or we are right on it */
1029e3fbd1f4SBarry Smith           cols[5] = idx_c[col+(m_ghost_c*n_ghost_c+1)]; /* one right and below, and front */
1030e3fbd1f4SBarry Smith           cols[6] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)]; /* one left and above and front*/
1031e3fbd1f4SBarry Smith           cols[7] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)]; /* one right and above and front */
1032b3bd94feSDave May 
1033b3bd94feSDave May           Ni[0] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
1034b3bd94feSDave May           Ni[1] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
1035b3bd94feSDave May           Ni[2] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);
1036b3bd94feSDave May           Ni[3] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);
1037b3bd94feSDave May 
1038b3bd94feSDave May           Ni[4] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
1039b3bd94feSDave May           Ni[5] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
1040b3bd94feSDave May           Ni[6] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);
1041b3bd94feSDave May           Ni[7] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);
1042b3bd94feSDave May 
1043b3bd94feSDave May           for (n=0; n<8; n++) {
10448865f1eaSKarl Rupp             if (PetscAbsScalar(Ni[n])<1.0e-32) cols[n]=-1;
1045b3bd94feSDave May           }
1046b3bd94feSDave May           ierr = MatSetValues(mat,1,&row,8,cols,Ni,INSERT_VALUES);CHKERRQ(ierr);
1047b3bd94feSDave May 
1048b3bd94feSDave May         }
1049b3bd94feSDave May       }
1050b3bd94feSDave May     }
1051b3bd94feSDave May     ierr = PetscFree(xi);CHKERRQ(ierr);
1052b3bd94feSDave May     ierr = PetscFree(eta);CHKERRQ(ierr);
1053b3bd94feSDave May     ierr = PetscFree(zeta);CHKERRQ(ierr);
1054b3bd94feSDave May   }
105545b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
105645b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
105747c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
105847c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
105947c6ae99SBarry Smith 
106047c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
1061fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
106247c6ae99SBarry Smith   PetscFunctionReturn(0);
106347c6ae99SBarry Smith }
106447c6ae99SBarry Smith 
1065e727c939SJed Brown PetscErrorCode  DMCreateInterpolation_DA(DM dac,DM daf,Mat *A,Vec *scale)
106647c6ae99SBarry Smith {
106747c6ae99SBarry Smith   PetscErrorCode   ierr;
106847c6ae99SBarry Smith   PetscInt         dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1069bff4a2f0SMatthew G. Knepley   DMBoundaryType   bxc,byc,bzc,bxf,byf,bzf;
1070aa219208SBarry Smith   DMDAStencilType  stc,stf;
107147c6ae99SBarry Smith   DM_DA            *ddc = (DM_DA*)dac->data;
107247c6ae99SBarry Smith 
107347c6ae99SBarry Smith   PetscFunctionBegin;
107447c6ae99SBarry Smith   PetscValidHeaderSpecific(dac,DM_CLASSID,1);
107547c6ae99SBarry Smith   PetscValidHeaderSpecific(daf,DM_CLASSID,2);
107647c6ae99SBarry Smith   PetscValidPointer(A,3);
107747c6ae99SBarry Smith   if (scale) PetscValidPointer(scale,4);
107847c6ae99SBarry Smith 
10791321219cSEthan Coon   ierr = DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);CHKERRQ(ierr);
10801321219cSEthan Coon   ierr = DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);CHKERRQ(ierr);
108113903a91SSatish Balay   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
108213903a91SSatish Balay   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
108313903a91SSatish Balay   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
108413903a91SSatish Balay   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
108513903a91SSatish Balay   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
108647c6ae99SBarry Smith   if (Mc < 2 && Mf > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
108747c6ae99SBarry Smith   if (dimc > 1 && Nc < 2 && Nf > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
108847c6ae99SBarry Smith   if (dimc > 2 && Pc < 2 && Pf > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");
108947c6ae99SBarry Smith 
1090aa219208SBarry Smith   if (ddc->interptype == DMDA_Q1) {
109147c6ae99SBarry Smith     if (dimc == 1) {
1092e727c939SJed Brown       ierr = DMCreateInterpolation_DA_1D_Q1(dac,daf,A);CHKERRQ(ierr);
109347c6ae99SBarry Smith     } else if (dimc == 2) {
1094e727c939SJed Brown       ierr = DMCreateInterpolation_DA_2D_Q1(dac,daf,A);CHKERRQ(ierr);
109547c6ae99SBarry Smith     } else if (dimc == 3) {
1096e727c939SJed Brown       ierr = DMCreateInterpolation_DA_3D_Q1(dac,daf,A);CHKERRQ(ierr);
1097ce94432eSBarry Smith     } else SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
1098aa219208SBarry Smith   } else if (ddc->interptype == DMDA_Q0) {
109947c6ae99SBarry Smith     if (dimc == 1) {
1100e727c939SJed Brown       ierr = DMCreateInterpolation_DA_1D_Q0(dac,daf,A);CHKERRQ(ierr);
110147c6ae99SBarry Smith     } else if (dimc == 2) {
1102e727c939SJed Brown       ierr = DMCreateInterpolation_DA_2D_Q0(dac,daf,A);CHKERRQ(ierr);
110347c6ae99SBarry Smith     } else if (dimc == 3) {
1104e727c939SJed Brown       ierr = DMCreateInterpolation_DA_3D_Q0(dac,daf,A);CHKERRQ(ierr);
1105ce94432eSBarry Smith     } else SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
110647c6ae99SBarry Smith   }
110747c6ae99SBarry Smith   if (scale) {
1108e727c939SJed Brown     ierr = DMCreateInterpolationScale((DM)dac,(DM)daf,*A,scale);CHKERRQ(ierr);
110947c6ae99SBarry Smith   }
111047c6ae99SBarry Smith   PetscFunctionReturn(0);
111147c6ae99SBarry Smith }
111247c6ae99SBarry Smith 
1113e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_1D(DM dac,DM daf,VecScatter *inject)
11140bb2b966SJungho Lee {
11150bb2b966SJungho Lee   PetscErrorCode         ierr;
11168ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx,dof;
11178ea3bf28SBarry Smith   const PetscInt         *idx_f;
1118e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f;
11198ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
11200bb2b966SJungho Lee   PetscInt               row,i_start_ghost,mx,m_c,nc,ratioi;
11210bb2b966SJungho Lee   PetscInt               i_start_c,i_start_ghost_c;
11220bb2b966SJungho Lee   PetscInt               *cols;
1123bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
11240bb2b966SJungho Lee   Vec                    vecf,vecc;
11250bb2b966SJungho Lee   IS                     isf;
11260bb2b966SJungho Lee 
11270bb2b966SJungho Lee   PetscFunctionBegin;
11280bb2b966SJungho Lee   ierr = DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);CHKERRQ(ierr);
11290bb2b966SJungho Lee   ierr = DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
1130bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
11310bb2b966SJungho Lee     ratioi = mx/Mx;
11320bb2b966SJungho Lee     if (ratioi*Mx != mx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
11330bb2b966SJungho Lee   } else {
11340bb2b966SJungho Lee     ratioi = (mx-1)/(Mx-1);
11350bb2b966SJungho Lee     if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
11360bb2b966SJungho Lee   }
11370bb2b966SJungho Lee 
11380bb2b966SJungho Lee   ierr = DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);CHKERRQ(ierr);
11390bb2b966SJungho Lee   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);CHKERRQ(ierr);
114045b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
114145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
11420bb2b966SJungho Lee 
11430bb2b966SJungho Lee   ierr = DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);CHKERRQ(ierr);
11440bb2b966SJungho Lee   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);CHKERRQ(ierr);
11450bb2b966SJungho Lee 
11460bb2b966SJungho Lee 
11470bb2b966SJungho Lee   /* loop over local fine grid nodes setting interpolation for those*/
11480bb2b966SJungho Lee   nc   = 0;
1149785e854fSJed Brown   ierr = PetscMalloc1(m_f,&cols);CHKERRQ(ierr);
11500bb2b966SJungho Lee 
11510bb2b966SJungho Lee 
11520bb2b966SJungho Lee   for (i=i_start_c; i<i_start_c+m_c; i++) {
11530bb2b966SJungho Lee     PetscInt i_f = i*ratioi;
11540bb2b966SJungho Lee 
11558865f1eaSKarl Rupp     if (i_f < i_start_ghost || i_f >= i_start_ghost+m_ghost) SETERRQ4(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);
11568865f1eaSKarl Rupp 
1157e3fbd1f4SBarry Smith     row        = idx_f[(i_f-i_start_ghost)];
1158e3fbd1f4SBarry Smith     cols[nc++] = row;
11590bb2b966SJungho Lee   }
11600bb2b966SJungho Lee 
116145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
1162ce94432eSBarry Smith   ierr = ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);CHKERRQ(ierr);
11630bb2b966SJungho Lee   ierr = DMGetGlobalVector(dac,&vecc);CHKERRQ(ierr);
11640bb2b966SJungho Lee   ierr = DMGetGlobalVector(daf,&vecf);CHKERRQ(ierr);
11659448b7f1SJunchao Zhang   ierr = VecScatterCreate(vecf,isf,vecc,NULL,inject);CHKERRQ(ierr);
11660bb2b966SJungho Lee   ierr = DMRestoreGlobalVector(dac,&vecc);CHKERRQ(ierr);
11670bb2b966SJungho Lee   ierr = DMRestoreGlobalVector(daf,&vecf);CHKERRQ(ierr);
11680bb2b966SJungho Lee   ierr = ISDestroy(&isf);CHKERRQ(ierr);
11690bb2b966SJungho Lee   PetscFunctionReturn(0);
11700bb2b966SJungho Lee }
11710bb2b966SJungho Lee 
1172e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_2D(DM dac,DM daf,VecScatter *inject)
117347c6ae99SBarry Smith {
117447c6ae99SBarry Smith   PetscErrorCode         ierr;
11758ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
11768ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
1177e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
11788ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c;
117947c6ae99SBarry Smith   PetscInt               row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
1180076202ddSJed Brown   PetscInt               i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
118147c6ae99SBarry Smith   PetscInt               *cols;
1182bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
118347c6ae99SBarry Smith   Vec                    vecf,vecc;
118447c6ae99SBarry Smith   IS                     isf;
118547c6ae99SBarry Smith 
118647c6ae99SBarry Smith   PetscFunctionBegin;
11871321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);CHKERRQ(ierr);
11881321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
1189bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
119047c6ae99SBarry Smith     ratioi = mx/Mx;
119147c6ae99SBarry Smith     if (ratioi*Mx != mx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
119247c6ae99SBarry Smith   } else {
119347c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
119447c6ae99SBarry Smith     if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
119547c6ae99SBarry Smith   }
1196bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
119747c6ae99SBarry Smith     ratioj = my/My;
119847c6ae99SBarry Smith     if (ratioj*My != my) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
119947c6ae99SBarry Smith   } else {
120047c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
120147c6ae99SBarry Smith     if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
120247c6ae99SBarry Smith   }
120347c6ae99SBarry Smith 
1204aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);CHKERRQ(ierr);
1205aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);CHKERRQ(ierr);
120645b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
120745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
120847c6ae99SBarry Smith 
1209aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);CHKERRQ(ierr);
1210aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);CHKERRQ(ierr);
121145b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
121245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
121347c6ae99SBarry Smith 
121447c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
121547c6ae99SBarry Smith   nc   = 0;
1216785e854fSJed Brown   ierr = PetscMalloc1(n_f*m_f,&cols);CHKERRQ(ierr);
1217076202ddSJed Brown   for (j=j_start_c; j<j_start_c+n_c; j++) {
1218076202ddSJed Brown     for (i=i_start_c; i<i_start_c+m_c; i++) {
1219076202ddSJed Brown       PetscInt i_f = i*ratioi,j_f = j*ratioj;
1220076202ddSJed Brown       if (j_f < j_start_ghost || j_f >= j_start_ghost+n_ghost) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
1221076202ddSJed Brown     j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
1222076202ddSJed Brown       if (i_f < i_start_ghost || i_f >= i_start_ghost+m_ghost) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA\n\
1223076202ddSJed Brown     i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1224e3fbd1f4SBarry Smith       row        = idx_f[(m_ghost*(j_f-j_start_ghost) + (i_f-i_start_ghost))];
1225e3fbd1f4SBarry Smith       cols[nc++] = row;
122647c6ae99SBarry Smith     }
122747c6ae99SBarry Smith   }
122845b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
122945b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
123047c6ae99SBarry Smith 
1231ce94432eSBarry Smith   ierr = ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);CHKERRQ(ierr);
12329a42bb27SBarry Smith   ierr = DMGetGlobalVector(dac,&vecc);CHKERRQ(ierr);
12339a42bb27SBarry Smith   ierr = DMGetGlobalVector(daf,&vecf);CHKERRQ(ierr);
12349448b7f1SJunchao Zhang   ierr = VecScatterCreate(vecf,isf,vecc,NULL,inject);CHKERRQ(ierr);
12359a42bb27SBarry Smith   ierr = DMRestoreGlobalVector(dac,&vecc);CHKERRQ(ierr);
12369a42bb27SBarry Smith   ierr = DMRestoreGlobalVector(daf,&vecf);CHKERRQ(ierr);
1237fcfd50ebSBarry Smith   ierr = ISDestroy(&isf);CHKERRQ(ierr);
123847c6ae99SBarry Smith   PetscFunctionReturn(0);
123947c6ae99SBarry Smith }
124047c6ae99SBarry Smith 
1241e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_3D(DM dac,DM daf,VecScatter *inject)
1242b1757049SJed Brown {
1243b1757049SJed Brown   PetscErrorCode         ierr;
1244b1757049SJed Brown   PetscInt               i,j,k,i_start,j_start,k_start,m_f,n_f,p_f,Mx,My,Mz;
1245b1757049SJed Brown   PetscInt               m_ghost,n_ghost,p_ghost,m_ghost_c,n_ghost_c,p_ghost_c;
1246b1757049SJed Brown   PetscInt               i_start_ghost,j_start_ghost,k_start_ghost;
1247b1757049SJed Brown   PetscInt               mx,my,mz,ratioi,ratioj,ratiok;
1248b1757049SJed Brown   PetscInt               i_start_c,j_start_c,k_start_c;
1249b1757049SJed Brown   PetscInt               m_c,n_c,p_c;
1250b1757049SJed Brown   PetscInt               i_start_ghost_c,j_start_ghost_c,k_start_ghost_c;
1251b1757049SJed Brown   PetscInt               row,nc,dof;
12528ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
1253e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
1254b1757049SJed Brown   PetscInt               *cols;
1255bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
1256b1757049SJed Brown   Vec                    vecf,vecc;
1257b1757049SJed Brown   IS                     isf;
1258b1757049SJed Brown 
1259b1757049SJed Brown   PetscFunctionBegin;
12601321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);CHKERRQ(ierr);
12611321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
1262b1757049SJed Brown 
1263bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
1264b1757049SJed Brown     ratioi = mx/Mx;
1265b1757049SJed Brown     if (ratioi*Mx != mx) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
1266b1757049SJed Brown   } else {
1267b1757049SJed Brown     ratioi = (mx-1)/(Mx-1);
1268b1757049SJed Brown     if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
1269b1757049SJed Brown   }
1270bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
1271b1757049SJed Brown     ratioj = my/My;
1272b1757049SJed Brown     if (ratioj*My != my) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
1273b1757049SJed Brown   } else {
1274b1757049SJed Brown     ratioj = (my-1)/(My-1);
1275b1757049SJed Brown     if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
1276b1757049SJed Brown   }
1277bff4a2f0SMatthew G. Knepley   if (bz == DM_BOUNDARY_PERIODIC) {
1278b1757049SJed Brown     ratiok = mz/Mz;
1279b1757049SJed Brown     if (ratiok*Mz != mz) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: mz/Mz  must be integer: mz %D My %D",mz,Mz);
1280b1757049SJed Brown   } else {
1281b1757049SJed Brown     ratiok = (mz-1)/(Mz-1);
1282b1757049SJed Brown     if (ratiok*(Mz-1) != mz-1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %D Mz %D",mz,Mz);
1283b1757049SJed Brown   }
1284b1757049SJed Brown 
1285b1757049SJed Brown   ierr = DMDAGetCorners(daf,&i_start,&j_start,&k_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
1286b1757049SJed Brown   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&k_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
128745b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
128845b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
1289b1757049SJed Brown 
1290b1757049SJed Brown   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&k_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
1291b1757049SJed Brown   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&k_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);CHKERRQ(ierr);
129245b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
129345b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
1294b1757049SJed Brown 
1295b1757049SJed Brown 
1296b1757049SJed Brown   /* loop over local fine grid nodes setting interpolation for those*/
1297b1757049SJed Brown   nc   = 0;
1298785e854fSJed Brown   ierr = PetscMalloc1(n_f*m_f*p_f,&cols);CHKERRQ(ierr);
1299b1757049SJed Brown   for (k=k_start_c; k<k_start_c+p_c; k++) {
1300b1757049SJed Brown     for (j=j_start_c; j<j_start_c+n_c; j++) {
1301b1757049SJed Brown       for (i=i_start_c; i<i_start_c+m_c; i++) {
1302b1757049SJed Brown         PetscInt i_f = i*ratioi,j_f = j*ratioj,k_f = k*ratiok;
1303b1757049SJed Brown         if (k_f < k_start_ghost || k_f >= k_start_ghost+p_ghost) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA  "
1304b1757049SJed Brown                                                                           "k_c %D k_f %D fine ghost range [%D,%D]",k,k_f,k_start_ghost,k_start_ghost+p_ghost);
1305b1757049SJed Brown         if (j_f < j_start_ghost || j_f >= j_start_ghost+n_ghost) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA  "
1306b1757049SJed Brown                                                                           "j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
1307b1757049SJed Brown         if (i_f < i_start_ghost || i_f >= i_start_ghost+m_ghost) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Processor's coarse DMDA must lie over fine DMDA  "
1308b1757049SJed Brown                                                                           "i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1309e3fbd1f4SBarry 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))];
1310e3fbd1f4SBarry Smith         cols[nc++] = row;
1311b1757049SJed Brown       }
1312b1757049SJed Brown     }
1313b1757049SJed Brown   }
131445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
131545b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
1316b1757049SJed Brown 
1317ce94432eSBarry Smith   ierr = ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);CHKERRQ(ierr);
1318b1757049SJed Brown   ierr = DMGetGlobalVector(dac,&vecc);CHKERRQ(ierr);
1319b1757049SJed Brown   ierr = DMGetGlobalVector(daf,&vecf);CHKERRQ(ierr);
13209448b7f1SJunchao Zhang   ierr = VecScatterCreate(vecf,isf,vecc,NULL,inject);CHKERRQ(ierr);
1321b1757049SJed Brown   ierr = DMRestoreGlobalVector(dac,&vecc);CHKERRQ(ierr);
1322b1757049SJed Brown   ierr = DMRestoreGlobalVector(daf,&vecf);CHKERRQ(ierr);
1323fcfd50ebSBarry Smith   ierr = ISDestroy(&isf);CHKERRQ(ierr);
1324b1757049SJed Brown   PetscFunctionReturn(0);
1325b1757049SJed Brown }
1326b1757049SJed Brown 
13276dbf9973SLawrence Mitchell PetscErrorCode  DMCreateInjection_DA(DM dac,DM daf,Mat *mat)
132847c6ae99SBarry Smith {
132947c6ae99SBarry Smith   PetscErrorCode  ierr;
133047c6ae99SBarry Smith   PetscInt        dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1331bff4a2f0SMatthew G. Knepley   DMBoundaryType  bxc,byc,bzc,bxf,byf,bzf;
1332aa219208SBarry Smith   DMDAStencilType stc,stf;
133360c16ac1SBarry Smith   VecScatter      inject = NULL;
133447c6ae99SBarry Smith 
133547c6ae99SBarry Smith   PetscFunctionBegin;
133647c6ae99SBarry Smith   PetscValidHeaderSpecific(dac,DM_CLASSID,1);
133747c6ae99SBarry Smith   PetscValidHeaderSpecific(daf,DM_CLASSID,2);
13386dbf9973SLawrence Mitchell   PetscValidPointer(mat,3);
133947c6ae99SBarry Smith 
13401321219cSEthan Coon   ierr = DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);CHKERRQ(ierr);
13411321219cSEthan Coon   ierr = DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);CHKERRQ(ierr);
134213903a91SSatish Balay   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
134313903a91SSatish Balay   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
134413903a91SSatish Balay   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
134513903a91SSatish Balay   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
134613903a91SSatish Balay   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
134747c6ae99SBarry Smith   if (Mc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
134847c6ae99SBarry Smith   if (dimc > 1 && Nc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
134947c6ae99SBarry Smith   if (dimc > 2 && Pc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");
135047c6ae99SBarry Smith 
13510bb2b966SJungho Lee   if (dimc == 1) {
13526dbf9973SLawrence Mitchell     ierr = DMCreateInjection_DA_1D(dac,daf,&inject);CHKERRQ(ierr);
13530bb2b966SJungho Lee   } else if (dimc == 2) {
13546dbf9973SLawrence Mitchell     ierr = DMCreateInjection_DA_2D(dac,daf,&inject);CHKERRQ(ierr);
1355b1757049SJed Brown   } else if (dimc == 3) {
13566dbf9973SLawrence Mitchell     ierr = DMCreateInjection_DA_3D(dac,daf,&inject);CHKERRQ(ierr);
135747c6ae99SBarry Smith   }
13586dbf9973SLawrence Mitchell   ierr = MatCreateScatter(PetscObjectComm((PetscObject)inject), inject, mat);CHKERRQ(ierr);
13596dbf9973SLawrence Mitchell   ierr = VecScatterDestroy(&inject);CHKERRQ(ierr);
136047c6ae99SBarry Smith   PetscFunctionReturn(0);
136147c6ae99SBarry Smith }
136247c6ae99SBarry Smith 
136397779f9aSLisandro Dalcin /*@
136497779f9aSLisandro Dalcin    DMCreateAggregates - Deprecated, see DMDACreateAggregates.
136597779f9aSLisandro Dalcin @*/
1366*a5bc1bf3SBarry Smith PetscErrorCode DMCreateAggregates(DM dac,DM daf,Mat *mat)
136797779f9aSLisandro Dalcin {
1368*a5bc1bf3SBarry Smith   return DMDACreateAggregates(dac,daf,mat);
136997779f9aSLisandro Dalcin }
137097779f9aSLisandro Dalcin 
137197779f9aSLisandro Dalcin /*@
137297779f9aSLisandro Dalcin    DMDACreateAggregates - Gets the aggregates that map between
137397779f9aSLisandro Dalcin    grids associated with two DMDAs.
137497779f9aSLisandro Dalcin 
137597779f9aSLisandro Dalcin    Collective on dmc
137697779f9aSLisandro Dalcin 
137797779f9aSLisandro Dalcin    Input Parameters:
137897779f9aSLisandro Dalcin +  dmc - the coarse grid DMDA
137997779f9aSLisandro Dalcin -  dmf - the fine grid DMDA
138097779f9aSLisandro Dalcin 
138197779f9aSLisandro Dalcin    Output Parameters:
138297779f9aSLisandro Dalcin .  rest - the restriction matrix (transpose of the projection matrix)
138397779f9aSLisandro Dalcin 
138497779f9aSLisandro Dalcin    Level: intermediate
138597779f9aSLisandro Dalcin 
138697779f9aSLisandro Dalcin    Note: This routine is not used by PETSc.
138797779f9aSLisandro Dalcin    It is not clear what its use case is and it may be removed in a future release.
138897779f9aSLisandro Dalcin    Users should contact petsc-maint@mcs.anl.gov if they plan to use it.
138997779f9aSLisandro Dalcin 
139097779f9aSLisandro Dalcin .seealso: DMRefine(), DMCreateInjection(), DMCreateInterpolation()
139197779f9aSLisandro Dalcin @*/
139297779f9aSLisandro Dalcin PetscErrorCode DMDACreateAggregates(DM dac,DM daf,Mat *rest)
139347c6ae99SBarry Smith {
139447c6ae99SBarry Smith   PetscErrorCode         ierr;
139547c6ae99SBarry Smith   PetscInt               dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc;
139647c6ae99SBarry Smith   PetscInt               dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1397bff4a2f0SMatthew G. Knepley   DMBoundaryType         bxc,byc,bzc,bxf,byf,bzf;
1398aa219208SBarry Smith   DMDAStencilType        stc,stf;
139947c6ae99SBarry Smith   PetscInt               i,j,l;
140047c6ae99SBarry Smith   PetscInt               i_start,j_start,l_start, m_f,n_f,p_f;
140147c6ae99SBarry Smith   PetscInt               i_start_ghost,j_start_ghost,l_start_ghost,m_ghost,n_ghost,p_ghost;
14028ea3bf28SBarry Smith   const PetscInt         *idx_f;
140347c6ae99SBarry Smith   PetscInt               i_c,j_c,l_c;
140447c6ae99SBarry Smith   PetscInt               i_start_c,j_start_c,l_start_c, m_c,n_c,p_c;
140547c6ae99SBarry Smith   PetscInt               i_start_ghost_c,j_start_ghost_c,l_start_ghost_c,m_ghost_c,n_ghost_c,p_ghost_c;
14068ea3bf28SBarry Smith   const PetscInt         *idx_c;
140747c6ae99SBarry Smith   PetscInt               d;
140847c6ae99SBarry Smith   PetscInt               a;
140947c6ae99SBarry Smith   PetscInt               max_agg_size;
141047c6ae99SBarry Smith   PetscInt               *fine_nodes;
141147c6ae99SBarry Smith   PetscScalar            *one_vec;
141247c6ae99SBarry Smith   PetscInt               fn_idx;
1413565245c5SBarry Smith   ISLocalToGlobalMapping ltogmf,ltogmc;
141447c6ae99SBarry Smith 
141547c6ae99SBarry Smith   PetscFunctionBegin;
141697779f9aSLisandro Dalcin   PetscValidHeaderSpecificType(dac,DM_CLASSID,1,DMDA);
141797779f9aSLisandro Dalcin   PetscValidHeaderSpecificType(daf,DM_CLASSID,2,DMDA);
141847c6ae99SBarry Smith   PetscValidPointer(rest,3);
141947c6ae99SBarry Smith 
14201321219cSEthan Coon   ierr = DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);CHKERRQ(ierr);
14211321219cSEthan Coon   ierr = DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);CHKERRQ(ierr);
142213903a91SSatish Balay   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
142313903a91SSatish Balay   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
142413903a91SSatish Balay   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
142513903a91SSatish Balay   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
142613903a91SSatish Balay   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
142747c6ae99SBarry Smith 
142847c6ae99SBarry Smith   if (Mf < Mc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Mc %D, Mf %D", Mc, Mf);
142947c6ae99SBarry Smith   if (Nf < Nc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Nc %D, Nf %D", Nc, Nf);
143047c6ae99SBarry Smith   if (Pf < Pc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Pc %D, Pf %D", Pc, Pf);
143147c6ae99SBarry Smith 
143247c6ae99SBarry Smith   if (Pc < 0) Pc = 1;
143347c6ae99SBarry Smith   if (Pf < 0) Pf = 1;
143447c6ae99SBarry Smith   if (Nc < 0) Nc = 1;
143547c6ae99SBarry Smith   if (Nf < 0) Nf = 1;
143647c6ae99SBarry Smith 
1437aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
1438aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
1439565245c5SBarry Smith 
1440565245c5SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltogmf);CHKERRQ(ierr);
1441565245c5SBarry Smith   ierr = ISLocalToGlobalMappingGetIndices(ltogmf,&idx_f);CHKERRQ(ierr);
144247c6ae99SBarry Smith 
1443aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
1444aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);CHKERRQ(ierr);
1445565245c5SBarry Smith 
1446565245c5SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltogmc);CHKERRQ(ierr);
1447565245c5SBarry Smith   ierr = ISLocalToGlobalMappingGetIndices(ltogmc,&idx_c);CHKERRQ(ierr);
144847c6ae99SBarry Smith 
144947c6ae99SBarry Smith   /*
145047c6ae99SBarry Smith      Basic idea is as follows. Here's a 2D example, suppose r_x, r_y are the ratios
145147c6ae99SBarry Smith      for dimension 1 and 2 respectively.
145247c6ae99SBarry Smith      Let (i,j) be a coarse grid node. All the fine grid nodes between r_x*i and r_x*(i+1)
145347c6ae99SBarry Smith      and r_y*j and r_y*(j+1) will be grouped into the same coarse grid agregate.
145447c6ae99SBarry Smith      Each specific dof on the fine grid is mapped to one dof on the coarse grid.
145547c6ae99SBarry Smith   */
145647c6ae99SBarry Smith 
145747c6ae99SBarry Smith   max_agg_size = (Mf/Mc+1)*(Nf/Nc+1)*(Pf/Pc+1);
145847c6ae99SBarry Smith 
145947c6ae99SBarry Smith   /* create the matrix that will contain the restriction operator */
1460ce94432eSBarry 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,
14610298fd71SBarry Smith                       max_agg_size, NULL, max_agg_size, NULL, rest);CHKERRQ(ierr);
146247c6ae99SBarry Smith 
146347c6ae99SBarry Smith   /* store nodes in the fine grid here */
1464dcca6d9dSJed Brown   ierr = PetscMalloc2(max_agg_size, &one_vec,max_agg_size, &fine_nodes);CHKERRQ(ierr);
146547c6ae99SBarry Smith   for (i=0; i<max_agg_size; i++) one_vec[i] = 1.0;
146647c6ae99SBarry Smith 
146747c6ae99SBarry Smith   /* loop over all coarse nodes */
146847c6ae99SBarry Smith   for (l_c=l_start_c; l_c<l_start_c+p_c; l_c++) {
146947c6ae99SBarry Smith     for (j_c=j_start_c; j_c<j_start_c+n_c; j_c++) {
147047c6ae99SBarry Smith       for (i_c=i_start_c; i_c<i_start_c+m_c; i_c++) {
147147c6ae99SBarry Smith         for (d=0; d<dofc; d++) {
147247c6ae99SBarry Smith           /* convert to local "natural" numbering and then to PETSc global numbering */
147347c6ae99SBarry 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;
147447c6ae99SBarry Smith 
147547c6ae99SBarry Smith           fn_idx = 0;
147647c6ae99SBarry Smith           /* Corresponding fine points are all points (i_f, j_f, l_f) such that
147747c6ae99SBarry Smith              i_c*Mf/Mc <= i_f < (i_c+1)*Mf/Mc
147847c6ae99SBarry Smith              (same for other dimensions)
147947c6ae99SBarry Smith           */
148047c6ae99SBarry Smith           for (l=l_c*Pf/Pc; l<PetscMin((l_c+1)*Pf/Pc,Pf); l++) {
148147c6ae99SBarry Smith             for (j=j_c*Nf/Nc; j<PetscMin((j_c+1)*Nf/Nc,Nf); j++) {
148247c6ae99SBarry Smith               for (i=i_c*Mf/Mc; i<PetscMin((i_c+1)*Mf/Mc,Mf); i++) {
148347c6ae99SBarry 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;
148447c6ae99SBarry Smith                 fn_idx++;
148547c6ae99SBarry Smith               }
148647c6ae99SBarry Smith             }
148747c6ae99SBarry Smith           }
148847c6ae99SBarry Smith           /* add all these points to one aggregate */
148947c6ae99SBarry Smith           ierr = MatSetValues(*rest, 1, &a, fn_idx, fine_nodes, one_vec, INSERT_VALUES);CHKERRQ(ierr);
149047c6ae99SBarry Smith         }
149147c6ae99SBarry Smith       }
149247c6ae99SBarry Smith     }
149347c6ae99SBarry Smith   }
1494565245c5SBarry Smith   ierr = ISLocalToGlobalMappingRestoreIndices(ltogmf,&idx_f);CHKERRQ(ierr);
1495565245c5SBarry Smith   ierr = ISLocalToGlobalMappingRestoreIndices(ltogmc,&idx_c);CHKERRQ(ierr);
149647c6ae99SBarry Smith   ierr = PetscFree2(one_vec,fine_nodes);CHKERRQ(ierr);
149747c6ae99SBarry Smith   ierr = MatAssemblyBegin(*rest, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
149847c6ae99SBarry Smith   ierr = MatAssemblyEnd(*rest, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
149947c6ae99SBarry Smith   PetscFunctionReturn(0);
150047c6ae99SBarry Smith }
1501