Actual source code: dainterp.c

  1: #define PETSCDM_DLL

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

 7:  #include src/dm/da/daimpl.h
 8:  #include petscmg.h

 12: PetscErrorCode  DMGetInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
 13: {
 15:   Vec            fine;
 16:   PetscScalar    one = 1.0;

 19:   DMCreateGlobalVector(daf,&fine);
 20:   DMCreateGlobalVector(dac,scale);
 21:   VecSet(fine,one);
 22:   MatRestrict(mat,fine,*scale);
 23:   VecDestroy(fine);
 24:   VecReciprocal(*scale);
 25:   return(0);
 26: }

 30: PetscErrorCode DAGetInterpolation_1D_Q1(DA dac,DA daf,Mat *A)
 31: {
 33:   PetscInt       i,i_start,m_f,Mx,*idx_f;
 34:   PetscInt       m_ghost,*idx_c,m_ghost_c;
 35:   PetscInt       row,col,i_start_ghost,mx,m_c,nc,ratio;
 36:   PetscInt       i_c,i_start_c,i_start_ghost_c,cols[2],dof;
 37:   PetscScalar    v[2],x,*coors = 0,*ccoors;
 38:   Mat            mat;
 39:   DAPeriodicType pt;
 40:   Vec            vcoors,cvcoors;

 43:   DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
 44:   DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
 45:   if (pt == DA_XPERIODIC) {
 46:     ratio = mx/Mx;
 47:     if (ratio*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
 48:   } else {
 49:     ratio = (mx-1)/(Mx-1);
 50:     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);
 51:   }

 53:   DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
 54:   DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
 55:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

 57:   DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
 58:   DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
 59:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

 61:   /* create interpolation matrix */
 62:   MatCreate(dac->comm,&mat);
 63:   MatSetSizes(mat,m_f,m_c,mx,Mx);
 64:   MatSetType(mat,MATAIJ);
 65:   MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
 66:   MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);
 67:   if (!DAXPeriodic(pt)){MatSetOption(mat,MAT_COLUMNS_SORTED);}

 69:   DAGetCoordinates(daf,&vcoors);
 70:   if (vcoors) {
 71:     DAGetGhostedCoordinates(dac,&cvcoors);
 72:     DAVecGetArray(daf->da_coordinates,vcoors,&coors);
 73:     DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
 74:   }
 75:   /* loop over local fine grid nodes setting interpolation for those*/
 76:   for (i=i_start; i<i_start+m_f; i++) {
 77:     /* convert to local "natural" numbering and then to PETSc global numbering */
 78:     row    = idx_f[dof*(i-i_start_ghost)]/dof;

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

 84:     /* 
 85:          Only include those interpolation points that are truly 
 86:          nonzero. Note this is very important for final grid lines
 87:          in x direction; since they have no right neighbor
 88:     */
 89:     if (coors) {
 90:       x = (coors[i] - ccoors[i_c]);
 91:       /* only access the next coors point if we know there is one */
 92:       /* note this is dangerous because x may not exactly equal ZERO */
 93:       if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[i_c+1] - ccoors[i_c]);
 94:     } else {
 95:       x  = ((double)(i - i_c*ratio))/((double)ratio);
 96:     }
 97:     nc = 0;
 98:       /* one left and below; or we are right on it */
 99:     col      = dof*(i_c-i_start_ghost_c);
100:     cols[nc] = idx_c[col]/dof;
101:     v[nc++]  = - x + 1.0;
102:     /* one right? */
103:     if (i_c*ratio != i) {
104:       cols[nc] = idx_c[col+dof]/dof;
105:       v[nc++]  = x;
106:     }
107:     MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
108:   }
109:   if (vcoors) {
110:     DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
111:     DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
112:   }
113:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
114:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
115:   MatCreateMAIJ(mat,dof,A);
116:   MatDestroy(mat);
117:   PetscLogFlops(5*m_f);
118:   return(0);
119: }

