Actual source code: dainterp.c

petsc-3.4.5 2014-06-29
  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 <petsc-private/dmdaimpl.h>    /*I   "petscdmda.h"   I*/

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

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

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

 30:   Level: developer

 32: .seealso: DMCreateInterpolation()

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

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

 53: PetscErrorCode DMCreateInterpolation_DA_1D_Q1(DM dac,DM daf,Mat *A)
 54: {
 55:   PetscErrorCode   ierr;
 56:   PetscInt         i,i_start,m_f,Mx,*idx_f;
 57:   PetscInt         m_ghost,*idx_c,m_ghost_c;
 58:   PetscInt         row,col,i_start_ghost,mx,m_c,nc,ratio;
 59:   PetscInt         i_c,i_start_c,i_start_ghost_c,cols[2],dof;
 60:   PetscScalar      v[2],x;
 61:   Mat              mat;
 62:   DMDABoundaryType bx;

 65:   DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);
 66:   DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);
 67:   if (bx == DMDA_BOUNDARY_PERIODIC) {
 68:     ratio = mx/Mx;
 69:     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);
 70:   } else {
 71:     ratio = (mx-1)/(Mx-1);
 72:     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);
 73:   }

 75:   DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);
 76:   DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
 77:   DMDAGetGlobalIndices(daf,NULL,&idx_f);

 79:   DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
 80:   DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
 81:   DMDAGetGlobalIndices(dac,NULL,&idx_c);

 83:   /* create interpolation matrix */
 84:   MatCreate(PetscObjectComm((PetscObject)dac),&mat);
 85:   MatSetSizes(mat,m_f,m_c,mx,Mx);
 86:   MatSetType(mat,MATAIJ);
 87:   MatSeqAIJSetPreallocation(mat,2,NULL);
 88:   MatMPIAIJSetPreallocation(mat,2,NULL,1,NULL);

 90:   /* loop over local fine grid nodes setting interpolation for those*/
 91:   if (!NEWVERSION) {

 93:     for (i=i_start; i<i_start+m_f; i++) {
 94:       /* convert to local "natural" numbering and then to PETSc global numbering */
 95:       row = idx_f[dof*(i-i_start_ghost)]/dof;

 97:       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
 98:       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\
 99:                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

101:       /*
102:        Only include those interpolation points that are truly
103:        nonzero. Note this is very important for final grid lines
104:        in x direction; since they have no right neighbor
105:        */
106:       x  = ((double)(i - i_c*ratio))/((double)ratio);
107:       nc = 0;
108:       /* one left and below; or we are right on it */
109:       col      = dof*(i_c-i_start_ghost_c);
110:       cols[nc] = idx_c[col]/dof;
111:       v[nc++]  = -x + 1.0;
112:       /* one right? */
113:       if (i_c*ratio != i) {
114:         cols[nc] = idx_c[col+dof]/dof;
115:         v[nc++]  = x;
116:       }
117:       MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
118:     }

120:   } else {
121:     PetscScalar *xi;
122:     PetscInt    li,nxi,n;
123:     PetscScalar Ni[2];

125:     /* compute local coordinate arrays */
126:     nxi  = ratio + 1;
127:     PetscMalloc(sizeof(PetscScalar)*nxi,&xi);
128:     for (li=0; li<nxi; li++) {
129:       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
130:     }

132:     for (i=i_start; i<i_start+m_f; i++) {
133:       /* convert to local "natural" numbering and then to PETSc global numbering */
134:       row = idx_f[dof*(i-i_start_ghost)]/dof;

136:       i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
137:       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\
138:                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

140:       /* remainders */
141:       li = i - ratio * (i/ratio);
142:       if (i==mx-1) li = nxi-1;

144:       /* corners */
145:       col     = dof*(i_c-i_start_ghost_c);
146:       cols[0] = idx_c[col]/dof;
147:       Ni[0]   = 1.0;
148:       if ((li==0) || (li==nxi-1)) {
149:         MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);
150:         continue;
151:       }

153:       /* edges + interior */
154:       /* remainders */
155:       if (i==mx-1) i_c--;

157:       col     = dof*(i_c-i_start_ghost_c);
158:       cols[0] = idx_c[col]/dof; /* one left and below; or we are right on it */
159:       cols[1] = idx_c[col+dof]/dof;

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

179: PetscErrorCode DMCreateInterpolation_DA_1D_Q0(DM dac,DM daf,Mat *A)
180: {
181:   PetscErrorCode   ierr;
182:   PetscInt         i,i_start,m_f,Mx,*idx_f;
183:   PetscInt         m_ghost,*idx_c,m_ghost_c;
184:   PetscInt         row,col,i_start_ghost,mx,m_c,nc,ratio;
185:   PetscInt         i_c,i_start_c,i_start_ghost_c,cols[2],dof;
186:   PetscScalar      v[2],x;
187:   Mat              mat;
188:   DMDABoundaryType bx;

191:   DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);
192:   DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);
193:   if (bx == DMDA_BOUNDARY_PERIODIC) {
194:     ratio = mx/Mx;
195:     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);
196:   } else {
197:     ratio = (mx-1)/(Mx-1);
198:     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);
199:   }

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

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

209:   /* create interpolation matrix */
210:   MatCreate(PetscObjectComm((PetscObject)dac),&mat);
211:   MatSetSizes(mat,m_f,m_c,mx,Mx);
212:   MatSetType(mat,MATAIJ);
213:   MatSeqAIJSetPreallocation(mat,2,NULL);
214:   MatMPIAIJSetPreallocation(mat,2,NULL,0,NULL);

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

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

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

