Actual source code: dainterp.c

  2: /*
  3:   Code for interpolating between grids represented by DMDAs
  4: */

  6: /*
  7:       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 
  8:    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
  9:    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 
 10:    consider it cleaner, but old version is turned on since it handles periodic case.
 11: */
 12: #define NEWVERSION 0

 14: #include <private/daimpl.h>    /*I   "petscdmda.h"   I*/
 15: #include <petscpcmg.h>

 19: /*@
 20:     DMGetInterpolationScale - Forms L = R*1/diag(R*1) - L.*v is like a coarse grid average of the 
 21:       nearby fine grid points.

 23:   Input Parameters:
 24: +      dac - DM that defines a coarse mesh
 25: .      daf - DM that defines a fine mesh
 26: -      mat - the restriction (or interpolation operator) from fine to coarse

 28:   Output Parameter:
 29: .    scale - the scaled vector

 31:   Level: developer

 33: .seealso: DMGetInterpolation()

 35: @*/
 36: PetscErrorCode  DMGetInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
 37: {
 39:   Vec            fine;
 40:   PetscScalar    one = 1.0;

 43:   DMCreateGlobalVector(daf,&fine);
 44:   DMCreateGlobalVector(dac,scale);
 45:   VecSet(fine,one);
 46:   MatRestrict(mat,fine,*scale);
 47:   VecDestroy(&fine);
 48:   VecReciprocal(*scale);
 49:   return(0);
 50: }

 54: PetscErrorCode DMGetInterpolation_DA_1D_Q1(DM dac,DM daf,Mat *A)
 55: {
 56:   PetscErrorCode   ierr;
 57:   PetscInt         i,i_start,m_f,Mx,*idx_f;
 58:   PetscInt         m_ghost,*idx_c,m_ghost_c;
 59:   PetscInt         row,col,i_start_ghost,mx,m_c,nc,ratio;
 60:   PetscInt         i_c,i_start_c,i_start_ghost_c,cols[2],dof;
 61:   PetscScalar      v[2],x;
 62:   Mat              mat;
 63:   DMDABoundaryType bx;
 64: 
 66:   DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);
 67:   DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);
 68:   if (bx == DMDA_BOUNDARY_PERIODIC){
 69:     ratio = mx/Mx;
 70:     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);
 71:   } else {
 72:     ratio = (mx-1)/(Mx-1);
 73:     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);
 74:   }
 75: 
 76:   DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);
 77:   DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
 78:   DMDAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
 79: 
 80:   DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
 81:   DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
 82:   DMDAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
 83: 
 84:   /* create interpolation matrix */
 85:   MatCreate(((PetscObject)dac)->comm,&mat);
 86:   MatSetSizes(mat,m_f,m_c,mx,Mx);
 87:   MatSetType(mat,MATAIJ);
 88:   MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
 89:   MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);
 90: 
 91:   /* loop over local fine grid nodes setting interpolation for those*/
 92:   if (!NEWVERSION) {

 94:     for (i=i_start; i<i_start+m_f; i++) {
 95:       /* convert to local "natural" numbering and then to PETSc global numbering */
 96:       row    = idx_f[dof*(i-i_start_ghost)]/dof;
 97: 
 98:       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
 99:       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\
100:                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
101: 
102:       /* 
103:        Only include those interpolation points that are truly 
104:        nonzero. Note this is very important for final grid lines
105:        in x direction; since they have no right neighbor
106:        */
107:       x  = ((double)(i - i_c*ratio))/((double)ratio);
108:       nc = 0;
109:       /* one left and below; or we are right on it */
110:       col      = dof*(i_c-i_start_ghost_c);
111:       cols[nc] = idx_c[col]/dof;
112:       v[nc++]  = - x + 1.0;
113:       /* one right? */
114:       if (i_c*ratio != i) {
115:         cols[nc] = idx_c[col+dof]/dof;
116:         v[nc++]  = x;
117:       }
118:       MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
119:     }
120: 
121:   } else {
122:     PetscScalar    *xi;
123:     PetscInt       li,nxi,n;
124:     PetscScalar    Ni[2];
125: 
126:     /* compute local coordinate arrays */
127:     nxi   = ratio + 1;
128:     PetscMalloc(sizeof(PetscScalar)*nxi,&xi);
129:     for (li=0; li<nxi; li++) {
130:       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
131:     }

133:     for (i=i_start; i<i_start+m_f; i++) {
134:       /* convert to local "natural" numbering and then to PETSc global numbering */
135:       row    = idx_f[dof*(i-i_start_ghost)]/dof;
136: 
137:       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
138:       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\
139:                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

141:       /* remainders */
142:       li = i - ratio * (i/ratio);
143:       if (i==mx-1){ li = nxi-1; }
144: 
145:       /* corners */
146:       col     = dof*(i_c-i_start_ghost_c);
147:       cols[0] = idx_c[col]/dof;
148:       Ni[0]   = 1.0;
149:       if ( (li==0) || (li==nxi-1) ) {
150:         MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);
151:         continue;
152:       }
153: 
154:       /* edges + interior */
155:       /* remainders */
156:       if (i==mx-1){ i_c--; }
157: 
158:       col     = dof*(i_c-i_start_ghost_c);
159:       cols[0] = idx_c[col]/dof; /* one left and below; or we are right on it */
160:       cols[1] = idx_c[col+dof]/dof;

162:       Ni[0] = 0.5*(1.0-xi[li]);
163:       Ni[1] = 0.5*(1.0+xi[li]);
164:       for (n=0; n<2; n++) {
165:         if( PetscAbsScalar(Ni[n])<1.0e-32) { cols[n]=-1; }
166:       }
167:       MatSetValues(mat,1,&row,2,cols,Ni,INSERT_VALUES);
168:     }
169:     PetscFree(xi);
170:   }
171:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
172:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
173:   MatCreateMAIJ(mat,dof,A);
174:   MatDestroy(&mat);
175:   return(0);
176: }

180: PetscErrorCode DMGetInterpolation_DA_1D_Q0(DM dac,DM daf,Mat *A)
181: {
182:   PetscErrorCode   ierr;
183:   PetscInt         i,i_start,m_f,Mx,*idx_f;
184:   PetscInt         m_ghost,*idx_c,m_ghost_c;
185:   PetscInt         row,col,i_start_ghost,mx,m_c,nc,ratio;
186:   PetscInt         i_c,i_start_c,i_start_ghost_c,cols[2],dof;
187:   PetscScalar      v[2],x;
188:   Mat              mat;
189:   DMDABoundaryType bx;
190: 
192:   DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);
193:   DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);
194:   if (bx == DMDA_BOUNDARY_PERIODIC){
195:     ratio = mx/Mx;
196:     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);
197:   } else {
198:     ratio = (mx-1)/(Mx-1);
199:     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);
200:   }