123: PetscErrorCode DAGetInterpolation_1D_Q0(DA dac,DA daf,Mat *A)
124: {
126:   PetscInt       i,i_start,m_f,Mx,*idx_f;
127:   PetscInt       m_ghost,*idx_c,m_ghost_c;
128:   PetscInt       row,col,i_start_ghost,mx,m_c,nc,ratio;
129:   PetscInt       i_c,i_start_c,i_start_ghost_c,cols[2],dof;
130:   PetscScalar    v[2],x;
131:   Mat            mat;
132:   DAPeriodicType pt;

135:   DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
136:   DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
137:   if (pt == DA_XPERIODIC) {
138:     ratio = mx/Mx;
139:     if (ratio*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
140:   } else {
141:     ratio = (mx-1)/(Mx-1);
142:     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);
143:   }

145:   DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
146:   DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
147:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

149:   DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
150:   DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
151:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

153:   /* create interpolation matrix */
154:   MatCreate(dac->comm,&mat);
155:   MatSetSizes(mat,m_f,m_c,mx,Mx);
156:   MatSetType(mat,MATAIJ);
157:   MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
158:   MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);
159:   if (!DAXPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}

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

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

168:     /* 
169:          Only include those interpolation points that are truly 
170:          nonzero. Note this is very important for final grid lines
171:          in x direction; since they have no right neighbor
172:     */
173:     x  = ((double)(i - i_c*ratio))/((double)ratio);
174:     nc = 0;
175:       /* one left and below; or we are right on it */
176:     col      = dof*(i_c-i_start_ghost_c);
177:     cols[nc] = idx_c[col]/dof;
178:     v[nc++]  = - x + 1.0;
179:     /* one right? */
180:     if (i_c*ratio != i) {
181:       cols[nc] = idx_c[col+dof]/dof;
182:       v[nc++]  = x;
183:     }
184:     MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
185:   }
186:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
187:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
188:   MatCreateMAIJ(mat,dof,A);
189:   MatDestroy(mat);
190:   PetscLogFlops(5*m_f);
191:   return(0);
192: }

196: PetscErrorCode DAGetInterpolation_2D_Q1(DA dac,DA daf,Mat *A)
197: {
199:   PetscInt       i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
200:   PetscInt       m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
201:   PetscInt       row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
202:   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;
203:   PetscMPIInt    size_c,size_f,rank_f;
204:   PetscScalar    v[4],x,y;
205:   Mat            mat;
206:   DAPeriodicType pt;
207:   DACoor2d       **coors = 0,**ccoors;
208:   Vec            vcoors,cvcoors;

211:   DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
212:   DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
213:   if (DAXPeriodic(pt)){
214:     ratioi = mx/Mx;
215:     if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
216:   } else {
217:     ratioi = (mx-1)/(Mx-1);
218:     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);
219:   }
220:   if (DAYPeriodic(pt)){
221:     ratioj = my/My;
222:     if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
223:   } else {
224:     ratioj = (my-1)/(My-1);
225:     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);
226:   }


229:   DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
230:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
231:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

233:   DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
234:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
235:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

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

245:      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
246:   */
247:   MPI_Comm_size(dac->comm,&size_c);
248:   MPI_Comm_size(daf->comm,&size_f);
249:   MPI_Comm_rank(daf->comm,&rank_f);
250:   col_scale = size_f/size_c;
251:   col_shift = Mx*My*(rank_f/size_c);

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

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

262:       if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
263:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
264:       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
265:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

267:       /* 
268:          Only include those interpolation points that are truly 
269:          nonzero. Note this is very important for final grid lines
270:          in x and y directions; since they have no right/top neighbors
271:       */
272:       nc = 0;
273:       /* one left and below; or we are right on it */
274:       col        = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
275:       cols[nc++] = col_shift + idx_c[col]/dof;
276:       /* one right and below */
277:       if (i_c*ratioi != i) {
278:         cols[nc++] = col_shift + idx_c[col+dof]/dof;
279:       }
280:       /* one left and above */
281:       if (j_c*ratioj != j) {
282:         cols[nc++] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
283:       }
284:       /* one right and above */
285:       if (j_c*ratioi != j && i_c*ratioj != i) {
286:         cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
287:       }
288:       MatPreallocateSet(row,nc,cols,dnz,onz);
289:     }
290:   }
291:   MatCreate(daf->comm,&mat);
292:   MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);
293:   MatSetType(mat,MATAIJ);
294:   MatSeqAIJSetPreallocation(mat,0,dnz);
295:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
296:   MatPreallocateFinalize(dnz,onz);
297:   if (!DAXPeriodic(pt) && !DAYPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}