251: PetscErrorCode DMCreateInterpolation_DA_2D_Q1(DM dac,DM daf,Mat *A)
252: {
253:   PetscErrorCode   ierr;
254:   PetscInt         i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
255:   PetscInt         m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
256:   PetscInt         row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
257:   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;
258:   PetscMPIInt      size_c,size_f,rank_f;
259:   PetscScalar      v[4],x,y;
260:   Mat              mat;
261:   DMDABoundaryType bx,by;

264:   DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);
265:   DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);
266:   if (bx == DMDA_BOUNDARY_PERIODIC) {
267:     ratioi = mx/Mx;
268:     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);
269:   } else {
270:     ratioi = (mx-1)/(Mx-1);
271:     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);
272:   }
273:   if (by == DMDA_BOUNDARY_PERIODIC) {
274:     ratioj = my/My;
275:     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);
276:   } else {
277:     ratioj = (my-1)/(My-1);
278:     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);
279:   }


282:   DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
283:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
284:   DMDAGetGlobalIndices(daf,NULL,&idx_f);

286:   DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
287:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
288:   DMDAGetGlobalIndices(dac,NULL,&idx_c);

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

298:    In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
299:    */
300:   MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);
301:   MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);
302:   MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);
303:   col_scale = size_f/size_c;
304:   col_shift = Mx*My*(rank_f/size_c);

306:   MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f,col_scale*m_c*n_c,dnz,onz);
307:   for (j=j_start; j<j_start+n_f; j++) {
308:     for (i=i_start; i<i_start+m_f; i++) {
309:       /* convert to local "natural" numbering and then to PETSc global numbering */
310:       row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;

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

315:       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\
316:                                           j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
317:       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\
318:                                           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

320:       /*
321:        Only include those interpolation points that are truly
322:        nonzero. Note this is very important for final grid lines
323:        in x and y directions; since they have no right/top neighbors
324:        */
325:       nc = 0;
326:       /* one left and below; or we are right on it */
327:       col        = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
328:       cols[nc++] = col_shift + idx_c[col]/dof;
329:       /* one right and below */
330:       if (i_c*ratioi != i) cols[nc++] = col_shift + idx_c[col+dof]/dof;
331:       /* one left and above */
332:       if (j_c*ratioj != j) cols[nc++] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
333:       /* one right and above */
334:       if (i_c*ratioi != i && j_c*ratioj != j) cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
335:       MatPreallocateSet(row,nc,cols,dnz,onz);
336:     }
337:   }
338:   MatCreate(PetscObjectComm((PetscObject)daf),&mat);
339:   MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);
340:   MatSetType(mat,MATAIJ);
341:   MatSeqAIJSetPreallocation(mat,0,dnz);
342:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
343:   MatPreallocateFinalize(dnz,onz);

345:   /* loop over local fine grid nodes setting interpolation for those*/
346:   if (!NEWVERSION) {

348:     for (j=j_start; j<j_start+n_f; j++) {
349:       for (i=i_start; i<i_start+m_f; i++) {
350:         /* convert to local "natural" numbering and then to PETSc global numbering */
351:         row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;

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

356:         /*
357:          Only include those interpolation points that are truly
358:          nonzero. Note this is very important for final grid lines
359:          in x and y directions; since they have no right/top neighbors
360:          */
361:         x = ((double)(i - i_c*ratioi))/((double)ratioi);
362:         y = ((double)(j - j_c*ratioj))/((double)ratioj);

364:         nc = 0;
365:         /* one left and below; or we are right on it */
366:         col      = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
367:         cols[nc] = col_shift + idx_c[col]/dof;
368:         v[nc++]  = x*y - x - y + 1.0;
369:         /* one right and below */
370:         if (i_c*ratioi != i) {
371:           cols[nc] = col_shift + idx_c[col+dof]/dof;
372:           v[nc++]  = -x*y + x;
373:         }
374:         /* one left and above */
375:         if (j_c*ratioj != j) {
376:           cols[nc] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
377:           v[nc++]  = -x*y + y;
378:         }
379:         /* one right and above */
380:         if (j_c*ratioj != j && i_c*ratioi != i) {
381:           cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
382:           v[nc++]  = x*y;
383:         }
384:         MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
385:       }
386:     }

388:   } else {
389:     PetscScalar Ni[4];
390:     PetscScalar *xi,*eta;
391:     PetscInt    li,nxi,lj,neta;

393:     /* compute local coordinate arrays */
394:     nxi  = ratioi + 1;
395:     neta = ratioj + 1;
396:     PetscMalloc(sizeof(PetscScalar)*nxi,&xi);
397:     PetscMalloc(sizeof(PetscScalar)*neta,&eta);
398:     for (li=0; li<nxi; li++) {
399:       xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
400:     }
401:     for (lj=0; lj<neta; lj++) {
402:       eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
403:     }

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

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

414:         /* remainders */
415:         li = i - ratioi * (i/ratioi);
416:         if (i==mx-1) li = nxi-1;
417:         lj = j - ratioj * (j/ratioj);
418:         if (j==my-1) lj = neta-1;

420:         /* corners */
421:         col     = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
422:         cols[0] = col_shift + idx_c[col]/dof; /* left, below */
423:         Ni[0]   = 1.0;
424:         if ((li==0) || (li==nxi-1)) {
425:           if ((lj==0) || (lj==neta-1)) {
426:             MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);
427:             continue;
428:           }
429:         }

431:         /* edges + interior */
432:         /* remainders */
433:         if (i==mx-1) i_c--;
434:         if (j==my-1) j_c--;