202:   DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);
203:   DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
204:   DMDAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

206:   DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
207:   DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
208:   DMDAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

210:   /* create interpolation matrix */
211:   MatCreate(((PetscObject)dac)->comm,&mat);
212:   MatSetSizes(mat,m_f,m_c,mx,Mx);
213:   MatSetType(mat,MATAIJ);
214:   MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
215:   MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);

217:   /* loop over local fine grid nodes setting interpolation for those*/
218:   for (i=i_start; i<i_start+m_f; i++) {
219:     /* convert to local "natural" numbering and then to PETSc global numbering */
220:     row    = idx_f[dof*(i-i_start_ghost)]/dof;

222:     i_c = (i/ratio);    /* coarse grid node to left of fine grid node */

224:     /* 
225:          Only include those interpolation points that are truly 
226:          nonzero. Note this is very important for final grid lines
227:          in x direction; since they have no right neighbor
228:     */
229:     x  = ((double)(i - i_c*ratio))/((double)ratio);
230:     nc = 0;
231:       /* one left and below; or we are right on it */
232:     col      = dof*(i_c-i_start_ghost_c);
233:     cols[nc] = idx_c[col]/dof;
234:     v[nc++]  = - x + 1.0;
235:     /* one right? */
236:     if (i_c*ratio != i) {
237:       cols[nc] = idx_c[col+dof]/dof;
238:       v[nc++]  = x;
239:     }
240:     MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
241:   }
242:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
243:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
244:   MatCreateMAIJ(mat,dof,A);
245:   MatDestroy(&mat);
246:   PetscLogFlops(5.0*m_f);
247:   return(0);
248: }

252: PetscErrorCode DMGetInterpolation_DA_2D_Q1(DM dac,DM daf,Mat *A)
253: {
254:   PetscErrorCode   ierr;
255:   PetscInt         i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
256:   PetscInt         m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
257:   PetscInt         row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
258:   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;
259:   PetscMPIInt      size_c,size_f,rank_f;
260:   PetscScalar      v[4],x,y;
261:   Mat              mat;
262:   DMDABoundaryType bx,by;
263: 
265:   DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);
266:   DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);
267:   if (bx == DMDA_BOUNDARY_PERIODIC){
268:     ratioi = mx/Mx;
269:     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);
270:   } else {
271:     ratioi = (mx-1)/(Mx-1);
272:     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);
273:   }
274:   if (by == DMDA_BOUNDARY_PERIODIC){
275:     ratioj = my/My;
276:     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);
277:   } else {
278:     ratioj = (my-1)/(My-1);
279:     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);
280:   }
281: 
282: 
283:   DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
284:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
285:   DMDAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
286: 
287:   DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
288:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
289:   DMDAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
290: 
291:   /*
292:    Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
293:    The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the 
294:    processors). It's effective length is hence 4 times its normal length, this is
295:    why the col_scale is multiplied by the interpolation matrix column sizes.
296:    sol_shift allows each set of 1/4 processors do its own interpolation using ITS
297:    copy of the coarse vector. A bit of a hack but you do better.
298:    
299:    In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
300:    */
301:   MPI_Comm_size(((PetscObject)dac)->comm,&size_c);
302:   MPI_Comm_size(((PetscObject)daf)->comm,&size_f);
303:   MPI_Comm_rank(((PetscObject)daf)->comm,&rank_f);
304:   col_scale = size_f/size_c;
305:   col_shift = Mx*My*(rank_f/size_c);
306: 
307:   MatPreallocateInitialize(((PetscObject)daf)->comm,m_f*n_f,col_scale*m_c*n_c,dnz,onz);
308:   for (j=j_start; j<j_start+n_f; j++) {
309:     for (i=i_start; i<i_start+m_f; i++) {
310:       /* convert to local "natural" numbering and then to PETSc global numbering */
311:       row    = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
312: 
313:       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
314:       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
315: 
316:       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\
317:                                           j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
318:       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\
319:                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
320: 
321:       /* 
322:        Only include those interpolation points that are truly 
323:        nonzero. Note this is very important for final grid lines
324:        in x and y directions; since they have no right/top neighbors
325:        */
326:       nc = 0;
327:       /* one left and below; or we are right on it */
328:       col        = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
329:       cols[nc++] = col_shift + idx_c[col]/dof;
330:       /* one right and below */
331:       if (i_c*ratioi != i) {
332:         cols[nc++] = col_shift + idx_c[col+dof]/dof;
333:       }
334:       /* one left and above */
335:       if (j_c*ratioj != j) {
336:         cols[nc++] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
337:       }
338:       /* one right and above */
339:       if (i_c*ratioi != i && j_c*ratioj != j) {
340:         cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
341:       }
342:       MatPreallocateSet(row,nc,cols,dnz,onz);
343:     }
344:   }
345:   MatCreate(((PetscObject)daf)->comm,&mat);
346:   MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);
347:   MatSetType(mat,MATAIJ);
348:   MatSeqAIJSetPreallocation(mat,0,dnz);
349:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
350:   MatPreallocateFinalize(dnz,onz);
351: 
352:   /* loop over local fine grid nodes setting interpolation for those*/
353:   if (!NEWVERSION) {
354: 
355:     for (j=j_start; j<j_start+n_f; j++) {
356:       for (i=i_start; i<i_start+m_f; i++) {
357:         /* convert to local "natural" numbering and then to PETSc global numbering */
358:         row    = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
359: 
360:         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
361:         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
362: 
363:         /* 
364:          Only include those interpolation points that are truly 
365:          nonzero. Note this is very important for final grid lines
366:          in x and y directions; since they have no right/top neighbors
367:          */
368:         x  = ((double)(i - i_c*ratioi))/((double)ratioi);
369:         y  = ((double)(j - j_c*ratioj))/((double)ratioj);
370: 
371:         nc = 0;
372:         /* one left and below; or we are right on it */
373:         col      = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
374:         cols[nc] = col_shift + idx_c[col]/dof;
375:         v[nc++]  = x*y - x - y + 1.0;
376:         /* one right and below */
377:         if (i_c*ratioi != i) {
378:           cols[nc] = col_shift + idx_c[col+dof]/dof;
379:           v[nc++]  = -x*y + x;
380:         }
381:         /* one left and above */
382:         if (j_c*ratioj != j) {
383:           cols[nc] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
384:           v[nc++]  = -x*y + y;
385:         }
386:         /* one right and above */
387:         if (j_c*ratioj != j && i_c*ratioi != i) {
388:           cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
389:           v[nc++]  = x*y;
390:         }
391:         MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
392:       }
393:     }
394: 
395:   } else {
396:     PetscScalar    Ni[4];
397:     PetscScalar    *xi,*eta;
398:     PetscInt       li,nxi,lj,neta;
399: 
400:     /* compute local coordinate arrays */
401:     nxi  = ratioi + 1;
402:     neta = ratioj + 1;
403:     PetscMalloc(sizeof(PetscScalar)*nxi,&xi);
404:     PetscMalloc(sizeof(PetscScalar)*neta,&eta);
405:     for (li=0; li<nxi; li++) {
406:       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
407:     }
408:     for (lj=0; lj<neta; lj++) {
409:       eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
410:     }

412:     /* loop over local fine grid nodes setting interpolation for those*/
413:     for (j=j_start; j<j_start+n_f; j++) {
414:       for (i=i_start; i<i_start+m_f; i++) {
415:         /* convert to local "natural" numbering and then to PETSc global numbering */
416:         row    = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
417: 
418:         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
419:         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
420: 
421:         /* remainders */
422:         li = i - ratioi * (i/ratioi);
423:         if (i==mx-1){ li = nxi-1; }
424:         lj = j - ratioj * (j/ratioj);
425:         if (j==my-1){ lj = neta-1; }
426: 
427:         /* corners */
428:         col     = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
429:         cols[0] = col_shift + idx_c[col]/dof; /* left, below */
430:         Ni[0]   = 1.0;
431:         if ( (li==0) || (li==nxi-1) ) {
432:           if ( (lj==0) || (lj==neta-1) ) {
433:             MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);
434:             continue;
435:           }
436:         }
437: 
438:         /* edges + interior */
439:         /* remainders */
440:         if (i==mx-1){ i_c--; }
441:         if (j==my-1){ j_c--; }

443:         col     = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
444:         cols[0] = col_shift + idx_c[col]/dof; /* left, below */
445:         cols[1] = col_shift + idx_c[col+dof]/dof; /* right, below */
446:         cols[2] = col_shift + idx_c[col+m_ghost_c*dof]/dof; /* left, above */
447:         cols[3] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof; /* right, above */

449:         Ni[0] = 0.25*(1.0-xi[li])*(1.0-eta[lj]);
450:         Ni[1] = 0.25*(1.0+xi[li])*(1.0-eta[lj]);
451:         Ni[2] = 0.25*(1.0-xi[li])*(1.0+eta[lj]);
452:         Ni[3] = 0.25*(1.0+xi[li])*(1.0+eta[lj]);

454:         nc = 0;
455:         if( PetscAbsScalar(Ni[0])<1.0e-32) { cols[0]=-1; }
456:         if( PetscAbsScalar(Ni[1])<1.0e-32) { cols[1]=-1; }
457:         if( PetscAbsScalar(Ni[2])<1.0e-32) { cols[2]=-1; }
458:         if( PetscAbsScalar(Ni[3])<1.0e-32) { cols[3]=-1; }
459: 
460:         MatSetValues(mat,1,&row,4,cols,Ni,INSERT_VALUES);
461:       }
462:     }
463:     PetscFree(xi);
464:     PetscFree(eta);
465:   }
466:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
467:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
468:   MatCreateMAIJ(mat,dof,A);
469:   MatDestroy(&mat);
470:   return(0);
471: }

