xref: /petsc/src/dm/impls/da/dainterp.c (revision 13903a915d446cc93f67d48f8375c735416781f4)
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 
1647c6ae99SBarry Smith /*@
17e727c939SJed Brown     DMCreateInterpolationScale - Forms L = R*1/diag(R*1) - L.*v is like a coarse grid average of the
1847c6ae99SBarry Smith       nearby fine grid points.
1947c6ae99SBarry Smith 
2047c6ae99SBarry Smith   Input Parameters:
2147c6ae99SBarry Smith +      dac - DM that defines a coarse mesh
2247c6ae99SBarry Smith .      daf - DM that defines a fine mesh
2347c6ae99SBarry Smith -      mat - the restriction (or interpolation operator) from fine to coarse
2447c6ae99SBarry Smith 
2547c6ae99SBarry Smith   Output Parameter:
2647c6ae99SBarry Smith .    scale - the scaled vector
2747c6ae99SBarry Smith 
2847c6ae99SBarry Smith   Level: developer
2947c6ae99SBarry Smith 
30e727c939SJed Brown .seealso: DMCreateInterpolation()
3147c6ae99SBarry Smith 
3247c6ae99SBarry Smith @*/
33e727c939SJed Brown PetscErrorCode  DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
3447c6ae99SBarry Smith {
3547c6ae99SBarry Smith   PetscErrorCode ierr;
3647c6ae99SBarry Smith   Vec            fine;
3747c6ae99SBarry Smith   PetscScalar    one = 1.0;
3847c6ae99SBarry Smith 
3947c6ae99SBarry Smith   PetscFunctionBegin;
4047c6ae99SBarry Smith   ierr = DMCreateGlobalVector(daf,&fine);CHKERRQ(ierr);
4147c6ae99SBarry Smith   ierr = DMCreateGlobalVector(dac,scale);CHKERRQ(ierr);
4247c6ae99SBarry Smith   ierr = VecSet(fine,one);CHKERRQ(ierr);
4347c6ae99SBarry Smith   ierr = MatRestrict(mat,fine,*scale);CHKERRQ(ierr);
44fcfd50ebSBarry Smith   ierr = VecDestroy(&fine);CHKERRQ(ierr);
4547c6ae99SBarry Smith   ierr = VecReciprocal(*scale);CHKERRQ(ierr);
4647c6ae99SBarry Smith   PetscFunctionReturn(0);
4747c6ae99SBarry Smith }
4847c6ae99SBarry Smith 
49e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_1D_Q1(DM dac,DM daf,Mat *A)
5047c6ae99SBarry Smith {
5147c6ae99SBarry Smith   PetscErrorCode         ierr;
528ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx;
538ea3bf28SBarry Smith   const PetscInt         *idx_f,*idx_c;
548ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
5547c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,mx,m_c,nc,ratio;
5647c6ae99SBarry Smith   PetscInt               i_c,i_start_c,i_start_ghost_c,cols[2],dof;
5785afcc9aSBarry Smith   PetscScalar            v[2],x;
5847c6ae99SBarry Smith   Mat                    mat;
59bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
60e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
61e3fbd1f4SBarry Smith 
6247c6ae99SBarry Smith 
6347c6ae99SBarry Smith   PetscFunctionBegin;
641321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);CHKERRQ(ierr);
651321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
66bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
6747c6ae99SBarry Smith     ratio = mx/Mx;
6847c6ae99SBarry 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);
6947c6ae99SBarry Smith   } else {
7047c6ae99SBarry Smith     ratio = (mx-1)/(Mx-1);
7147c6ae99SBarry 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);
7247c6ae99SBarry Smith   }
7347c6ae99SBarry Smith 
74aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);CHKERRQ(ierr);
75aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);CHKERRQ(ierr);
7645b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
7745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
7847c6ae99SBarry Smith 
79aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);CHKERRQ(ierr);
80aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);CHKERRQ(ierr);
8145b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
8245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
8347c6ae99SBarry Smith 
8447c6ae99SBarry Smith   /* create interpolation matrix */
85ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)dac),&mat);CHKERRQ(ierr);
8647c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f,m_c,mx,Mx);CHKERRQ(ierr);
8747c6ae99SBarry Smith   ierr = MatSetType(mat,MATAIJ);CHKERRQ(ierr);
880298fd71SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,2,NULL);CHKERRQ(ierr);
890298fd71SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,2,NULL,1,NULL);CHKERRQ(ierr);
9047c6ae99SBarry Smith 
9147c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
9285afcc9aSBarry Smith   if (!NEWVERSION) {
93b3bd94feSDave May 
9447c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
9547c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
96e3fbd1f4SBarry Smith       row = idx_f[i-i_start_ghost];
9747c6ae99SBarry Smith 
9847c6ae99SBarry Smith       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
99aa219208SBarry 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\
10047c6ae99SBarry Smith                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
10147c6ae99SBarry Smith 
10247c6ae99SBarry Smith       /*
10347c6ae99SBarry Smith        Only include those interpolation points that are truly
10447c6ae99SBarry Smith        nonzero. Note this is very important for final grid lines
10547c6ae99SBarry Smith        in x direction; since they have no right neighbor
10647c6ae99SBarry Smith        */
1076712e2f1SBarry Smith       x  = ((PetscReal)(i - i_c*ratio))/((PetscReal)ratio);
10847c6ae99SBarry Smith       nc = 0;
10947c6ae99SBarry Smith       /* one left and below; or we are right on it */
110e3fbd1f4SBarry Smith       col      = (i_c-i_start_ghost_c);
111e3fbd1f4SBarry Smith       cols[nc] = idx_c[col];
11247c6ae99SBarry Smith       v[nc++]  = -x + 1.0;
11347c6ae99SBarry Smith       /* one right? */
11447c6ae99SBarry Smith       if (i_c*ratio != i) {
115e3fbd1f4SBarry Smith         cols[nc] = idx_c[col+1];
11647c6ae99SBarry Smith         v[nc++]  = x;
11747c6ae99SBarry Smith       }
11847c6ae99SBarry Smith       ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
11947c6ae99SBarry Smith     }
120b3bd94feSDave May 
121b3bd94feSDave May   } else {
122b3bd94feSDave May     PetscScalar *xi;
123b3bd94feSDave May     PetscInt    li,nxi,n;
124b3bd94feSDave May     PetscScalar Ni[2];
125b3bd94feSDave May 
126b3bd94feSDave May     /* compute local coordinate arrays */
127b3bd94feSDave May     nxi  = ratio + 1;
128854ce69bSBarry Smith     ierr = PetscMalloc1(nxi,&xi);CHKERRQ(ierr);
129b3bd94feSDave May     for (li=0; li<nxi; li++) {
13052218ef2SJed Brown       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
131b3bd94feSDave May     }
132b3bd94feSDave May 
133b3bd94feSDave May     for (i=i_start; i<i_start+m_f; i++) {
134b3bd94feSDave May       /* convert to local "natural" numbering and then to PETSc global numbering */
135e3fbd1f4SBarry Smith       row = idx_f[(i-i_start_ghost)];
136b3bd94feSDave May 
137b3bd94feSDave May       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
138b3bd94feSDave 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\
139b3bd94feSDave May                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
140b3bd94feSDave May 
141b3bd94feSDave May       /* remainders */
142b3bd94feSDave May       li = i - ratio * (i/ratio);
1438865f1eaSKarl Rupp       if (i==mx-1) li = nxi-1;
144b3bd94feSDave May 
145b3bd94feSDave May       /* corners */
146e3fbd1f4SBarry Smith       col     = (i_c-i_start_ghost_c);
147e3fbd1f4SBarry Smith       cols[0] = idx_c[col];
148b3bd94feSDave May       Ni[0]   = 1.0;
149b3bd94feSDave May       if ((li==0) || (li==nxi-1)) {
150b3bd94feSDave May         ierr = MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);CHKERRQ(ierr);
151b3bd94feSDave May         continue;
152b3bd94feSDave May       }
153b3bd94feSDave May 
154b3bd94feSDave May       /* edges + interior */
155b3bd94feSDave May       /* remainders */
1568865f1eaSKarl Rupp       if (i==mx-1) i_c--;
157b3bd94feSDave May 
158e3fbd1f4SBarry Smith       col     = (i_c-i_start_ghost_c);
159e3fbd1f4SBarry Smith       cols[0] = idx_c[col]; /* one left and below; or we are right on it */
160e3fbd1f4SBarry Smith       cols[1] = idx_c[col+1];
161b3bd94feSDave May 
162b3bd94feSDave May       Ni[0] = 0.5*(1.0-xi[li]);
163b3bd94feSDave May       Ni[1] = 0.5*(1.0+xi[li]);
164b3bd94feSDave May       for (n=0; n<2; n++) {
1658865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[n])<1.0e-32) cols[n]=-1;
166b3bd94feSDave May       }
167b3bd94feSDave May       ierr = MatSetValues(mat,1,&row,2,cols,Ni,INSERT_VALUES);CHKERRQ(ierr);
168b3bd94feSDave May     }
169b3bd94feSDave May     ierr = PetscFree(xi);CHKERRQ(ierr);
170b3bd94feSDave May   }
17145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
17245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
17347c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
17447c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
17547c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
176fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
17747c6ae99SBarry Smith   PetscFunctionReturn(0);
17847c6ae99SBarry Smith }
17947c6ae99SBarry Smith 
180e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_1D_Q0(DM dac,DM daf,Mat *A)
18147c6ae99SBarry Smith {
18247c6ae99SBarry Smith   PetscErrorCode         ierr;
1838ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx;
1848ea3bf28SBarry Smith   const PetscInt         *idx_f,*idx_c;
185e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
1868ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
18747c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,mx,m_c,nc,ratio;
18847c6ae99SBarry Smith   PetscInt               i_c,i_start_c,i_start_ghost_c,cols[2],dof;
18947c6ae99SBarry Smith   PetscScalar            v[2],x;
19047c6ae99SBarry Smith   Mat                    mat;
191bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
19247c6ae99SBarry Smith 
19347c6ae99SBarry Smith   PetscFunctionBegin;
1941321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);CHKERRQ(ierr);
1951321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
196bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
19747c6ae99SBarry Smith     ratio = mx/Mx;
19847c6ae99SBarry 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);
19947c6ae99SBarry Smith   } else {
20047c6ae99SBarry Smith     ratio = (mx-1)/(Mx-1);
20147c6ae99SBarry 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);
20247c6ae99SBarry Smith   }
20347c6ae99SBarry Smith 
204aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);CHKERRQ(ierr);
205aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);CHKERRQ(ierr);
20645b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
20745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
20847c6ae99SBarry Smith 
209aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);CHKERRQ(ierr);
210aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);CHKERRQ(ierr);
21145b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
21245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
21347c6ae99SBarry Smith 
21447c6ae99SBarry Smith   /* create interpolation matrix */
215ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)dac),&mat);CHKERRQ(ierr);
21647c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f,m_c,mx,Mx);CHKERRQ(ierr);
21747c6ae99SBarry Smith   ierr = MatSetType(mat,MATAIJ);CHKERRQ(ierr);
2180298fd71SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,2,NULL);CHKERRQ(ierr);
2190298fd71SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,2,NULL,0,NULL);CHKERRQ(ierr);
22047c6ae99SBarry Smith 
22147c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
22247c6ae99SBarry Smith   for (i=i_start; i<i_start+m_f; i++) {
22347c6ae99SBarry Smith     /* convert to local "natural" numbering and then to PETSc global numbering */
224e3fbd1f4SBarry Smith     row = idx_f[(i-i_start_ghost)];
22547c6ae99SBarry Smith 
22647c6ae99SBarry Smith     i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
22747c6ae99SBarry Smith 
22847c6ae99SBarry Smith     /*
22947c6ae99SBarry Smith          Only include those interpolation points that are truly
23047c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
23147c6ae99SBarry Smith          in x direction; since they have no right neighbor
23247c6ae99SBarry Smith     */
2336712e2f1SBarry Smith     x  = ((PetscReal)(i - i_c*ratio))/((PetscReal)ratio);
23447c6ae99SBarry Smith     nc = 0;
23547c6ae99SBarry Smith     /* one left and below; or we are right on it */
236e3fbd1f4SBarry Smith     col      = (i_c-i_start_ghost_c);
237e3fbd1f4SBarry Smith     cols[nc] = idx_c[col];
23847c6ae99SBarry Smith     v[nc++]  = -x + 1.0;
23947c6ae99SBarry Smith     /* one right? */
24047c6ae99SBarry Smith     if (i_c*ratio != i) {
241e3fbd1f4SBarry Smith       cols[nc] = idx_c[col+1];
24247c6ae99SBarry Smith       v[nc++]  = x;
24347c6ae99SBarry Smith     }
24447c6ae99SBarry Smith     ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
24547c6ae99SBarry Smith   }
24645b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
24745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
24847c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
24947c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
25047c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
251fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
25247c6ae99SBarry Smith   ierr = PetscLogFlops(5.0*m_f);CHKERRQ(ierr);
25347c6ae99SBarry Smith   PetscFunctionReturn(0);
25447c6ae99SBarry Smith }
25547c6ae99SBarry Smith 
256e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_2D_Q1(DM dac,DM daf,Mat *A)
25747c6ae99SBarry Smith {
25847c6ae99SBarry Smith   PetscErrorCode         ierr;
2598ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
2608ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
261e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
2628ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,*dnz,*onz;
26347c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
26447c6ae99SBarry 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;
26547c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
26647c6ae99SBarry Smith   PetscScalar            v[4],x,y;
26747c6ae99SBarry Smith   Mat                    mat;
268bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
26947c6ae99SBarry Smith 
27047c6ae99SBarry Smith   PetscFunctionBegin;
2711321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);CHKERRQ(ierr);
2721321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
273bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
27447c6ae99SBarry Smith     ratioi = mx/Mx;
27547c6ae99SBarry 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);
27647c6ae99SBarry Smith   } else {
27747c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
27847c6ae99SBarry 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);
27947c6ae99SBarry Smith   }
280bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
28147c6ae99SBarry Smith     ratioj = my/My;
28247c6ae99SBarry 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);
28347c6ae99SBarry Smith   } else {
28447c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
28547c6ae99SBarry 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);
28647c6ae99SBarry Smith   }
28747c6ae99SBarry Smith 
28847c6ae99SBarry Smith 
289aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);CHKERRQ(ierr);
290aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);CHKERRQ(ierr);
29145b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
29245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
29347c6ae99SBarry Smith 
294aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);CHKERRQ(ierr);
295aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);CHKERRQ(ierr);
29645b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
29745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
29847c6ae99SBarry Smith 
29947c6ae99SBarry Smith   /*
300aa219208SBarry Smith    Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
30147c6ae99SBarry Smith    The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
30247c6ae99SBarry Smith    processors). It's effective length is hence 4 times its normal length, this is
30347c6ae99SBarry Smith    why the col_scale is multiplied by the interpolation matrix column sizes.
30447c6ae99SBarry Smith    sol_shift allows each set of 1/4 processors do its own interpolation using ITS
30547c6ae99SBarry Smith    copy of the coarse vector. A bit of a hack but you do better.
30647c6ae99SBarry Smith 
30747c6ae99SBarry Smith    In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
30847c6ae99SBarry Smith    */
309ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);CHKERRQ(ierr);
310ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);CHKERRQ(ierr);
311ce94432eSBarry Smith   ierr      = MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);CHKERRQ(ierr);
31247c6ae99SBarry Smith   col_scale = size_f/size_c;
31347c6ae99SBarry Smith   col_shift = Mx*My*(rank_f/size_c);
31447c6ae99SBarry Smith 
315ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f,col_scale*m_c*n_c,dnz,onz);CHKERRQ(ierr);
31647c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
31747c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
31847c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
319e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
32047c6ae99SBarry Smith 
32147c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
32247c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
32347c6ae99SBarry Smith 
324aa219208SBarry 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\
32547c6ae99SBarry Smith                                           j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
326aa219208SBarry 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\
32747c6ae99SBarry Smith                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
32847c6ae99SBarry Smith 
32947c6ae99SBarry Smith       /*
33047c6ae99SBarry Smith        Only include those interpolation points that are truly
33147c6ae99SBarry Smith        nonzero. Note this is very important for final grid lines
33247c6ae99SBarry Smith        in x and y directions; since they have no right/top neighbors
33347c6ae99SBarry Smith        */
33447c6ae99SBarry Smith       nc = 0;
33547c6ae99SBarry Smith       /* one left and below; or we are right on it */
336e3fbd1f4SBarry Smith       col        = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
337e3fbd1f4SBarry Smith       cols[nc++] = col_shift + idx_c[col];
33847c6ae99SBarry Smith       /* one right and below */
339e3fbd1f4SBarry Smith       if (i_c*ratioi != i) cols[nc++] = col_shift + idx_c[col+1];
34047c6ae99SBarry Smith       /* one left and above */
341e3fbd1f4SBarry Smith       if (j_c*ratioj != j) cols[nc++] = col_shift + idx_c[col+m_ghost_c];
34247c6ae99SBarry Smith       /* one right and above */
343e3fbd1f4SBarry Smith       if (i_c*ratioi != i && j_c*ratioj != j) cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)];
34447c6ae99SBarry Smith       ierr = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
34547c6ae99SBarry Smith     }
34647c6ae99SBarry Smith   }
347ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)daf),&mat);CHKERRQ(ierr);
34847c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);CHKERRQ(ierr);
34947c6ae99SBarry Smith   ierr = MatSetType(mat,MATAIJ);CHKERRQ(ierr);
35047c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
35147c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
35247c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
35347c6ae99SBarry Smith 
35447c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
35585afcc9aSBarry Smith   if (!NEWVERSION) {
356b3bd94feSDave May 
35747c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
35847c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
35947c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
360e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
36147c6ae99SBarry Smith 
36247c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
36347c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
36447c6ae99SBarry Smith 
36547c6ae99SBarry Smith         /*
36647c6ae99SBarry Smith          Only include those interpolation points that are truly
36747c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
36847c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
36947c6ae99SBarry Smith          */
3706712e2f1SBarry Smith         x = ((PetscReal)(i - i_c*ratioi))/((PetscReal)ratioi);
3716712e2f1SBarry Smith         y = ((PetscReal)(j - j_c*ratioj))/((PetscReal)ratioj);
372b3bd94feSDave May 
37347c6ae99SBarry Smith         nc = 0;
37447c6ae99SBarry Smith         /* one left and below; or we are right on it */
375e3fbd1f4SBarry Smith         col      = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
376e3fbd1f4SBarry Smith         cols[nc] = col_shift + idx_c[col];
37747c6ae99SBarry Smith         v[nc++]  = x*y - x - y + 1.0;
37847c6ae99SBarry Smith         /* one right and below */
37947c6ae99SBarry Smith         if (i_c*ratioi != i) {
380e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+1];
38147c6ae99SBarry Smith           v[nc++]  = -x*y + x;
38247c6ae99SBarry Smith         }
38347c6ae99SBarry Smith         /* one left and above */
38447c6ae99SBarry Smith         if (j_c*ratioj != j) {
385e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+m_ghost_c];
38647c6ae99SBarry Smith           v[nc++]  = -x*y + y;
38747c6ae99SBarry Smith         }
38847c6ae99SBarry Smith         /* one right and above */
38947c6ae99SBarry Smith         if (j_c*ratioj != j && i_c*ratioi != i) {
390e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)];
39147c6ae99SBarry Smith           v[nc++]  = x*y;
39247c6ae99SBarry Smith         }
39347c6ae99SBarry Smith         ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
39447c6ae99SBarry Smith       }
39547c6ae99SBarry Smith     }
396b3bd94feSDave May 
397b3bd94feSDave May   } else {
398b3bd94feSDave May     PetscScalar Ni[4];
399b3bd94feSDave May     PetscScalar *xi,*eta;
400b3bd94feSDave May     PetscInt    li,nxi,lj,neta;
401b3bd94feSDave May 
402b3bd94feSDave May     /* compute local coordinate arrays */
403b3bd94feSDave May     nxi  = ratioi + 1;
404b3bd94feSDave May     neta = ratioj + 1;
405854ce69bSBarry Smith     ierr = PetscMalloc1(nxi,&xi);CHKERRQ(ierr);
406854ce69bSBarry Smith     ierr = PetscMalloc1(neta,&eta);CHKERRQ(ierr);
407b3bd94feSDave May     for (li=0; li<nxi; li++) {
40852218ef2SJed Brown       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
409b3bd94feSDave May     }
410b3bd94feSDave May     for (lj=0; lj<neta; lj++) {
41152218ef2SJed Brown       eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
412b3bd94feSDave May     }
413b3bd94feSDave May 
414b3bd94feSDave May     /* loop over local fine grid nodes setting interpolation for those*/
415b3bd94feSDave May     for (j=j_start; j<j_start+n_f; j++) {
416b3bd94feSDave May       for (i=i_start; i<i_start+m_f; i++) {
417b3bd94feSDave May         /* convert to local "natural" numbering and then to PETSc global numbering */
418e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
419b3bd94feSDave May 
420b3bd94feSDave May         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
421b3bd94feSDave May         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
422b3bd94feSDave May 
423b3bd94feSDave May         /* remainders */
424b3bd94feSDave May         li = i - ratioi * (i/ratioi);
4258865f1eaSKarl Rupp         if (i==mx-1) li = nxi-1;
426b3bd94feSDave May         lj = j - ratioj * (j/ratioj);
4278865f1eaSKarl Rupp         if (j==my-1) lj = neta-1;
428b3bd94feSDave May 
429b3bd94feSDave May         /* corners */
430e3fbd1f4SBarry Smith         col     = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
431e3fbd1f4SBarry Smith         cols[0] = col_shift + idx_c[col]; /* left, below */
432b3bd94feSDave May         Ni[0]   = 1.0;
433b3bd94feSDave May         if ((li==0) || (li==nxi-1)) {
434b3bd94feSDave May           if ((lj==0) || (lj==neta-1)) {
435b3bd94feSDave May             ierr = MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);CHKERRQ(ierr);
436b3bd94feSDave May             continue;
437b3bd94feSDave May           }
438b3bd94feSDave May         }
439b3bd94feSDave May 
440b3bd94feSDave May         /* edges + interior */
441b3bd94feSDave May         /* remainders */
4428865f1eaSKarl Rupp         if (i==mx-1) i_c--;
4438865f1eaSKarl Rupp         if (j==my-1) j_c--;
444b3bd94feSDave May 
445e3fbd1f4SBarry Smith         col     = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
446e3fbd1f4SBarry Smith         cols[0] = col_shift + idx_c[col]; /* left, below */
447e3fbd1f4SBarry Smith         cols[1] = col_shift + idx_c[col+1]; /* right, below */
448e3fbd1f4SBarry Smith         cols[2] = col_shift + idx_c[col+m_ghost_c]; /* left, above */
449e3fbd1f4SBarry Smith         cols[3] = col_shift + idx_c[col+(m_ghost_c+1)]; /* right, above */
450b3bd94feSDave May 
451b3bd94feSDave May         Ni[0] = 0.25*(1.0-xi[li])*(1.0-eta[lj]);
452b3bd94feSDave May         Ni[1] = 0.25*(1.0+xi[li])*(1.0-eta[lj]);
453b3bd94feSDave May         Ni[2] = 0.25*(1.0-xi[li])*(1.0+eta[lj]);
454b3bd94feSDave May         Ni[3] = 0.25*(1.0+xi[li])*(1.0+eta[lj]);
455b3bd94feSDave May 
456b3bd94feSDave May         nc = 0;
4578865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[0])<1.0e-32) cols[0]=-1;
4588865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[1])<1.0e-32) cols[1]=-1;
4598865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[2])<1.0e-32) cols[2]=-1;
4608865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[3])<1.0e-32) cols[3]=-1;
461b3bd94feSDave May 
462b3bd94feSDave May         ierr = MatSetValues(mat,1,&row,4,cols,Ni,INSERT_VALUES);CHKERRQ(ierr);
463b3bd94feSDave May       }
464b3bd94feSDave May     }
465b3bd94feSDave May     ierr = PetscFree(xi);CHKERRQ(ierr);
466b3bd94feSDave May     ierr = PetscFree(eta);CHKERRQ(ierr);
467b3bd94feSDave May   }
46845b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
46945b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
47047c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
47147c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
47247c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
473fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
47447c6ae99SBarry Smith   PetscFunctionReturn(0);
47547c6ae99SBarry Smith }
47647c6ae99SBarry Smith 
47747c6ae99SBarry Smith /*
47847c6ae99SBarry Smith        Contributed by Andrei Draganescu <aidraga@sandia.gov>
47947c6ae99SBarry Smith */
480e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_2D_Q0(DM dac,DM daf,Mat *A)
48147c6ae99SBarry Smith {
48247c6ae99SBarry Smith   PetscErrorCode         ierr;
4838ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
4848ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
485e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
4868ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,*dnz,*onz;
48747c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
48847c6ae99SBarry 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;
48947c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
49047c6ae99SBarry Smith   PetscScalar            v[4];
49147c6ae99SBarry Smith   Mat                    mat;
492bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
49347c6ae99SBarry Smith 
49447c6ae99SBarry Smith   PetscFunctionBegin;
4951321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);CHKERRQ(ierr);
4961321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
49747c6ae99SBarry Smith   ratioi = mx/Mx;
49847c6ae99SBarry Smith   ratioj = my/My;
499ce94432eSBarry 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");
500ce94432eSBarry 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");
501ce94432eSBarry Smith   if (ratioi != 2) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 2");
502ce94432eSBarry Smith   if (ratioj != 2) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 2");
50347c6ae99SBarry Smith 
504aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);CHKERRQ(ierr);
505aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);CHKERRQ(ierr);
50645b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
50745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
50847c6ae99SBarry Smith 
509aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);CHKERRQ(ierr);
510aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);CHKERRQ(ierr);
51145b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
51245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
51347c6ae99SBarry Smith 
51447c6ae99SBarry Smith   /*
515aa219208SBarry Smith      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
51647c6ae99SBarry Smith      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
51747c6ae99SBarry Smith      processors). It's effective length is hence 4 times its normal length, this is
51847c6ae99SBarry Smith      why the col_scale is multiplied by the interpolation matrix column sizes.
51947c6ae99SBarry Smith      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
52047c6ae99SBarry Smith      copy of the coarse vector. A bit of a hack but you do better.
52147c6ae99SBarry Smith 
52247c6ae99SBarry Smith      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
52347c6ae99SBarry Smith   */
524ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);CHKERRQ(ierr);
525ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);CHKERRQ(ierr);
526ce94432eSBarry Smith   ierr      = MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);CHKERRQ(ierr);
52747c6ae99SBarry Smith   col_scale = size_f/size_c;
52847c6ae99SBarry Smith   col_shift = Mx*My*(rank_f/size_c);
52947c6ae99SBarry Smith 
530ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f,col_scale*m_c*n_c,dnz,onz);CHKERRQ(ierr);
53147c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
53247c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
53347c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
534e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
53547c6ae99SBarry Smith 
53647c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
53747c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
53847c6ae99SBarry Smith 
539aa219208SBarry 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\
54047c6ae99SBarry Smith     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
541aa219208SBarry 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\
54247c6ae99SBarry Smith     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
54347c6ae99SBarry Smith 
54447c6ae99SBarry Smith       /*
54547c6ae99SBarry Smith          Only include those interpolation points that are truly
54647c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
54747c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
54847c6ae99SBarry Smith       */
54947c6ae99SBarry Smith       nc = 0;
55047c6ae99SBarry Smith       /* one left and below; or we are right on it */
551e3fbd1f4SBarry Smith       col        = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
552e3fbd1f4SBarry Smith       cols[nc++] = col_shift + idx_c[col];
55347c6ae99SBarry Smith       ierr       = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
55447c6ae99SBarry Smith     }
55547c6ae99SBarry Smith   }
556ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)daf),&mat);CHKERRQ(ierr);
55747c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);CHKERRQ(ierr);
55847c6ae99SBarry Smith   ierr = MatSetType(mat,MATAIJ);CHKERRQ(ierr);
55947c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
56047c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
56147c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
56247c6ae99SBarry Smith 
56347c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
56447c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
56547c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
56647c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
567e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
56847c6ae99SBarry Smith 
56947c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
57047c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
57147c6ae99SBarry Smith       nc  = 0;
57247c6ae99SBarry Smith       /* one left and below; or we are right on it */
573e3fbd1f4SBarry Smith       col      = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
574e3fbd1f4SBarry Smith       cols[nc] = col_shift + idx_c[col];
57547c6ae99SBarry Smith       v[nc++]  = 1.0;
57647c6ae99SBarry Smith 
57747c6ae99SBarry Smith       ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
57847c6ae99SBarry Smith     }
57947c6ae99SBarry Smith   }
58045b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
58145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
58247c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
58347c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
58447c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
585fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
58647c6ae99SBarry Smith   ierr = PetscLogFlops(13.0*m_f*n_f);CHKERRQ(ierr);
58747c6ae99SBarry Smith   PetscFunctionReturn(0);
58847c6ae99SBarry Smith }
58947c6ae99SBarry Smith 
59047c6ae99SBarry Smith /*
59147c6ae99SBarry Smith        Contributed by Jianming Yang <jianming-yang@uiowa.edu>
59247c6ae99SBarry Smith */
593e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_3D_Q0(DM dac,DM daf,Mat *A)
59447c6ae99SBarry Smith {
59547c6ae99SBarry Smith   PetscErrorCode         ierr;
5968ea3bf28SBarry Smith   PetscInt               i,j,l,i_start,j_start,l_start,m_f,n_f,p_f,Mx,My,Mz,dof;
5978ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
598e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
5998ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,p_ghost,m_ghost_c,n_ghost_c,p_ghost_c,nc,*dnz,*onz;
60047c6ae99SBarry 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;
60147c6ae99SBarry 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;
60247c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
60347c6ae99SBarry Smith   PetscScalar            v[8];
60447c6ae99SBarry Smith   Mat                    mat;
605bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
60647c6ae99SBarry Smith 
60747c6ae99SBarry Smith   PetscFunctionBegin;
6081321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);CHKERRQ(ierr);
6091321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
61047c6ae99SBarry Smith   ratioi = mx/Mx;
61147c6ae99SBarry Smith   ratioj = my/My;
61247c6ae99SBarry Smith   ratiol = mz/Mz;
613ce94432eSBarry 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");
614ce94432eSBarry 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");
615ce94432eSBarry 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");
616ce94432eSBarry Smith   if (ratioi != 2 && ratioi != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 1 or 2");
617ce94432eSBarry Smith   if (ratioj != 2 && ratioj != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 1 or 2");
618ce94432eSBarry Smith   if (ratiol != 2 && ratiol != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in z must be 1 or 2");
61947c6ae99SBarry Smith 
620aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
621aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
62245b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
62345b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
62447c6ae99SBarry Smith 
625aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
626aa219208SBarry 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);
62745b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
62845b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
629e3fbd1f4SBarry Smith 
63047c6ae99SBarry Smith   /*
631aa219208SBarry Smith      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
63247c6ae99SBarry Smith      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
63347c6ae99SBarry Smith      processors). It's effective length is hence 4 times its normal length, this is
63447c6ae99SBarry Smith      why the col_scale is multiplied by the interpolation matrix column sizes.
63547c6ae99SBarry Smith      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
63647c6ae99SBarry Smith      copy of the coarse vector. A bit of a hack but you do better.
63747c6ae99SBarry Smith 
63847c6ae99SBarry Smith      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
63947c6ae99SBarry Smith   */
640ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);CHKERRQ(ierr);
641ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);CHKERRQ(ierr);
642ce94432eSBarry Smith   ierr      = MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);CHKERRQ(ierr);
64347c6ae99SBarry Smith   col_scale = size_f/size_c;
64447c6ae99SBarry Smith   col_shift = Mx*My*Mz*(rank_f/size_c);
64547c6ae99SBarry Smith 
646ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f*p_f,col_scale*m_c*n_c*p_c,dnz,onz);CHKERRQ(ierr);
64747c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
64847c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
64947c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
65047c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
651e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
65247c6ae99SBarry Smith 
65347c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
65447c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
65547c6ae99SBarry Smith         l_c = (l/ratiol);
65647c6ae99SBarry Smith 
657aa219208SBarry 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\
65847c6ae99SBarry Smith     l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
659aa219208SBarry 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\
66047c6ae99SBarry Smith     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
661aa219208SBarry 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\
66247c6ae99SBarry Smith     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
66347c6ae99SBarry Smith 
66447c6ae99SBarry Smith         /*
66547c6ae99SBarry Smith            Only include those interpolation points that are truly
66647c6ae99SBarry Smith            nonzero. Note this is very important for final grid lines
66747c6ae99SBarry Smith            in x and y directions; since they have no right/top neighbors
66847c6ae99SBarry Smith         */
66947c6ae99SBarry Smith         nc = 0;
67047c6ae99SBarry Smith         /* one left and below; or we are right on it */
671e3fbd1f4SBarry 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));
672e3fbd1f4SBarry Smith         cols[nc++] = col_shift + idx_c[col];
67347c6ae99SBarry Smith         ierr       = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
67447c6ae99SBarry Smith       }
67547c6ae99SBarry Smith     }
67647c6ae99SBarry Smith   }
677ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)daf),&mat);CHKERRQ(ierr);
67847c6ae99SBarry 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);
67947c6ae99SBarry Smith   ierr = MatSetType(mat,MATAIJ);CHKERRQ(ierr);
68047c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
68147c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
68247c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
68347c6ae99SBarry Smith 
68447c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
68547c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
68647c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
68747c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
68847c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
689e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
69047c6ae99SBarry Smith 
69147c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
69247c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
69347c6ae99SBarry Smith         l_c = (l/ratiol);
69447c6ae99SBarry Smith         nc  = 0;
69547c6ae99SBarry Smith         /* one left and below; or we are right on it */
696e3fbd1f4SBarry 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));
697e3fbd1f4SBarry Smith         cols[nc] = col_shift + idx_c[col];
69847c6ae99SBarry Smith         v[nc++]  = 1.0;
69947c6ae99SBarry Smith 
70047c6ae99SBarry Smith         ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
70147c6ae99SBarry Smith       }
70247c6ae99SBarry Smith     }
70347c6ae99SBarry Smith   }
70445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
70545b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
70647c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
70747c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
70847c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
709fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
71047c6ae99SBarry Smith   ierr = PetscLogFlops(13.0*m_f*n_f*p_f);CHKERRQ(ierr);
71147c6ae99SBarry Smith   PetscFunctionReturn(0);
71247c6ae99SBarry Smith }
71347c6ae99SBarry Smith 
714e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_3D_Q1(DM dac,DM daf,Mat *A)
71547c6ae99SBarry Smith {
71647c6ae99SBarry Smith   PetscErrorCode         ierr;
7178ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof,l;
7188ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
719e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
7208ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,Mz,mz;
72147c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
72247c6ae99SBarry Smith   PetscInt               i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
72347c6ae99SBarry Smith   PetscInt               l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
72447c6ae99SBarry Smith   PetscInt               l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
72547c6ae99SBarry Smith   PetscScalar            v[8],x,y,z;
72647c6ae99SBarry Smith   Mat                    mat;
727bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
72847c6ae99SBarry Smith 
72947c6ae99SBarry Smith   PetscFunctionBegin;
7301321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);CHKERRQ(ierr);
7311321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
73247c6ae99SBarry Smith   if (mx == Mx) {
73347c6ae99SBarry Smith     ratioi = 1;
734bff4a2f0SMatthew G. Knepley   } else if (bx == DM_BOUNDARY_PERIODIC) {
73547c6ae99SBarry Smith     ratioi = mx/Mx;
73647c6ae99SBarry 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);
73747c6ae99SBarry Smith   } else {
73847c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
73947c6ae99SBarry 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);
74047c6ae99SBarry Smith   }
74147c6ae99SBarry Smith   if (my == My) {
74247c6ae99SBarry Smith     ratioj = 1;
743bff4a2f0SMatthew G. Knepley   } else if (by == DM_BOUNDARY_PERIODIC) {
74447c6ae99SBarry Smith     ratioj = my/My;
74547c6ae99SBarry 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);
74647c6ae99SBarry Smith   } else {
74747c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
74847c6ae99SBarry 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);
74947c6ae99SBarry Smith   }
75047c6ae99SBarry Smith   if (mz == Mz) {
75147c6ae99SBarry Smith     ratiok = 1;
752bff4a2f0SMatthew G. Knepley   } else if (bz == DM_BOUNDARY_PERIODIC) {
75347c6ae99SBarry Smith     ratiok = mz/Mz;
75447c6ae99SBarry 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);
75547c6ae99SBarry Smith   } else {
75647c6ae99SBarry Smith     ratiok = (mz-1)/(Mz-1);
75747c6ae99SBarry 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);
75847c6ae99SBarry Smith   }
75947c6ae99SBarry Smith 
760aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
761aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
76245b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
76345b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
76447c6ae99SBarry Smith 
765aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
766aa219208SBarry 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);
76745b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
76845b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
76947c6ae99SBarry Smith 
77047c6ae99SBarry Smith   /* create interpolation matrix, determining exact preallocation */
771ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)dac),m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);CHKERRQ(ierr);
77247c6ae99SBarry Smith   /* loop over local fine grid nodes counting interpolating points */
77347c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
77447c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
77547c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
77647c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
777e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
77847c6ae99SBarry Smith         i_c = (i/ratioi);
77947c6ae99SBarry Smith         j_c = (j/ratioj);
78047c6ae99SBarry Smith         l_c = (l/ratiok);
781aa219208SBarry 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\
78247c6ae99SBarry Smith                                             l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
783aa219208SBarry 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\
78447c6ae99SBarry Smith                                             j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
785aa219208SBarry 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\
78647c6ae99SBarry Smith                                             i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
78747c6ae99SBarry Smith 
78847c6ae99SBarry Smith         /*
78947c6ae99SBarry Smith          Only include those interpolation points that are truly
79047c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
79147c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
79247c6ae99SBarry Smith          */
79347c6ae99SBarry Smith         nc         = 0;
794e3fbd1f4SBarry 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));
795e3fbd1f4SBarry Smith         cols[nc++] = idx_c[col];
79647c6ae99SBarry Smith         if (i_c*ratioi != i) {
797e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+1];
79847c6ae99SBarry Smith         }
79947c6ae99SBarry Smith         if (j_c*ratioj != j) {
800e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+m_ghost_c];
80147c6ae99SBarry Smith         }
80247c6ae99SBarry Smith         if (l_c*ratiok != l) {
803e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c];
80447c6ae99SBarry Smith         }
80547c6ae99SBarry Smith         if (j_c*ratioj != j && i_c*ratioi != i) {
806e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c+1)];
80747c6ae99SBarry Smith         }
80847c6ae99SBarry Smith         if (j_c*ratioj != j && l_c*ratiok != l) {
809e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)];
81047c6ae99SBarry Smith         }
81147c6ae99SBarry Smith         if (i_c*ratioi != i && l_c*ratiok != l) {
812e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)];
81347c6ae99SBarry Smith         }
81447c6ae99SBarry Smith         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
815e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)];
81647c6ae99SBarry Smith         }
81747c6ae99SBarry Smith         ierr = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
81847c6ae99SBarry Smith       }
81947c6ae99SBarry Smith     }
82047c6ae99SBarry Smith   }
821ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)dac),&mat);CHKERRQ(ierr);
82247c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz);CHKERRQ(ierr);
82347c6ae99SBarry Smith   ierr = MatSetType(mat,MATAIJ);CHKERRQ(ierr);
82447c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
82547c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
82647c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
82747c6ae99SBarry Smith 
82847c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
8292adb9dcfSBarry Smith   if (!NEWVERSION) {
830b3bd94feSDave May 
83147c6ae99SBarry Smith     for (l=l_start; l<l_start+p_f; l++) {
83247c6ae99SBarry Smith       for (j=j_start; j<j_start+n_f; j++) {
83347c6ae99SBarry Smith         for (i=i_start; i<i_start+m_f; i++) {
83447c6ae99SBarry Smith           /* convert to local "natural" numbering and then to PETSc global numbering */
835e3fbd1f4SBarry Smith           row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
83647c6ae99SBarry Smith 
83747c6ae99SBarry Smith           i_c = (i/ratioi);
83847c6ae99SBarry Smith           j_c = (j/ratioj);
83947c6ae99SBarry Smith           l_c = (l/ratiok);
84047c6ae99SBarry Smith 
84147c6ae99SBarry Smith           /*
84247c6ae99SBarry Smith            Only include those interpolation points that are truly
84347c6ae99SBarry Smith            nonzero. Note this is very important for final grid lines
84447c6ae99SBarry Smith            in x and y directions; since they have no right/top neighbors
84547c6ae99SBarry Smith            */
8466712e2f1SBarry Smith           x = ((PetscReal)(i - i_c*ratioi))/((PetscReal)ratioi);
8476712e2f1SBarry Smith           y = ((PetscReal)(j - j_c*ratioj))/((PetscReal)ratioj);
8486712e2f1SBarry Smith           z = ((PetscReal)(l - l_c*ratiok))/((PetscReal)ratiok);
849b3bd94feSDave May 
85047c6ae99SBarry Smith           nc = 0;
85147c6ae99SBarry Smith           /* one left and below; or we are right on it */
852e3fbd1f4SBarry 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));
85347c6ae99SBarry Smith 
854e3fbd1f4SBarry Smith           cols[nc] = idx_c[col];
85547c6ae99SBarry Smith           v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
85647c6ae99SBarry Smith 
85747c6ae99SBarry Smith           if (i_c*ratioi != i) {
858e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+1];
85947c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
86047c6ae99SBarry Smith           }
86147c6ae99SBarry Smith 
86247c6ae99SBarry Smith           if (j_c*ratioj != j) {
863e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+m_ghost_c];
86447c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
86547c6ae99SBarry Smith           }
86647c6ae99SBarry Smith 
86747c6ae99SBarry Smith           if (l_c*ratiok != l) {
868e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+m_ghost_c*n_ghost_c];
86947c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
87047c6ae99SBarry Smith           }
87147c6ae99SBarry Smith 
87247c6ae99SBarry Smith           if (j_c*ratioj != j && i_c*ratioi != i) {
873e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c+1)];
87447c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
87547c6ae99SBarry Smith           }
87647c6ae99SBarry Smith 
87747c6ae99SBarry Smith           if (j_c*ratioj != j && l_c*ratiok != l) {
878e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)];
87947c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
88047c6ae99SBarry Smith           }
88147c6ae99SBarry Smith 
88247c6ae99SBarry Smith           if (i_c*ratioi != i && l_c*ratiok != l) {
883e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+1)];
88447c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
88547c6ae99SBarry Smith           }
88647c6ae99SBarry Smith 
88747c6ae99SBarry Smith           if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
888e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)];
88947c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
89047c6ae99SBarry Smith           }
89147c6ae99SBarry Smith           ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
89247c6ae99SBarry Smith         }
89347c6ae99SBarry Smith       }
89447c6ae99SBarry Smith     }
895b3bd94feSDave May 
896b3bd94feSDave May   } else {
897b3bd94feSDave May     PetscScalar *xi,*eta,*zeta;
898b3bd94feSDave May     PetscInt    li,nxi,lj,neta,lk,nzeta,n;
899b3bd94feSDave May     PetscScalar Ni[8];
900b3bd94feSDave May 
901b3bd94feSDave May     /* compute local coordinate arrays */
902b3bd94feSDave May     nxi   = ratioi + 1;
903b3bd94feSDave May     neta  = ratioj + 1;
904b3bd94feSDave May     nzeta = ratiok + 1;
905854ce69bSBarry Smith     ierr  = PetscMalloc1(nxi,&xi);CHKERRQ(ierr);
906854ce69bSBarry Smith     ierr  = PetscMalloc1(neta,&eta);CHKERRQ(ierr);
907854ce69bSBarry Smith     ierr  = PetscMalloc1(nzeta,&zeta);CHKERRQ(ierr);
9088865f1eaSKarl Rupp     for (li=0; li<nxi; li++) xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
9098865f1eaSKarl Rupp     for (lj=0; lj<neta; lj++) eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
9108865f1eaSKarl Rupp     for (lk=0; lk<nzeta; lk++) zeta[lk] = -1.0 + (PetscScalar)lk*(2.0/(PetscScalar)(nzeta-1));
911b3bd94feSDave May 
912b3bd94feSDave May     for (l=l_start; l<l_start+p_f; l++) {
913b3bd94feSDave May       for (j=j_start; j<j_start+n_f; j++) {
914b3bd94feSDave May         for (i=i_start; i<i_start+m_f; i++) {
915b3bd94feSDave May           /* convert to local "natural" numbering and then to PETSc global numbering */
916e3fbd1f4SBarry Smith           row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
917b3bd94feSDave May 
918b3bd94feSDave May           i_c = (i/ratioi);
919b3bd94feSDave May           j_c = (j/ratioj);
920b3bd94feSDave May           l_c = (l/ratiok);
921b3bd94feSDave May 
922b3bd94feSDave May           /* remainders */
923b3bd94feSDave May           li = i - ratioi * (i/ratioi);
9248865f1eaSKarl Rupp           if (i==mx-1) li = nxi-1;
925b3bd94feSDave May           lj = j - ratioj * (j/ratioj);
9268865f1eaSKarl Rupp           if (j==my-1) lj = neta-1;
927b3bd94feSDave May           lk = l - ratiok * (l/ratiok);
9288865f1eaSKarl Rupp           if (l==mz-1) lk = nzeta-1;
929b3bd94feSDave May 
930b3bd94feSDave May           /* corners */
931e3fbd1f4SBarry 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));
932e3fbd1f4SBarry Smith           cols[0] = idx_c[col];
933b3bd94feSDave May           Ni[0]   = 1.0;
934b3bd94feSDave May           if ((li==0) || (li==nxi-1)) {
935b3bd94feSDave May             if ((lj==0) || (lj==neta-1)) {
936b3bd94feSDave May               if ((lk==0) || (lk==nzeta-1)) {
937b3bd94feSDave May                 ierr = MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);CHKERRQ(ierr);
938b3bd94feSDave May                 continue;
939b3bd94feSDave May               }
940b3bd94feSDave May             }
941b3bd94feSDave May           }
942b3bd94feSDave May 
943b3bd94feSDave May           /* edges + interior */
944b3bd94feSDave May           /* remainders */
9458865f1eaSKarl Rupp           if (i==mx-1) i_c--;
9468865f1eaSKarl Rupp           if (j==my-1) j_c--;
9478865f1eaSKarl Rupp           if (l==mz-1) l_c--;
948b3bd94feSDave May 
949e3fbd1f4SBarry 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));
950e3fbd1f4SBarry Smith           cols[0] = idx_c[col]; /* one left and below; or we are right on it */
951e3fbd1f4SBarry Smith           cols[1] = idx_c[col+1]; /* one right and below */
952e3fbd1f4SBarry Smith           cols[2] = idx_c[col+m_ghost_c];  /* one left and above */
953e3fbd1f4SBarry Smith           cols[3] = idx_c[col+(m_ghost_c+1)]; /* one right and above */
954b3bd94feSDave May 
955e3fbd1f4SBarry Smith           cols[4] = idx_c[col+m_ghost_c*n_ghost_c]; /* one left and below and front; or we are right on it */
956e3fbd1f4SBarry Smith           cols[5] = idx_c[col+(m_ghost_c*n_ghost_c+1)]; /* one right and below, and front */
957e3fbd1f4SBarry Smith           cols[6] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)]; /* one left and above and front*/
958e3fbd1f4SBarry Smith           cols[7] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)]; /* one right and above and front */
959b3bd94feSDave May 
960b3bd94feSDave May           Ni[0] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
961b3bd94feSDave May           Ni[1] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
962b3bd94feSDave May           Ni[2] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);
963b3bd94feSDave May           Ni[3] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);
964b3bd94feSDave May 
965b3bd94feSDave May           Ni[4] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
966b3bd94feSDave May           Ni[5] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
967b3bd94feSDave May           Ni[6] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);
968b3bd94feSDave May           Ni[7] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);
969b3bd94feSDave May 
970b3bd94feSDave May           for (n=0; n<8; n++) {
9718865f1eaSKarl Rupp             if (PetscAbsScalar(Ni[n])<1.0e-32) cols[n]=-1;
972b3bd94feSDave May           }
973b3bd94feSDave May           ierr = MatSetValues(mat,1,&row,8,cols,Ni,INSERT_VALUES);CHKERRQ(ierr);
974b3bd94feSDave May 
975b3bd94feSDave May         }
976b3bd94feSDave May       }
977b3bd94feSDave May     }
978b3bd94feSDave May     ierr = PetscFree(xi);CHKERRQ(ierr);
979b3bd94feSDave May     ierr = PetscFree(eta);CHKERRQ(ierr);
980b3bd94feSDave May     ierr = PetscFree(zeta);CHKERRQ(ierr);
981b3bd94feSDave May   }
98245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
98345b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
98447c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
98547c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
98647c6ae99SBarry Smith 
98747c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
988fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
98947c6ae99SBarry Smith   PetscFunctionReturn(0);
99047c6ae99SBarry Smith }
99147c6ae99SBarry Smith 
992e727c939SJed Brown PetscErrorCode  DMCreateInterpolation_DA(DM dac,DM daf,Mat *A,Vec *scale)
99347c6ae99SBarry Smith {
99447c6ae99SBarry Smith   PetscErrorCode   ierr;
99547c6ae99SBarry Smith   PetscInt         dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
996bff4a2f0SMatthew G. Knepley   DMBoundaryType   bxc,byc,bzc,bxf,byf,bzf;
997aa219208SBarry Smith   DMDAStencilType  stc,stf;
99847c6ae99SBarry Smith   DM_DA            *ddc = (DM_DA*)dac->data;
99947c6ae99SBarry Smith 
100047c6ae99SBarry Smith   PetscFunctionBegin;
100147c6ae99SBarry Smith   PetscValidHeaderSpecific(dac,DM_CLASSID,1);
100247c6ae99SBarry Smith   PetscValidHeaderSpecific(daf,DM_CLASSID,2);
100347c6ae99SBarry Smith   PetscValidPointer(A,3);
100447c6ae99SBarry Smith   if (scale) PetscValidPointer(scale,4);
100547c6ae99SBarry Smith 
10061321219cSEthan Coon   ierr = DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);CHKERRQ(ierr);
10071321219cSEthan Coon   ierr = DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);CHKERRQ(ierr);
1008*13903a91SSatish Balay   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
1009*13903a91SSatish Balay   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
1010*13903a91SSatish Balay   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
1011*13903a91SSatish Balay   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
1012*13903a91SSatish Balay   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
101347c6ae99SBarry Smith   if (Mc < 2 && Mf > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
101447c6ae99SBarry 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");
101547c6ae99SBarry 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");
101647c6ae99SBarry Smith 
1017aa219208SBarry Smith   if (ddc->interptype == DMDA_Q1) {
101847c6ae99SBarry Smith     if (dimc == 1) {
1019e727c939SJed Brown       ierr = DMCreateInterpolation_DA_1D_Q1(dac,daf,A);CHKERRQ(ierr);
102047c6ae99SBarry Smith     } else if (dimc == 2) {
1021e727c939SJed Brown       ierr = DMCreateInterpolation_DA_2D_Q1(dac,daf,A);CHKERRQ(ierr);
102247c6ae99SBarry Smith     } else if (dimc == 3) {
1023e727c939SJed Brown       ierr = DMCreateInterpolation_DA_3D_Q1(dac,daf,A);CHKERRQ(ierr);
1024ce94432eSBarry Smith     } else SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
1025aa219208SBarry Smith   } else if (ddc->interptype == DMDA_Q0) {
102647c6ae99SBarry Smith     if (dimc == 1) {
1027e727c939SJed Brown       ierr = DMCreateInterpolation_DA_1D_Q0(dac,daf,A);CHKERRQ(ierr);
102847c6ae99SBarry Smith     } else if (dimc == 2) {
1029e727c939SJed Brown       ierr = DMCreateInterpolation_DA_2D_Q0(dac,daf,A);CHKERRQ(ierr);
103047c6ae99SBarry Smith     } else if (dimc == 3) {
1031e727c939SJed Brown       ierr = DMCreateInterpolation_DA_3D_Q0(dac,daf,A);CHKERRQ(ierr);
1032ce94432eSBarry Smith     } else SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
103347c6ae99SBarry Smith   }
103447c6ae99SBarry Smith   if (scale) {
1035e727c939SJed Brown     ierr = DMCreateInterpolationScale((DM)dac,(DM)daf,*A,scale);CHKERRQ(ierr);
103647c6ae99SBarry Smith   }
103747c6ae99SBarry Smith   PetscFunctionReturn(0);
103847c6ae99SBarry Smith }
103947c6ae99SBarry Smith 
1040e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_1D(DM dac,DM daf,VecScatter *inject)
10410bb2b966SJungho Lee {
10420bb2b966SJungho Lee   PetscErrorCode         ierr;
10438ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx,dof;
10448ea3bf28SBarry Smith   const PetscInt         *idx_f;
1045e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f;
10468ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
10470bb2b966SJungho Lee   PetscInt               row,i_start_ghost,mx,m_c,nc,ratioi;
10480bb2b966SJungho Lee   PetscInt               i_start_c,i_start_ghost_c;
10490bb2b966SJungho Lee   PetscInt               *cols;
1050bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
10510bb2b966SJungho Lee   Vec                    vecf,vecc;
10520bb2b966SJungho Lee   IS                     isf;
10530bb2b966SJungho Lee 
10540bb2b966SJungho Lee   PetscFunctionBegin;
10550bb2b966SJungho Lee   ierr = DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);CHKERRQ(ierr);
10560bb2b966SJungho Lee   ierr = DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
1057bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
10580bb2b966SJungho Lee     ratioi = mx/Mx;
10590bb2b966SJungho 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);
10600bb2b966SJungho Lee   } else {
10610bb2b966SJungho Lee     ratioi = (mx-1)/(Mx-1);
10620bb2b966SJungho 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);
10630bb2b966SJungho Lee   }
10640bb2b966SJungho Lee 
10650bb2b966SJungho Lee   ierr = DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);CHKERRQ(ierr);
10660bb2b966SJungho Lee   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);CHKERRQ(ierr);
106745b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
106845b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
10690bb2b966SJungho Lee 
10700bb2b966SJungho Lee   ierr = DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);CHKERRQ(ierr);
10710bb2b966SJungho Lee   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);CHKERRQ(ierr);
10720bb2b966SJungho Lee 
10730bb2b966SJungho Lee 
10740bb2b966SJungho Lee   /* loop over local fine grid nodes setting interpolation for those*/
10750bb2b966SJungho Lee   nc   = 0;
1076785e854fSJed Brown   ierr = PetscMalloc1(m_f,&cols);CHKERRQ(ierr);
10770bb2b966SJungho Lee 
10780bb2b966SJungho Lee 
10790bb2b966SJungho Lee   for (i=i_start_c; i<i_start_c+m_c; i++) {
10800bb2b966SJungho Lee     PetscInt i_f = i*ratioi;
10810bb2b966SJungho Lee 
10828865f1eaSKarl 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);
10838865f1eaSKarl Rupp 
1084e3fbd1f4SBarry Smith     row        = idx_f[(i_f-i_start_ghost)];
1085e3fbd1f4SBarry Smith     cols[nc++] = row;
10860bb2b966SJungho Lee   }
10870bb2b966SJungho Lee 
108845b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
1089ce94432eSBarry Smith   ierr = ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);CHKERRQ(ierr);
10900bb2b966SJungho Lee   ierr = DMGetGlobalVector(dac,&vecc);CHKERRQ(ierr);
10910bb2b966SJungho Lee   ierr = DMGetGlobalVector(daf,&vecf);CHKERRQ(ierr);
10920298fd71SBarry Smith   ierr = VecScatterCreate(vecf,isf,vecc,NULL,inject);CHKERRQ(ierr);
10930bb2b966SJungho Lee   ierr = DMRestoreGlobalVector(dac,&vecc);CHKERRQ(ierr);
10940bb2b966SJungho Lee   ierr = DMRestoreGlobalVector(daf,&vecf);CHKERRQ(ierr);
10950bb2b966SJungho Lee   ierr = ISDestroy(&isf);CHKERRQ(ierr);
10960bb2b966SJungho Lee   PetscFunctionReturn(0);
10970bb2b966SJungho Lee }
10980bb2b966SJungho Lee 
1099e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_2D(DM dac,DM daf,VecScatter *inject)
110047c6ae99SBarry Smith {
110147c6ae99SBarry Smith   PetscErrorCode         ierr;
11028ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
11038ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
1104e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
11058ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c;
110647c6ae99SBarry Smith   PetscInt               row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
1107076202ddSJed Brown   PetscInt               i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
110847c6ae99SBarry Smith   PetscInt               *cols;
1109bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
111047c6ae99SBarry Smith   Vec                    vecf,vecc;
111147c6ae99SBarry Smith   IS                     isf;
111247c6ae99SBarry Smith 
111347c6ae99SBarry Smith   PetscFunctionBegin;
11141321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);CHKERRQ(ierr);
11151321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
1116bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
111747c6ae99SBarry Smith     ratioi = mx/Mx;
111847c6ae99SBarry 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);
111947c6ae99SBarry Smith   } else {
112047c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
112147c6ae99SBarry 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);
112247c6ae99SBarry Smith   }
1123bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
112447c6ae99SBarry Smith     ratioj = my/My;
112547c6ae99SBarry 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);
112647c6ae99SBarry Smith   } else {
112747c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
112847c6ae99SBarry 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);
112947c6ae99SBarry Smith   }
113047c6ae99SBarry Smith 
1131aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);CHKERRQ(ierr);
1132aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);CHKERRQ(ierr);
113345b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
113445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
113547c6ae99SBarry Smith 
1136aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);CHKERRQ(ierr);
1137aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);CHKERRQ(ierr);
113845b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
113945b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
114047c6ae99SBarry Smith 
114147c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
114247c6ae99SBarry Smith   nc   = 0;
1143785e854fSJed Brown   ierr = PetscMalloc1(n_f*m_f,&cols);CHKERRQ(ierr);
1144076202ddSJed Brown   for (j=j_start_c; j<j_start_c+n_c; j++) {
1145076202ddSJed Brown     for (i=i_start_c; i<i_start_c+m_c; i++) {
1146076202ddSJed Brown       PetscInt i_f = i*ratioi,j_f = j*ratioj;
1147076202ddSJed 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\
1148076202ddSJed Brown     j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
1149076202ddSJed 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\
1150076202ddSJed Brown     i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1151e3fbd1f4SBarry Smith       row        = idx_f[(m_ghost*(j_f-j_start_ghost) + (i_f-i_start_ghost))];
1152e3fbd1f4SBarry Smith       cols[nc++] = row;
115347c6ae99SBarry Smith     }
115447c6ae99SBarry Smith   }
115545b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
115645b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
115747c6ae99SBarry Smith 
1158ce94432eSBarry Smith   ierr = ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);CHKERRQ(ierr);
11599a42bb27SBarry Smith   ierr = DMGetGlobalVector(dac,&vecc);CHKERRQ(ierr);
11609a42bb27SBarry Smith   ierr = DMGetGlobalVector(daf,&vecf);CHKERRQ(ierr);
11610298fd71SBarry Smith   ierr = VecScatterCreate(vecf,isf,vecc,NULL,inject);CHKERRQ(ierr);
11629a42bb27SBarry Smith   ierr = DMRestoreGlobalVector(dac,&vecc);CHKERRQ(ierr);
11639a42bb27SBarry Smith   ierr = DMRestoreGlobalVector(daf,&vecf);CHKERRQ(ierr);
1164fcfd50ebSBarry Smith   ierr = ISDestroy(&isf);CHKERRQ(ierr);
116547c6ae99SBarry Smith   PetscFunctionReturn(0);
116647c6ae99SBarry Smith }
116747c6ae99SBarry Smith 
1168e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_3D(DM dac,DM daf,VecScatter *inject)
1169b1757049SJed Brown {
1170b1757049SJed Brown   PetscErrorCode         ierr;
1171b1757049SJed Brown   PetscInt               i,j,k,i_start,j_start,k_start,m_f,n_f,p_f,Mx,My,Mz;
1172b1757049SJed Brown   PetscInt               m_ghost,n_ghost,p_ghost,m_ghost_c,n_ghost_c,p_ghost_c;
1173b1757049SJed Brown   PetscInt               i_start_ghost,j_start_ghost,k_start_ghost;
1174b1757049SJed Brown   PetscInt               mx,my,mz,ratioi,ratioj,ratiok;
1175b1757049SJed Brown   PetscInt               i_start_c,j_start_c,k_start_c;
1176b1757049SJed Brown   PetscInt               m_c,n_c,p_c;
1177b1757049SJed Brown   PetscInt               i_start_ghost_c,j_start_ghost_c,k_start_ghost_c;
1178b1757049SJed Brown   PetscInt               row,nc,dof;
11798ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
1180e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
1181b1757049SJed Brown   PetscInt               *cols;
1182bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
1183b1757049SJed Brown   Vec                    vecf,vecc;
1184b1757049SJed Brown   IS                     isf;
1185b1757049SJed Brown 
1186b1757049SJed Brown   PetscFunctionBegin;
11871321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);CHKERRQ(ierr);
11881321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
1189b1757049SJed Brown 
1190bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
1191b1757049SJed Brown     ratioi = mx/Mx;
1192b1757049SJed 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);
1193b1757049SJed Brown   } else {
1194b1757049SJed Brown     ratioi = (mx-1)/(Mx-1);
1195b1757049SJed 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);
1196b1757049SJed Brown   }
1197bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
1198b1757049SJed Brown     ratioj = my/My;
1199b1757049SJed 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);
1200b1757049SJed Brown   } else {
1201b1757049SJed Brown     ratioj = (my-1)/(My-1);
1202b1757049SJed 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);
1203b1757049SJed Brown   }
1204bff4a2f0SMatthew G. Knepley   if (bz == DM_BOUNDARY_PERIODIC) {
1205b1757049SJed Brown     ratiok = mz/Mz;
1206b1757049SJed 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);
1207b1757049SJed Brown   } else {
1208b1757049SJed Brown     ratiok = (mz-1)/(Mz-1);
1209b1757049SJed 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);
1210b1757049SJed Brown   }
1211b1757049SJed Brown 
1212b1757049SJed Brown   ierr = DMDAGetCorners(daf,&i_start,&j_start,&k_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
1213b1757049SJed Brown   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&k_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
121445b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
121545b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
1216b1757049SJed Brown 
1217b1757049SJed Brown   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&k_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
1218b1757049SJed 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);
121945b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
122045b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
1221b1757049SJed Brown 
1222b1757049SJed Brown 
1223b1757049SJed Brown   /* loop over local fine grid nodes setting interpolation for those*/
1224b1757049SJed Brown   nc   = 0;
1225785e854fSJed Brown   ierr = PetscMalloc1(n_f*m_f*p_f,&cols);CHKERRQ(ierr);
1226b1757049SJed Brown   for (k=k_start_c; k<k_start_c+p_c; k++) {
1227b1757049SJed Brown     for (j=j_start_c; j<j_start_c+n_c; j++) {
1228b1757049SJed Brown       for (i=i_start_c; i<i_start_c+m_c; i++) {
1229b1757049SJed Brown         PetscInt i_f = i*ratioi,j_f = j*ratioj,k_f = k*ratiok;
1230b1757049SJed 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  "
1231b1757049SJed Brown                                                                           "k_c %D k_f %D fine ghost range [%D,%D]",k,k_f,k_start_ghost,k_start_ghost+p_ghost);
1232b1757049SJed 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  "
1233b1757049SJed Brown                                                                           "j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
1234b1757049SJed 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  "
1235b1757049SJed Brown                                                                           "i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1236e3fbd1f4SBarry 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))];
1237e3fbd1f4SBarry Smith         cols[nc++] = row;
1238b1757049SJed Brown       }
1239b1757049SJed Brown     }
1240b1757049SJed Brown   }
124145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
124245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
1243b1757049SJed Brown 
1244ce94432eSBarry Smith   ierr = ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);CHKERRQ(ierr);
1245b1757049SJed Brown   ierr = DMGetGlobalVector(dac,&vecc);CHKERRQ(ierr);
1246b1757049SJed Brown   ierr = DMGetGlobalVector(daf,&vecf);CHKERRQ(ierr);
12470298fd71SBarry Smith   ierr = VecScatterCreate(vecf,isf,vecc,NULL,inject);CHKERRQ(ierr);
1248b1757049SJed Brown   ierr = DMRestoreGlobalVector(dac,&vecc);CHKERRQ(ierr);
1249b1757049SJed Brown   ierr = DMRestoreGlobalVector(daf,&vecf);CHKERRQ(ierr);
1250fcfd50ebSBarry Smith   ierr = ISDestroy(&isf);CHKERRQ(ierr);
1251b1757049SJed Brown   PetscFunctionReturn(0);
1252b1757049SJed Brown }
1253b1757049SJed Brown 
12546dbf9973SLawrence Mitchell PetscErrorCode  DMCreateInjection_DA(DM dac,DM daf,Mat *mat)
125547c6ae99SBarry Smith {
125647c6ae99SBarry Smith   PetscErrorCode  ierr;
125747c6ae99SBarry Smith   PetscInt        dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1258bff4a2f0SMatthew G. Knepley   DMBoundaryType  bxc,byc,bzc,bxf,byf,bzf;
1259aa219208SBarry Smith   DMDAStencilType stc,stf;
126060c16ac1SBarry Smith   VecScatter      inject = NULL;
126147c6ae99SBarry Smith 
126247c6ae99SBarry Smith   PetscFunctionBegin;
126347c6ae99SBarry Smith   PetscValidHeaderSpecific(dac,DM_CLASSID,1);
126447c6ae99SBarry Smith   PetscValidHeaderSpecific(daf,DM_CLASSID,2);
12656dbf9973SLawrence Mitchell   PetscValidPointer(mat,3);
126647c6ae99SBarry Smith 
12671321219cSEthan Coon   ierr = DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);CHKERRQ(ierr);
12681321219cSEthan Coon   ierr = DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);CHKERRQ(ierr);
1269*13903a91SSatish Balay   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
1270*13903a91SSatish Balay   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
1271*13903a91SSatish Balay   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
1272*13903a91SSatish Balay   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
1273*13903a91SSatish Balay   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
127447c6ae99SBarry Smith   if (Mc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
127547c6ae99SBarry Smith   if (dimc > 1 && Nc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
127647c6ae99SBarry Smith   if (dimc > 2 && Pc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");
127747c6ae99SBarry Smith 
12780bb2b966SJungho Lee   if (dimc == 1) {
12796dbf9973SLawrence Mitchell     ierr = DMCreateInjection_DA_1D(dac,daf,&inject);CHKERRQ(ierr);
12800bb2b966SJungho Lee   } else if (dimc == 2) {
12816dbf9973SLawrence Mitchell     ierr = DMCreateInjection_DA_2D(dac,daf,&inject);CHKERRQ(ierr);
1282b1757049SJed Brown   } else if (dimc == 3) {
12836dbf9973SLawrence Mitchell     ierr = DMCreateInjection_DA_3D(dac,daf,&inject);CHKERRQ(ierr);
128447c6ae99SBarry Smith   }
12856dbf9973SLawrence Mitchell   ierr = MatCreateScatter(PetscObjectComm((PetscObject)inject), inject, mat);CHKERRQ(ierr);
12866dbf9973SLawrence Mitchell   ierr = VecScatterDestroy(&inject);CHKERRQ(ierr);
128747c6ae99SBarry Smith   PetscFunctionReturn(0);
128847c6ae99SBarry Smith }
128947c6ae99SBarry Smith 
1290e727c939SJed Brown PetscErrorCode  DMCreateAggregates_DA(DM dac,DM daf,Mat *rest)
129147c6ae99SBarry Smith {
129247c6ae99SBarry Smith   PetscErrorCode         ierr;
129347c6ae99SBarry Smith   PetscInt               dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc;
129447c6ae99SBarry Smith   PetscInt               dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1295bff4a2f0SMatthew G. Knepley   DMBoundaryType         bxc,byc,bzc,bxf,byf,bzf;
1296aa219208SBarry Smith   DMDAStencilType        stc,stf;
129747c6ae99SBarry Smith   PetscInt               i,j,l;
129847c6ae99SBarry Smith   PetscInt               i_start,j_start,l_start, m_f,n_f,p_f;
129947c6ae99SBarry Smith   PetscInt               i_start_ghost,j_start_ghost,l_start_ghost,m_ghost,n_ghost,p_ghost;
13008ea3bf28SBarry Smith   const PetscInt         *idx_f;
130147c6ae99SBarry Smith   PetscInt               i_c,j_c,l_c;
130247c6ae99SBarry Smith   PetscInt               i_start_c,j_start_c,l_start_c, m_c,n_c,p_c;
130347c6ae99SBarry Smith   PetscInt               i_start_ghost_c,j_start_ghost_c,l_start_ghost_c,m_ghost_c,n_ghost_c,p_ghost_c;
13048ea3bf28SBarry Smith   const PetscInt         *idx_c;
130547c6ae99SBarry Smith   PetscInt               d;
130647c6ae99SBarry Smith   PetscInt               a;
130747c6ae99SBarry Smith   PetscInt               max_agg_size;
130847c6ae99SBarry Smith   PetscInt               *fine_nodes;
130947c6ae99SBarry Smith   PetscScalar            *one_vec;
131047c6ae99SBarry Smith   PetscInt               fn_idx;
1311565245c5SBarry Smith   ISLocalToGlobalMapping ltogmf,ltogmc;
131247c6ae99SBarry Smith 
131347c6ae99SBarry Smith   PetscFunctionBegin;
131447c6ae99SBarry Smith   PetscValidHeaderSpecific(dac,DM_CLASSID,1);
131547c6ae99SBarry Smith   PetscValidHeaderSpecific(daf,DM_CLASSID,2);
131647c6ae99SBarry Smith   PetscValidPointer(rest,3);
131747c6ae99SBarry Smith 
13181321219cSEthan Coon   ierr = DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);CHKERRQ(ierr);
13191321219cSEthan Coon   ierr = DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);CHKERRQ(ierr);
1320*13903a91SSatish Balay   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
1321*13903a91SSatish Balay   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
1322*13903a91SSatish Balay   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
1323*13903a91SSatish Balay   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
1324*13903a91SSatish Balay   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
132547c6ae99SBarry Smith 
132647c6ae99SBarry 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);
132747c6ae99SBarry 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);
132847c6ae99SBarry 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);
132947c6ae99SBarry Smith 
133047c6ae99SBarry Smith   if (Pc < 0) Pc = 1;
133147c6ae99SBarry Smith   if (Pf < 0) Pf = 1;
133247c6ae99SBarry Smith   if (Nc < 0) Nc = 1;
133347c6ae99SBarry Smith   if (Nf < 0) Nf = 1;
133447c6ae99SBarry Smith 
1335aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
1336aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
1337565245c5SBarry Smith 
1338565245c5SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltogmf);CHKERRQ(ierr);
1339565245c5SBarry Smith   ierr = ISLocalToGlobalMappingGetIndices(ltogmf,&idx_f);CHKERRQ(ierr);
134047c6ae99SBarry Smith 
1341aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
1342aa219208SBarry 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);
1343565245c5SBarry Smith 
1344565245c5SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltogmc);CHKERRQ(ierr);
1345565245c5SBarry Smith   ierr = ISLocalToGlobalMappingGetIndices(ltogmc,&idx_c);CHKERRQ(ierr);
134647c6ae99SBarry Smith 
134747c6ae99SBarry Smith   /*
134847c6ae99SBarry Smith      Basic idea is as follows. Here's a 2D example, suppose r_x, r_y are the ratios
134947c6ae99SBarry Smith      for dimension 1 and 2 respectively.
135047c6ae99SBarry Smith      Let (i,j) be a coarse grid node. All the fine grid nodes between r_x*i and r_x*(i+1)
135147c6ae99SBarry Smith      and r_y*j and r_y*(j+1) will be grouped into the same coarse grid agregate.
135247c6ae99SBarry Smith      Each specific dof on the fine grid is mapped to one dof on the coarse grid.
135347c6ae99SBarry Smith   */
135447c6ae99SBarry Smith 
135547c6ae99SBarry Smith   max_agg_size = (Mf/Mc+1)*(Nf/Nc+1)*(Pf/Pc+1);
135647c6ae99SBarry Smith 
135747c6ae99SBarry Smith   /* create the matrix that will contain the restriction operator */
1358ce94432eSBarry 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,
13590298fd71SBarry Smith                       max_agg_size, NULL, max_agg_size, NULL, rest);CHKERRQ(ierr);
136047c6ae99SBarry Smith 
136147c6ae99SBarry Smith   /* store nodes in the fine grid here */
1362dcca6d9dSJed Brown   ierr = PetscMalloc2(max_agg_size, &one_vec,max_agg_size, &fine_nodes);CHKERRQ(ierr);
136347c6ae99SBarry Smith   for (i=0; i<max_agg_size; i++) one_vec[i] = 1.0;
136447c6ae99SBarry Smith 
136547c6ae99SBarry Smith   /* loop over all coarse nodes */
136647c6ae99SBarry Smith   for (l_c=l_start_c; l_c<l_start_c+p_c; l_c++) {
136747c6ae99SBarry Smith     for (j_c=j_start_c; j_c<j_start_c+n_c; j_c++) {
136847c6ae99SBarry Smith       for (i_c=i_start_c; i_c<i_start_c+m_c; i_c++) {
136947c6ae99SBarry Smith         for (d=0; d<dofc; d++) {
137047c6ae99SBarry Smith           /* convert to local "natural" numbering and then to PETSc global numbering */
137147c6ae99SBarry 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;
137247c6ae99SBarry Smith 
137347c6ae99SBarry Smith           fn_idx = 0;
137447c6ae99SBarry Smith           /* Corresponding fine points are all points (i_f, j_f, l_f) such that
137547c6ae99SBarry Smith              i_c*Mf/Mc <= i_f < (i_c+1)*Mf/Mc
137647c6ae99SBarry Smith              (same for other dimensions)
137747c6ae99SBarry Smith           */
137847c6ae99SBarry Smith           for (l=l_c*Pf/Pc; l<PetscMin((l_c+1)*Pf/Pc,Pf); l++) {
137947c6ae99SBarry Smith             for (j=j_c*Nf/Nc; j<PetscMin((j_c+1)*Nf/Nc,Nf); j++) {
138047c6ae99SBarry Smith               for (i=i_c*Mf/Mc; i<PetscMin((i_c+1)*Mf/Mc,Mf); i++) {
138147c6ae99SBarry 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;
138247c6ae99SBarry Smith                 fn_idx++;
138347c6ae99SBarry Smith               }
138447c6ae99SBarry Smith             }
138547c6ae99SBarry Smith           }
138647c6ae99SBarry Smith           /* add all these points to one aggregate */
138747c6ae99SBarry Smith           ierr = MatSetValues(*rest, 1, &a, fn_idx, fine_nodes, one_vec, INSERT_VALUES);CHKERRQ(ierr);
138847c6ae99SBarry Smith         }
138947c6ae99SBarry Smith       }
139047c6ae99SBarry Smith     }
139147c6ae99SBarry Smith   }
1392565245c5SBarry Smith   ierr = ISLocalToGlobalMappingRestoreIndices(ltogmf,&idx_f);CHKERRQ(ierr);
1393565245c5SBarry Smith   ierr = ISLocalToGlobalMappingRestoreIndices(ltogmc,&idx_c);CHKERRQ(ierr);
139447c6ae99SBarry Smith   ierr = PetscFree2(one_vec,fine_nodes);CHKERRQ(ierr);
139547c6ae99SBarry Smith   ierr = MatAssemblyBegin(*rest, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
139647c6ae99SBarry Smith   ierr = MatAssemblyEnd(*rest, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
139747c6ae99SBarry Smith   PetscFunctionReturn(0);
139847c6ae99SBarry Smith }
1399