436:         col     = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
437:         cols[0] = col_shift + idx_c[col]/dof; /* left, below */
438:         cols[1] = col_shift + idx_c[col+dof]/dof; /* right, below */
439:         cols[2] = col_shift + idx_c[col+m_ghost_c*dof]/dof; /* left, above */
440:         cols[3] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof; /* right, above */

442:         Ni[0] = 0.25*(1.0-xi[li])*(1.0-eta[lj]);
443:         Ni[1] = 0.25*(1.0+xi[li])*(1.0-eta[lj]);
444:         Ni[2] = 0.25*(1.0-xi[li])*(1.0+eta[lj]);
445:         Ni[3] = 0.25*(1.0+xi[li])*(1.0+eta[lj]);

447:         nc = 0;
448:         if (PetscAbsScalar(Ni[0])<1.0e-32) cols[0]=-1;
449:         if (PetscAbsScalar(Ni[1])<1.0e-32) cols[1]=-1;
450:         if (PetscAbsScalar(Ni[2])<1.0e-32) cols[2]=-1;
451:         if (PetscAbsScalar(Ni[3])<1.0e-32) cols[3]=-1;

453:         MatSetValues(mat,1,&row,4,cols,Ni,INSERT_VALUES);
454:       }
455:     }
456:     PetscFree(xi);
457:     PetscFree(eta);
458:   }
459:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
460:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
461:   MatCreateMAIJ(mat,dof,A);
462:   MatDestroy(&mat);
463:   return(0);
464: }

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

484:   DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);
485:   DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);
486:   if (bx == DMDA_BOUNDARY_PERIODIC) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in x");
487:   if (by == DMDA_BOUNDARY_PERIODIC) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in y");
488:   ratioi = mx/Mx;
489:   ratioj = my/My;
490:   if (ratioi*Mx != mx) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
491:   if (ratioj*My != my) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
492:   if (ratioi != 2) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 2");
493:   if (ratioj != 2) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 2");

495:   DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
496:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
497:   DMDAGetGlobalIndices(daf,NULL,&idx_f);

499:   DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
500:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
501:   DMDAGetGlobalIndices(dac,NULL,&idx_c);

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

511:      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
512:   */
513:   MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);
514:   MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);
515:   MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);
516:   col_scale = size_f/size_c;
517:   col_shift = Mx*My*(rank_f/size_c);

519:   MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f,col_scale*m_c*n_c,dnz,onz);
520:   for (j=j_start; j<j_start+n_f; j++) {
521:     for (i=i_start; i<i_start+m_f; i++) {
522:       /* convert to local "natural" numbering and then to PETSc global numbering */
523:       row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;

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

528:       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\
529:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
530:       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\
531:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

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

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

558:       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
559:       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
560:       nc  = 0;
561:       /* one left and below; or we are right on it */
562:       col      = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
563:       cols[nc] = col_shift + idx_c[col]/dof;
564:       v[nc++]  = 1.0;

566:       MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
567:     }
568:   }
569:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
570:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
571:   MatCreateMAIJ(mat,dof,A);
572:   MatDestroy(&mat);
573:   PetscLogFlops(13.0*m_f*n_f);
574:   return(0);
575: }