473: /* 
474:        Contributed by Andrei Draganescu <aidraga@sandia.gov>
475: */
478: PetscErrorCode DMGetInterpolation_DA_2D_Q0(DM dac,DM daf,Mat *A)
479: {
480:   PetscErrorCode   ierr;
481:   PetscInt         i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
482:   PetscInt         m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
483:   PetscInt         row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
484:   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;
485:   PetscMPIInt      size_c,size_f,rank_f;
486:   PetscScalar      v[4];
487:   Mat              mat;
488:   DMDABoundaryType bx,by;

491:   DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);
492:   DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);
493:   if (bx == DMDA_BOUNDARY_PERIODIC) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in x");
494:   if (by == DMDA_BOUNDARY_PERIODIC) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in y");
495:   ratioi = mx/Mx;
496:   ratioj = my/My;
497:   if (ratioi*Mx != mx) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
498:   if (ratioj*My != my) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
499:   if (ratioi != 2) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 2");
500:   if (ratioj != 2) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 2");

502:   DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
503:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
504:   DMDAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

506:   DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
507:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
508:   DMDAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

510:   /*
511:      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
512:      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the 
513:      processors). It's effective length is hence 4 times its normal length, this is
514:      why the col_scale is multiplied by the interpolation matrix column sizes.
515:      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
516:      copy of the coarse vector. A bit of a hack but you do better.

518:      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
519:   */
520:   MPI_Comm_size(((PetscObject)dac)->comm,&size_c);
521:   MPI_Comm_size(((PetscObject)daf)->comm,&size_f);
522:   MPI_Comm_rank(((PetscObject)daf)->comm,&rank_f);
523:   col_scale = size_f/size_c;
524:   col_shift = Mx*My*(rank_f/size_c);

526:   MatPreallocateInitialize(((PetscObject)daf)->comm,m_f*n_f,col_scale*m_c*n_c,dnz,onz);
527:   for (j=j_start; j<j_start+n_f; j++) {
528:     for (i=i_start; i<i_start+m_f; i++) {
529:       /* convert to local "natural" numbering and then to PETSc global numbering */
530:       row    = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;

532:       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
533:       j_c = (j/ratioj);    /* coarse grid node below fine grid node */

535:       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\
536:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
537:       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\
538:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

540:       /* 
541:          Only include those interpolation points that are truly 
542:          nonzero. Note this is very important for final grid lines
543:          in x and y directions; since they have no right/top neighbors
544:       */
545:       nc = 0;
546:       /* one left and below; or we are right on it */
547:       col        = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
548:       cols[nc++] = col_shift + idx_c[col]/dof;
549:       MatPreallocateSet(row,nc,cols,dnz,onz);
550:     }
551:   }
552:   MatCreate(((PetscObject)daf)->comm,&mat);
553:   MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);
554:   MatSetType(mat,MATAIJ);
555:   MatSeqAIJSetPreallocation(mat,0,dnz);
556:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
557:   MatPreallocateFinalize(dnz,onz);