299:   DAGetCoordinates(daf,&vcoors);
300:   if (vcoors) {
301:     DAGetGhostedCoordinates(dac,&cvcoors);
302:     DAVecGetArray(daf->da_coordinates,vcoors,&coors);
303:     DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
304:   }

306:   /* loop over local fine grid nodes setting interpolation for those*/
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:       /* 
316:          Only include those interpolation points that are truly 
317:          nonzero. Note this is very important for final grid lines
318:          in x and y directions; since they have no right/top neighbors
319:       */
320:       if (coors) {
321:         /* only access the next coors point if we know there is one */
322:         /* note this is dangerous because x may not exactly equal ZERO */
323:         x = (coors[j][i].x - ccoors[j_c][i_c].x);
324:         if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[j_c][i_c+1].x - ccoors[j_c][i_c].x);
325:         y = (coors[j][i].y - ccoors[j_c][i_c].y);
326:         if (PetscAbsScalar(y) != 0.0) y = y/(ccoors[j_c+1][i_c].y - ccoors[j_c][i_c].y);
327:       } else {
328:         x  = ((double)(i - i_c*ratioi))/((double)ratioi);
329:         y  = ((double)(j - j_c*ratioj))/((double)ratioj);
330:       }
331:       nc = 0;
332:       /* one left and below; or we are right on it */
333:       col      = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
334:       cols[nc] = col_shift + idx_c[col]/dof;
335:       v[nc++]  = x*y - x - y + 1.0;
336:       /* one right and below */
337:       if (i_c*ratioi != i) {
338:         cols[nc] = col_shift + idx_c[col+dof]/dof;
339:         v[nc++]  = -x*y + x;
340:       }
341:       /* one left and above */
342:       if (j_c*ratioj != j) {
343:         cols[nc] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
344:         v[nc++]  = -x*y + y;
345:       }
346:       /* one right and above */
347:       if (j_c*ratioj != j && i_c*ratioi != i) {
348:         cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
349:         v[nc++]  = x*y;
350:       }
351:       MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
352:     }
353:   }
354:   if (vcoors) {
355:     DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
356:     DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
357:   }
358:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
359:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
360:   MatCreateMAIJ(mat,dof,A);
361:   MatDestroy(mat);
362:   PetscLogFlops(13*m_f*n_f);
363:   return(0);
364: }

366: /* 
367:        Contributed by Andrei Draganescu <aidraga@sandia.gov>
368: */
371: PetscErrorCode DAGetInterpolation_2D_Q0(DA dac,DA daf,Mat *A)
372: {
374:   PetscInt       i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
375:   PetscInt       m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
376:   PetscInt       row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
377:   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;
378:   PetscMPIInt    size_c,size_f,rank_f;
379:   PetscScalar    v[4];
380:   Mat            mat;
381:   DAPeriodicType pt;

384:   DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
385:   DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
386:   if (DAXPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in x");
387:   if (DAYPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in y");
388:   ratioi = mx/Mx;
389:   ratioj = my/My;
390:   if (ratioi*Mx != mx) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
391:   if (ratioj*My != my) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
392:   if (ratioi != 2) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 2");
393:   if (ratioj != 2) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 2");

395:   DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
396:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
397:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

399:   DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
400:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
401:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

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

411:      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
412:   */
413:   MPI_Comm_size(dac->comm,&size_c);
414:   MPI_Comm_size(daf->comm,&size_f);
415:   MPI_Comm_rank(daf->comm,&rank_f);
416:   col_scale = size_f/size_c;
417:   col_shift = Mx*My*(rank_f/size_c);

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

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

428:       if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
429:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
430:       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
431:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

433:       /* 
434:          Only include those interpolation points that are truly 
435:          nonzero. Note this is very important for final grid lines
436:          in x and y directions; since they have no right/top neighbors
437:       */
438:       nc = 0;
439:       /* one left and below; or we are right on it */
440:       col        = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
441:       cols[nc++] = col_shift + idx_c[col]/dof;
442:       MatPreallocateSet(row,nc,cols,dnz,onz);
443:     }
444:   }
445:   MatCreate(daf->comm,&mat);
446:   MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);
447:   MatSetType(mat,MATAIJ);
448:   MatSeqAIJSetPreallocation(mat,0,dnz);
449:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
450:   MatPreallocateFinalize(dnz,onz);
451:   if (!DAXPeriodic(pt) && !DAYPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}

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