577: /*
578:        Contributed by Jianming Yang <jianming-yang@uiowa.edu>
579: */
582: PetscErrorCode DMCreateInterpolation_DA_3D_Q0(DM dac,DM daf,Mat *A)
583: {
584:   PetscErrorCode   ierr;
585:   PetscInt         i,j,l,i_start,j_start,l_start,m_f,n_f,p_f,Mx,My,Mz,*idx_f,dof;
586:   PetscInt         m_ghost,n_ghost,p_ghost,*idx_c,m_ghost_c,n_ghost_c,p_ghost_c,nc,*dnz,*onz;
587:   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;
588:   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;
589:   PetscMPIInt      size_c,size_f,rank_f;
590:   PetscScalar      v[8];
591:   Mat              mat;
592:   DMDABoundaryType bx,by,bz;

595:   DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);
596:   DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);
597:   if (bx == DMDA_BOUNDARY_PERIODIC) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in x");
598:   if (by == DMDA_BOUNDARY_PERIODIC) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in y");
599:   if (bz == DMDA_BOUNDARY_PERIODIC) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in z");
600:   ratioi = mx/Mx;
601:   ratioj = my/My;
602:   ratiol = mz/Mz;
603:   if (ratioi*Mx != mx) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
604:   if (ratioj*My != my) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
605:   if (ratiol*Mz != mz) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in z");
606:   if (ratioi != 2 && ratioi != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 1 or 2");
607:   if (ratioj != 2 && ratioj != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 1 or 2");
608:   if (ratiol != 2 && ratiol != 1) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_WRONG,"Coarsening factor in z must be 1 or 2");

610:   DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
611:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
612:   DMDAGetGlobalIndices(daf,NULL,&idx_f);

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

625:      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
626:   */
627:   MPI_Comm_size(PetscObjectComm((PetscObject)dac),&size_c);
628:   MPI_Comm_size(PetscObjectComm((PetscObject)daf),&size_f);
629:   MPI_Comm_rank(PetscObjectComm((PetscObject)daf),&rank_f);
630:   col_scale = size_f/size_c;
631:   col_shift = Mx*My*Mz*(rank_f/size_c);

633:   MatPreallocateInitialize(PetscObjectComm((PetscObject)daf),m_f*n_f*p_f,col_scale*m_c*n_c*p_c,dnz,onz);
634:   for (l=l_start; l<l_start+p_f; l++) {
635:     for (j=j_start; j<j_start+n_f; j++) {
636:       for (i=i_start; i<i_start+m_f; i++) {
637:         /* convert to local "natural" numbering and then to PETSc global numbering */
638:         row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;

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

644:         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\
645:     l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
646:         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\
647:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
648:         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\
649:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

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

671:   /* loop over local fine grid nodes setting interpolation for those*/
672:   for (l=l_start; l<l_start+p_f; l++) {
673:     for (j=j_start; j<j_start+n_f; j++) {
674:       for (i=i_start; i<i_start+m_f; i++) {
675:         /* convert to local "natural" numbering and then to PETSc global numbering */
676:         row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;

678:         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
679:         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
680:         l_c = (l/ratiol);
681:         nc  = 0;
682:         /* one left and below; or we are right on it */
683:         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));
684:         cols[nc] = col_shift + idx_c[col]/dof;
685:         v[nc++]  = 1.0;

687:         MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
688:       }
689:     }
690:   }
691:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
692:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
693:   MatCreateMAIJ(mat,dof,A);
694:   MatDestroy(&mat);
695:   PetscLogFlops(13.0*m_f*n_f*p_f);
696:   return(0);
697: }

701: PetscErrorCode DMCreateInterpolation_DA_3D_Q1(DM dac,DM daf,Mat *A)
702: {
703:   PetscErrorCode   ierr;
704:   PetscInt         i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof,l;
705:   PetscInt         m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,Mz,mz;
706:   PetscInt         row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
707:   PetscInt         i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
708:   PetscInt         l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
709:   PetscInt         l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
710:   PetscScalar      v[8],x,y,z;
711:   Mat              mat;
712:   DMDABoundaryType bx,by,bz;

715:   DMDAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&bx,&by,&bz,0);
716:   DMDAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0,0,0);
717:   if (mx == Mx) {
718:     ratioi = 1;
719:   } else if (bx == DMDA_BOUNDARY_PERIODIC) {
720:     ratioi = mx/Mx;
721:     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);
722:   } else {
723:     ratioi = (mx-1)/(Mx-1);
724:     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);
725:   }
726:   if (my == My) {
727:     ratioj = 1;
728:   } else if (by == DMDA_BOUNDARY_PERIODIC) {
729:     ratioj = my/My;
730:     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);
731:   } else {
732:     ratioj = (my-1)/(My-1);
733:     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);
734:   }
735:   if (mz == Mz) {
736:     ratiok = 1;
737:   } else if (bz == DMDA_BOUNDARY_PERIODIC) {
738:     ratiok = mz/Mz;
739:     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);
740:   } else {
741:     ratiok = (mz-1)/(Mz-1);
742:     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);
743:   }

745:   DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
746:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
747:   DMDAGetGlobalIndices(daf,NULL,&idx_f);

749:   DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
750:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
751:   DMDAGetGlobalIndices(dac,NULL,&idx_c);

753:   /* create interpolation matrix, determining exact preallocation */
754:   MatPreallocateInitialize(PetscObjectComm((PetscObject)dac),m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);
755:   /* loop over local fine grid nodes counting interpolating points */
756:   for (l=l_start; l<l_start+p_f; l++) {
757:     for (j=j_start; j<j_start+n_f; j++) {
758:       for (i=i_start; i<i_start+m_f; i++) {
759:         /* convert to local "natural" numbering and then to PETSc global numbering */
760:         row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
761:         i_c = (i/ratioi);
762:         j_c = (j/ratioj);
763:         l_c = (l/ratiok);
764:         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\
765:                                             l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
766:         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\
767:                                             j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
768:         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\
769:                                             i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

771:         /*
772:          Only include those interpolation points that are truly
773:          nonzero. Note this is very important for final grid lines
774:          in x and y directions; since they have no right/top neighbors
775:          */
776:         nc         = 0;
777:         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));
778:         cols[nc++] = idx_c[col]/dof;
779:         if (i_c*ratioi != i) {
780:           cols[nc++] = idx_c[col+dof]/dof;
781:         }
782:         if (j_c*ratioj != j) {
783:           cols[nc++] = idx_c[col+m_ghost_c*dof]/dof;
784:         }
785:         if (l_c*ratiok != l) {
786:           cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
787:         }
788:         if (j_c*ratioj != j && i_c*ratioi != i) {
789:           cols[nc++] = idx_c[col+(m_ghost_c+1)*dof]/dof;
790:         }
791:         if (j_c*ratioj != j && l_c*ratiok != l) {
792:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
793:         }
794:         if (i_c*ratioi != i && l_c*ratiok != l) {
795:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
796:         }
797:         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
798:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
799:         }
800:         MatPreallocateSet(row,nc,cols,dnz,onz);
801:       }
802:     }
803:   }
804:   MatCreate(PetscObjectComm((PetscObject)dac),&mat);
805:   MatSetSizes(mat,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz);
806:   MatSetType(mat,MATAIJ);
807:   MatSeqAIJSetPreallocation(mat,0,dnz);
808:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
809:   MatPreallocateFinalize(dnz,onz);