559:   /* loop over local fine grid nodes setting interpolation for those*/
560:   for (j=j_start; j<j_start+n_f; j++) {
561:     for (i=i_start; i<i_start+m_f; i++) {
562:       /* convert to local "natural" numbering and then to PETSc global numbering */
563:       row    = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;

565:       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
566:       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
567:       nc = 0;
568:       /* one left and below; or we are right on it */
569:       col      = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
570:       cols[nc] = col_shift + idx_c[col]/dof;
571:       v[nc++]  = 1.0;
572: 
573:       MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
574:     }
575:   }
576:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
577:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
578:   MatCreateMAIJ(mat,dof,A);
579:   MatDestroy(&mat);
580:   PetscLogFlops(13.0*m_f*n_f);
581:   return(0);
582: }

584: /* 
585:        Contributed by Jianming Yang <jianming-yang@uiowa.edu>
586: */
589: PetscErrorCode DMGetInterpolation_DA_3D_Q0(DM dac,DM daf,Mat *A)
590: {
591:   PetscErrorCode   ierr;
592:   PetscInt         i,j,l,i_start,j_start,l_start,m_f,n_f,p_f,Mx,My,Mz,*idx_f,dof;
593:   PetscInt         m_ghost,n_ghost,p_ghost,*idx_c,m_ghost_c,n_ghost_c,p_ghost_c,nc,*dnz,*onz;
594:   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;
595:   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;
596:   PetscMPIInt      size_c,size_f,rank_f;
597:   PetscScalar      v[8];
598:   Mat              mat;
599:   DMDABoundaryType bx,by,bz;
600: 
602:   DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);
603:   DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);
604:   if (bx == DMDA_BOUNDARY_PERIODIC) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in x");
605:   if (by == DMDA_BOUNDARY_PERIODIC) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in y");
606:   if (bz == DMDA_BOUNDARY_PERIODIC) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in z");
607:   ratioi = mx/Mx;
608:   ratioj = my/My;
609:   ratiol = mz/Mz;
610:   if (ratioi*Mx != mx) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
611:   if (ratioj*My != my) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
612:   if (ratiol*Mz != mz) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in z");
613:   if (ratioi != 2 && ratioi != 1) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 1 or 2");
614:   if (ratioj != 2 && ratioj != 1) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 1 or 2");
615:   if (ratiol != 2 && ratiol != 1) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_WRONG,"Coarsening factor in z must be 1 or 2");

617:   DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
618:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
619:   DMDAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

621:   DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
622:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
623:   DMDAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
624:   /*
625:      Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
626:      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the 
627:      processors). It's effective length is hence 4 times its normal length, this is
628:      why the col_scale is multiplied by the interpolation matrix column sizes.
629:      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
630:      copy of the coarse vector. A bit of a hack but you do better.

632:      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
633:   */
634:   MPI_Comm_size(((PetscObject)dac)->comm,&size_c);
635:   MPI_Comm_size(((PetscObject)daf)->comm,&size_f);
636:   MPI_Comm_rank(((PetscObject)daf)->comm,&rank_f);
637:   col_scale = size_f/size_c;
638:   col_shift = Mx*My*Mz*(rank_f/size_c);

640:   MatPreallocateInitialize(((PetscObject)daf)->comm,m_f*n_f*p_f,col_scale*m_c*n_c*p_c,dnz,onz);
641:   for (l=l_start; l<l_start+p_f; l++) {
642:     for (j=j_start; j<j_start+n_f; j++) {
643:       for (i=i_start; i<i_start+m_f; i++) {
644:         /* convert to local "natural" numbering and then to PETSc global numbering */
645:         row    = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;

647:         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
648:         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
649:         l_c = (l/ratiol);

651:         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\
652:     l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
653:         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\
654:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
655:         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\
656:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

658:         /* 
659:            Only include those interpolation points that are truly 
660:            nonzero. Note this is very important for final grid lines
661:            in x and y directions; since they have no right/top neighbors
662:         */
663:         nc = 0;
664:         /* one left and below; or we are right on it */
665:         col        = dof*(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));
666:         cols[nc++] = col_shift + idx_c[col]/dof;
667:         MatPreallocateSet(row,nc,cols,dnz,onz);
668:       }
669:     }
670:   }
671:   MatCreate(((PetscObject)daf)->comm,&mat);
672:   MatSetSizes(mat,m_f*n_f*p_f,col_scale*m_c*n_c*p_c,mx*my*mz,col_scale*Mx*My*Mz);
673:   MatSetType(mat,MATAIJ);
674:   MatSeqAIJSetPreallocation(mat,0,dnz);
675:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
676:   MatPreallocateFinalize(dnz,onz);

678:   /* loop over local fine grid nodes setting interpolation for those*/
679:   for (l=l_start; l<l_start+p_f; l++) {
680:     for (j=j_start; j<j_start+n_f; j++) {
681:       for (i=i_start; i<i_start+m_f; i++) {
682:         /* convert to local "natural" numbering and then to PETSc global numbering */
683:         row    = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
684: 
685:         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
686:         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
687:         l_c = (l/ratiol);
688:         nc = 0;
689:         /* one left and below; or we are right on it */
690:         col      = dof*(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));
691:         cols[nc] = col_shift + idx_c[col]/dof;
692:         v[nc++]  = 1.0;
693: 
694:         MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
695:       }
696:     }
697:   }
698:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
699:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
700:   MatCreateMAIJ(mat,dof,A);
701:   MatDestroy(&mat);
702:   PetscLogFlops(13.0*m_f*n_f*p_f);
703:   return(0);
704: }

