Actual source code: dainterp.c

  1: #define PETSCDM_DLL

  3: /*
  4:   Code for interpolating between grids represented by DAs
  5: */

 7:  #include private/daimpl.h
 8:  #include petscmg.h

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

 16:   Input Parameters:
 17: +      dac - DM that defines a coarse mesh
 18: .      daf - DM that defines a fine mesh
 19: -      mat - the restriction (or interpolation operator) from fine to coarse

 21:   Output Parameter:
 22: .    scale - the scaled vector

 24:   Level: developer

 26: .seealso: DMGetInterpolation()

 28: @*/
 29: PetscErrorCode  DMGetInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
 30: {
 32:   Vec            fine;
 33:   PetscScalar    one = 1.0;

 36:   DMCreateGlobalVector(daf,&fine);
 37:   DMCreateGlobalVector(dac,scale);
 38:   VecSet(fine,one);
 39:   MatRestrict(mat,fine,*scale);
 40:   VecDestroy(fine);
 41:   VecReciprocal(*scale);
 42:   return(0);
 43: }

 47: PetscErrorCode DAGetInterpolation_1D_Q1(DA dac,DA daf,Mat *A)
 48: {
 50:   PetscInt       i,i_start,m_f,Mx,*idx_f;
 51:   PetscInt       m_ghost,*idx_c,m_ghost_c;
 52:   PetscInt       row,col,i_start_ghost,mx,m_c,nc,ratio;
 53:   PetscInt       i_c,i_start_c,i_start_ghost_c,cols[2],dof;
 54:   PetscScalar    v[2],x,*coors = 0,*ccoors;
 55:   Mat            mat;
 56:   DAPeriodicType pt;
 57:   Vec            vcoors,cvcoors;

 60:   DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
 61:   DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
 62:   if (pt == DA_XPERIODIC) {
 63:     ratio = mx/Mx;
 64:     if (ratio*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
 65:   } else {
 66:     ratio = (mx-1)/(Mx-1);
 67:     if (ratio*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
 68:   }

 70:   DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
 71:   DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
 72:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

 74:   DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
 75:   DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
 76:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

 78:   /* create interpolation matrix */
 79:   MatCreate(((PetscObject)dac)->comm,&mat);
 80:   MatSetSizes(mat,m_f,m_c,mx,Mx);
 81:   MatSetType(mat,MATAIJ);
 82:   MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
 83:   MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);

 85:   DAGetCoordinates(daf,&vcoors);
 86:   if (vcoors) {
 87:     DAGetGhostedCoordinates(dac,&cvcoors);
 88:     DAVecGetArray(daf->da_coordinates,vcoors,&coors);
 89:     DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
 90:   }
 91:   /* loop over local fine grid nodes setting interpolation for those*/
 92:   for (i=i_start; i<i_start+m_f; i++) {
 93:     /* convert to local "natural" numbering and then to PETSc global numbering */
 94:     row    = idx_f[dof*(i-i_start_ghost)]/dof;

 96:     i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
 97:     if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
 98:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

100:     /* 
101:          Only include those interpolation points that are truly 
102:          nonzero. Note this is very important for final grid lines
103:          in x direction; since they have no right neighbor
104:     */
105:     if (coors) {
106:       x = (coors[i] - ccoors[i_c]);
107:       /* only access the next coors point if we know there is one */
108:       /* note this is dangerous because x may not exactly equal ZERO */
109:       if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[i_c+1] - ccoors[i_c]);
110:     } else {
111:       x  = ((double)(i - i_c*ratio))/((double)ratio);
112:     }
113:     nc = 0;
114:       /* one left and below; or we are right on it */
115:     col      = dof*(i_c-i_start_ghost_c);
116:     cols[nc] = idx_c[col]/dof;
117:     v[nc++]  = - x + 1.0;
118:     /* one right? */
119:     if (i_c*ratio != i) {
120:       cols[nc] = idx_c[col+dof]/dof;
121:       v[nc++]  = x;
122:     }
123:     MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
124:   }
125:   if (vcoors) {
126:     DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
127:     DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
128:     VecDestroy(cvcoors);
129:     VecDestroy(vcoors);
130:   }
131:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
132:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
133:   MatCreateMAIJ(mat,dof,A);
134:   MatDestroy(mat);
135:   PetscLogFlops(5.0*m_f);
136:   return(0);
137: }