459:       i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
460:       j_c = (j/ratioj);    /* coarse grid node below fine grid node */
461:       nc = 0;
462:       /* one left and below; or we are right on it */
463:       col      = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
464:       cols[nc] = col_shift + idx_c[col]/dof;
465:       v[nc++]  = 1.0;
466: 
467:       MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
468:     }
469:   }
470:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
471:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
472:   MatCreateMAIJ(mat,dof,A);
473:   MatDestroy(mat);
474:   PetscLogFlops(13*m_f*n_f);
475:   return(0);
476: }

478: /* 
479:        Contributed by Jianming Yang <jianming-yang@uiowa.edu>
480: */
483: PetscErrorCode DAGetInterpolation_3D_Q0(DA dac,DA daf,Mat *A)
484: {
486:   PetscInt       i,j,l,i_start,j_start,l_start,m_f,n_f,p_f,Mx,My,Mz,*idx_f,dof;
487:   PetscInt       m_ghost,n_ghost,p_ghost,*idx_c,m_ghost_c,n_ghost_c,p_ghost_c,nc,*dnz,*onz;
488:   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;
489:   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;
490:   PetscMPIInt    size_c,size_f,rank_f;
491:   PetscScalar    v[8];
492:   Mat            mat;
493:   DAPeriodicType pt;

496:   DAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&pt,0);
497:   DAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0);
498:   if (DAXPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in x");
499:   if (DAYPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in y");
500:   if (DAZPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in z");
501:   ratioi = mx/Mx;
502:   ratioj = my/My;
503:   ratiol = mz/Mz;
504:   if (ratioi*Mx != mx) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
505:   if (ratioj*My != my) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
506:   if (ratiol*Mz != mz) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in z");
507:   if (ratioi != 2) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 2");
508:   if (ratioj != 2) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 2");
509:   if (ratiol != 2) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in z must be 2");

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

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

526:      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
527:   */
528:   MPI_Comm_size(dac->comm,&size_c);
529:   MPI_Comm_size(daf->comm,&size_f);
530:   MPI_Comm_rank(daf->comm,&rank_f);
531:   col_scale = size_f/size_c;
532:   col_shift = Mx*My*Mz*(rank_f/size_c);

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

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

545:         if (l_c < l_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
546:     l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
547:         if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
548:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
549:         if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
550:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

552:         /* 
553:            Only include those interpolation points that are truly 
554:            nonzero. Note this is very important for final grid lines
555:            in x and y directions; since they have no right/top neighbors
556:         */
557:         nc = 0;
558:         /* one left and below; or we are right on it */
559:         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));
560:         cols[nc++] = col_shift + idx_c[col]/dof;
561:         MatPreallocateSet(row,nc,cols,dnz,onz);
562:       }
563:     }
564:   }
565:   MatCreate(daf->comm,&mat);
566:   MatSetSizes(mat,m_f*n_f*p_f,col_scale*m_c*n_c*p_c,mx*my*mz,col_scale*Mx*My*Mz);
567:   MatSetType(mat,MATAIJ);
568:   MatSeqAIJSetPreallocation(mat,0,dnz);
569:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
570:   MatPreallocateFinalize(dnz,onz);
571:   if (!DAXPeriodic(pt) && !DAYPeriodic(pt) && !DAZPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}