708: PetscErrorCode DMGetInterpolation_DA_3D_Q1(DM dac,DM daf,Mat *A)
709: {
710:   PetscErrorCode   ierr;
711:   PetscInt         i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof,l;
712:   PetscInt         m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,Mz,mz;
713:   PetscInt         row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
714:   PetscInt         i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
715:   PetscInt         l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
716:   PetscInt         l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
717:   PetscScalar      v[8],x,y,z;
718:   Mat              mat;
719:   DMDABoundaryType bx,by,bz;
720: 
722:   DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);
723:   DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);
724:   if (mx == Mx) {
725:     ratioi = 1;
726:   } else if (bx == DMDA_BOUNDARY_PERIODIC) {
727:     ratioi = mx/Mx;
728:     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);
729:   } else {
730:     ratioi = (mx-1)/(Mx-1);
731:     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);
732:   }
733:   if (my == My) {
734:     ratioj = 1;
735:   } else if (by == DMDA_BOUNDARY_PERIODIC) {
736:     ratioj = my/My;
737:     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);
738:   } else {
739:     ratioj = (my-1)/(My-1);
740:     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);
741:   }
742:   if (mz == Mz) {
743:     ratiok = 1;
744:   } else if (bz == DMDA_BOUNDARY_PERIODIC) {
745:     ratiok = mz/Mz;
746:     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);
747:   } else {
748:     ratiok = (mz-1)/(Mz-1);
749:     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);
750:   }
751: 
752:   DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
753:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
754:   DMDAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
755: 
756:   DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
757:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
758:   DMDAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
759: 
760:   /* create interpolation matrix, determining exact preallocation */
761:   MatPreallocateInitialize(((PetscObject)dac)->comm,m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);
762:   /* loop over local fine grid nodes counting interpolating points */
763:   for (l=l_start; l<l_start+p_f; l++) {
764:     for (j=j_start; j<j_start+n_f; j++) {
765:       for (i=i_start; i<i_start+m_f; i++) {
766:         /* convert to local "natural" numbering and then to PETSc global numbering */
767:         row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
768:         i_c = (i/ratioi);
769:         j_c = (j/ratioj);
770:         l_c = (l/ratiok);
771:         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\
772:                                             l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
773:         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\
774:                                             j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
775:         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\
776:                                             i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
777: 
778:         /* 
779:          Only include those interpolation points that are truly 
780:          nonzero. Note this is very important for final grid lines
781:          in x and y directions; since they have no right/top neighbors
782:          */
783:         nc       = 0;
784:         col      = dof*(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));
785:         cols[nc++] = idx_c[col]/dof;
786:         if (i_c*ratioi != i) {
787:           cols[nc++] = idx_c[col+dof]/dof;
788:         }
789:         if (j_c*ratioj != j) {
790:           cols[nc++] = idx_c[col+m_ghost_c*dof]/dof;
791:         }
792:         if (l_c*ratiok != l) {
793:           cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
794:         }
795:         if (j_c*ratioj != j && i_c*ratioi != i) {
796:           cols[nc++] = idx_c[col+(m_ghost_c+1)*dof]/dof;
797:         }
798:         if (j_c*ratioj != j && l_c*ratiok != l) {
799:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
800:         }
801:         if (i_c*ratioi != i && l_c*ratiok != l) {
802:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
803:         }
804:         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
805:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
806:         }
807:         MatPreallocateSet(row,nc,cols,dnz,onz);
808:       }
809:     }
810:   }
811:   MatCreate(((PetscObject)dac)->comm,&mat);
812:   MatSetSizes(mat,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz);
813:   MatSetType(mat,MATAIJ);
814:   MatSeqAIJSetPreallocation(mat,0,dnz);
815:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
816:   MatPreallocateFinalize(dnz,onz);
817: 
818:   /* loop over local fine grid nodes setting interpolation for those*/
819:   if (!NEWVERSION) {

821:     for (l=l_start; l<l_start+p_f; l++) {
822:       for (j=j_start; j<j_start+n_f; j++) {
823:         for (i=i_start; i<i_start+m_f; i++) {
824:           /* convert to local "natural" numbering and then to PETSc global numbering */
825:           row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
826: 
827:           i_c = (i/ratioi);
828:           j_c = (j/ratioj);
829:           l_c = (l/ratiok);
830: 
831:         /* 
832:          Only include those interpolation points that are truly 
833:          nonzero. Note this is very important for final grid lines
834:          in x and y directions; since they have no right/top neighbors
835:          */
836:           x  = ((double)(i - i_c*ratioi))/((double)ratioi);
837:           y  = ((double)(j - j_c*ratioj))/((double)ratioj);
838:           z  = ((double)(l - l_c*ratiok))/((double)ratiok);

840:           nc = 0;
841:           /* one left and below; or we are right on it */
842:           col      = dof*(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));
843: 
844:           cols[nc] = idx_c[col]/dof;
845:           v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
846: 
847:           if (i_c*ratioi != i) {
848:             cols[nc] = idx_c[col+dof]/dof;
849:             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
850:           }
851: 
852:           if (j_c*ratioj != j) {
853:             cols[nc] = idx_c[col+m_ghost_c*dof]/dof;
854:             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
855:           }
856: 
857:           if (l_c*ratiok != l) {
858:             cols[nc] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
859:             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
860:           }
861: 
862:           if (j_c*ratioj != j && i_c*ratioi != i) {
863:             cols[nc] = idx_c[col+(m_ghost_c+1)*dof]/dof;
864:             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
865:           }
866: 
867:           if (j_c*ratioj != j && l_c*ratiok != l) {
868:             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
869:             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
870:           }
871: 
872:           if (i_c*ratioi != i && l_c*ratiok != l) {
873:             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
874:             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
875:           }
876: 
877:           if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
878:             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
879:             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
880:           }
881:           MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
882:         }
883:       }
884:     }
885: 
886:   } else {
887:     PetscScalar    *xi,*eta,*zeta;
888:     PetscInt       li,nxi,lj,neta,lk,nzeta,n;
889:     PetscScalar    Ni[8];
890: 
891:     /* compute local coordinate arrays */
892:     nxi   = ratioi + 1;
893:     neta  = ratioj + 1;
894:     nzeta = ratiok + 1;
895:     PetscMalloc(sizeof(PetscScalar)*nxi,&xi);
896:     PetscMalloc(sizeof(PetscScalar)*neta,&eta);
897:     PetscMalloc(sizeof(PetscScalar)*nzeta,&zeta);
898:     for (li=0; li<nxi; li++) {
899:       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
900:     }
901:     for (lj=0; lj<neta; lj++) {
902:       eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
903:     }
904:     for (lk=0; lk<nzeta; lk++) {
905:       zeta[lk] = -1.0 + (PetscScalar)lk*(2.0/(PetscScalar)(nzeta-1));
906:     }
907: 
908:     for (l=l_start; l<l_start+p_f; l++) {
909:       for (j=j_start; j<j_start+n_f; j++) {
910:         for (i=i_start; i<i_start+m_f; i++) {
911:           /* convert to local "natural" numbering and then to PETSc global numbering */
912:           row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
913: 
914:           i_c = (i/ratioi);
915:           j_c = (j/ratioj);
916:           l_c = (l/ratiok);

918:           /* remainders */
919:           li = i - ratioi * (i/ratioi);
920:           if (i==mx-1){ li = nxi-1; }
921:           lj = j - ratioj * (j/ratioj);
922:           if (j==my-1){ lj = neta-1; }
923:           lk = l - ratiok * (l/ratiok);
924:           if (l==mz-1){ lk = nzeta-1; }
925: 
926:           /* corners */
927:           col     = dof*(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));
928:           cols[0] = idx_c[col]/dof;
929:           Ni[0]   = 1.0;
930:           if ( (li==0) || (li==nxi-1) ) {
931:             if ( (lj==0) || (lj==neta-1) ) {
932:               if ( (lk==0) || (lk==nzeta-1) ) {
933:                 MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);
934:                 continue;
935:               }
936:             }
937:           }
938: 
939:           /* edges + interior */
940:           /* remainders */
941:           if (i==mx-1){ i_c--; }
942:           if (j==my-1){ j_c--; }
943:           if (l==mz-1){ l_c--; }
944: 
945:           col      = dof*(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));
946:           cols[0] = idx_c[col]/dof; /* one left and below; or we are right on it */
947:           cols[1] = idx_c[col+dof]/dof; /* one right and below */
948:           cols[2] = idx_c[col+m_ghost_c*dof]/dof;  /* one left and above */
949:           cols[3] = idx_c[col+(m_ghost_c+1)*dof]/dof; /* one right and above */

951:           cols[4] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof; /* one left and below and front; or we are right on it */
952:           cols[5] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof; /* one right and below, and front */
953:           cols[6] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;/* one left and above and front*/
954:           cols[7] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof; /* one right and above and front */

956:           Ni[0] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
957:           Ni[1] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
958:           Ni[2] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);
959:           Ni[3] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);