141: PetscErrorCode DAGetInterpolation_1D_Q0(DA dac,DA daf,Mat *A)
142: {
144:   PetscInt       i,i_start,m_f,Mx,*idx_f;
145:   PetscInt       m_ghost,*idx_c,m_ghost_c;
146:   PetscInt       row,col,i_start_ghost,mx,m_c,nc,ratio;
147:   PetscInt       i_c,i_start_c,i_start_ghost_c,cols[2],dof;
148:   PetscScalar    v[2],x;
149:   Mat            mat;
150:   DAPeriodicType pt;

153:   DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
154:   DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
155:   if (pt == DA_XPERIODIC) {
156:     ratio = mx/Mx;
157:     if (ratio*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
158:   } else {
159:     ratio = (mx-1)/(Mx-1);
160:     if (ratio*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
161:   }

163:   DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
164:   DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
165:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

167:   DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
168:   DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
169:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

171:   /* create interpolation matrix */
172:   MatCreate(((PetscObject)dac)->comm,&mat);
173:   MatSetSizes(mat,m_f,m_c,mx,Mx);
174:   MatSetType(mat,MATAIJ);
175:   MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
176:   MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);

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

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

185:     /* 
186:          Only include those interpolation points that are truly 
187:          nonzero. Note this is very important for final grid lines
188:          in x direction; since they have no right neighbor
189:     */
190:     x  = ((double)(i - i_c*ratio))/((double)ratio);
191:     nc = 0;
192:       /* one left and below; or we are right on it */
193:     col      = dof*(i_c-i_start_ghost_c);
194:     cols[nc] = idx_c[col]/dof;
195:     v[nc++]  = - x + 1.0;
196:     /* one right? */
197:     if (i_c*ratio != i) {
198:       cols[nc] = idx_c[col+dof]/dof;
199:       v[nc++]  = x;
200:     }
201:     MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
202:   }
203:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
204:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
205:   MatCreateMAIJ(mat,dof,A);
206:   MatDestroy(mat);
207:   PetscLogFlops(5.0*m_f);
208:   return(0);
209: }

213: PetscErrorCode DAGetInterpolation_2D_Q1(DA dac,DA daf,Mat *A)
214: {
216:   PetscInt       i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
217:   PetscInt       m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
218:   PetscInt       row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
219:   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;
220:   PetscMPIInt    size_c,size_f,rank_f;
221:   PetscScalar    v[4],x,y;
222:   Mat            mat;
223:   DAPeriodicType pt;
224:   DACoor2d       **coors = 0,**ccoors;
225:   Vec            vcoors,cvcoors;

228:   DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
229:   DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
230:   if (DAXPeriodic(pt)){
231:     ratioi = mx/Mx;
232:     if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
233:   } else {
234:     ratioi = (mx-1)/(Mx-1);
235:     if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
236:   }
237:   if (DAYPeriodic(pt)){
238:     ratioj = my/My;
239:     if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
240:   } else {
241:     ratioj = (my-1)/(My-1);
242:     if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
243:   }


246:   DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
247:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
248:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

250:   DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
251:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
252:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

254:   /*
255:      Used for handling a coarse DA that lives on 1/4 the processors of the fine DA.
256:      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the 
257:      processors). It's effective length is hence 4 times its normal length, this is
258:      why the col_scale is multiplied by the interpolation matrix column sizes.
259:      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
260:      copy of the coarse vector. A bit of a hack but you do better.

262:      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
263:   */
264:   MPI_Comm_size(((PetscObject)dac)->comm,&size_c);
265:   MPI_Comm_size(((PetscObject)daf)->comm,&size_f);
266:   MPI_Comm_rank(((PetscObject)daf)->comm,&rank_f);
267:   col_scale = size_f/size_c;
268:   col_shift = Mx*My*(rank_f/size_c);

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

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

279:       if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
280:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
281:       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
282:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

284:       /* 
285:          Only include those interpolation points that are truly 
286:          nonzero. Note this is very important for final grid lines
287:          in x and y directions; since they have no right/top neighbors
288:       */
289:       nc = 0;
290:       /* one left and below; or we are right on it */
291:       col        = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
292:       cols[nc++] = col_shift + idx_c[col]/dof;
293:       /* one right and below */
294:       if (i_c*ratioi != i) {
295:         cols[nc++] = col_shift + idx_c[col+dof]/dof;
296:       }
297:       /* one left and above */
298:       if (j_c*ratioj != j) {
299:         cols[nc++] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
300:       }
301:       /* one right and above */
302:       if (j_c*ratioi != j && i_c*ratioj != i) {
303:         cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
304:       }
305:       MatPreallocateSet(row,nc,cols,dnz,onz);
306:     }
307:   }
308:   MatCreate(((PetscObject)daf)->comm,&mat);
309:   MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);
310:   MatSetType(mat,MATAIJ);
311:   MatSeqAIJSetPreallocation(mat,0,dnz);
312:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
313:   MatPreallocateFinalize(dnz,onz);