573:   /* loop over local fine grid nodes setting interpolation for those*/
574:   for (l=l_start; l<l_start+p_f; l++) {
575:     for (j=j_start; j<j_start+n_f; j++) {
576:       for (i=i_start; i<i_start+m_f; i++) {
577:         /* convert to local "natural" numbering and then to PETSc global numbering */
578:         row    = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
579: 
580:         i_c = (i/ratioi);    /* coarse grid node to left of fine grid node */
581:         j_c = (j/ratioj);    /* coarse grid node below fine grid node */
582:         l_c = (l/ratiol);
583:         nc = 0;
584:         /* one left and below; or we are right on it */
585:         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));
586:         cols[nc] = col_shift + idx_c[col]/dof;
587:         v[nc++]  = 1.0;
588: 
589:         MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
590:       }
591:     }
592:   }
593:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
594:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
595:   MatCreateMAIJ(mat,dof,A);
596:   MatDestroy(mat);
597:   PetscLogFlops(13*m_f*n_f*p_f);
598:   return(0);
599: }

603: PetscErrorCode DAGetInterpolation_3D_Q1(DA dac,DA daf,Mat *A)
604: {
606:   PetscInt       i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof,l;
607:   PetscInt       m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,Mz,mz;
608:   PetscInt       row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
609:   PetscInt       i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
610:   PetscInt       l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
611:   PetscInt       l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
612:   PetscScalar    v[8],x,y,z;
613:   Mat            mat;
614:   DAPeriodicType pt;
615:   DACoor3d       ***coors = 0,***ccoors;
616:   Vec            vcoors,cvcoors;

619:   DAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&pt,0);
620:   DAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0);
621:   if (mx == Mx) {
622:     ratioi = 1;
623:   } else if (DAXPeriodic(pt)){
624:     ratioi = mx/Mx;
625:     if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
626:   } else {
627:     ratioi = (mx-1)/(Mx-1);
628:     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);
629:   }
630:   if (my == My) {
631:     ratioj = 1;
632:   } else if (DAYPeriodic(pt)){
633:     ratioj = my/My;
634:     if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
635:   } else {
636:     ratioj = (my-1)/(My-1);
637:     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);
638:   }
639:   if (mz == Mz) {
640:     ratiok = 1;
641:   } else if (DAZPeriodic(pt)){
642:     ratiok = mz/Mz;
643:     if (ratiok*Mz != mz) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mz/Mz  must be integer: mz %D Mz %D",mz,Mz);
644:   } else {
645:     ratiok = (mz-1)/(Mz-1);
646:     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);
647:   }

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

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

657:   /* create interpolation matrix, determining exact preallocation */
658:   MatPreallocateInitialize(dac->comm,m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);
659:   /* loop over local fine grid nodes counting interpolating points */
660:   for (l=l_start; l<l_start+p_f; l++) {
661:     for (j=j_start; j<j_start+n_f; j++) {
662:       for (i=i_start; i<i_start+m_f; i++) {
663:         /* convert to local "natural" numbering and then to PETSc global numbering */
664:         row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
665:         i_c = (i/ratioi);
666:         j_c = (j/ratioj);
667:         l_c = (l/ratiok);
668:         if (l_c < l_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
669:           l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
670:         if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
671:           j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
672:         if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
673:           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

675:         /* 
676:          Only include those interpolation points that are truly 
677:          nonzero. Note this is very important for final grid lines
678:          in x and y directions; since they have no right/top neighbors
679:         */
680:         nc       = 0;
681:         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));
682:         cols[nc++] = idx_c[col]/dof;
683:         if (i_c*ratioi != i) {
684:           cols[nc++] = idx_c[col+dof]/dof;
685:         }
686:         if (j_c*ratioj != j) {
687:           cols[nc++] = idx_c[col+m_ghost_c*dof]/dof;
688:         }
689:         if (l_c*ratiok != l) {
690:           cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
691:         }
692:         if (j_c*ratioj != j && i_c*ratioi != i) {
693:           cols[nc++] = idx_c[col+(m_ghost_c+1)*dof]/dof;
694:         }
695:         if (j_c*ratioj != j && l_c*ratiok != l) {
696:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
697:         }
698:         if (i_c*ratioi != i && l_c*ratiok != l) {
699:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
700:         }
701:         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
702:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
703:         }
704:         MatPreallocateSet(row,nc,cols,dnz,onz);
705:       }
706:     }
707:   }
708:   MatCreate(dac->comm,&mat);
709:   MatSetSizes(mat,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz);
710:   MatSetType(mat,MATAIJ);
711:   MatSeqAIJSetPreallocation(mat,0,dnz);
712:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
713:   MatPreallocateFinalize(dnz,onz);
714:   if (!DAXPeriodic(pt) && !DAYPeriodic(pt) && !DAZPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}