961:           Ni[4] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
962:           Ni[5] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
963:           Ni[6] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);
964:           Ni[7] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);

966:           for (n=0; n<8; n++) {
967:             if( PetscAbsScalar(Ni[n])<1.0e-32) { cols[n]=-1; }
968:           }
969:           MatSetValues(mat,1,&row,8,cols,Ni,INSERT_VALUES);
970: 
971:         }
972:       }
973:     }
974:     PetscFree(xi);
975:     PetscFree(eta);
976:     PetscFree(zeta);
977:   }
978: 
979:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
980:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
981: 
982:   MatCreateMAIJ(mat,dof,A);
983:   MatDestroy(&mat);
984:   return(0);
985: }

989: PetscErrorCode  DMGetInterpolation_DA(DM dac,DM daf,Mat *A,Vec *scale)
990: {
991:   PetscErrorCode   ierr;
992:   PetscInt         dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
993:   DMDABoundaryType bxc,byc,bzc,bxf,byf,bzf;
994:   DMDAStencilType  stc,stf;
995:   DM_DA            *ddc = (DM_DA*)dac->data;


1003:   DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);
1004:   DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);
1005:   if (dimc != dimf) SETERRQ2(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
1006:   if (dofc != doff) SETERRQ2(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
1007:   if (sc != sf) SETERRQ2(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
1008:   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
1009:   if (stc != stf) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
1010:   if (Mc < 2 && Mf > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
1011:   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");
1012:   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");

1014:   if (ddc->interptype == DMDA_Q1){
1015:     if (dimc == 1){
1016:       DMGetInterpolation_DA_1D_Q1(dac,daf,A);
1017:     } else if (dimc == 2){
1018:       DMGetInterpolation_DA_2D_Q1(dac,daf,A);
1019:     } else if (dimc == 3){
1020:       DMGetInterpolation_DA_3D_Q1(dac,daf,A);
1021:     } else SETERRQ2(((PetscObject)daf)->comm,PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
1022:   } else if (ddc->interptype == DMDA_Q0){
1023:     if (dimc == 1){
1024:       DMGetInterpolation_DA_1D_Q0(dac,daf,A);
1025:     } else if (dimc == 2){
1026:        DMGetInterpolation_DA_2D_Q0(dac,daf,A);
1027:     } else if (dimc == 3){
1028:        DMGetInterpolation_DA_3D_Q0(dac,daf,A);
1029:     } else SETERRQ2(((PetscObject)daf)->comm,PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
1030:   }
1031:   if (scale) {
1032:     DMGetInterpolationScale((DM)dac,(DM)daf,*A,scale);
1033:   }
1034:   return(0);
1035: }

1039: PetscErrorCode DMGetInjection_DA_1D(DM dac,DM daf,VecScatter *inject)
1040: {
1041:     PetscErrorCode   ierr;
1042:     PetscInt         i,i_start,m_f,Mx,*idx_f,dof;
1043:     PetscInt         m_ghost,*idx_c,m_ghost_c;
1044:     PetscInt         row,i_start_ghost,mx,m_c,nc,ratioi;
1045:     PetscInt         i_start_c,i_start_ghost_c;
1046:     PetscInt         *cols;
1047:     DMDABoundaryType bx;
1048:     Vec              vecf,vecc;
1049:     IS               isf;
1050: 
1052:     DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);
1053:     DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);
1054:     if (bx == DMDA_BOUNDARY_PERIODIC) {
1055:         ratioi = mx/Mx;
1056:         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);
1057:     } else {
1058:         ratioi = (mx-1)/(Mx-1);
1059:         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);
1060:     }
1061: 
1062:     DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);
1063:     DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
1064:     DMDAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
1065: 
1066:     DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
1067:     DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
1068:     DMDAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
1069: 
1070: 
1071:     /* loop over local fine grid nodes setting interpolation for those*/
1072:     nc = 0;
1073:     PetscMalloc(m_f*sizeof(PetscInt),&cols);
1074: 
1075: 
1076:     for (i=i_start_c; i<i_start_c+m_c; i++) {
1077:         PetscInt i_f = i*ratioi;

1079:            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\
1080:  i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1081:             row = idx_f[dof*(i_f-i_start_ghost)];
1082:             cols[nc++] = row/dof;
1083:     }
1084: 

1086:     ISCreateBlock(((PetscObject)daf)->comm,dof,nc,cols,PETSC_OWN_POINTER,&isf);
1087:     DMGetGlobalVector(dac,&vecc);
1088:     DMGetGlobalVector(daf,&vecf);
1089:     VecScatterCreate(vecf,isf,vecc,PETSC_NULL,inject);
1090:     DMRestoreGlobalVector(dac,&vecc);
1091:     DMRestoreGlobalVector(daf,&vecf);
1092:     ISDestroy(&isf);
1093:     return(0);
1094: }