315:   DAGetCoordinates(daf,&vcoors);
316:   if (vcoors) {
317:     DAGetGhostedCoordinates(dac,&cvcoors);
318:     DAVecGetArray(daf->da_coordinates,vcoors,&coors);
319:     DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
320:   }

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

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

331:       /* 
332:          Only include those interpolation points that are truly 
333:          nonzero. Note this is very important for final grid lines
334:          in x and y directions; since they have no right/top neighbors
335:       */
336:       if (coors) {
337:         /* only access the next coors point if we know there is one */
338:         /* note this is dangerous because x may not exactly equal ZERO */
339:         x = (coors[j][i].x - ccoors[j_c][i_c].x);
340:         if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[j_c][i_c+1].x - ccoors[j_c][i_c].x);
341:         y = (coors[j][i].y - ccoors[j_c][i_c].y);
342:         if (PetscAbsScalar(y) != 0.0) y = y/(ccoors[j_c+1][i_c].y - ccoors[j_c][i_c].y);
343:       } else {
344:         x  = ((double)(i - i_c*ratioi))/((double)ratioi);
345:         y  = ((double)(j - j_c*ratioj))/((double)ratioj);
346:       }
347:       nc = 0;
348:       /* one left and below; or we are right on it */
349:       col      = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
350:       cols[nc] = col_shift + idx_c[col]/dof;
351:       v[nc++]  = x*y - x - y + 1.0;
352:       /* one right and below */
353:       if (i_c*ratioi != i) {
354:         cols[nc] = col_shift + idx_c[col+dof]/dof;
355:         v[nc++]  = -x*y + x;
356:       }
357:       /* one left and above */
358:       if (j_c*ratioj != j) {
359:         cols[nc] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
360:         v[nc++]  = -x*y + y;
361:       }
362:       /* one right and above */
363:       if (j_c*ratioj != j && i_c*ratioi != i) {
364:         cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
365:         v[nc++]  = x*y;
366:       }
367:       MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
368:     }
369:   }
370:   if (vcoors) {
371:     DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
372:     DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
373:     VecDestroy(cvcoors);
374:     VecDestroy(vcoors);
375:   }
376:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
377:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
378:   MatCreateMAIJ(mat,dof,A);
379:   MatDestroy(mat);
380:   PetscLogFlops(13.0*m_f*n_f);
381:   return(0);
382: }

384: /* 
385:        Contributed by Andrei Draganescu <aidraga@sandia.gov>
386: */
389: PetscErrorCode DAGetInterpolation_2D_Q0(DA dac,DA daf,Mat *A)
390: {
392:   PetscInt       i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
393:   PetscInt       m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
394:   PetscInt       row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
395:   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;
396:   PetscMPIInt    size_c,size_f,rank_f;
397:   PetscScalar    v[4];
398:   Mat            mat;
399:   DAPeriodicType pt;

402:   DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
403:   DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
404:   if (DAXPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in x");
405:   if (DAYPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in y");
406:   ratioi = mx/Mx;
407:   ratioj = my/My;
408:   if (ratioi*Mx != mx) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
409:   if (ratioj*My != my) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
410:   if (ratioi != 2) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 2");
411:   if (ratioj != 2) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 2");

413:   DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
414:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
415:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

417:   DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
418:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
419:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

421:   /*
422:      Used for handling a coarse DA that lives on 1/4 the processors of the fine DA.
423:      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the 
424:      processors). It's effective length is hence 4 times its normal length, this is
425:      why the col_scale is multiplied by the interpolation matrix column sizes.
426:      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
427:      copy of the coarse vector. A bit of a hack but you do better.

429:      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
430:   */
431:   MPI_Comm_size(((PetscObject)dac)->comm,&size_c);
432:   MPI_Comm_size(((PetscObject)daf)->comm,&size_f);
433:   MPI_Comm_rank(((PetscObject)daf)->comm,&rank_f);
434:   col_scale = size_f/size_c;
435:   col_shift = Mx*My*(rank_f/size_c);

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

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

446:       if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
447:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
448:       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
449:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

451:       /* 
452:          Only include those interpolation points that are truly 
453:          nonzero. Note this is very important for final grid lines
454:          in x and y directions; since they have no right/top neighbors
455:       */
456:       nc = 0;
457:       /* one left and below; or we are right on it */
458:       col        = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
459:       cols[nc++] = col_shift + idx_c[col]/dof;
460:       MatPreallocateSet(row,nc,cols,dnz,onz);
461:     }
462:   }
463:   MatCreate(((PetscObject)daf)->comm,&mat);
464:   MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);
465:   MatSetType(mat,MATAIJ);
466:   MatSeqAIJSetPreallocation(mat,0,dnz);
467:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
468:   MatPreallocateFinalize(dnz,onz);

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