811:   /* loop over local fine grid nodes setting interpolation for those*/
812:   if (!NEWVERSION) {

814:     for (l=l_start; l<l_start+p_f; l++) {
815:       for (j=j_start; j<j_start+n_f; j++) {
816:         for (i=i_start; i<i_start+m_f; i++) {
817:           /* convert to local "natural" numbering and then to PETSc global numbering */
818:           row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;

820:           i_c = (i/ratioi);
821:           j_c = (j/ratioj);
822:           l_c = (l/ratiok);

824:           /*
825:            Only include those interpolation points that are truly
826:            nonzero. Note this is very important for final grid lines
827:            in x and y directions; since they have no right/top neighbors
828:            */
829:           x = ((double)(i - i_c*ratioi))/((double)ratioi);
830:           y = ((double)(j - j_c*ratioj))/((double)ratioj);
831:           z = ((double)(l - l_c*ratiok))/((double)ratiok);

833:           nc = 0;
834:           /* one left and below; or we are right on it */
835:           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));

837:           cols[nc] = idx_c[col]/dof;
838:           v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));

840:           if (i_c*ratioi != i) {
841:             cols[nc] = idx_c[col+dof]/dof;
842:             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
843:           }

845:           if (j_c*ratioj != j) {
846:             cols[nc] = idx_c[col+m_ghost_c*dof]/dof;
847:             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
848:           }

850:           if (l_c*ratiok != l) {
851:             cols[nc] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
852:             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
853:           }

855:           if (j_c*ratioj != j && i_c*ratioi != i) {
856:             cols[nc] = idx_c[col+(m_ghost_c+1)*dof]/dof;
857:             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
858:           }

860:           if (j_c*ratioj != j && l_c*ratiok != l) {
861:             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
862:             v[nc++]  = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
863:           }

865:           if (i_c*ratioi != i && l_c*ratiok != l) {
866:             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
867:             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
868:           }

870:           if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
871:             cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
872:             v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
873:           }
874:           MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
875:         }
876:       }
877:     }

879:   } else {
880:     PetscScalar *xi,*eta,*zeta;
881:     PetscInt    li,nxi,lj,neta,lk,nzeta,n;
882:     PetscScalar Ni[8];

884:     /* compute local coordinate arrays */
885:     nxi   = ratioi + 1;
886:     neta  = ratioj + 1;
887:     nzeta = ratiok + 1;
888:     PetscMalloc(sizeof(PetscScalar)*nxi,&xi);
889:     PetscMalloc(sizeof(PetscScalar)*neta,&eta);
890:     PetscMalloc(sizeof(PetscScalar)*nzeta,&zeta);
891:     for (li=0; li<nxi; li++) xi[li] = -1.0 + (PetscScalar)li*(2.0/(PetscScalar)(nxi-1));
892:     for (lj=0; lj<neta; lj++) eta[lj] = -1.0 + (PetscScalar)lj*(2.0/(PetscScalar)(neta-1));
893:     for (lk=0; lk<nzeta; lk++) zeta[lk] = -1.0 + (PetscScalar)lk*(2.0/(PetscScalar)(nzeta-1));

895:     for (l=l_start; l<l_start+p_f; l++) {
896:       for (j=j_start; j<j_start+n_f; j++) {
897:         for (i=i_start; i<i_start+m_f; i++) {
898:           /* convert to local "natural" numbering and then to PETSc global numbering */
899:           row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;

901:           i_c = (i/ratioi);
902:           j_c = (j/ratioj);
903:           l_c = (l/ratiok);

905:           /* remainders */
906:           li = i - ratioi * (i/ratioi);
907:           if (i==mx-1) li = nxi-1;
908:           lj = j - ratioj * (j/ratioj);
909:           if (j==my-1) lj = neta-1;
910:           lk = l - ratiok * (l/ratiok);
911:           if (l==mz-1) lk = nzeta-1;

913:           /* corners */
914:           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));
915:           cols[0] = idx_c[col]/dof;
916:           Ni[0]   = 1.0;
917:           if ((li==0) || (li==nxi-1)) {
918:             if ((lj==0) || (lj==neta-1)) {
919:               if ((lk==0) || (lk==nzeta-1)) {
920:                 MatSetValue(mat,row,cols[0],Ni[0],INSERT_VALUES);
921:                 continue;
922:               }
923:             }
924:           }

926:           /* edges + interior */
927:           /* remainders */
928:           if (i==mx-1) i_c--;
929:           if (j==my-1) j_c--;
930:           if (l==mz-1) l_c--;

932:           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));
933:           cols[0] = idx_c[col]/dof; /* one left and below; or we are right on it */
934:           cols[1] = idx_c[col+dof]/dof; /* one right and below */
935:           cols[2] = idx_c[col+m_ghost_c*dof]/dof;  /* one left and above */
936:           cols[3] = idx_c[col+(m_ghost_c+1)*dof]/dof; /* one right and above */

938:           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 */
939:           cols[5] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof; /* one right and below, and front */
940:           cols[6] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof; /* one left and above and front*/
941:           cols[7] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof; /* one right and above and front */

943:           Ni[0] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
944:           Ni[1] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0-zeta[lk]);
945:           Ni[2] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);
946:           Ni[3] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0-zeta[lk]);

948:           Ni[4] = 0.125*(1.0-xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
949:           Ni[5] = 0.125*(1.0+xi[li])*(1.0-eta[lj])*(1.0+zeta[lk]);
950:           Ni[6] = 0.125*(1.0-xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);
951:           Ni[7] = 0.125*(1.0+xi[li])*(1.0+eta[lj])*(1.0+zeta[lk]);

953:           for (n=0; n<8; n++) {
954:             if (PetscAbsScalar(Ni[n])<1.0e-32) cols[n]=-1;
955:           }
956:           MatSetValues(mat,1,&row,8,cols,Ni,INSERT_VALUES);

958:         }
959:       }
960:     }
961:     PetscFree(xi);
962:     PetscFree(eta);
963:     PetscFree(zeta);
964:   }

966:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
967:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);