1098: PetscErrorCode DMGetInjection_DA_2D(DM dac,DM daf,VecScatter *inject)
1099: {
1100:   PetscErrorCode   ierr;
1101:   PetscInt         i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
1102:   PetscInt         m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c;
1103:   PetscInt         row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
1104:   PetscInt         i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
1105:   PetscInt         *cols;
1106:   DMDABoundaryType bx,by;
1107:   Vec              vecf,vecc;
1108:   IS               isf;

1111:   DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);
1112:   DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);
1113:   if (bx == DMDA_BOUNDARY_PERIODIC) {
1114:     ratioi = mx/Mx;
1115:     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);
1116:   } else {
1117:     ratioi = (mx-1)/(Mx-1);
1118:     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);
1119:   }
1120:   if (by == DMDA_BOUNDARY_PERIODIC) {
1121:     ratioj = my/My;
1122:     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);
1123:   } else {
1124:     ratioj = (my-1)/(My-1);
1125:     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);
1126:   }

1128:   DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
1129:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
1130:   DMDAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

1132:   DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
1133:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
1134:   DMDAGetGlobalIndices(dac,PETSC_NULL,&idx_c);


1137:   /* loop over local fine grid nodes setting interpolation for those*/
1138:   nc = 0;
1139:   PetscMalloc(n_f*m_f*sizeof(PetscInt),&cols);
1140:   for (j=j_start_c; j<j_start_c+n_c; j++) {
1141:     for (i=i_start_c; i<i_start_c+m_c; i++) {
1142:       PetscInt i_f = i*ratioi,j_f = j*ratioj;
1143:       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\
1144:     j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
1145:       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\
1146:     i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1147:       row = idx_f[dof*(m_ghost*(j_f-j_start_ghost) + (i_f-i_start_ghost))];
1148:       cols[nc++] = row/dof;
1149:     }
1150:   }

1152:   ISCreateBlock(((PetscObject)daf)->comm,dof,nc,cols,PETSC_OWN_POINTER,&isf);
1153:   DMGetGlobalVector(dac,&vecc);
1154:   DMGetGlobalVector(daf,&vecf);
1155:   VecScatterCreate(vecf,isf,vecc,PETSC_NULL,inject);
1156:   DMRestoreGlobalVector(dac,&vecc);
1157:   DMRestoreGlobalVector(daf,&vecf);
1158:   ISDestroy(&isf);
1159:   return(0);
1160: }

1164: PetscErrorCode DMGetInjection_DA_3D(DM dac,DM daf,VecScatter *inject)
1165: {
1166:   PetscErrorCode   ierr;
1167:   PetscInt         i,j,k,i_start,j_start,k_start,m_f,n_f,p_f,Mx,My,Mz;
1168:   PetscInt         m_ghost,n_ghost,p_ghost,m_ghost_c,n_ghost_c,p_ghost_c;
1169:   PetscInt         i_start_ghost,j_start_ghost,k_start_ghost;
1170:   PetscInt         mx,my,mz,ratioi,ratioj,ratiok;
1171:   PetscInt         i_start_c,j_start_c,k_start_c;
1172:   PetscInt         m_c,n_c,p_c;
1173:   PetscInt         i_start_ghost_c,j_start_ghost_c,k_start_ghost_c;
1174:   PetscInt         row,nc,dof;
1175:   PetscInt         *idx_c,*idx_f;
1176:   PetscInt         *cols;
1177:   DMDABoundaryType bx,by,bz;
1178:   Vec              vecf,vecc;
1179:   IS               isf;

1182:   DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);
1183:   DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);

1185:   if (bx == DMDA_BOUNDARY_PERIODIC){
1186:     ratioi = mx/Mx;
1187:     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);
1188:   } else {
1189:     ratioi = (mx-1)/(Mx-1);
1190:     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);
1191:   }
1192:   if (by == DMDA_BOUNDARY_PERIODIC){
1193:     ratioj = my/My;
1194:     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);
1195:   } else {
1196:     ratioj = (my-1)/(My-1);
1197:     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);
1198:   }
1199:   if (bz == DMDA_BOUNDARY_PERIODIC){
1200:     ratiok = mz/Mz;
1201:     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);
1202:   } else {
1203:     ratiok = (mz-1)/(Mz-1);
1204:     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);
1205:   }

1207:   DMDAGetCorners(daf,&i_start,&j_start,&k_start,&m_f,&n_f,&p_f);
1208:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&k_start_ghost,&m_ghost,&n_ghost,&p_ghost);
1209:   DMDAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

1211:   DMDAGetCorners(dac,&i_start_c,&j_start_c,&k_start_c,&m_c,&n_c,&p_c);
1212:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&k_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
1213:   DMDAGetGlobalIndices(dac,PETSC_NULL,&idx_c);


1216:   /* loop over local fine grid nodes setting interpolation for those*/
1217:   nc = 0;
1218:   PetscMalloc(n_f*m_f*p_f*sizeof(PetscInt),&cols);
1219:   for (k=k_start_c; k<k_start_c+p_c; k++) {
1220:     for (j=j_start_c; j<j_start_c+n_c; j++) {
1221:       for (i=i_start_c; i<i_start_c+m_c; i++) {
1222:         PetscInt i_f = i*ratioi,j_f = j*ratioj,k_f = k*ratiok;
1223:         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  "
1224:                                                                           "k_c %D k_f %D fine ghost range [%D,%D]",k,k_f,k_start_ghost,k_start_ghost+p_ghost);
1225:         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  "
1226:                                                                           "j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
1227:         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  "
1228:                                                                           "i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1229:         row = idx_f[dof*(m_ghost*n_ghost*(k_f-k_start_ghost) + m_ghost*(j_f-j_start_ghost) + (i_f-i_start_ghost))];
1230:         cols[nc++] = row/dof;
1231:       }
1232:     }
1233:   }