476:       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
477:       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
478:       nc = 0;
479:       /* one left and below; or we are right on it */
480:       col      = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
481:       cols[nc] = col_shift + idx_c[col]/dof;
482:       v[nc++]  = 1.0;
483: 
484:       MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
485:     }
486:   }
487:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
488:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
489:   MatCreateMAIJ(mat,dof,A);
490:   MatDestroy(mat);
491:   PetscLogFlops(13.0*m_f*n_f);
492:   return(0);
493: }

495: /* 
496:        Contributed by Jianming Yang <jianming-yang@uiowa.edu>
497: */
500: PetscErrorCode DAGetInterpolation_3D_Q0(DA dac,DA daf,Mat *A)
501: {
503:   PetscInt       i,j,l,i_start,j_start,l_start,m_f,n_f,p_f,Mx,My,Mz,*idx_f,dof;
504:   PetscInt       m_ghost,n_ghost,p_ghost,*idx_c,m_ghost_c,n_ghost_c,p_ghost_c,nc,*dnz,*onz;
505:   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;
506:   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;
507:   PetscMPIInt    size_c,size_f,rank_f;
508:   PetscScalar    v[8];
509:   Mat            mat;
510:   DAPeriodicType pt;

513:   DAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&pt,0);
514:   DAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0);
515:   if (DAXPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in x");
516:   if (DAYPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in y");
517:   if (DAZPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in z");
518:   ratioi = mx/Mx;
519:   ratioj = my/My;
520:   ratiol = mz/Mz;
521:   if (ratioi*Mx != mx) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
522:   if (ratioj*My != my) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
523:   if (ratiol*Mz != mz) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in z");
524:   if (ratioi != 2 && ratioi != 1) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 1 or 2");
525:   if (ratioj != 2 && ratioj != 1) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 1 or 2");
526:   if (ratiol != 2 && ratiol != 1) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in z must be 1 or 2");

528:   DAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
529:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
530:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

532:   DAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
533:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
534:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
535:   /*
536:      Used for handling a coarse DA that lives on 1/4 the processors of the fine DA.
537:      The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the 
538:      processors). It's effective length is hence 4 times its normal length, this is
539:      why the col_scale is multiplied by the interpolation matrix column sizes.
540:      sol_shift allows each set of 1/4 processors do its own interpolation using ITS
541:      copy of the coarse vector. A bit of a hack but you do better.

543:      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
544:   */
545:   MPI_Comm_size(((PetscObject)dac)->comm,&size_c);
546:   MPI_Comm_size(((PetscObject)daf)->comm,&size_f);
547:   MPI_Comm_rank(((PetscObject)daf)->comm,&rank_f);
548:   col_scale = size_f/size_c;
549:   col_shift = Mx*My*Mz*(rank_f/size_c);

551:   MatPreallocateInitialize(((PetscObject)daf)->comm,m_f*n_f*p_f,col_scale*m_c*n_c*p_c,dnz,onz);
552:   for (l=l_start; l<l_start+p_f; l++) {
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*n_ghost*(l-l_start_ghost) + 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:         l_c = (l/ratiol);

562:         if (l_c < l_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
563:     l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
564:         if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
565:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
566:         if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
567:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

569:         /* 
570:            Only include those interpolation points that are truly 
571:            nonzero. Note this is very important for final grid lines
572:            in x and y directions; since they have no right/top neighbors
573:         */
574:         nc = 0;
575:         /* one left and below; or we are right on it */
576:         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));
577:         cols[nc++] = col_shift + idx_c[col]/dof;
578:         MatPreallocateSet(row,nc,cols,dnz,onz);
579:       }
580:     }
581:   }
582:   MatCreate(((PetscObject)daf)->comm,&mat);
583:   MatSetSizes(mat,m_f*n_f*p_f,col_scale*m_c*n_c*p_c,mx*my*mz,col_scale*Mx*My*Mz);
584:   MatSetType(mat,MATAIJ);
585:   MatSeqAIJSetPreallocation(mat,0,dnz);
586:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
587:   MatPreallocateFinalize(dnz,onz);