969:   MatCreateMAIJ(mat,dof,A);
970:   MatDestroy(&mat);
971:   return(0);
972: }

976: PetscErrorCode  DMCreateInterpolation_DA(DM dac,DM daf,Mat *A,Vec *scale)
977: {
978:   PetscErrorCode   ierr;
979:   PetscInt         dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
980:   DMDABoundaryType bxc,byc,bzc,bxf,byf,bzf;
981:   DMDAStencilType  stc,stf;
982:   DM_DA            *ddc = (DM_DA*)dac->data;


990:   DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);
991:   DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);
992:   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
993:   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
994:   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
995:   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
996:   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
997:   if (Mc < 2 && Mf > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
998:   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");
999:   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");

1001:   if (ddc->interptype == DMDA_Q1) {
1002:     if (dimc == 1) {
1003:       DMCreateInterpolation_DA_1D_Q1(dac,daf,A);
1004:     } else if (dimc == 2) {
1005:       DMCreateInterpolation_DA_2D_Q1(dac,daf,A);
1006:     } else if (dimc == 3) {
1007:       DMCreateInterpolation_DA_3D_Q1(dac,daf,A);
1008:     } else SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
1009:   } else if (ddc->interptype == DMDA_Q0) {
1010:     if (dimc == 1) {
1011:       DMCreateInterpolation_DA_1D_Q0(dac,daf,A);
1012:     } else if (dimc == 2) {
1013:       DMCreateInterpolation_DA_2D_Q0(dac,daf,A);
1014:     } else if (dimc == 3) {
1015:       DMCreateInterpolation_DA_3D_Q0(dac,daf,A);
1016:     } else SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_SUP,"No support for this DMDA dimension %D for interpolation type %d",dimc,(int)ddc->interptype);
1017:   }
1018:   if (scale) {
1019:     DMCreateInterpolationScale((DM)dac,(DM)daf,*A,scale);
1020:   }
1021:   return(0);
1022: }

1026: PetscErrorCode DMCreateInjection_DA_1D(DM dac,DM daf,VecScatter *inject)
1027: {
1028:   PetscErrorCode   ierr;
1029:   PetscInt         i,i_start,m_f,Mx,*idx_f,dof;
1030:   PetscInt         m_ghost,*idx_c,m_ghost_c;
1031:   PetscInt         row,i_start_ghost,mx,m_c,nc,ratioi;
1032:   PetscInt         i_start_c,i_start_ghost_c;
1033:   PetscInt         *cols;
1034:   DMDABoundaryType bx;
1035:   Vec              vecf,vecc;
1036:   IS               isf;

1039:   DMDAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&bx,0,0,0);
1040:   DMDAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0,0,0);
1041:   if (bx == DMDA_BOUNDARY_PERIODIC) {
1042:     ratioi = mx/Mx;
1043:     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);
1044:   } else {
1045:     ratioi = (mx-1)/(Mx-1);
1046:     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);
1047:   }

1049:   DMDAGetCorners(daf,&i_start,0,0,&m_f,0,0);
1050:   DMDAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
1051:   DMDAGetGlobalIndices(daf,NULL,&idx_f);

1053:   DMDAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
1054:   DMDAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
1055:   DMDAGetGlobalIndices(dac,NULL,&idx_c);


1058:   /* loop over local fine grid nodes setting interpolation for those*/
1059:   nc   = 0;
1060:   PetscMalloc(m_f*sizeof(PetscInt),&cols);


1063:   for (i=i_start_c; i<i_start_c+m_c; i++) {
1064:     PetscInt i_f = i*ratioi;

1066:     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);

1068:     row        = idx_f[dof*(i_f-i_start_ghost)];
1069:     cols[nc++] = row/dof;
1070:   }


1073:   ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);
1074:   DMGetGlobalVector(dac,&vecc);
1075:   DMGetGlobalVector(daf,&vecf);
1076:   VecScatterCreate(vecf,isf,vecc,NULL,inject);
1077:   DMRestoreGlobalVector(dac,&vecc);
1078:   DMRestoreGlobalVector(daf,&vecf);
1079:   ISDestroy(&isf);
1080:   return(0);
1081: }

1085: PetscErrorCode DMCreateInjection_DA_2D(DM dac,DM daf,VecScatter *inject)
1086: {
1087:   PetscErrorCode   ierr;
1088:   PetscInt         i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
1089:   PetscInt         m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c;
1090:   PetscInt         row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
1091:   PetscInt         i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
1092:   PetscInt         *cols;
1093:   DMDABoundaryType bx,by;
1094:   Vec              vecf,vecc;
1095:   IS               isf;

1098:   DMDAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&bx,&by,0,0);
1099:   DMDAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0,0,0);
1100:   if (bx == DMDA_BOUNDARY_PERIODIC) {
1101:     ratioi = mx/Mx;
1102:     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);
1103:   } else {
1104:     ratioi = (mx-1)/(Mx-1);
1105:     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);
1106:   }
1107:   if (by == DMDA_BOUNDARY_PERIODIC) {
1108:     ratioj = my/My;
1109:     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);
1110:   } else {
1111:     ratioj = (my-1)/(My-1);
1112:     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);
1113:   }

1115:   DMDAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
1116:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
1117:   DMDAGetGlobalIndices(daf,NULL,&idx_f);

1119:   DMDAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
1120:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
1121:   DMDAGetGlobalIndices(dac,NULL,&idx_c);