1235:   ISCreateBlock(((PetscObject)daf)->comm,dof,nc,cols,PETSC_OWN_POINTER,&isf);
1236:   DMGetGlobalVector(dac,&vecc);
1237:   DMGetGlobalVector(daf,&vecf);
1238:   VecScatterCreate(vecf,isf,vecc,PETSC_NULL,inject);
1239:   DMRestoreGlobalVector(dac,&vecc);
1240:   DMRestoreGlobalVector(daf,&vecf);
1241:   ISDestroy(&isf);
1242:   return(0);
1243: }

1247: PetscErrorCode  DMGetInjection_DA(DM dac,DM daf,VecScatter *inject)
1248: {
1249:   PetscErrorCode   ierr;
1250:   PetscInt         dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1251:   DMDABoundaryType bxc,byc,bzc,bxf,byf,bzf;
1252:   DMDAStencilType  stc,stf;


1259:   DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);
1260:   DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);
1261:   if (dimc != dimf) SETERRQ2(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
1262:   if (dofc != doff) SETERRQ2(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
1263:   if (sc != sf) SETERRQ2(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
1264:   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
1265:   if (stc != stf) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
1266:   if (Mc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
1267:   if (dimc > 1 && Nc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
1268:   if (dimc > 2 && Pc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");

1270:   if (dimc == 1){
1271:     DMGetInjection_DA_1D(dac,daf,inject);
1272:   } else if (dimc == 2) {
1273:     DMGetInjection_DA_2D(dac,daf,inject);
1274:   } else if (dimc == 3) {
1275:     DMGetInjection_DA_3D(dac,daf,inject);
1276:   }
1277:   return(0);
1278: }

1282: PetscErrorCode  DMGetAggregates_DA(DM dac,DM daf,Mat *rest)
1283: {
1284:   PetscErrorCode   ierr;
1285:   PetscInt         dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc;
1286:   PetscInt         dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1287:   DMDABoundaryType bxc,byc,bzc,bxf,byf,bzf;
1288:   DMDAStencilType  stc,stf;
1289:   PetscInt         i,j,l;
1290:   PetscInt         i_start,j_start,l_start, m_f,n_f,p_f;
1291:   PetscInt         i_start_ghost,j_start_ghost,l_start_ghost,m_ghost,n_ghost,p_ghost;
1292:   PetscInt         *idx_f;
1293:   PetscInt         i_c,j_c,l_c;
1294:   PetscInt         i_start_c,j_start_c,l_start_c, m_c,n_c,p_c;
1295:   PetscInt         i_start_ghost_c,j_start_ghost_c,l_start_ghost_c,m_ghost_c,n_ghost_c,p_ghost_c;
1296:   PetscInt         *idx_c;
1297:   PetscInt         d;
1298:   PetscInt         a;
1299:   PetscInt         max_agg_size;
1300:   PetscInt         *fine_nodes;
1301:   PetscScalar      *one_vec;
1302:   PetscInt         fn_idx;


1309:   DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);
1310:   DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);
1311:   if (dimc != dimf) SETERRQ2(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
1312:   if (dofc != doff) SETERRQ2(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
1313:   if (sc != sf) SETERRQ2(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
1314:   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
1315:   if (stc != stf) SETERRQ(((PetscObject)daf)->comm,PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");

1317:   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);
1318:   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);
1319:   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);

1321:   if (Pc < 0) Pc = 1;
1322:   if (Pf < 0) Pf = 1;
1323:   if (Nc < 0) Nc = 1;
1324:   if (Nf < 0) Nf = 1;

1326:   DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
1327:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
1328:   DMDAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

1330:   DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
1331:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
1332:   DMDAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

1334:   /* 
1335:      Basic idea is as follows. Here's a 2D example, suppose r_x, r_y are the ratios
1336:      for dimension 1 and 2 respectively.
1337:      Let (i,j) be a coarse grid node. All the fine grid nodes between r_x*i and r_x*(i+1)
1338:      and r_y*j and r_y*(j+1) will be grouped into the same coarse grid agregate.
1339:      Each specific dof on the fine grid is mapped to one dof on the coarse grid.
1340:   */

1342:   max_agg_size = (Mf/Mc+1)*(Nf/Nc+1)*(Pf/Pc+1);

1344:   /* create the matrix that will contain the restriction operator */
1345:   MatCreateMPIAIJ( ((PetscObject)daf)->comm, m_c*n_c*p_c*dofc, m_f*n_f*p_f*doff, Mc*Nc*Pc*dofc, Mf*Nf*Pf*doff,
1346:                           max_agg_size, PETSC_NULL, max_agg_size, PETSC_NULL, rest);

1348:   /* store nodes in the fine grid here */
1349:   PetscMalloc2(max_agg_size,PetscScalar, &one_vec,max_agg_size,PetscInt, &fine_nodes);
1350:   for(i=0; i<max_agg_size; i++) one_vec[i] = 1.0;
1351: 
1352:   /* loop over all coarse nodes */
1353:   for (l_c=l_start_c; l_c<l_start_c+p_c; l_c++) {
1354:     for (j_c=j_start_c; j_c<j_start_c+n_c; j_c++) {
1355:       for (i_c=i_start_c; i_c<i_start_c+m_c; i_c++) {
1356:         for(d=0; d<dofc; d++) {
1357:           /* convert to local "natural" numbering and then to PETSc global numbering */
1358:           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;

1360:           fn_idx = 0;
1361:           /* Corresponding fine points are all points (i_f, j_f, l_f) such that
1362:              i_c*Mf/Mc <= i_f < (i_c+1)*Mf/Mc
1363:              (same for other dimensions)
1364:           */
1365:           for (l=l_c*Pf/Pc; l<PetscMin((l_c+1)*Pf/Pc,Pf); l++) {
1366:             for (j=j_c*Nf/Nc; j<PetscMin((j_c+1)*Nf/Nc,Nf); j++) {
1367:               for (i=i_c*Mf/Mc; i<PetscMin((i_c+1)*Mf/Mc,Mf); i++) {
1368:                 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;
1369:                 fn_idx++;
1370:               }
1371:             }
1372:           }
1373:           /* add all these points to one aggregate */
1374:           MatSetValues(*rest, 1, &a, fn_idx, fine_nodes, one_vec, INSERT_VALUES);
1375:         }
1376:       }
1377:     }
1378:   }
1379:   PetscFree2(one_vec,fine_nodes);
1380:   MatAssemblyBegin(*rest, MAT_FINAL_ASSEMBLY);
1381:   MatAssemblyEnd(*rest, MAT_FINAL_ASSEMBLY);
1382:   return(0);
1383: }