589:   /* loop over local fine grid nodes setting interpolation for those*/
590:   for (l=l_start; l<l_start+p_f; l++) {
591:     for (j=j_start; j<j_start+n_f; j++) {
592:       for (i=i_start; i<i_start+m_f; i++) {
593:         /* convert to local "natural" numbering and then to PETSc global numbering */
594:         row    = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
595: 
596:         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
597:         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
598:         l_c = (l/ratiol);
599:         nc = 0;
600:         /* one left and below; or we are right on it */
601:         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));
602:         cols[nc] = col_shift + idx_c[col]/dof;
603:         v[nc++]  = 1.0;
604: 
605:         MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
606:       }
607:     }
608:   }
609:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
610:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
611:   MatCreateMAIJ(mat,dof,A);
612:   MatDestroy(mat);
613:   PetscLogFlops(13.0*m_f*n_f*p_f);
614:   return(0);
615: }

619: PetscErrorCode DAGetInterpolation_3D_Q1(DA dac,DA daf,Mat *A)
620: {
622:   PetscInt       i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof,l;
623:   PetscInt       m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,Mz,mz;
624:   PetscInt       row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
625:   PetscInt       i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
626:   PetscInt       l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
627:   PetscInt       l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
628:   PetscScalar    v[8],x,y,z;
629:   Mat            mat;
630:   DAPeriodicType pt;
631:   DACoor3d       ***coors = 0,***ccoors;
632:   Vec            vcoors,cvcoors;

635:   DAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&pt,0);
636:   DAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0);
637:   if (mx == Mx) {
638:     ratioi = 1;
639:   } else if (DAXPeriodic(pt)){
640:     ratioi = mx/Mx;
641:     if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
642:   } else {
643:     ratioi = (mx-1)/(Mx-1);
644:     if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
645:   }
646:   if (my == My) {
647:     ratioj = 1;
648:   } else if (DAYPeriodic(pt)){
649:     ratioj = my/My;
650:     if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
651:   } else {
652:     ratioj = (my-1)/(My-1);
653:     if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
654:   }
655:   if (mz == Mz) {
656:     ratiok = 1;
657:   } else if (DAZPeriodic(pt)){
658:     ratiok = mz/Mz;
659:     if (ratiok*Mz != mz) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mz/Mz  must be integer: mz %D Mz %D",mz,Mz);
660:   } else {
661:     ratiok = (mz-1)/(Mz-1);
662:     if (ratiok*(Mz-1) != mz-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %D Mz %D",mz,Mz);
663:   }

665:   DAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
666:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
667:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

669:   DAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
670:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
671:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

673:   /* create interpolation matrix, determining exact preallocation */
674:   MatPreallocateInitialize(((PetscObject)dac)->comm,m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);
675:   /* loop over local fine grid nodes counting interpolating points */
676:   for (l=l_start; l<l_start+p_f; l++) {
677:     for (j=j_start; j<j_start+n_f; j++) {
678:       for (i=i_start; i<i_start+m_f; i++) {
679:         /* convert to local "natural" numbering and then to PETSc global numbering */
680:         row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
681:         i_c = (i/ratioi);
682:         j_c = (j/ratioj);
683:         l_c = (l/ratiok);
684:         if (l_c < l_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
685:           l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
686:         if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
687:           j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
688:         if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
689:           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

691:         /* 
692:          Only include those interpolation points that are truly 
693:          nonzero. Note this is very important for final grid lines
694:          in x and y directions; since they have no right/top neighbors
695:         */
696:         nc       = 0;
697:         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));
698:         cols[nc++] = idx_c[col]/dof;
699:         if (i_c*ratioi != i) {
700:           cols[nc++] = idx_c[col+dof]/dof;
701:         }
702:         if (j_c*ratioj != j) {
703:           cols[nc++] = idx_c[col+m_ghost_c*dof]/dof;
704:         }
705:         if (l_c*ratiok != l) {
706:           cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
707:         }
708:         if (j_c*ratioj != j && i_c*ratioi != i) {
709:           cols[nc++] = idx_c[col+(m_ghost_c+1)*dof]/dof;
710:         }
711:         if (j_c*ratioj != j && l_c*ratiok != l) {
712:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
713:         }
714:         if (i_c*ratioi != i && l_c*ratiok != l) {
715:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
716:         }
717:         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
718:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
719:         }
720:         MatPreallocateSet(row,nc,cols,dnz,onz);
721:       }
722:     }
723:   }
724:   MatCreate(((PetscObject)dac)->comm,&mat);
725:   MatSetSizes(mat,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz);
726:   MatSetType(mat,MATAIJ);
727:   MatSeqAIJSetPreallocation(mat,0,dnz);
728:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
729:   MatPreallocateFinalize(dnz,onz);