716:   DAGetCoordinates(daf,&vcoors);
717:   if (vcoors) {
718:     DAGetGhostedCoordinates(dac,&cvcoors);
719:     DAVecGetArray(daf->da_coordinates,vcoors,&coors);
720:     DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
721:   }

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

730:         i_c = (i/ratioi);
731:         j_c = (j/ratioj);
732:         l_c = (l/ratiok);

734:         /* 
735:            Only include those interpolation points that are truly 
736:            nonzero. Note this is very important for final grid lines
737:            in x and y directions; since they have no right/top neighbors
738:         */
739:         if (coors) {
740:           /* only access the next coors point if we know there is one */
741:           /* note this is dangerous because x may not exactly equal ZERO */
742:           x = (coors[l][j][i].x - ccoors[l_c][j_c][i_c].x);
743:           if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[l_c][j_c][i_c+1].x - ccoors[l_c][j_c][i_c].x);
744:           y = (coors[l][j][i].y - ccoors[l_c][j_c][i_c].y);
745:           if (PetscAbsScalar(y) != 0.0) y = y/(ccoors[l_c][j_c+1][i_c].y - ccoors[l_c][j_c][i_c].y);
746:           z = (coors[l][j][i].z - ccoors[l_c][j_c][i_c].z);
747:           if (PetscAbsScalar(z) != 0.0) z = z/(ccoors[l_c+1][j_c][i_c].z - ccoors[l_c][j_c][i_c].z);
748:         } else {
749:           x  = ((double)(i - i_c*ratioi))/((double)ratioi);
750:           y  = ((double)(j - j_c*ratioj))/((double)ratioj);
751:           z  = ((double)(l - l_c*ratiok))/((double)ratiok);
752:         }
753:         nc = 0;
754:         /* one left and below; or we are right on it */
755:         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));

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

760:         if (i_c*ratioi != i) {
761:           cols[nc] = idx_c[col+dof]/dof;
762:           v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
763:         }

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

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

775:         if (j_c*ratioj != j && i_c*ratioi != i) {
776:           cols[nc] = idx_c[col+(m_ghost_c+1)*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 && l_c*ratiok != l) {
781:           cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+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 (i_c*ratioi != i && l_c*ratiok != l) {
786:           cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
787:           v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
788:         }

790:         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
791:           cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+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:         }
794:         MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
795:       }
796:     }
797:   }
798:   if (vcoors) {
799:     DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
800:     DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
801:   }
802:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
803:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);

805:   MatCreateMAIJ(mat,dof,A);
806:   MatDestroy(mat);
807:   PetscLogFlops(13*m_f*n_f);
808:   return(0);
809: }

