xref: /petsc/src/dm/impls/da/dainterp.c (revision fdc842d1a43d22858d8041cc45d2f5b4ad073a0b)
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 
49*fdc842d1SBarry Smith /*
50*fdc842d1SBarry Smith    Since the interpolation uses MATMAIJ for dof > 0 we convert request for non-MATAIJ baseded matrices to MATAIJ.
51*fdc842d1SBarry Smith    This is a bit of a hack, the reason for it is partially because -dm_mat_type defines the
52*fdc842d1SBarry Smith    matrix type for both the operator matrices and the interpolation matrices so that users
53*fdc842d1SBarry Smith    can select matrix types of base MATAIJ for accelerators
54*fdc842d1SBarry Smith */
55*fdc842d1SBarry Smith static PetscErrorCode ConvertToAIJ(MatType intype,MatType *outtype)
56*fdc842d1SBarry Smith {
57*fdc842d1SBarry Smith   PetscErrorCode ierr;
58*fdc842d1SBarry Smith   PetscInt       i;
59*fdc842d1SBarry Smith   char           const *types[3] = {MATAIJ,MATSEQAIJ,MATMPIAIJ};
60*fdc842d1SBarry Smith   PetscBool      flg;
61*fdc842d1SBarry Smith 
62*fdc842d1SBarry Smith   PetscFunctionBegin;
63*fdc842d1SBarry Smith   for (i=0; i<3; i++) {
64*fdc842d1SBarry Smith     ierr = PetscStrbeginswith(intype,types[i],&flg);CHKERRQ(ierr);
65*fdc842d1SBarry Smith     if (flg) {
66*fdc842d1SBarry Smith       *outtype = intype;
67*fdc842d1SBarry Smith       PetscFunctionReturn(0);
68*fdc842d1SBarry Smith     }
69*fdc842d1SBarry Smith   }
70*fdc842d1SBarry Smith   *outtype = MATAIJ;
71*fdc842d1SBarry Smith   PetscFunctionReturn(0);
72*fdc842d1SBarry Smith }
73*fdc842d1SBarry Smith 
74e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_1D_Q1(DM dac,DM daf,Mat *A)
7547c6ae99SBarry Smith {
7647c6ae99SBarry Smith   PetscErrorCode         ierr;
778ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx;
788ea3bf28SBarry Smith   const PetscInt         *idx_f,*idx_c;
798ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
8047c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,mx,m_c,nc,ratio;
8147c6ae99SBarry Smith   PetscInt               i_c,i_start_c,i_start_ghost_c,cols[2],dof;
8285afcc9aSBarry Smith   PetscScalar            v[2],x;
8347c6ae99SBarry Smith   Mat                    mat;
84bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
85e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
86*fdc842d1SBarry Smith   MatType                mattype;
8747c6ae99SBarry Smith 
8847c6ae99SBarry Smith   PetscFunctionBegin;
891321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);CHKERRQ(ierr);
901321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
91bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
9247c6ae99SBarry Smith     ratio = mx/Mx;
9347c6ae99SBarry 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);
9447c6ae99SBarry Smith   } else {
9547c6ae99SBarry Smith     ratio = (mx-1)/(Mx-1);
9647c6ae99SBarry 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);
9747c6ae99SBarry Smith   }
9847c6ae99SBarry Smith 
99aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);CHKERRQ(ierr);
100aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);CHKERRQ(ierr);
10145b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
10245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
10347c6ae99SBarry Smith 
104aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);CHKERRQ(ierr);
105aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);CHKERRQ(ierr);
10645b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
10745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
10847c6ae99SBarry Smith 
10947c6ae99SBarry Smith   /* create interpolation matrix */
110ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)dac),&mat);CHKERRQ(ierr);
111*fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
112*fdc842d1SBarry Smith   /*
113*fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
114*fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
115*fdc842d1SBarry Smith    */
116*fdc842d1SBarry Smith   if (dof > 1) {
117*fdc842d1SBarry Smith     ierr = MatPinToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
118*fdc842d1SBarry Smith   }
119*fdc842d1SBarry Smith   #endif
12047c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f,m_c,mx,Mx);CHKERRQ(ierr);
121*fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
122*fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
1230298fd71SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,2,NULL);CHKERRQ(ierr);
1240298fd71SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,2,NULL,1,NULL);CHKERRQ(ierr);
12547c6ae99SBarry Smith 
12647c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
12785afcc9aSBarry Smith   if (!NEWVERSION) {
128b3bd94feSDave May 
12947c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
13047c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
131e3fbd1f4SBarry Smith       row = idx_f[i-i_start_ghost];
13247c6ae99SBarry Smith 
13347c6ae99SBarry Smith       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
134aa219208SBarry 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\
13547c6ae99SBarry Smith                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
13647c6ae99SBarry Smith 
13747c6ae99SBarry Smith       /*
13847c6ae99SBarry Smith        Only include those interpolation points that are truly
13947c6ae99SBarry Smith        nonzero. Note this is very important for final grid lines
14047c6ae99SBarry Smith        in x direction; since they have no right neighbor
14147c6ae99SBarry Smith        */
1426712e2f1SBarry Smith       x  = ((PetscReal)(i - i_c*ratio))/((PetscReal)ratio);
14347c6ae99SBarry Smith       nc = 0;
14447c6ae99SBarry Smith       /* one left and below; or we are right on it */
145e3fbd1f4SBarry Smith       col      = (i_c-i_start_ghost_c);
146e3fbd1f4SBarry Smith       cols[nc] = idx_c[col];
14747c6ae99SBarry Smith       v[nc++]  = -x + 1.0;
14847c6ae99SBarry Smith       /* one right? */
14947c6ae99SBarry Smith       if (i_c*ratio != i) {
150e3fbd1f4SBarry Smith         cols[nc] = idx_c[col+1];
15147c6ae99SBarry Smith         v[nc++]  = x;
15247c6ae99SBarry Smith       }
15347c6ae99SBarry Smith       ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
15447c6ae99SBarry Smith     }
155b3bd94feSDave May 
156b3bd94feSDave May   } else {
157b3bd94feSDave May     PetscScalar *xi;
158b3bd94feSDave May     PetscInt    li,nxi,n;
159b3bd94feSDave May     PetscScalar Ni[2];
160b3bd94feSDave May 
161b3bd94feSDave May     /* compute local coordinate arrays */
162b3bd94feSDave May     nxi  = ratio + 1;
163854ce69bSBarry Smith     ierr = PetscMalloc1(nxi,&xi);CHKERRQ(ierr);
164b3bd94feSDave May     for (li=0; li<nxi; li++) {
16552218ef2SJed Brown       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
166b3bd94feSDave May     }
167b3bd94feSDave May 
168b3bd94feSDave May     for (i=i_start; i<i_start+m_f; i++) {
169b3bd94feSDave May       /* convert to local "natural" numbering and then to PETSc global numbering */
170e3fbd1f4SBarry Smith       row = idx_f[(i-i_start_ghost)];
171b3bd94feSDave May 
172b3bd94feSDave May       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
173b3bd94feSDave 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\
174b3bd94feSDave May                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
175b3bd94feSDave May 
176b3bd94feSDave May       /* remainders */
177b3bd94feSDave May       li = i - ratio * (i/ratio);
1788865f1eaSKarl Rupp       if (i==mx-1) li = nxi-1;
179b3bd94feSDave May 
180b3bd94feSDave May       /* corners */
181e3fbd1f4SBarry Smith       col     = (i_c-i_start_ghost_c);
182e3fbd1f4SBarry Smith       cols[0] = idx_c[col];
183b3bd94feSDave May       Ni[0]   = 1.0;
184b3bd94feSDave May       if ((li==0) || (li==nxi-1)) {
185b3bd94feSDave May         ierr = MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);CHKERRQ(ierr);
186b3bd94feSDave May         continue;
187b3bd94feSDave May       }
188b3bd94feSDave May 
189b3bd94feSDave May       /* edges + interior */
190b3bd94feSDave May       /* remainders */
1918865f1eaSKarl Rupp       if (i==mx-1) i_c--;
192b3bd94feSDave May 
193e3fbd1f4SBarry Smith       col     = (i_c-i_start_ghost_c);
194e3fbd1f4SBarry Smith       cols[0] = idx_c[col]; /* one left and below; or we are right on it */
195e3fbd1f4SBarry Smith       cols[1] = idx_c[col+1];
196b3bd94feSDave May 
197b3bd94feSDave May       Ni[0] = 0.5*(1.0-xi[li]);
198b3bd94feSDave May       Ni[1] = 0.5*(1.0+xi[li]);
199b3bd94feSDave May       for (n=0; n<2; n++) {
2008865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[n])<1.0e-32) cols[n]=-1;
201b3bd94feSDave May       }
202b3bd94feSDave May       ierr = MatSetValues(mat,1,&row,2,cols,Ni,INSERT_VALUES);CHKERRQ(ierr);
203b3bd94feSDave May     }
204b3bd94feSDave May     ierr = PetscFree(xi);CHKERRQ(ierr);
205b3bd94feSDave May   }
20645b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
20745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
20847c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
20947c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
21047c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
211fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
21247c6ae99SBarry Smith   PetscFunctionReturn(0);
21347c6ae99SBarry Smith }
21447c6ae99SBarry Smith 
215e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_1D_Q0(DM dac,DM daf,Mat *A)
21647c6ae99SBarry Smith {
21747c6ae99SBarry Smith   PetscErrorCode         ierr;
2188ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx;
2198ea3bf28SBarry Smith   const PetscInt         *idx_f,*idx_c;
220e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
2218ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
22247c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,mx,m_c,nc,ratio;
22347c6ae99SBarry Smith   PetscInt               i_c,i_start_c,i_start_ghost_c,cols[2],dof;
22447c6ae99SBarry Smith   PetscScalar            v[2],x;
22547c6ae99SBarry Smith   Mat                    mat;
226bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
227*fdc842d1SBarry Smith   MatType                mattype;
22847c6ae99SBarry Smith 
22947c6ae99SBarry Smith   PetscFunctionBegin;
2301321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);CHKERRQ(ierr);
2311321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
232bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
2333a586487SStefano Zampini     if (!Mx) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
23447c6ae99SBarry Smith     ratio = mx/Mx;
23547c6ae99SBarry 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);
23647c6ae99SBarry Smith   } else {
2373a586487SStefano Zampini     if (Mx < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be greater than 1",Mx);
23847c6ae99SBarry Smith     ratio = (mx-1)/(Mx-1);
23947c6ae99SBarry 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);
24047c6ae99SBarry Smith   }
24147c6ae99SBarry Smith 
242aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);CHKERRQ(ierr);
243aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);CHKERRQ(ierr);
24445b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
24545b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
24647c6ae99SBarry Smith 
247aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);CHKERRQ(ierr);
248aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);CHKERRQ(ierr);
24945b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
25045b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
25147c6ae99SBarry Smith 
25247c6ae99SBarry Smith   /* create interpolation matrix */
253ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)dac),&mat);CHKERRQ(ierr);
254*fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
255*fdc842d1SBarry Smith   /*
256*fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
257*fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
258*fdc842d1SBarry Smith    */
259*fdc842d1SBarry Smith   if (dof > 1) {
260*fdc842d1SBarry Smith     ierr = MatPinToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
261*fdc842d1SBarry Smith   }
262*fdc842d1SBarry Smith   #endif
26347c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f,m_c,mx,Mx);CHKERRQ(ierr);
264*fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
265*fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
2660298fd71SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,2,NULL);CHKERRQ(ierr);
2670298fd71SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,2,NULL,0,NULL);CHKERRQ(ierr);
26847c6ae99SBarry Smith 
26947c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
27047c6ae99SBarry Smith   for (i=i_start; i<i_start+m_f; i++) {
27147c6ae99SBarry Smith     /* convert to local "natural" numbering and then to PETSc global numbering */
272e3fbd1f4SBarry Smith     row = idx_f[(i-i_start_ghost)];
27347c6ae99SBarry Smith 
27447c6ae99SBarry Smith     i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
27547c6ae99SBarry Smith 
27647c6ae99SBarry Smith     /*
27747c6ae99SBarry Smith          Only include those interpolation points that are truly
27847c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
27947c6ae99SBarry Smith          in x direction; since they have no right neighbor
28047c6ae99SBarry Smith     */
2816712e2f1SBarry Smith     x  = ((PetscReal)(i - i_c*ratio))/((PetscReal)ratio);
28247c6ae99SBarry Smith     nc = 0;
28347c6ae99SBarry Smith     /* one left and below; or we are right on it */
284e3fbd1f4SBarry Smith     col      = (i_c-i_start_ghost_c);
285e3fbd1f4SBarry Smith     cols[nc] = idx_c[col];
28647c6ae99SBarry Smith     v[nc++]  = -x + 1.0;
28747c6ae99SBarry Smith     /* one right? */
28847c6ae99SBarry Smith     if (i_c*ratio != i) {
289e3fbd1f4SBarry Smith       cols[nc] = idx_c[col+1];
29047c6ae99SBarry Smith       v[nc++]  = x;
29147c6ae99SBarry Smith     }
29247c6ae99SBarry Smith     ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
29347c6ae99SBarry Smith   }
29445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
29545b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
29647c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
29747c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
29847c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
299fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
30047c6ae99SBarry Smith   ierr = PetscLogFlops(5.0*m_f);CHKERRQ(ierr);
30147c6ae99SBarry Smith   PetscFunctionReturn(0);
30247c6ae99SBarry Smith }
30347c6ae99SBarry Smith 
304e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_2D_Q1(DM dac,DM daf,Mat *A)
30547c6ae99SBarry Smith {
30647c6ae99SBarry Smith   PetscErrorCode         ierr;
3078ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
3088ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
309e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
3108ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,*dnz,*onz;
31147c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
31247c6ae99SBarry 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;
31347c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
31447c6ae99SBarry Smith   PetscScalar            v[4],x,y;
31547c6ae99SBarry Smith   Mat                    mat;
316bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
317*fdc842d1SBarry Smith   MatType                mattype;
31847c6ae99SBarry Smith 
31947c6ae99SBarry Smith   PetscFunctionBegin;
3201321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);CHKERRQ(ierr);
3211321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
322bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
3233a586487SStefano Zampini     if (!Mx) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
32447c6ae99SBarry Smith     ratioi = mx/Mx;
32547c6ae99SBarry 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);
32647c6ae99SBarry Smith   } else {
3273a586487SStefano Zampini     if (Mx < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be greater than 1",Mx);
32847c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
32947c6ae99SBarry 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);
33047c6ae99SBarry Smith   }
331bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
3323a586487SStefano Zampini     if (!My) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
33347c6ae99SBarry Smith     ratioj = my/My;
33447c6ae99SBarry 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);
33547c6ae99SBarry Smith   } else {
3363a586487SStefano Zampini     if (My < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be greater than 1",My);
33747c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
33847c6ae99SBarry 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);
33947c6ae99SBarry Smith   }
34047c6ae99SBarry Smith 
341aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);CHKERRQ(ierr);
342aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);CHKERRQ(ierr);
34345b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
34445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
34547c6ae99SBarry Smith 
346aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);CHKERRQ(ierr);
347aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);CHKERRQ(ierr);
34845b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
34945b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
35047c6ae99SBarry Smith 
35147c6ae99SBarry Smith   /*
352aa219208SBarry Smith    Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
35347c6ae99SBarry Smith    The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
35447c6ae99SBarry Smith    processors). It's effective length is hence 4 times its normal length, this is
35547c6ae99SBarry Smith    why the col_scale is multiplied by the interpolation matrix column sizes.
35647c6ae99SBarry Smith    sol_shift allows each set of 1/4 processors do its own interpolation using ITS
35747c6ae99SBarry Smith    copy of the coarse vector. A bit of a hack but you do better.
35847c6ae99SBarry Smith 
35947c6ae99SBarry Smith    In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
36047c6ae99SBarry Smith    */
361ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);CHKERRQ(ierr);
362ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);CHKERRQ(ierr);
363ce94432eSBarry Smith   ierr      = MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);CHKERRQ(ierr);
36447c6ae99SBarry Smith   col_scale = size_f/size_c;
36547c6ae99SBarry Smith   col_shift = Mx*My*(rank_f/size_c);
36647c6ae99SBarry Smith 
367ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f,col_scale*m_c*n_c,dnz,onz);CHKERRQ(ierr);
36847c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
36947c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
37047c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
371e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
37247c6ae99SBarry Smith 
37347c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
37447c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
37547c6ae99SBarry Smith 
376aa219208SBarry 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\
37747c6ae99SBarry Smith                                           j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
378aa219208SBarry 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\
37947c6ae99SBarry Smith                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
38047c6ae99SBarry Smith 
38147c6ae99SBarry Smith       /*
38247c6ae99SBarry Smith        Only include those interpolation points that are truly
38347c6ae99SBarry Smith        nonzero. Note this is very important for final grid lines
38447c6ae99SBarry Smith        in x and y directions; since they have no right/top neighbors
38547c6ae99SBarry Smith        */
38647c6ae99SBarry Smith       nc = 0;
38747c6ae99SBarry Smith       /* one left and below; or we are right on it */
388e3fbd1f4SBarry Smith       col        = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
389e3fbd1f4SBarry Smith       cols[nc++] = col_shift + idx_c[col];
39047c6ae99SBarry Smith       /* one right and below */
391e3fbd1f4SBarry Smith       if (i_c*ratioi != i) cols[nc++] = col_shift + idx_c[col+1];
39247c6ae99SBarry Smith       /* one left and above */
393e3fbd1f4SBarry Smith       if (j_c*ratioj != j) cols[nc++] = col_shift + idx_c[col+m_ghost_c];
39447c6ae99SBarry Smith       /* one right and above */
395e3fbd1f4SBarry Smith       if (i_c*ratioi != i && j_c*ratioj != j) cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)];
39647c6ae99SBarry Smith       ierr = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
39747c6ae99SBarry Smith     }
39847c6ae99SBarry Smith   }
399ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)daf),&mat);CHKERRQ(ierr);
400*fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
401*fdc842d1SBarry Smith   /*
402*fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
403*fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
404*fdc842d1SBarry Smith   */
405*fdc842d1SBarry Smith   if (dof > 1) {
406*fdc842d1SBarry Smith     ierr = MatPinToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
407*fdc842d1SBarry Smith   }
408*fdc842d1SBarry Smith #endif
40947c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);CHKERRQ(ierr);
410*fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
411*fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
41247c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
41347c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
41447c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
41547c6ae99SBarry Smith 
41647c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
41785afcc9aSBarry Smith   if (!NEWVERSION) {
418b3bd94feSDave May 
41947c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
42047c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
42147c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
422e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
42347c6ae99SBarry Smith 
42447c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
42547c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
42647c6ae99SBarry Smith 
42747c6ae99SBarry Smith         /*
42847c6ae99SBarry Smith          Only include those interpolation points that are truly
42947c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
43047c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
43147c6ae99SBarry Smith          */
4326712e2f1SBarry Smith         x = ((PetscReal)(i - i_c*ratioi))/((PetscReal)ratioi);
4336712e2f1SBarry Smith         y = ((PetscReal)(j - j_c*ratioj))/((PetscReal)ratioj);
434b3bd94feSDave May 
43547c6ae99SBarry Smith         nc = 0;
43647c6ae99SBarry Smith         /* one left and below; or we are right on it */
437e3fbd1f4SBarry Smith         col      = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
438e3fbd1f4SBarry Smith         cols[nc] = col_shift + idx_c[col];
43947c6ae99SBarry Smith         v[nc++]  = x*y - x - y + 1.0;
44047c6ae99SBarry Smith         /* one right and below */
44147c6ae99SBarry Smith         if (i_c*ratioi != i) {
442e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+1];
44347c6ae99SBarry Smith           v[nc++]  = -x*y + x;
44447c6ae99SBarry Smith         }
44547c6ae99SBarry Smith         /* one left and above */
44647c6ae99SBarry Smith         if (j_c*ratioj != j) {
447e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+m_ghost_c];
44847c6ae99SBarry Smith           v[nc++]  = -x*y + y;
44947c6ae99SBarry Smith         }
45047c6ae99SBarry Smith         /* one right and above */
45147c6ae99SBarry Smith         if (j_c*ratioj != j && i_c*ratioi != i) {
452e3fbd1f4SBarry Smith           cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)];
45347c6ae99SBarry Smith           v[nc++]  = x*y;
45447c6ae99SBarry Smith         }
45547c6ae99SBarry Smith         ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
45647c6ae99SBarry Smith       }
45747c6ae99SBarry Smith     }
458b3bd94feSDave May 
459b3bd94feSDave May   } else {
460b3bd94feSDave May     PetscScalar Ni[4];
461b3bd94feSDave May     PetscScalar *xi,*eta;
462b3bd94feSDave May     PetscInt    li,nxi,lj,neta;
463b3bd94feSDave May 
464b3bd94feSDave May     /* compute local coordinate arrays */
465b3bd94feSDave May     nxi  = ratioi + 1;
466b3bd94feSDave May     neta = ratioj + 1;
467854ce69bSBarry Smith     ierr = PetscMalloc1(nxi,&xi);CHKERRQ(ierr);
468854ce69bSBarry Smith     ierr = PetscMalloc1(neta,&eta);CHKERRQ(ierr);
469b3bd94feSDave May     for (li=0; li<nxi; li++) {
47052218ef2SJed Brown       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
471b3bd94feSDave May     }
472b3bd94feSDave May     for (lj=0; lj<neta; lj++) {
47352218ef2SJed Brown       eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
474b3bd94feSDave May     }
475b3bd94feSDave May 
476b3bd94feSDave May     /* loop over local fine grid nodes setting interpolation for those*/
477b3bd94feSDave May     for (j=j_start; j<j_start+n_f; j++) {
478b3bd94feSDave May       for (i=i_start; i<i_start+m_f; i++) {
479b3bd94feSDave May         /* convert to local "natural" numbering and then to PETSc global numbering */
480e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
481b3bd94feSDave May 
482b3bd94feSDave May         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
483b3bd94feSDave May         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
484b3bd94feSDave May 
485b3bd94feSDave May         /* remainders */
486b3bd94feSDave May         li = i - ratioi * (i/ratioi);
4878865f1eaSKarl Rupp         if (i==mx-1) li = nxi-1;
488b3bd94feSDave May         lj = j - ratioj * (j/ratioj);
4898865f1eaSKarl Rupp         if (j==my-1) lj = neta-1;
490b3bd94feSDave May 
491b3bd94feSDave May         /* corners */
492e3fbd1f4SBarry Smith         col     = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
493e3fbd1f4SBarry Smith         cols[0] = col_shift + idx_c[col]; /* left, below */
494b3bd94feSDave May         Ni[0]   = 1.0;
495b3bd94feSDave May         if ((li==0) || (li==nxi-1)) {
496b3bd94feSDave May           if ((lj==0) || (lj==neta-1)) {
497b3bd94feSDave May             ierr = MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);CHKERRQ(ierr);
498b3bd94feSDave May             continue;
499b3bd94feSDave May           }
500b3bd94feSDave May         }
501b3bd94feSDave May 
502b3bd94feSDave May         /* edges + interior */
503b3bd94feSDave May         /* remainders */
5048865f1eaSKarl Rupp         if (i==mx-1) i_c--;
5058865f1eaSKarl Rupp         if (j==my-1) j_c--;
506b3bd94feSDave May 
507e3fbd1f4SBarry Smith         col     = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
508e3fbd1f4SBarry Smith         cols[0] = col_shift + idx_c[col]; /* left, below */
509e3fbd1f4SBarry Smith         cols[1] = col_shift + idx_c[col+1]; /* right, below */
510e3fbd1f4SBarry Smith         cols[2] = col_shift + idx_c[col+m_ghost_c]; /* left, above */
511e3fbd1f4SBarry Smith         cols[3] = col_shift + idx_c[col+(m_ghost_c+1)]; /* right, above */
512b3bd94feSDave May 
513b3bd94feSDave May         Ni[0] = 0.25*(1.0-xi[li])*(1.0-eta[lj]);
514b3bd94feSDave May         Ni[1] = 0.25*(1.0+xi[li])*(1.0-eta[lj]);
515b3bd94feSDave May         Ni[2] = 0.25*(1.0-xi[li])*(1.0+eta[lj]);
516b3bd94feSDave May         Ni[3] = 0.25*(1.0+xi[li])*(1.0+eta[lj]);
517b3bd94feSDave May 
518b3bd94feSDave May         nc = 0;
5198865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[0])<1.0e-32) cols[0]=-1;
5208865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[1])<1.0e-32) cols[1]=-1;
5218865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[2])<1.0e-32) cols[2]=-1;
5228865f1eaSKarl Rupp         if (PetscAbsScalar(Ni[3])<1.0e-32) cols[3]=-1;
523b3bd94feSDave May 
524b3bd94feSDave May         ierr = MatSetValues(mat,1,&row,4,cols,Ni,INSERT_VALUES);CHKERRQ(ierr);
525b3bd94feSDave May       }
526b3bd94feSDave May     }
527b3bd94feSDave May     ierr = PetscFree(xi);CHKERRQ(ierr);
528b3bd94feSDave May     ierr = PetscFree(eta);CHKERRQ(ierr);
529b3bd94feSDave May   }
53045b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
53145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
53247c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
53347c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
53447c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
535fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
53647c6ae99SBarry Smith   PetscFunctionReturn(0);
53747c6ae99SBarry Smith }
53847c6ae99SBarry Smith 
53947c6ae99SBarry Smith /*
54047c6ae99SBarry Smith        Contributed by Andrei Draganescu <aidraga@sandia.gov>
54147c6ae99SBarry Smith */
542e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_2D_Q0(DM dac,DM daf,Mat *A)
54347c6ae99SBarry Smith {
54447c6ae99SBarry Smith   PetscErrorCode         ierr;
5458ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
5468ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
547e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
5488ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,*dnz,*onz;
54947c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
55047c6ae99SBarry 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;
55147c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
55247c6ae99SBarry Smith   PetscScalar            v[4];
55347c6ae99SBarry Smith   Mat                    mat;
554bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
555*fdc842d1SBarry Smith   MatType                mattype;
55647c6ae99SBarry Smith 
55747c6ae99SBarry Smith   PetscFunctionBegin;
5581321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);CHKERRQ(ierr);
5591321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
5603a586487SStefano Zampini   if (!Mx) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
5613a586487SStefano Zampini   if (!My) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
56247c6ae99SBarry Smith   ratioi = mx/Mx;
56347c6ae99SBarry Smith   ratioj = my/My;
564ce94432eSBarry 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");
565ce94432eSBarry 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");
566ce94432eSBarry Smith   if (ratioi != 2) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 2");
567ce94432eSBarry Smith   if (ratioj != 2) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 2");
56847c6ae99SBarry Smith 
569aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);CHKERRQ(ierr);
570aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);CHKERRQ(ierr);
57145b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
57245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
57347c6ae99SBarry Smith 
574aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);CHKERRQ(ierr);
575aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);CHKERRQ(ierr);
57645b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
57745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
57847c6ae99SBarry Smith 
57947c6ae99SBarry Smith   /*
580aa219208SBarry Smith      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
58147c6ae99SBarry Smith      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
58247c6ae99SBarry Smith      processors). It's effective length is hence 4 times its normal length, this is
58347c6ae99SBarry Smith      why the col_scale is multiplied by the interpolation matrix column sizes.
58447c6ae99SBarry Smith      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
58547c6ae99SBarry Smith      copy of the coarse vector. A bit of a hack but you do better.
58647c6ae99SBarry Smith 
58747c6ae99SBarry Smith      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
58847c6ae99SBarry Smith   */
589ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);CHKERRQ(ierr);
590ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);CHKERRQ(ierr);
591ce94432eSBarry Smith   ierr      = MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);CHKERRQ(ierr);
59247c6ae99SBarry Smith   col_scale = size_f/size_c;
59347c6ae99SBarry Smith   col_shift = Mx*My*(rank_f/size_c);
59447c6ae99SBarry Smith 
595ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f,col_scale*m_c*n_c,dnz,onz);CHKERRQ(ierr);
59647c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
59747c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
59847c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
599e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
60047c6ae99SBarry Smith 
60147c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
60247c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
60347c6ae99SBarry Smith 
604aa219208SBarry 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\
60547c6ae99SBarry Smith     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
606aa219208SBarry 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\
60747c6ae99SBarry Smith     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
60847c6ae99SBarry Smith 
60947c6ae99SBarry Smith       /*
61047c6ae99SBarry Smith          Only include those interpolation points that are truly
61147c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
61247c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
61347c6ae99SBarry Smith       */
61447c6ae99SBarry Smith       nc = 0;
61547c6ae99SBarry Smith       /* one left and below; or we are right on it */
616e3fbd1f4SBarry Smith       col        = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
617e3fbd1f4SBarry Smith       cols[nc++] = col_shift + idx_c[col];
61847c6ae99SBarry Smith       ierr       = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
61947c6ae99SBarry Smith     }
62047c6ae99SBarry Smith   }
621ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)daf),&mat);CHKERRQ(ierr);
622*fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
623*fdc842d1SBarry Smith   /*
624*fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
625*fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
626*fdc842d1SBarry Smith   */
627*fdc842d1SBarry Smith   if (dof > 1) {
628*fdc842d1SBarry Smith     ierr = MatPinToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
629*fdc842d1SBarry Smith   }
630*fdc842d1SBarry Smith   #endif
63147c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);CHKERRQ(ierr);
632*fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
633*fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
63447c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
63547c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
63647c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
63747c6ae99SBarry Smith 
63847c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
63947c6ae99SBarry Smith   for (j=j_start; j<j_start+n_f; j++) {
64047c6ae99SBarry Smith     for (i=i_start; i<i_start+m_f; i++) {
64147c6ae99SBarry Smith       /* convert to local "natural" numbering and then to PETSc global numbering */
642e3fbd1f4SBarry Smith       row = idx_f[(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
64347c6ae99SBarry Smith 
64447c6ae99SBarry Smith       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
64547c6ae99SBarry Smith       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
64647c6ae99SBarry Smith       nc  = 0;
64747c6ae99SBarry Smith       /* one left and below; or we are right on it */
648e3fbd1f4SBarry Smith       col      = (m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
649e3fbd1f4SBarry Smith       cols[nc] = col_shift + idx_c[col];
65047c6ae99SBarry Smith       v[nc++]  = 1.0;
65147c6ae99SBarry Smith 
65247c6ae99SBarry Smith       ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
65347c6ae99SBarry Smith     }
65447c6ae99SBarry Smith   }
65545b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
65645b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
65747c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
65847c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
65947c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
660fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
66147c6ae99SBarry Smith   ierr = PetscLogFlops(13.0*m_f*n_f);CHKERRQ(ierr);
66247c6ae99SBarry Smith   PetscFunctionReturn(0);
66347c6ae99SBarry Smith }
66447c6ae99SBarry Smith 
66547c6ae99SBarry Smith /*
66647c6ae99SBarry Smith        Contributed by Jianming Yang <jianming-yang@uiowa.edu>
66747c6ae99SBarry Smith */
668e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_3D_Q0(DM dac,DM daf,Mat *A)
66947c6ae99SBarry Smith {
67047c6ae99SBarry Smith   PetscErrorCode         ierr;
6718ea3bf28SBarry Smith   PetscInt               i,j,l,i_start,j_start,l_start,m_f,n_f,p_f,Mx,My,Mz,dof;
6728ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
673e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
6748ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,p_ghost,m_ghost_c,n_ghost_c,p_ghost_c,nc,*dnz,*onz;
67547c6ae99SBarry 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;
67647c6ae99SBarry 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;
67747c6ae99SBarry Smith   PetscMPIInt            size_c,size_f,rank_f;
67847c6ae99SBarry Smith   PetscScalar            v[8];
67947c6ae99SBarry Smith   Mat                    mat;
680bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
681*fdc842d1SBarry Smith   MatType                mattype;
68247c6ae99SBarry Smith 
68347c6ae99SBarry Smith   PetscFunctionBegin;
6841321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);CHKERRQ(ierr);
6853a586487SStefano Zampini   if (!Mx) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
6863a586487SStefano Zampini   if (!My) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
6873a586487SStefano Zampini   if (!Mz) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of z coarse grid points %D must be positive",Mz);
6881321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
68947c6ae99SBarry Smith   ratioi = mx/Mx;
69047c6ae99SBarry Smith   ratioj = my/My;
69147c6ae99SBarry Smith   ratiol = mz/Mz;
692ce94432eSBarry 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");
693ce94432eSBarry 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");
694ce94432eSBarry 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");
695ce94432eSBarry Smith   if (ratioi != 2 && ratioi != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 1 or 2");
696ce94432eSBarry Smith   if (ratioj != 2 && ratioj != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 1 or 2");
697ce94432eSBarry Smith   if (ratiol != 2 && ratiol != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in z must be 1 or 2");
69847c6ae99SBarry Smith 
699aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
700aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
70145b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
70245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
70347c6ae99SBarry Smith 
704aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
705aa219208SBarry 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);
70645b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
70745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
708e3fbd1f4SBarry Smith 
70947c6ae99SBarry Smith   /*
710aa219208SBarry Smith      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
71147c6ae99SBarry Smith      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
71247c6ae99SBarry Smith      processors). It's effective length is hence 4 times its normal length, this is
71347c6ae99SBarry Smith      why the col_scale is multiplied by the interpolation matrix column sizes.
71447c6ae99SBarry Smith      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
71547c6ae99SBarry Smith      copy of the coarse vector. A bit of a hack but you do better.
71647c6ae99SBarry Smith 
71747c6ae99SBarry Smith      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
71847c6ae99SBarry Smith   */
719ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);CHKERRQ(ierr);
720ce94432eSBarry Smith   ierr      = MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);CHKERRQ(ierr);
721ce94432eSBarry Smith   ierr      = MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);CHKERRQ(ierr);
72247c6ae99SBarry Smith   col_scale = size_f/size_c;
72347c6ae99SBarry Smith   col_shift = Mx*My*Mz*(rank_f/size_c);
72447c6ae99SBarry Smith 
725ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f*p_f,col_scale*m_c*n_c*p_c,dnz,onz);CHKERRQ(ierr);
72647c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
72747c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
72847c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
72947c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
730e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
73147c6ae99SBarry Smith 
73247c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
73347c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
73447c6ae99SBarry Smith         l_c = (l/ratiol);
73547c6ae99SBarry Smith 
736aa219208SBarry 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\
73747c6ae99SBarry Smith     l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
738aa219208SBarry 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\
73947c6ae99SBarry Smith     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
740aa219208SBarry 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\
74147c6ae99SBarry Smith     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
74247c6ae99SBarry Smith 
74347c6ae99SBarry Smith         /*
74447c6ae99SBarry Smith            Only include those interpolation points that are truly
74547c6ae99SBarry Smith            nonzero. Note this is very important for final grid lines
74647c6ae99SBarry Smith            in x and y directions; since they have no right/top neighbors
74747c6ae99SBarry Smith         */
74847c6ae99SBarry Smith         nc = 0;
74947c6ae99SBarry Smith         /* one left and below; or we are right on it */
750e3fbd1f4SBarry 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));
751e3fbd1f4SBarry Smith         cols[nc++] = col_shift + idx_c[col];
75247c6ae99SBarry Smith         ierr       = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
75347c6ae99SBarry Smith       }
75447c6ae99SBarry Smith     }
75547c6ae99SBarry Smith   }
756ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)daf),&mat);CHKERRQ(ierr);
757*fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
758*fdc842d1SBarry Smith   /*
759*fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
760*fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
761*fdc842d1SBarry Smith   */
762*fdc842d1SBarry Smith   if (dof > 1) {
763*fdc842d1SBarry Smith     ierr = MatPinToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
764*fdc842d1SBarry Smith   }
765*fdc842d1SBarry Smith   #endif
76647c6ae99SBarry 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);
767*fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
768*fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
76947c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
77047c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
77147c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
77247c6ae99SBarry Smith 
77347c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
77447c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
77547c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
77647c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
77747c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
778e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
77947c6ae99SBarry Smith 
78047c6ae99SBarry Smith         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
78147c6ae99SBarry Smith         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
78247c6ae99SBarry Smith         l_c = (l/ratiol);
78347c6ae99SBarry Smith         nc  = 0;
78447c6ae99SBarry Smith         /* one left and below; or we are right on it */
785e3fbd1f4SBarry 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));
786e3fbd1f4SBarry Smith         cols[nc] = col_shift + idx_c[col];
78747c6ae99SBarry Smith         v[nc++]  = 1.0;
78847c6ae99SBarry Smith 
78947c6ae99SBarry Smith         ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
79047c6ae99SBarry Smith       }
79147c6ae99SBarry Smith     }
79247c6ae99SBarry Smith   }
79345b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
79445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
79547c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
79647c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
79747c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
798fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
79947c6ae99SBarry Smith   ierr = PetscLogFlops(13.0*m_f*n_f*p_f);CHKERRQ(ierr);
80047c6ae99SBarry Smith   PetscFunctionReturn(0);
80147c6ae99SBarry Smith }
80247c6ae99SBarry Smith 
803e727c939SJed Brown PetscErrorCode DMCreateInterpolation_DA_3D_Q1(DM dac,DM daf,Mat *A)
80447c6ae99SBarry Smith {
80547c6ae99SBarry Smith   PetscErrorCode         ierr;
8068ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof,l;
8078ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
808e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
8098ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c,Mz,mz;
81047c6ae99SBarry Smith   PetscInt               row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
81147c6ae99SBarry Smith   PetscInt               i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
81247c6ae99SBarry Smith   PetscInt               l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
81347c6ae99SBarry Smith   PetscInt               l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
81447c6ae99SBarry Smith   PetscScalar            v[8],x,y,z;
81547c6ae99SBarry Smith   Mat                    mat;
816bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
817*fdc842d1SBarry Smith   MatType                mattype;
81847c6ae99SBarry Smith 
81947c6ae99SBarry Smith   PetscFunctionBegin;
8201321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);CHKERRQ(ierr);
8211321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
82247c6ae99SBarry Smith   if (mx == Mx) {
82347c6ae99SBarry Smith     ratioi = 1;
824bff4a2f0SMatthew G. Knepley   } else if (bx == DM_BOUNDARY_PERIODIC) {
8253a586487SStefano Zampini     if (!Mx) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be positive",Mx);
82647c6ae99SBarry Smith     ratioi = mx/Mx;
82747c6ae99SBarry 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);
82847c6ae99SBarry Smith   } else {
8293a586487SStefano Zampini     if (Mx < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of x coarse grid points %D must be greater than 1",Mx);
83047c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
83147c6ae99SBarry 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);
83247c6ae99SBarry Smith   }
83347c6ae99SBarry Smith   if (my == My) {
83447c6ae99SBarry Smith     ratioj = 1;
835bff4a2f0SMatthew G. Knepley   } else if (by == DM_BOUNDARY_PERIODIC) {
8363a586487SStefano Zampini     if (!My) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be positive",My);
83747c6ae99SBarry Smith     ratioj = my/My;
83847c6ae99SBarry 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);
83947c6ae99SBarry Smith   } else {
8403a586487SStefano Zampini     if (My < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of y coarse grid points %D must be greater than 1",My);
84147c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
84247c6ae99SBarry 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);
84347c6ae99SBarry Smith   }
84447c6ae99SBarry Smith   if (mz == Mz) {
84547c6ae99SBarry Smith     ratiok = 1;
846bff4a2f0SMatthew G. Knepley   } else if (bz == DM_BOUNDARY_PERIODIC) {
8473a586487SStefano Zampini     if (!Mz) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of z coarse grid points %D must be positive",Mz);
84847c6ae99SBarry Smith     ratiok = mz/Mz;
84947c6ae99SBarry 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);
85047c6ae99SBarry Smith   } else {
8513a586487SStefano Zampini     if (Mz < 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of z coarse grid points %D must be greater than 1",Mz);
85247c6ae99SBarry Smith     ratiok = (mz-1)/(Mz-1);
85347c6ae99SBarry 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);
85447c6ae99SBarry Smith   }
85547c6ae99SBarry Smith 
856aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
857aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
85845b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
85945b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
86047c6ae99SBarry Smith 
861aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
862aa219208SBarry 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);
86345b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
86445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
86547c6ae99SBarry Smith 
86647c6ae99SBarry Smith   /* create interpolation matrix, determining exact preallocation */
867ce94432eSBarry Smith   ierr = MatPreallocateInitialize(PetscObjectComm((PetscObject)dac),m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);CHKERRQ(ierr);
86847c6ae99SBarry Smith   /* loop over local fine grid nodes counting interpolating points */
86947c6ae99SBarry Smith   for (l=l_start; l<l_start+p_f; l++) {
87047c6ae99SBarry Smith     for (j=j_start; j<j_start+n_f; j++) {
87147c6ae99SBarry Smith       for (i=i_start; i<i_start+m_f; i++) {
87247c6ae99SBarry Smith         /* convert to local "natural" numbering and then to PETSc global numbering */
873e3fbd1f4SBarry Smith         row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
87447c6ae99SBarry Smith         i_c = (i/ratioi);
87547c6ae99SBarry Smith         j_c = (j/ratioj);
87647c6ae99SBarry Smith         l_c = (l/ratiok);
877aa219208SBarry 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\
87847c6ae99SBarry Smith                                             l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
879aa219208SBarry 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\
88047c6ae99SBarry Smith                                             j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
881aa219208SBarry 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\
88247c6ae99SBarry Smith                                             i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
88347c6ae99SBarry Smith 
88447c6ae99SBarry Smith         /*
88547c6ae99SBarry Smith          Only include those interpolation points that are truly
88647c6ae99SBarry Smith          nonzero. Note this is very important for final grid lines
88747c6ae99SBarry Smith          in x and y directions; since they have no right/top neighbors
88847c6ae99SBarry Smith          */
88947c6ae99SBarry Smith         nc         = 0;
890e3fbd1f4SBarry 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));
891e3fbd1f4SBarry Smith         cols[nc++] = idx_c[col];
89247c6ae99SBarry Smith         if (i_c*ratioi != i) {
893e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+1];
89447c6ae99SBarry Smith         }
89547c6ae99SBarry Smith         if (j_c*ratioj != j) {
896e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+m_ghost_c];
89747c6ae99SBarry Smith         }
89847c6ae99SBarry Smith         if (l_c*ratiok != l) {
899e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c];
90047c6ae99SBarry Smith         }
90147c6ae99SBarry Smith         if (j_c*ratioj != j && i_c*ratioi != i) {
902e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c+1)];
90347c6ae99SBarry Smith         }
90447c6ae99SBarry Smith         if (j_c*ratioj != j && l_c*ratiok != l) {
905e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)];
90647c6ae99SBarry Smith         }
90747c6ae99SBarry Smith         if (i_c*ratioi != i && l_c*ratiok != l) {
908e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)];
90947c6ae99SBarry Smith         }
91047c6ae99SBarry Smith         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
911e3fbd1f4SBarry Smith           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)];
91247c6ae99SBarry Smith         }
91347c6ae99SBarry Smith         ierr = MatPreallocateSet(row,nc,cols,dnz,onz);CHKERRQ(ierr);
91447c6ae99SBarry Smith       }
91547c6ae99SBarry Smith     }
91647c6ae99SBarry Smith   }
917ce94432eSBarry Smith   ierr = MatCreate(PetscObjectComm((PetscObject)dac),&mat);CHKERRQ(ierr);
918*fdc842d1SBarry Smith #if defined(PETSC_HAVE_CUDA)
919*fdc842d1SBarry Smith   /*
920*fdc842d1SBarry Smith      Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
921*fdc842d1SBarry Smith      we don't want the original unconverted matrix copied to the GPU
922*fdc842d1SBarry Smith   */
923*fdc842d1SBarry Smith   if (dof > 1) {
924*fdc842d1SBarry Smith     ierr = MatPinToCPU(mat,PETSC_TRUE);CHKERRQ(ierr);
925*fdc842d1SBarry Smith   }
926*fdc842d1SBarry Smith   #endif
92747c6ae99SBarry Smith   ierr = MatSetSizes(mat,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz);CHKERRQ(ierr);
928*fdc842d1SBarry Smith   ierr = ConvertToAIJ(dac->mattype,&mattype);CHKERRQ(ierr);
929*fdc842d1SBarry Smith   ierr = MatSetType(mat,mattype);CHKERRQ(ierr);
93047c6ae99SBarry Smith   ierr = MatSeqAIJSetPreallocation(mat,0,dnz);CHKERRQ(ierr);
93147c6ae99SBarry Smith   ierr = MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);CHKERRQ(ierr);
93247c6ae99SBarry Smith   ierr = MatPreallocateFinalize(dnz,onz);CHKERRQ(ierr);
93347c6ae99SBarry Smith 
93447c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
9352adb9dcfSBarry Smith   if (!NEWVERSION) {
936b3bd94feSDave May 
93747c6ae99SBarry Smith     for (l=l_start; l<l_start+p_f; l++) {
93847c6ae99SBarry Smith       for (j=j_start; j<j_start+n_f; j++) {
93947c6ae99SBarry Smith         for (i=i_start; i<i_start+m_f; i++) {
94047c6ae99SBarry Smith           /* convert to local "natural" numbering and then to PETSc global numbering */
941e3fbd1f4SBarry Smith           row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
94247c6ae99SBarry Smith 
94347c6ae99SBarry Smith           i_c = (i/ratioi);
94447c6ae99SBarry Smith           j_c = (j/ratioj);
94547c6ae99SBarry Smith           l_c = (l/ratiok);
94647c6ae99SBarry Smith 
94747c6ae99SBarry Smith           /*
94847c6ae99SBarry Smith            Only include those interpolation points that are truly
94947c6ae99SBarry Smith            nonzero. Note this is very important for final grid lines
95047c6ae99SBarry Smith            in x and y directions; since they have no right/top neighbors
95147c6ae99SBarry Smith            */
9526712e2f1SBarry Smith           x = ((PetscReal)(i - i_c*ratioi))/((PetscReal)ratioi);
9536712e2f1SBarry Smith           y = ((PetscReal)(j - j_c*ratioj))/((PetscReal)ratioj);
9546712e2f1SBarry Smith           z = ((PetscReal)(l - l_c*ratiok))/((PetscReal)ratiok);
955b3bd94feSDave May 
95647c6ae99SBarry Smith           nc = 0;
95747c6ae99SBarry Smith           /* one left and below; or we are right on it */
958e3fbd1f4SBarry 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));
95947c6ae99SBarry Smith 
960e3fbd1f4SBarry Smith           cols[nc] = idx_c[col];
96147c6ae99SBarry Smith           v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
96247c6ae99SBarry Smith 
96347c6ae99SBarry Smith           if (i_c*ratioi != i) {
964e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+1];
96547c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
96647c6ae99SBarry Smith           }
96747c6ae99SBarry Smith 
96847c6ae99SBarry Smith           if (j_c*ratioj != j) {
969e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+m_ghost_c];
97047c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
97147c6ae99SBarry Smith           }
97247c6ae99SBarry Smith 
97347c6ae99SBarry Smith           if (l_c*ratiok != l) {
974e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+m_ghost_c*n_ghost_c];
97547c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
97647c6ae99SBarry Smith           }
97747c6ae99SBarry Smith 
97847c6ae99SBarry Smith           if (j_c*ratioj != j && i_c*ratioi != i) {
979e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c+1)];
98047c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
98147c6ae99SBarry Smith           }
98247c6ae99SBarry Smith 
98347c6ae99SBarry Smith           if (j_c*ratioj != j && l_c*ratiok != l) {
984e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)];
98547c6ae99SBarry Smith             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
98647c6ae99SBarry Smith           }
98747c6ae99SBarry Smith 
98847c6ae99SBarry Smith           if (i_c*ratioi != i && l_c*ratiok != l) {
989e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+1)];
99047c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
99147c6ae99SBarry Smith           }
99247c6ae99SBarry Smith 
99347c6ae99SBarry Smith           if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
994e3fbd1f4SBarry Smith             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)];
99547c6ae99SBarry Smith             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
99647c6ae99SBarry Smith           }
99747c6ae99SBarry Smith           ierr = MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);CHKERRQ(ierr);
99847c6ae99SBarry Smith         }
99947c6ae99SBarry Smith       }
100047c6ae99SBarry Smith     }
1001b3bd94feSDave May 
1002b3bd94feSDave May   } else {
1003b3bd94feSDave May     PetscScalar *xi,*eta,*zeta;
1004b3bd94feSDave May     PetscInt    li,nxi,lj,neta,lk,nzeta,n;
1005b3bd94feSDave May     PetscScalar Ni[8];
1006b3bd94feSDave May 
1007b3bd94feSDave May     /* compute local coordinate arrays */
1008b3bd94feSDave May     nxi   = ratioi + 1;
1009b3bd94feSDave May     neta  = ratioj + 1;
1010b3bd94feSDave May     nzeta = ratiok + 1;
1011854ce69bSBarry Smith     ierr  = PetscMalloc1(nxi,&xi);CHKERRQ(ierr);
1012854ce69bSBarry Smith     ierr  = PetscMalloc1(neta,&eta);CHKERRQ(ierr);
1013854ce69bSBarry Smith     ierr  = PetscMalloc1(nzeta,&zeta);CHKERRQ(ierr);
10148865f1eaSKarl Rupp     for (li=0; li<nxi; li++) xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
10158865f1eaSKarl Rupp     for (lj=0; lj<neta; lj++) eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
10168865f1eaSKarl Rupp     for (lk=0; lk<nzeta; lk++) zeta[lk] = -1.0 + (PetscScalar)lk*(2.0/(PetscScalar)(nzeta-1));
1017b3bd94feSDave May 
1018b3bd94feSDave May     for (l=l_start; l<l_start+p_f; l++) {
1019b3bd94feSDave May       for (j=j_start; j<j_start+n_f; j++) {
1020b3bd94feSDave May         for (i=i_start; i<i_start+m_f; i++) {
1021b3bd94feSDave May           /* convert to local "natural" numbering and then to PETSc global numbering */
1022e3fbd1f4SBarry Smith           row = idx_f[(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
1023b3bd94feSDave May 
1024b3bd94feSDave May           i_c = (i/ratioi);
1025b3bd94feSDave May           j_c = (j/ratioj);
1026b3bd94feSDave May           l_c = (l/ratiok);
1027b3bd94feSDave May 
1028b3bd94feSDave May           /* remainders */
1029b3bd94feSDave May           li = i - ratioi * (i/ratioi);
10308865f1eaSKarl Rupp           if (i==mx-1) li = nxi-1;
1031b3bd94feSDave May           lj = j - ratioj * (j/ratioj);
10328865f1eaSKarl Rupp           if (j==my-1) lj = neta-1;
1033b3bd94feSDave May           lk = l - ratiok * (l/ratiok);
10348865f1eaSKarl Rupp           if (l==mz-1) lk = nzeta-1;
1035b3bd94feSDave May 
1036b3bd94feSDave May           /* corners */
1037e3fbd1f4SBarry 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));
1038e3fbd1f4SBarry Smith           cols[0] = idx_c[col];
1039b3bd94feSDave May           Ni[0]   = 1.0;
1040b3bd94feSDave May           if ((li==0) || (li==nxi-1)) {
1041b3bd94feSDave May             if ((lj==0) || (lj==neta-1)) {
1042b3bd94feSDave May               if ((lk==0) || (lk==nzeta-1)) {
1043b3bd94feSDave May                 ierr = MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);CHKERRQ(ierr);
1044b3bd94feSDave May                 continue;
1045b3bd94feSDave May               }
1046b3bd94feSDave May             }
1047b3bd94feSDave May           }
1048b3bd94feSDave May 
1049b3bd94feSDave May           /* edges + interior */
1050b3bd94feSDave May           /* remainders */
10518865f1eaSKarl Rupp           if (i==mx-1) i_c--;
10528865f1eaSKarl Rupp           if (j==my-1) j_c--;
10538865f1eaSKarl Rupp           if (l==mz-1) l_c--;
1054b3bd94feSDave May 
1055e3fbd1f4SBarry 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));
1056e3fbd1f4SBarry Smith           cols[0] = idx_c[col]; /* one left and below; or we are right on it */
1057e3fbd1f4SBarry Smith           cols[1] = idx_c[col+1]; /* one right and below */
1058e3fbd1f4SBarry Smith           cols[2] = idx_c[col+m_ghost_c];  /* one left and above */
1059e3fbd1f4SBarry Smith           cols[3] = idx_c[col+(m_ghost_c+1)]; /* one right and above */
1060b3bd94feSDave May 
1061e3fbd1f4SBarry Smith           cols[4] = idx_c[col+m_ghost_c*n_ghost_c]; /* one left and below and front; or we are right on it */
1062e3fbd1f4SBarry Smith           cols[5] = idx_c[col+(m_ghost_c*n_ghost_c+1)]; /* one right and below, and front */
1063e3fbd1f4SBarry Smith           cols[6] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)]; /* one left and above and front*/
1064e3fbd1f4SBarry Smith           cols[7] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)]; /* one right and above and front */
1065b3bd94feSDave May 
1066b3bd94feSDave May           Ni[0] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
1067b3bd94feSDave May           Ni[1] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
1068b3bd94feSDave May           Ni[2] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);
1069b3bd94feSDave May           Ni[3] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);
1070b3bd94feSDave May 
1071b3bd94feSDave May           Ni[4] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
1072b3bd94feSDave May           Ni[5] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
1073b3bd94feSDave May           Ni[6] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);
1074b3bd94feSDave May           Ni[7] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);
1075b3bd94feSDave May 
1076b3bd94feSDave May           for (n=0; n<8; n++) {
10778865f1eaSKarl Rupp             if (PetscAbsScalar(Ni[n])<1.0e-32) cols[n]=-1;
1078b3bd94feSDave May           }
1079b3bd94feSDave May           ierr = MatSetValues(mat,1,&row,8,cols,Ni,INSERT_VALUES);CHKERRQ(ierr);
1080b3bd94feSDave May 
1081b3bd94feSDave May         }
1082b3bd94feSDave May       }
1083b3bd94feSDave May     }
1084b3bd94feSDave May     ierr = PetscFree(xi);CHKERRQ(ierr);
1085b3bd94feSDave May     ierr = PetscFree(eta);CHKERRQ(ierr);
1086b3bd94feSDave May     ierr = PetscFree(zeta);CHKERRQ(ierr);
1087b3bd94feSDave May   }
108845b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
108945b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
109047c6ae99SBarry Smith   ierr = MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
109147c6ae99SBarry Smith   ierr = MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
109247c6ae99SBarry Smith 
109347c6ae99SBarry Smith   ierr = MatCreateMAIJ(mat,dof,A);CHKERRQ(ierr);
1094fcfd50ebSBarry Smith   ierr = MatDestroy(&mat);CHKERRQ(ierr);
109547c6ae99SBarry Smith   PetscFunctionReturn(0);
109647c6ae99SBarry Smith }
109747c6ae99SBarry Smith 
1098e727c939SJed Brown PetscErrorCode  DMCreateInterpolation_DA(DM dac,DM daf,Mat *A,Vec *scale)
109947c6ae99SBarry Smith {
110047c6ae99SBarry Smith   PetscErrorCode   ierr;
110147c6ae99SBarry Smith   PetscInt         dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1102bff4a2f0SMatthew G. Knepley   DMBoundaryType   bxc,byc,bzc,bxf,byf,bzf;
1103aa219208SBarry Smith   DMDAStencilType  stc,stf;
110447c6ae99SBarry Smith   DM_DA            *ddc = (DM_DA*)dac->data;
110547c6ae99SBarry Smith 
110647c6ae99SBarry Smith   PetscFunctionBegin;
110747c6ae99SBarry Smith   PetscValidHeaderSpecific(dac,DM_CLASSID,1);
110847c6ae99SBarry Smith   PetscValidHeaderSpecific(daf,DM_CLASSID,2);
110947c6ae99SBarry Smith   PetscValidPointer(A,3);
111047c6ae99SBarry Smith   if (scale) PetscValidPointer(scale,4);
111147c6ae99SBarry Smith 
11121321219cSEthan Coon   ierr = DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);CHKERRQ(ierr);
11131321219cSEthan Coon   ierr = DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);CHKERRQ(ierr);
111413903a91SSatish Balay   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
111513903a91SSatish Balay   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
111613903a91SSatish Balay   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
111713903a91SSatish Balay   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
111813903a91SSatish Balay   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
111947c6ae99SBarry Smith   if (Mc < 2 && Mf > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
112047c6ae99SBarry 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");
112147c6ae99SBarry 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");
112247c6ae99SBarry Smith 
1123aa219208SBarry Smith   if (ddc->interptype == DMDA_Q1) {
112447c6ae99SBarry Smith     if (dimc == 1) {
1125e727c939SJed Brown       ierr = DMCreateInterpolation_DA_1D_Q1(dac,daf,A);CHKERRQ(ierr);
112647c6ae99SBarry Smith     } else if (dimc == 2) {
1127e727c939SJed Brown       ierr = DMCreateInterpolation_DA_2D_Q1(dac,daf,A);CHKERRQ(ierr);
112847c6ae99SBarry Smith     } else if (dimc == 3) {
1129e727c939SJed Brown       ierr = DMCreateInterpolation_DA_3D_Q1(dac,daf,A);CHKERRQ(ierr);
1130ce94432eSBarry Smith     } else SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
1131aa219208SBarry Smith   } else if (ddc->interptype == DMDA_Q0) {
113247c6ae99SBarry Smith     if (dimc == 1) {
1133e727c939SJed Brown       ierr = DMCreateInterpolation_DA_1D_Q0(dac,daf,A);CHKERRQ(ierr);
113447c6ae99SBarry Smith     } else if (dimc == 2) {
1135e727c939SJed Brown       ierr = DMCreateInterpolation_DA_2D_Q0(dac,daf,A);CHKERRQ(ierr);
113647c6ae99SBarry Smith     } else if (dimc == 3) {
1137e727c939SJed Brown       ierr = DMCreateInterpolation_DA_3D_Q0(dac,daf,A);CHKERRQ(ierr);
1138ce94432eSBarry Smith     } else SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
113947c6ae99SBarry Smith   }
114047c6ae99SBarry Smith   if (scale) {
1141e727c939SJed Brown     ierr = DMCreateInterpolationScale((DM)dac,(DM)daf,*A,scale);CHKERRQ(ierr);
114247c6ae99SBarry Smith   }
114347c6ae99SBarry Smith   PetscFunctionReturn(0);
114447c6ae99SBarry Smith }
114547c6ae99SBarry Smith 
1146e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_1D(DM dac,DM daf,VecScatter *inject)
11470bb2b966SJungho Lee {
11480bb2b966SJungho Lee   PetscErrorCode         ierr;
11498ea3bf28SBarry Smith   PetscInt               i,i_start,m_f,Mx,dof;
11508ea3bf28SBarry Smith   const PetscInt         *idx_f;
1151e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f;
11528ea3bf28SBarry Smith   PetscInt               m_ghost,m_ghost_c;
11530bb2b966SJungho Lee   PetscInt               row,i_start_ghost,mx,m_c,nc,ratioi;
11540bb2b966SJungho Lee   PetscInt               i_start_c,i_start_ghost_c;
11550bb2b966SJungho Lee   PetscInt               *cols;
1156bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx;
11570bb2b966SJungho Lee   Vec                    vecf,vecc;
11580bb2b966SJungho Lee   IS                     isf;
11590bb2b966SJungho Lee 
11600bb2b966SJungho Lee   PetscFunctionBegin;
11610bb2b966SJungho Lee   ierr = DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);CHKERRQ(ierr);
11620bb2b966SJungho Lee   ierr = DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
1163bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
11640bb2b966SJungho Lee     ratioi = mx/Mx;
11650bb2b966SJungho 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);
11660bb2b966SJungho Lee   } else {
11670bb2b966SJungho Lee     ratioi = (mx-1)/(Mx-1);
11680bb2b966SJungho 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);
11690bb2b966SJungho Lee   }
11700bb2b966SJungho Lee 
11710bb2b966SJungho Lee   ierr = DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);CHKERRQ(ierr);
11720bb2b966SJungho Lee   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);CHKERRQ(ierr);
117345b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
117445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
11750bb2b966SJungho Lee 
11760bb2b966SJungho Lee   ierr = DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);CHKERRQ(ierr);
11770bb2b966SJungho Lee   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);CHKERRQ(ierr);
11780bb2b966SJungho Lee 
11790bb2b966SJungho Lee 
11800bb2b966SJungho Lee   /* loop over local fine grid nodes setting interpolation for those*/
11810bb2b966SJungho Lee   nc   = 0;
1182785e854fSJed Brown   ierr = PetscMalloc1(m_f,&cols);CHKERRQ(ierr);
11830bb2b966SJungho Lee 
11840bb2b966SJungho Lee 
11850bb2b966SJungho Lee   for (i=i_start_c; i<i_start_c+m_c; i++) {
11860bb2b966SJungho Lee     PetscInt i_f = i*ratioi;
11870bb2b966SJungho Lee 
11888865f1eaSKarl 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);
11898865f1eaSKarl Rupp 
1190e3fbd1f4SBarry Smith     row        = idx_f[(i_f-i_start_ghost)];
1191e3fbd1f4SBarry Smith     cols[nc++] = row;
11920bb2b966SJungho Lee   }
11930bb2b966SJungho Lee 
119445b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
1195ce94432eSBarry Smith   ierr = ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);CHKERRQ(ierr);
11960bb2b966SJungho Lee   ierr = DMGetGlobalVector(dac,&vecc);CHKERRQ(ierr);
11970bb2b966SJungho Lee   ierr = DMGetGlobalVector(daf,&vecf);CHKERRQ(ierr);
11989448b7f1SJunchao Zhang   ierr = VecScatterCreate(vecf,isf,vecc,NULL,inject);CHKERRQ(ierr);
11990bb2b966SJungho Lee   ierr = DMRestoreGlobalVector(dac,&vecc);CHKERRQ(ierr);
12000bb2b966SJungho Lee   ierr = DMRestoreGlobalVector(daf,&vecf);CHKERRQ(ierr);
12010bb2b966SJungho Lee   ierr = ISDestroy(&isf);CHKERRQ(ierr);
12020bb2b966SJungho Lee   PetscFunctionReturn(0);
12030bb2b966SJungho Lee }
12040bb2b966SJungho Lee 
1205e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_2D(DM dac,DM daf,VecScatter *inject)
120647c6ae99SBarry Smith {
120747c6ae99SBarry Smith   PetscErrorCode         ierr;
12088ea3bf28SBarry Smith   PetscInt               i,j,i_start,j_start,m_f,n_f,Mx,My,dof;
12098ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
1210e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
12118ea3bf28SBarry Smith   PetscInt               m_ghost,n_ghost,m_ghost_c,n_ghost_c;
121247c6ae99SBarry Smith   PetscInt               row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
1213076202ddSJed Brown   PetscInt               i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
121447c6ae99SBarry Smith   PetscInt               *cols;
1215bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by;
121647c6ae99SBarry Smith   Vec                    vecf,vecc;
121747c6ae99SBarry Smith   IS                     isf;
121847c6ae99SBarry Smith 
121947c6ae99SBarry Smith   PetscFunctionBegin;
12201321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);CHKERRQ(ierr);
12211321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
1222bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
122347c6ae99SBarry Smith     ratioi = mx/Mx;
122447c6ae99SBarry 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);
122547c6ae99SBarry Smith   } else {
122647c6ae99SBarry Smith     ratioi = (mx-1)/(Mx-1);
122747c6ae99SBarry 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);
122847c6ae99SBarry Smith   }
1229bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
123047c6ae99SBarry Smith     ratioj = my/My;
123147c6ae99SBarry 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);
123247c6ae99SBarry Smith   } else {
123347c6ae99SBarry Smith     ratioj = (my-1)/(My-1);
123447c6ae99SBarry 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);
123547c6ae99SBarry Smith   }
123647c6ae99SBarry Smith 
1237aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);CHKERRQ(ierr);
1238aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);CHKERRQ(ierr);
123945b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
124045b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
124147c6ae99SBarry Smith 
1242aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);CHKERRQ(ierr);
1243aa219208SBarry Smith   ierr = DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);CHKERRQ(ierr);
124445b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
124545b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
124647c6ae99SBarry Smith 
124747c6ae99SBarry Smith   /* loop over local fine grid nodes setting interpolation for those*/
124847c6ae99SBarry Smith   nc   = 0;
1249785e854fSJed Brown   ierr = PetscMalloc1(n_f*m_f,&cols);CHKERRQ(ierr);
1250076202ddSJed Brown   for (j=j_start_c; j<j_start_c+n_c; j++) {
1251076202ddSJed Brown     for (i=i_start_c; i<i_start_c+m_c; i++) {
1252076202ddSJed Brown       PetscInt i_f = i*ratioi,j_f = j*ratioj;
1253076202ddSJed 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\
1254076202ddSJed Brown     j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
1255076202ddSJed 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\
1256076202ddSJed Brown     i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1257e3fbd1f4SBarry Smith       row        = idx_f[(m_ghost*(j_f-j_start_ghost) + (i_f-i_start_ghost))];
1258e3fbd1f4SBarry Smith       cols[nc++] = row;
125947c6ae99SBarry Smith     }
126047c6ae99SBarry Smith   }
126145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
126245b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
126347c6ae99SBarry Smith 
1264ce94432eSBarry Smith   ierr = ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);CHKERRQ(ierr);
12659a42bb27SBarry Smith   ierr = DMGetGlobalVector(dac,&vecc);CHKERRQ(ierr);
12669a42bb27SBarry Smith   ierr = DMGetGlobalVector(daf,&vecf);CHKERRQ(ierr);
12679448b7f1SJunchao Zhang   ierr = VecScatterCreate(vecf,isf,vecc,NULL,inject);CHKERRQ(ierr);
12689a42bb27SBarry Smith   ierr = DMRestoreGlobalVector(dac,&vecc);CHKERRQ(ierr);
12699a42bb27SBarry Smith   ierr = DMRestoreGlobalVector(daf,&vecf);CHKERRQ(ierr);
1270fcfd50ebSBarry Smith   ierr = ISDestroy(&isf);CHKERRQ(ierr);
127147c6ae99SBarry Smith   PetscFunctionReturn(0);
127247c6ae99SBarry Smith }
127347c6ae99SBarry Smith 
1274e727c939SJed Brown PetscErrorCode DMCreateInjection_DA_3D(DM dac,DM daf,VecScatter *inject)
1275b1757049SJed Brown {
1276b1757049SJed Brown   PetscErrorCode         ierr;
1277b1757049SJed Brown   PetscInt               i,j,k,i_start,j_start,k_start,m_f,n_f,p_f,Mx,My,Mz;
1278b1757049SJed Brown   PetscInt               m_ghost,n_ghost,p_ghost,m_ghost_c,n_ghost_c,p_ghost_c;
1279b1757049SJed Brown   PetscInt               i_start_ghost,j_start_ghost,k_start_ghost;
1280b1757049SJed Brown   PetscInt               mx,my,mz,ratioi,ratioj,ratiok;
1281b1757049SJed Brown   PetscInt               i_start_c,j_start_c,k_start_c;
1282b1757049SJed Brown   PetscInt               m_c,n_c,p_c;
1283b1757049SJed Brown   PetscInt               i_start_ghost_c,j_start_ghost_c,k_start_ghost_c;
1284b1757049SJed Brown   PetscInt               row,nc,dof;
12858ea3bf28SBarry Smith   const PetscInt         *idx_c,*idx_f;
1286e3fbd1f4SBarry Smith   ISLocalToGlobalMapping ltog_f,ltog_c;
1287b1757049SJed Brown   PetscInt               *cols;
1288bff4a2f0SMatthew G. Knepley   DMBoundaryType         bx,by,bz;
1289b1757049SJed Brown   Vec                    vecf,vecc;
1290b1757049SJed Brown   IS                     isf;
1291b1757049SJed Brown 
1292b1757049SJed Brown   PetscFunctionBegin;
12931321219cSEthan Coon   ierr = DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);CHKERRQ(ierr);
12941321219cSEthan Coon   ierr = DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);CHKERRQ(ierr);
1295b1757049SJed Brown 
1296bff4a2f0SMatthew G. Knepley   if (bx == DM_BOUNDARY_PERIODIC) {
1297b1757049SJed Brown     ratioi = mx/Mx;
1298b1757049SJed 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);
1299b1757049SJed Brown   } else {
1300b1757049SJed Brown     ratioi = (mx-1)/(Mx-1);
1301b1757049SJed 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);
1302b1757049SJed Brown   }
1303bff4a2f0SMatthew G. Knepley   if (by == DM_BOUNDARY_PERIODIC) {
1304b1757049SJed Brown     ratioj = my/My;
1305b1757049SJed 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);
1306b1757049SJed Brown   } else {
1307b1757049SJed Brown     ratioj = (my-1)/(My-1);
1308b1757049SJed 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);
1309b1757049SJed Brown   }
1310bff4a2f0SMatthew G. Knepley   if (bz == DM_BOUNDARY_PERIODIC) {
1311b1757049SJed Brown     ratiok = mz/Mz;
1312b1757049SJed 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);
1313b1757049SJed Brown   } else {
1314b1757049SJed Brown     ratiok = (mz-1)/(Mz-1);
1315b1757049SJed 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);
1316b1757049SJed Brown   }
1317b1757049SJed Brown 
1318b1757049SJed Brown   ierr = DMDAGetCorners(daf,&i_start,&j_start,&k_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
1319b1757049SJed Brown   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&k_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
132045b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltog_f);CHKERRQ(ierr);
132145b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
1322b1757049SJed Brown 
1323b1757049SJed Brown   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&k_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
1324b1757049SJed 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);
132545b6f7e9SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltog_c);CHKERRQ(ierr);
132645b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingGetBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
1327b1757049SJed Brown 
1328b1757049SJed Brown 
1329b1757049SJed Brown   /* loop over local fine grid nodes setting interpolation for those*/
1330b1757049SJed Brown   nc   = 0;
1331785e854fSJed Brown   ierr = PetscMalloc1(n_f*m_f*p_f,&cols);CHKERRQ(ierr);
1332b1757049SJed Brown   for (k=k_start_c; k<k_start_c+p_c; k++) {
1333b1757049SJed Brown     for (j=j_start_c; j<j_start_c+n_c; j++) {
1334b1757049SJed Brown       for (i=i_start_c; i<i_start_c+m_c; i++) {
1335b1757049SJed Brown         PetscInt i_f = i*ratioi,j_f = j*ratioj,k_f = k*ratiok;
1336b1757049SJed 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  "
1337b1757049SJed Brown                                                                           "k_c %D k_f %D fine ghost range [%D,%D]",k,k_f,k_start_ghost,k_start_ghost+p_ghost);
1338b1757049SJed 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  "
1339b1757049SJed Brown                                                                           "j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
1340b1757049SJed 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  "
1341b1757049SJed Brown                                                                           "i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1342e3fbd1f4SBarry 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))];
1343e3fbd1f4SBarry Smith         cols[nc++] = row;
1344b1757049SJed Brown       }
1345b1757049SJed Brown     }
1346b1757049SJed Brown   }
134745b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_f,&idx_f);CHKERRQ(ierr);
134845b6f7e9SBarry Smith   ierr = ISLocalToGlobalMappingRestoreBlockIndices(ltog_c,&idx_c);CHKERRQ(ierr);
1349b1757049SJed Brown 
1350ce94432eSBarry Smith   ierr = ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);CHKERRQ(ierr);
1351b1757049SJed Brown   ierr = DMGetGlobalVector(dac,&vecc);CHKERRQ(ierr);
1352b1757049SJed Brown   ierr = DMGetGlobalVector(daf,&vecf);CHKERRQ(ierr);
13539448b7f1SJunchao Zhang   ierr = VecScatterCreate(vecf,isf,vecc,NULL,inject);CHKERRQ(ierr);
1354b1757049SJed Brown   ierr = DMRestoreGlobalVector(dac,&vecc);CHKERRQ(ierr);
1355b1757049SJed Brown   ierr = DMRestoreGlobalVector(daf,&vecf);CHKERRQ(ierr);
1356fcfd50ebSBarry Smith   ierr = ISDestroy(&isf);CHKERRQ(ierr);
1357b1757049SJed Brown   PetscFunctionReturn(0);
1358b1757049SJed Brown }
1359b1757049SJed Brown 
13606dbf9973SLawrence Mitchell PetscErrorCode  DMCreateInjection_DA(DM dac,DM daf,Mat *mat)
136147c6ae99SBarry Smith {
136247c6ae99SBarry Smith   PetscErrorCode  ierr;
136347c6ae99SBarry Smith   PetscInt        dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1364bff4a2f0SMatthew G. Knepley   DMBoundaryType  bxc,byc,bzc,bxf,byf,bzf;
1365aa219208SBarry Smith   DMDAStencilType stc,stf;
136660c16ac1SBarry Smith   VecScatter      inject = NULL;
136747c6ae99SBarry Smith 
136847c6ae99SBarry Smith   PetscFunctionBegin;
136947c6ae99SBarry Smith   PetscValidHeaderSpecific(dac,DM_CLASSID,1);
137047c6ae99SBarry Smith   PetscValidHeaderSpecific(daf,DM_CLASSID,2);
13716dbf9973SLawrence Mitchell   PetscValidPointer(mat,3);
137247c6ae99SBarry Smith 
13731321219cSEthan Coon   ierr = DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);CHKERRQ(ierr);
13741321219cSEthan Coon   ierr = DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);CHKERRQ(ierr);
137513903a91SSatish Balay   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
137613903a91SSatish Balay   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
137713903a91SSatish Balay   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
137813903a91SSatish Balay   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
137913903a91SSatish Balay   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
138047c6ae99SBarry Smith   if (Mc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
138147c6ae99SBarry Smith   if (dimc > 1 && Nc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
138247c6ae99SBarry Smith   if (dimc > 2 && Pc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");
138347c6ae99SBarry Smith 
13840bb2b966SJungho Lee   if (dimc == 1) {
13856dbf9973SLawrence Mitchell     ierr = DMCreateInjection_DA_1D(dac,daf,&inject);CHKERRQ(ierr);
13860bb2b966SJungho Lee   } else if (dimc == 2) {
13876dbf9973SLawrence Mitchell     ierr = DMCreateInjection_DA_2D(dac,daf,&inject);CHKERRQ(ierr);
1388b1757049SJed Brown   } else if (dimc == 3) {
13896dbf9973SLawrence Mitchell     ierr = DMCreateInjection_DA_3D(dac,daf,&inject);CHKERRQ(ierr);
139047c6ae99SBarry Smith   }
13916dbf9973SLawrence Mitchell   ierr = MatCreateScatter(PetscObjectComm((PetscObject)inject), inject, mat);CHKERRQ(ierr);
13926dbf9973SLawrence Mitchell   ierr = VecScatterDestroy(&inject);CHKERRQ(ierr);
139347c6ae99SBarry Smith   PetscFunctionReturn(0);
139447c6ae99SBarry Smith }
139547c6ae99SBarry Smith 
1396e727c939SJed Brown PetscErrorCode  DMCreateAggregates_DA(DM dac,DM daf,Mat *rest)
139747c6ae99SBarry Smith {
139847c6ae99SBarry Smith   PetscErrorCode         ierr;
139947c6ae99SBarry Smith   PetscInt               dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc;
140047c6ae99SBarry Smith   PetscInt               dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1401bff4a2f0SMatthew G. Knepley   DMBoundaryType         bxc,byc,bzc,bxf,byf,bzf;
1402aa219208SBarry Smith   DMDAStencilType        stc,stf;
140347c6ae99SBarry Smith   PetscInt               i,j,l;
140447c6ae99SBarry Smith   PetscInt               i_start,j_start,l_start, m_f,n_f,p_f;
140547c6ae99SBarry Smith   PetscInt               i_start_ghost,j_start_ghost,l_start_ghost,m_ghost,n_ghost,p_ghost;
14068ea3bf28SBarry Smith   const PetscInt         *idx_f;
140747c6ae99SBarry Smith   PetscInt               i_c,j_c,l_c;
140847c6ae99SBarry Smith   PetscInt               i_start_c,j_start_c,l_start_c, m_c,n_c,p_c;
140947c6ae99SBarry Smith   PetscInt               i_start_ghost_c,j_start_ghost_c,l_start_ghost_c,m_ghost_c,n_ghost_c,p_ghost_c;
14108ea3bf28SBarry Smith   const PetscInt         *idx_c;
141147c6ae99SBarry Smith   PetscInt               d;
141247c6ae99SBarry Smith   PetscInt               a;
141347c6ae99SBarry Smith   PetscInt               max_agg_size;
141447c6ae99SBarry Smith   PetscInt               *fine_nodes;
141547c6ae99SBarry Smith   PetscScalar            *one_vec;
141647c6ae99SBarry Smith   PetscInt               fn_idx;
1417565245c5SBarry Smith   ISLocalToGlobalMapping ltogmf,ltogmc;
141847c6ae99SBarry Smith 
141947c6ae99SBarry Smith   PetscFunctionBegin;
142047c6ae99SBarry Smith   PetscValidHeaderSpecific(dac,DM_CLASSID,1);
142147c6ae99SBarry Smith   PetscValidHeaderSpecific(daf,DM_CLASSID,2);
142247c6ae99SBarry Smith   PetscValidPointer(rest,3);
142347c6ae99SBarry Smith 
14241321219cSEthan Coon   ierr = DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);CHKERRQ(ierr);
14251321219cSEthan Coon   ierr = DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);CHKERRQ(ierr);
142613903a91SSatish Balay   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
142713903a91SSatish Balay   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
142813903a91SSatish Balay   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
142913903a91SSatish Balay   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
143013903a91SSatish Balay   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
143147c6ae99SBarry Smith 
143247c6ae99SBarry 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);
143347c6ae99SBarry 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);
143447c6ae99SBarry 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);
143547c6ae99SBarry Smith 
143647c6ae99SBarry Smith   if (Pc < 0) Pc = 1;
143747c6ae99SBarry Smith   if (Pf < 0) Pf = 1;
143847c6ae99SBarry Smith   if (Nc < 0) Nc = 1;
143947c6ae99SBarry Smith   if (Nf < 0) Nf = 1;
144047c6ae99SBarry Smith 
1441aa219208SBarry Smith   ierr = DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);CHKERRQ(ierr);
1442aa219208SBarry Smith   ierr = DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);CHKERRQ(ierr);
1443565245c5SBarry Smith 
1444565245c5SBarry Smith   ierr = DMGetLocalToGlobalMapping(daf,&ltogmf);CHKERRQ(ierr);
1445565245c5SBarry Smith   ierr = ISLocalToGlobalMappingGetIndices(ltogmf,&idx_f);CHKERRQ(ierr);
144647c6ae99SBarry Smith 
1447aa219208SBarry Smith   ierr = DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);CHKERRQ(ierr);
1448aa219208SBarry 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);
1449565245c5SBarry Smith 
1450565245c5SBarry Smith   ierr = DMGetLocalToGlobalMapping(dac,&ltogmc);CHKERRQ(ierr);
1451565245c5SBarry Smith   ierr = ISLocalToGlobalMappingGetIndices(ltogmc,&idx_c);CHKERRQ(ierr);
145247c6ae99SBarry Smith 
145347c6ae99SBarry Smith   /*
145447c6ae99SBarry Smith      Basic idea is as follows. Here's a 2D example, suppose r_x, r_y are the ratios
145547c6ae99SBarry Smith      for dimension 1 and 2 respectively.
145647c6ae99SBarry Smith      Let (i,j) be a coarse grid node. All the fine grid nodes between r_x*i and r_x*(i+1)
145747c6ae99SBarry Smith      and r_y*j and r_y*(j+1) will be grouped into the same coarse grid agregate.
145847c6ae99SBarry Smith      Each specific dof on the fine grid is mapped to one dof on the coarse grid.
145947c6ae99SBarry Smith   */
146047c6ae99SBarry Smith 
146147c6ae99SBarry Smith   max_agg_size = (Mf/Mc+1)*(Nf/Nc+1)*(Pf/Pc+1);
146247c6ae99SBarry Smith 
146347c6ae99SBarry Smith   /* create the matrix that will contain the restriction operator */
1464ce94432eSBarry 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,
14650298fd71SBarry Smith                       max_agg_size, NULL, max_agg_size, NULL, rest);CHKERRQ(ierr);
146647c6ae99SBarry Smith 
146747c6ae99SBarry Smith   /* store nodes in the fine grid here */
1468dcca6d9dSJed Brown   ierr = PetscMalloc2(max_agg_size, &one_vec,max_agg_size, &fine_nodes);CHKERRQ(ierr);
146947c6ae99SBarry Smith   for (i=0; i<max_agg_size; i++) one_vec[i] = 1.0;
147047c6ae99SBarry Smith 
147147c6ae99SBarry Smith   /* loop over all coarse nodes */
147247c6ae99SBarry Smith   for (l_c=l_start_c; l_c<l_start_c+p_c; l_c++) {
147347c6ae99SBarry Smith     for (j_c=j_start_c; j_c<j_start_c+n_c; j_c++) {
147447c6ae99SBarry Smith       for (i_c=i_start_c; i_c<i_start_c+m_c; i_c++) {
147547c6ae99SBarry Smith         for (d=0; d<dofc; d++) {
147647c6ae99SBarry Smith           /* convert to local "natural" numbering and then to PETSc global numbering */
147747c6ae99SBarry 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;
147847c6ae99SBarry Smith 
147947c6ae99SBarry Smith           fn_idx = 0;
148047c6ae99SBarry Smith           /* Corresponding fine points are all points (i_f, j_f, l_f) such that
148147c6ae99SBarry Smith              i_c*Mf/Mc <= i_f < (i_c+1)*Mf/Mc
148247c6ae99SBarry Smith              (same for other dimensions)
148347c6ae99SBarry Smith           */
148447c6ae99SBarry Smith           for (l=l_c*Pf/Pc; l<PetscMin((l_c+1)*Pf/Pc,Pf); l++) {
148547c6ae99SBarry Smith             for (j=j_c*Nf/Nc; j<PetscMin((j_c+1)*Nf/Nc,Nf); j++) {
148647c6ae99SBarry Smith               for (i=i_c*Mf/Mc; i<PetscMin((i_c+1)*Mf/Mc,Mf); i++) {
148747c6ae99SBarry 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;
148847c6ae99SBarry Smith                 fn_idx++;
148947c6ae99SBarry Smith               }
149047c6ae99SBarry Smith             }
149147c6ae99SBarry Smith           }
149247c6ae99SBarry Smith           /* add all these points to one aggregate */
149347c6ae99SBarry Smith           ierr = MatSetValues(*rest, 1, &a, fn_idx, fine_nodes, one_vec, INSERT_VALUES);CHKERRQ(ierr);
149447c6ae99SBarry Smith         }
149547c6ae99SBarry Smith       }
149647c6ae99SBarry Smith     }
149747c6ae99SBarry Smith   }
1498565245c5SBarry Smith   ierr = ISLocalToGlobalMappingRestoreIndices(ltogmf,&idx_f);CHKERRQ(ierr);
1499565245c5SBarry Smith   ierr = ISLocalToGlobalMappingRestoreIndices(ltogmc,&idx_c);CHKERRQ(ierr);
150047c6ae99SBarry Smith   ierr = PetscFree2(one_vec,fine_nodes);CHKERRQ(ierr);
150147c6ae99SBarry Smith   ierr = MatAssemblyBegin(*rest, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
150247c6ae99SBarry Smith   ierr = MatAssemblyEnd(*rest, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
150347c6ae99SBarry Smith   PetscFunctionReturn(0);
150447c6ae99SBarry Smith }
1505