1124:   /* loop over local fine grid nodes setting interpolation for those*/
1125:   nc   = 0;
1126:   PetscMalloc(n_f*m_f*sizeof(PetscInt),&cols);
1127:   for (j=j_start_c; j<j_start_c+n_c; j++) {
1128:     for (i=i_start_c; i<i_start_c+m_c; i++) {
1129:       PetscInt i_f = i*ratioi,j_f = j*ratioj;
1130:       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\
1131:     j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
1132:       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\
1133:     i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1134:       row        = idx_f[dof*(m_ghost*(j_f-j_start_ghost) + (i_f-i_start_ghost))];
1135:       cols[nc++] = row/dof;
1136:     }
1137:   }

1139:   ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);
1140:   DMGetGlobalVector(dac,&vecc);
1141:   DMGetGlobalVector(daf,&vecf);
1142:   VecScatterCreate(vecf,isf,vecc,NULL,inject);
1143:   DMRestoreGlobalVector(dac,&vecc);
1144:   DMRestoreGlobalVector(daf,&vecf);
1145:   ISDestroy(&isf);
1146:   return(0);
1147: }

1151: PetscErrorCode DMCreateInjection_DA_3D(DM dac,DM daf,VecScatter *inject)
1152: {
1153:   PetscErrorCode   ierr;
1154:   PetscInt         i,j,k,i_start,j_start,k_start,m_f,n_f,p_f,Mx,My,Mz;
1155:   PetscInt         m_ghost,n_ghost,p_ghost,m_ghost_c,n_ghost_c,p_ghost_c;
1156:   PetscInt         i_start_ghost,j_start_ghost,k_start_ghost;
1157:   PetscInt         mx,my,mz,ratioi,ratioj,ratiok;
1158:   PetscInt         i_start_c,j_start_c,k_start_c;
1159:   PetscInt         m_c,n_c,p_c;
1160:   PetscInt         i_start_ghost_c,j_start_ghost_c,k_start_ghost_c;
1161:   PetscInt         row,nc,dof;
1162:   PetscInt         *idx_c,*idx_f;
1163:   PetscInt         *cols;
1164:   DMDABoundaryType bx,by,bz;
1165:   Vec              vecf,vecc;
1166:   IS               isf;

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

1172:   if (bx == DMDA_BOUNDARY_PERIODIC) {
1173:     ratioi = mx/Mx;
1174:     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);
1175:   } else {
1176:     ratioi = (mx-1)/(Mx-1);
1177:     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);
1178:   }
1179:   if (by == DMDA_BOUNDARY_PERIODIC) {
1180:     ratioj = my/My;
1181:     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);
1182:   } else {
1183:     ratioj = (my-1)/(My-1);
1184:     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);
1185:   }
1186:   if (bz == DMDA_BOUNDARY_PERIODIC) {
1187:     ratiok = mz/Mz;
1188:     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);
1189:   } else {
1190:     ratiok = (mz-1)/(Mz-1);
1191:     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);
1192:   }

1194:   DMDAGetCorners(daf,&i_start,&j_start,&k_start,&m_f,&n_f,&p_f);
1195:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&k_start_ghost,&m_ghost,&n_ghost,&p_ghost);
1196:   DMDAGetGlobalIndices(daf,NULL,&idx_f);

1198:   DMDAGetCorners(dac,&i_start_c,&j_start_c,&k_start_c,&m_c,&n_c,&p_c);
1199:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&k_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
1200:   DMDAGetGlobalIndices(dac,NULL,&idx_c);


1203:   /* loop over local fine grid nodes setting interpolation for those*/
1204:   nc   = 0;
1205:   PetscMalloc(n_f*m_f*p_f*sizeof(PetscInt),&cols);
1206:   for (k=k_start_c; k<k_start_c+p_c; k++) {
1207:     for (j=j_start_c; j<j_start_c+n_c; j++) {
1208:       for (i=i_start_c; i<i_start_c+m_c; i++) {
1209:         PetscInt i_f = i*ratioi,j_f = j*ratioj,k_f = k*ratiok;
1210:         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  "
1211:                                                                           "k_c %D k_f %D fine ghost range [%D,%D]",k,k_f,k_start_ghost,k_start_ghost+p_ghost);
1212:         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  "
1213:                                                                           "j_c %D j_f %D fine ghost range [%D,%D]",j,j_f,j_start_ghost,j_start_ghost+n_ghost);
1214:         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  "
1215:                                                                           "i_c %D i_f %D fine ghost range [%D,%D]",i,i_f,i_start_ghost,i_start_ghost+m_ghost);
1216:         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))];
1217:         cols[nc++] = row/dof;
1218:       }
1219:     }
1220:   }

1222:   ISCreateBlock(PetscObjectComm((PetscObject)daf),dof,nc,cols,PETSC_OWN_POINTER,&isf);
1223:   DMGetGlobalVector(dac,&vecc);
1224:   DMGetGlobalVector(daf,&vecf);
1225:   VecScatterCreate(vecf,isf,vecc,NULL,inject);
1226:   DMRestoreGlobalVector(dac,&vecc);
1227:   DMRestoreGlobalVector(daf,&vecf);
1228:   ISDestroy(&isf);
1229:   return(0);
1230: }