731:   DAGetCoordinates(daf,&vcoors);
732:   if (vcoors) {
733:     DAGetGhostedCoordinates(dac,&cvcoors);
734:     DAVecGetArray(daf->da_coordinates,vcoors,&coors);
735:     DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
736:   }

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

745:         i_c = (i/ratioi);
746:         j_c = (j/ratioj);
747:         l_c = (l/ratiok);

749:         /* 
750:            Only include those interpolation points that are truly 
751:            nonzero. Note this is very important for final grid lines
752:            in x and y directions; since they have no right/top neighbors
753:         */
754:         if (coors) {
755:           /* only access the next coors point if we know there is one */
756:           /* note this is dangerous because x may not exactly equal ZERO */
757:           x = (coors[l][j][i].x - ccoors[l_c][j_c][i_c].x);
758:           if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[l_c][j_c][i_c+1].x - ccoors[l_c][j_c][i_c].x);
759:           y = (coors[l][j][i].y - ccoors[l_c][j_c][i_c].y);
760:           if (PetscAbsScalar(y) != 0.0) y = y/(ccoors[l_c][j_c+1][i_c].y - ccoors[l_c][j_c][i_c].y);
761:           z = (coors[l][j][i].z - ccoors[l_c][j_c][i_c].z);
762:           if (PetscAbsScalar(z) != 0.0) z = z/(ccoors[l_c+1][j_c][i_c].z - ccoors[l_c][j_c][i_c].z);
763:         } else {
764:           x  = ((double)(i - i_c*ratioi))/((double)ratioi);
765:           y  = ((double)(j - j_c*ratioj))/((double)ratioj);
766:           z  = ((double)(l - l_c*ratiok))/((double)ratiok);
767:         }
768:         nc = 0;
769:         /* one left and below; or we are right on it */
770:         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));

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

775:         if (i_c*ratioi != i) {
776:           cols[nc] = idx_c[col+dof]/dof;
777:           v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
778:         }

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

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

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

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

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

805:         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
806:           cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
807:           v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
808:         }
809:         MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
810:       }
811:     }
812:   }
813:   if (vcoors) {
814:     DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
815:     DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
816:     VecDestroy(cvcoors);
817:     VecDestroy(vcoors);
818:   }
819:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
820:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);

822:   MatCreateMAIJ(mat,dof,A);
823:   MatDestroy(mat);
824:   PetscLogFlops(13.0*m_f*n_f);
825:   return(0);
826: }