813: /*@C
814:    DAGetInterpolation - Gets an interpolation matrix that maps between 
815:    grids associated with two DAs.

817:    Collective on DA

819:    Input Parameters:
820: +  dac - the coarse grid DA
821: -  daf - the fine grid DA

823:    Output Parameters:
824: +  A - the interpolation matrix
825: -  scale - a scaling vector used to scale the coarse grid restricted vector before applying the 
826:            grid function or grid Jacobian to it.

828:    Level: intermediate

830: .keywords: interpolation, restriction, multigrid 

832: .seealso: DARefine(), DAGetInjection()
833: @*/
834: PetscErrorCode  DAGetInterpolation(DA dac,DA daf,Mat *A,Vec *scale)
835: {
837:   PetscInt       dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
838:   DAPeriodicType wrapc,wrapf;
839:   DAStencilType  stc,stf;


847:   DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
848:   DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
849:   if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
850:   if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
851:   if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
852:   if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
853:   if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");
854:   if (Mc < 2 && Mf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
855:   if (dimc > 1 && Nc < 2 && Nf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
856:   if (dimc > 2 && Pc < 2 && Pf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");

858:   if (dac->interptype == DA_Q1){
859:     if (dimc == 1){
860:       DAGetInterpolation_1D_Q1(dac,daf,A);
861:     } else if (dimc == 2){
862:       DAGetInterpolation_2D_Q1(dac,daf,A);
863:     } else if (dimc == 3){
864:       DAGetInterpolation_3D_Q1(dac,daf,A);
865:     } else {
866:       SETERRQ2(PETSC_ERR_SUP,"No support for this DA dimension %D for interpolation type %d",dimc,(int)dac->interptype);
867:     }
868:   } else if (dac->interptype == DA_Q0){
869:     if (dimc == 1){
870:       DAGetInterpolation_1D_Q0(dac,daf,A);
871:     } else if (dimc == 2){
872:        DAGetInterpolation_2D_Q0(dac,daf,A);
873:     } else if (dimc == 3){
874:        DAGetInterpolation_3D_Q0(dac,daf,A);
875:     } else {
876:       SETERRQ2(PETSC_ERR_SUP,"No support for this DA dimension %D for interpolation type %d",dimc,(int)dac->interptype);
877:     }
878:   }
879:   if (scale) {
880:     DMGetInterpolationScale((DM)dac,(DM)daf,*A,scale);
881:   }
882:   return(0);
883: }

887: PetscErrorCode DAGetInjection_2D(DA dac,DA daf,VecScatter *inject)
888: {
890:   PetscInt       i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
891:   PetscInt       m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c;
892:   PetscInt       row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
893:   PetscInt       i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
894:   PetscInt       *cols;
895:   DAPeriodicType pt;
896:   Vec            vecf,vecc;
897:   IS             isf;


901:   DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
902:   DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
903:   if (DAXPeriodic(pt)){
904:     ratioi = mx/Mx;
905:     if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
906:   } else {
907:     ratioi = (mx-1)/(Mx-1);
908:     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);
909:   }
910:   if (DAYPeriodic(pt)){
911:     ratioj = my/My;
912:     if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
913:   } else {
914:     ratioj = (my-1)/(My-1);
915:     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);
916:   }


919:   DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
920:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
921:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

923:   DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
924:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
925:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);


928:   /* loop over local fine grid nodes setting interpolation for those*/
929:   nc = 0;
930:   PetscMalloc(n_f*m_f*sizeof(PetscInt),&cols);
931:   for (j=j_start; j<j_start+n_f; j++) {
932:     for (i=i_start; i<i_start+m_f; i++) {

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

937:       if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
938:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
939:       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
940:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

942:       if (i_c*ratioi == i && j_c*ratioj == j) {
943:         /* convert to local "natural" numbering and then to PETSc global numbering */
944:         row    = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
945:         cols[nc++] = row;
946:       }
947:     }
948:   }

950:   ISCreateBlock(daf->comm,dof,nc,cols,&isf);
951:   DAGetGlobalVector(dac,&vecc);
952:   DAGetGlobalVector(daf,&vecf);
953:   VecScatterCreate(vecf,isf,vecc,PETSC_NULL,inject);
954:   DARestoreGlobalVector(dac,&vecc);
955:   DARestoreGlobalVector(daf,&vecf);
956:   ISDestroy(isf);
957:   PetscFree(cols);
958:   return(0);
959: }

963: /*@C
964:    DAGetInjection - Gets an injection matrix that maps between 
965:    grids associated with two DAs.

967:    Collective on DA

969:    Input Parameters:
970: +  dac - the coarse grid DA
971: -  daf - the fine grid DA

973:    Output Parameters:
974: .  inject - the injection scatter

976:    Level: intermediate

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

980: .seealso: DARefine(), DAGetInterpolation()
981: @*/
982: PetscErrorCode  DAGetInjection(DA dac,DA daf,VecScatter *inject)
983: {
985:   PetscInt       dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
986:   DAPeriodicType wrapc,wrapf;
987:   DAStencilType  stc,stf;


994:   DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
995:   DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
996:   if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
997:   if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
998:   if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
999:   if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
1000:   if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");
1001:   if (Mc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
1002:   if (dimc > 1 && Nc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
1003:   if (dimc > 2 && Pc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");

1005:   if (dimc == 2){
1006:     DAGetInjection_2D(dac,daf,inject);
1007:   } else {
1008:     SETERRQ1(PETSC_ERR_SUP,"No support for this DA dimension %D",dimc);
1009:   }
1010:   return(0);
1011: }