1234: PetscErrorCode  DMCreateInjection_DA(DM dac,DM daf,VecScatter *inject)
1235: {
1236:   PetscErrorCode   ierr;
1237:   PetscInt         dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1238:   DMDABoundaryType bxc,byc,bzc,bxf,byf,bzf;
1239:   DMDAStencilType  stc,stf;


1246:   DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);
1247:   DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);
1248:   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
1249:   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
1250:   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
1251:   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
1252:   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");
1253:   if (Mc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
1254:   if (dimc > 1 && Nc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
1255:   if (dimc > 2 && Pc < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");

1257:   if (dimc == 1) {
1258:     DMCreateInjection_DA_1D(dac,daf,inject);
1259:   } else if (dimc == 2) {
1260:     DMCreateInjection_DA_2D(dac,daf,inject);
1261:   } else if (dimc == 3) {
1262:     DMCreateInjection_DA_3D(dac,daf,inject);
1263:   }
1264:   return(0);
1265: }

1269: PetscErrorCode  DMCreateAggregates_DA(DM dac,DM daf,Mat *rest)
1270: {
1271:   PetscErrorCode   ierr;
1272:   PetscInt         dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc;
1273:   PetscInt         dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1274:   DMDABoundaryType bxc,byc,bzc,bxf,byf,bzf;
1275:   DMDAStencilType  stc,stf;
1276:   PetscInt         i,j,l;
1277:   PetscInt         i_start,j_start,l_start, m_f,n_f,p_f;
1278:   PetscInt         i_start_ghost,j_start_ghost,l_start_ghost,m_ghost,n_ghost,p_ghost;
1279:   PetscInt         *idx_f;
1280:   PetscInt         i_c,j_c,l_c;
1281:   PetscInt         i_start_c,j_start_c,l_start_c, m_c,n_c,p_c;
1282:   PetscInt         i_start_ghost_c,j_start_ghost_c,l_start_ghost_c,m_ghost_c,n_ghost_c,p_ghost_c;
1283:   PetscInt         *idx_c;
1284:   PetscInt         d;
1285:   PetscInt         a;
1286:   PetscInt         max_agg_size;
1287:   PetscInt         *fine_nodes;
1288:   PetscScalar      *one_vec;
1289:   PetscInt         fn_idx;


1296:   DMDAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&bxc,&byc,&bzc,&stc);
1297:   DMDAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&bxf,&byf,&bzf,&stf);
1298:   if (dimc != dimf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Dimensions of DMDA do not match %D %D",dimc,dimf);
1299:   if (dofc != doff) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"DOF of DMDA do not match %D %D",dofc,doff);
1300:   if (sc != sf) SETERRQ2(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil width of DMDA do not match %D %D",sc,sf);
1301:   if (bxc != bxf || byc != byf || bzc != bzf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Boundary type different in two DMDAs");
1302:   if (stc != stf) SETERRQ(PetscObjectComm((PetscObject)daf),PETSC_ERR_ARG_INCOMP,"Stencil type different in two DMDAs");

1304:   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);
1305:   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);
1306:   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);

1308:   if (Pc < 0) Pc = 1;
1309:   if (Pf < 0) Pf = 1;
1310:   if (Nc < 0) Nc = 1;
1311:   if (Nf < 0) Nf = 1;

1313:   DMDAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
1314:   DMDAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
1315:   DMDAGetGlobalIndices(daf,NULL,&idx_f);

1317:   DMDAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
1318:   DMDAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
1319:   DMDAGetGlobalIndices(dac,NULL,&idx_c);

1321:   /*
1322:      Basic idea is as follows. Here's a 2D example, suppose r_x, r_y are the ratios
1323:      for dimension 1 and 2 respectively.
1324:      Let (i,j) be a coarse grid node. All the fine grid nodes between r_x*i and r_x*(i+1)
1325:      and r_y*j and r_y*(j+1) will be grouped into the same coarse grid agregate.
1326:      Each specific dof on the fine grid is mapped to one dof on the coarse grid.
1327:   */

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

1331:   /* create the matrix that will contain the restriction operator */
1332:   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,
1333:                       max_agg_size, NULL, max_agg_size, NULL, rest);

1335:   /* store nodes in the fine grid here */
1336:   PetscMalloc2(max_agg_size,PetscScalar, &one_vec,max_agg_size,PetscInt, &fine_nodes);
1337:   for (i=0; i<max_agg_size; i++) one_vec[i] = 1.0;

1339:   /* loop over all coarse nodes */
1340:   for (l_c=l_start_c; l_c<l_start_c+p_c; l_c++) {
1341:     for (j_c=j_start_c; j_c<j_start_c+n_c; j_c++) {
1342:       for (i_c=i_start_c; i_c<i_start_c+m_c; i_c++) {
1343:         for (d=0; d<dofc; d++) {
1344:           /* convert to local "natural" numbering and then to PETSc global numbering */
1345:           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;

1347:           fn_idx = 0;
1348:           /* Corresponding fine points are all points (i_f, j_f, l_f) such that
1349:              i_c*Mf/Mc <= i_f < (i_c+1)*Mf/Mc
1350:              (same for other dimensions)
1351:           */
1352:           for (l=l_c*Pf/Pc; l<PetscMin((l_c+1)*Pf/Pc,Pf); l++) {
1353:             for (j=j_c*Nf/Nc; j<PetscMin((j_c+1)*Nf/Nc,Nf); j++) {
1354:               for (i=i_c*Mf/Mc; i<PetscMin((i_c+1)*Mf/Mc,Mf); i++) {
1355:                 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;
1356:                 fn_idx++;
1357:               }
1358:             }
1359:           }
1360:           /* add all these points to one aggregate */
1361:           MatSetValues(*rest, 1, &a, fn_idx, fine_nodes, one_vec, INSERT_VALUES);
1362:         }
1363:       }
1364:     }
1365:   }
1366:   PetscFree2(one_vec,fine_nodes);
1367:   MatAssemblyBegin(*rest, MAT_FINAL_ASSEMBLY);
1368:   MatAssemblyEnd(*rest, MAT_FINAL_ASSEMBLY);
1369:   return(0);
1370: }