830: /*@C
831:    DAGetInterpolation - Gets an interpolation matrix that maps between 
832:    grids associated with two DAs.

834:    Collective on DA

836:    Input Parameters:
837: +  dac - the coarse grid DA
838: -  daf - the fine grid DA

840:    Output Parameters:
841: +  A - the interpolation matrix
842: -  scale - a scaling vector used to scale the coarse grid restricted vector before applying the 
843:            grid function or grid Jacobian to it.

845:    Level: intermediate

847: .keywords: interpolation, restriction, multigrid 

849: .seealso: DARefine(), DAGetInjection()
850: @*/
851: PetscErrorCode  DAGetInterpolation(DA dac,DA daf,Mat *A,Vec *scale)
852: {
854:   PetscInt       dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
855:   DAPeriodicType wrapc,wrapf;
856:   DAStencilType  stc,stf;


864:   DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
865:   DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
866:   if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
867:   if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
868:   if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
869:   if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
870:   if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");
871:   if (Mc < 2 && Mf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
872:   if (dimc > 1 && Nc < 2 && Nf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
873:   if (dimc > 2 && Pc < 2 && Pf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");

875:   if (dac->interptype == DA_Q1){
876:     if (dimc == 1){
877:       DAGetInterpolation_1D_Q1(dac,daf,A);
878:     } else if (dimc == 2){
879:       DAGetInterpolation_2D_Q1(dac,daf,A);
880:     } else if (dimc == 3){
881:       DAGetInterpolation_3D_Q1(dac,daf,A);
882:     } else {
883:       SETERRQ2(PETSC_ERR_SUP,"No support for this DA dimension %D for interpolation type %d",dimc,(int)dac->interptype);
884:     }
885:   } else if (dac->interptype == DA_Q0){
886:     if (dimc == 1){
887:       DAGetInterpolation_1D_Q0(dac,daf,A);
888:     } else if (dimc == 2){
889:        DAGetInterpolation_2D_Q0(dac,daf,A);
890:     } else if (dimc == 3){
891:        DAGetInterpolation_3D_Q0(dac,daf,A);
892:     } else {
893:       SETERRQ2(PETSC_ERR_SUP,"No support for this DA dimension %D for interpolation type %d",dimc,(int)dac->interptype);
894:     }
895:   }
896:   if (scale) {
897:     DMGetInterpolationScale((DM)dac,(DM)daf,*A,scale);
898:   }
899:   return(0);
900: }

904: PetscErrorCode DAGetInjection_2D(DA dac,DA daf,VecScatter *inject)
905: {
907:   PetscInt       i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
908:   PetscInt       m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c;
909:   PetscInt       row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
910:   PetscInt       i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
911:   PetscInt       *cols;
912:   DAPeriodicType pt;
913:   Vec            vecf,vecc;
914:   IS             isf;


918:   DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
919:   DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
920:   if (DAXPeriodic(pt)){
921:     ratioi = mx/Mx;
922:     if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
923:   } else {
924:     ratioi = (mx-1)/(Mx-1);
925:     if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
926:   }
927:   if (DAYPeriodic(pt)){
928:     ratioj = my/My;
929:     if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
930:   } else {
931:     ratioj = (my-1)/(My-1);
932:     if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
933:   }


936:   DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
937:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
938:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

940:   DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
941:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
942:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);


945:   /* loop over local fine grid nodes setting interpolation for those*/
946:   nc = 0;
947:   PetscMalloc(n_f*m_f*sizeof(PetscInt),&cols);
948:   for (j=j_start; j<j_start+n_f; j++) {
949:     for (i=i_start; i<i_start+m_f; i++) {

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

954:       if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
955:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
956:       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
957:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

959:       if (i_c*ratioi == i && j_c*ratioj == j) {
960:         /* convert to local "natural" numbering and then to PETSc global numbering */
961:         row    = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
962:         cols[nc++] = row;
963:       }
964:     }
965:   }

967:   ISCreateBlock(((PetscObject)daf)->comm,dof,nc,cols,&isf);
968:   DAGetGlobalVector(dac,&vecc);
969:   DAGetGlobalVector(daf,&vecf);
970:   VecScatterCreate(vecf,isf,vecc,PETSC_NULL,inject);
971:   DARestoreGlobalVector(dac,&vecc);
972:   DARestoreGlobalVector(daf,&vecf);
973:   ISDestroy(isf);
974:   PetscFree(cols);
975:   return(0);
976: }

980: /*@
981:    DAGetInjection - Gets an injection matrix that maps between 
982:    grids associated with two DAs.

984:    Collective on DA

986:    Input Parameters:
987: +  dac - the coarse grid DA
988: -  daf - the fine grid DA

990:    Output Parameters:
991: .  inject - the injection scatter

993:    Level: intermediate

995: .keywords: interpolation, restriction, multigrid, injection 

997: .seealso: DARefine(), DAGetInterpolation()
998: @*/
999: PetscErrorCode  DAGetInjection(DA dac,DA daf,VecScatter *inject)
1000: {
1002:   PetscInt       dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1003:   DAPeriodicType wrapc,wrapf;
1004:   DAStencilType  stc,stf;


1011:   DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
1012:   DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
1013:   if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
1014:   if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
1015:   if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
1016:   if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
1017:   if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");
1018:   if (Mc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
1019:   if (dimc > 1 && Nc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
1020:   if (dimc > 2 && Pc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");

1022:   if (dimc == 2){
1023:     DAGetInjection_2D(dac,daf,inject);
1024:   } else {
1025:     SETERRQ1(PETSC_ERR_SUP,"No support for this DA dimension %D",dimc);
1026:   }
1027:   return(0);
1028: }

1032: /*@
1033:    DAGetAggregates - Gets the aggregates that map between 
1034:    grids associated with two DAs.

1036:    Collective on DA

1038:    Input Parameters:
1039: +  dac - the coarse grid DA
1040: -  daf - the fine grid DA

1042:    Output Parameters:
1043: .  rest - the restriction matrix (transpose of the projection matrix)

1045:    Level: intermediate

1047: .keywords: interpolation, restriction, multigrid 

1049: .seealso: DARefine(), DAGetInjection(), DAGetInterpolation()
1050: @*/
1051: PetscErrorCode  DAGetAggregates(DA dac,DA daf,Mat *rest)
1052: {
1054:   PetscInt       dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc;
1055:   PetscInt       dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1056:   DAPeriodicType wrapc,wrapf;
1057:   DAStencilType  stc,stf;
1058: /*   PetscReal      r_x, r_y, r_z; */

1060:   PetscInt       i,j,l;
1061:   PetscInt       i_start,j_start,l_start, m_f,n_f,p_f;
1062:   PetscInt       i_start_ghost,j_start_ghost,l_start_ghost,m_ghost,n_ghost,p_ghost;
1063:   PetscInt       *idx_f;
1064:   PetscInt       i_c,j_c,l_c;
1065:   PetscInt       i_start_c,j_start_c,l_start_c, m_c,n_c,p_c;
1066:   PetscInt       i_start_ghost_c,j_start_ghost_c,l_start_ghost_c,m_ghost_c,n_ghost_c,p_ghost_c;
1067:   PetscInt       *idx_c;
1068:   PetscInt       d;
1069:   PetscInt       a;
1070:   PetscInt       max_agg_size;
1071:   PetscInt       *fine_nodes;
1072:   PetscScalar    *one_vec;
1073:   PetscInt       fn_idx;


1080:   DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
1081:   DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
1082:   if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
1083:   if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
1084:   if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
1085:   if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
1086:   if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");

1088:   if( Mf < Mc ) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Mc %D, Mf %D", Mc, Mf);
1089:   if( Nf < Nc ) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Nc %D, Nf %D", Nc, Nf);
1090:   if( Pf < Pc ) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Pc %D, Pf %D", Pc, Pf);

1092:   DAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
1093:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
1094:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

1096:   DAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
1097:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
1098:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

1100:   /* 
1101:      Basic idea is as follows. Here's a 2D example, suppose r_x, r_y are the ratios
1102:      for dimension 1 and 2 respectively.
1103:      Let (i,j) be a coarse grid node. All the fine grid nodes between r_x*i and r_x*(i+1)
1104:      and r_y*j and r_y*(j+1) will be grouped into the same coarse grid agregate.
1105:      Each specific dof on the fine grid is mapped to one dof on the coarse grid.
1106:   */

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

1110:   /* create the matrix that will contain the restriction operator */
1111:   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,
1112:                           max_agg_size, PETSC_NULL, max_agg_size, PETSC_NULL, rest);

1114:   /* store nodes in the fine grid here */
1115:   PetscMalloc2(max_agg_size,PetscScalar, &one_vec,max_agg_size,PetscInt, &fine_nodes);
1116:   for(i=0; i<max_agg_size; i++) one_vec[i] = 1.0;
1117: 
1118:   /* loop over all coarse nodes */
1119:   for (l_c=l_start_c; l_c<l_start_c+p_c; l_c++) {
1120:     for (j_c=j_start_c; j_c<j_start_c+n_c; j_c++) {
1121:       for (i_c=i_start_c; i_c<i_start_c+m_c; i_c++) {
1122:         for(d=0; d<dofc; d++) {
1123:           /* convert to local "natural" numbering and then to PETSc global numbering */
1124:           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;

1126:           fn_idx = 0;
1127:           /* Corresponding fine points are all points (i_f, j_f, l_f) such that
1128:              i_c*Mf/Mc <= i_f < (i_c+1)*Mf/Mc
1129:              (same for other dimensions)
1130:           */
1131:           for (l=l_c*Pf/Pc; l<PetscMin((l_c+1)*Pf/Pc,Pf); l++) {
1132:             for (j=j_c*Nf/Nc; j<PetscMin((j_c+1)*Nf/Nc,Nf); j++) {
1133:               for (i=i_c*Mf/Mc; i<PetscMin((i_c+1)*Mf/Mc,Mf); i++) {
1134:                 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;
1135:                 fn_idx++;
1136:               }
1137:             }
1138:           }
1139:           /* add all these points to one aggregate */
1140:           MatSetValues(*rest, 1, &a, fn_idx, fine_nodes, one_vec, INSERT_VALUES);
1141:         }
1142:       }
1143:     }
1144:   }
1145:   PetscFree2(one_vec,fine_nodes);
1146:   MatAssemblyBegin(*rest, MAT_FINAL_ASSEMBLY);
1147:   MatAssemblyEnd(*rest, MAT_FINAL_ASSEMBLY);
1148:   return(0);
1149: }