Actual source code: dainterp.c

  1: /*
  2:   Code for interpolating between grids represented by DAs
  3: */

 5:  #include src/dm/da/daimpl.h
 6:  #include petscmg.h

 10: PetscErrorCode DMGetInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
 11: {
 13:   Vec            fine;
 14:   PetscScalar    one = 1.0;

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

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

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

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

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

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

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

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

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

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

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

142:   DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
143:   DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
144:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

146:   DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
147:   DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
148:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

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

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

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

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

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

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


225:   DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
226:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
227:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

229:   DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
230:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
231:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

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

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

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

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

258:       if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
259:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
260:       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
261:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

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

294:   DAGetCoordinates(daf,&vcoors);
295:   if (vcoors) {
296:     DAGetGhostedCoordinates(dac,&cvcoors);
297:     DAVecGetArray(daf->da_coordinates,vcoors,&coors);
298:     DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
299:   }

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

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

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


362: /*   dof degree of freedom per node, nonperiodic */
365: PetscErrorCode DAGetInterpolation_3D_Q1(DA dac,DA daf,Mat *A)
366: {
368:   PetscInt       i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof,l;
369:   PetscInt       m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,Mz,mz;
370:   PetscInt       row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
371:   PetscInt       i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
372:   PetscInt       l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
373:   PetscInt       l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
374:   PetscScalar    v[8],x,y,z;
375:   Mat            mat;
376:   DAPeriodicType pt;
377:   DACoor3d       ***coors = 0,***ccoors;
378:   Vec            vcoors,cvcoors;

381:   DAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&pt,0);
382:   DAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0);
383:   if (mx == My) {
384:     ratioi = 1;
385:   } else if (DAXPeriodic(pt)){
386:     ratioi = mx/Mx;
387:     if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
388:   } else {
389:     ratioi = (mx-1)/(Mx-1);
390:     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);
391:   }
392:   if (my == My) {
393:     ratioj = 1;
394:   } else if (DAYPeriodic(pt)){
395:     ratioj = my/My;
396:     if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
397:   } else {
398:     ratioj = (my-1)/(My-1);
399:     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);
400:   }
401:   if (mz == Mz) {
402:     ratiok = 1;
403:   } else if (DAZPeriodic(pt)){
404:     ratiok = mz/Mz;
405:     if (ratiok*Mz != mz) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mz/Mz  must be integer: mz %D Mz %D",mz,Mz);
406:   } else {
407:     ratiok = (mz-1)/(Mz-1);
408:     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);
409:   }

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

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

419:   /* create interpolation matrix, determining exact preallocation */
420:   MatPreallocateInitialize(dac->comm,m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);
421:   /* loop over local fine grid nodes counting interpolating points */
422:   for (l=l_start; l<l_start+p_f; l++) {
423:     for (j=j_start; j<j_start+n_f; j++) {
424:       for (i=i_start; i<i_start+m_f; i++) {
425:         /* convert to local "natural" numbering and then to PETSc global numbering */
426:         row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
427:         i_c = (i/ratioi);
428:         j_c = (j/ratioj);
429:         l_c = (l/ratiok);
430:         if (l_c < l_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
431:           l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
432:         if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
433:           j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
434:         if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
435:           i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

437:         /* 
438:          Only include those interpolation points that are truly 
439:          nonzero. Note this is very important for final grid lines
440:          in x and y directions; since they have no right/top neighbors
441:         */
442:         nc       = 0;
443:         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));
444:         cols[nc++] = idx_c[col]/dof;
445:         if (i_c*ratioi != i) {
446:           cols[nc++] = idx_c[col+dof]/dof;
447:         }
448:         if (j_c*ratioj != j) {
449:           cols[nc++] = idx_c[col+m_ghost_c*dof]/dof;
450:         }
451:         if (l_c*ratiok != l) {
452:           cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
453:         }
454:         if (j_c*ratioj != j && i_c*ratioi != i) {
455:           cols[nc++] = idx_c[col+(m_ghost_c+1)*dof]/dof;
456:         }
457:         if (j_c*ratioj != j && l_c*ratiok != l) {
458:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
459:         }
460:         if (i_c*ratioi != i && l_c*ratiok != l) {
461:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
462:         }
463:         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
464:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
465:         }
466:         MatPreallocateSet(row,nc,cols,dnz,onz);
467:       }
468:     }
469:   }
470:   MatCreate(dac->comm,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz,&mat);
471:   MatSetType(mat,MATAIJ);
472:   MatSeqAIJSetPreallocation(mat,0,dnz);
473:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
474:   MatPreallocateFinalize(dnz,onz);
475:   if (!DAXPeriodic(pt) && !DAYPeriodic(pt) && !DAZPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}

477:   DAGetCoordinates(daf,&vcoors);
478:   if (vcoors) {
479:     DAGetGhostedCoordinates(dac,&cvcoors);
480:     DAVecGetArray(daf->da_coordinates,vcoors,&coors);
481:     DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
482:   }

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

491:         i_c = (i/ratioi);
492:         j_c = (j/ratioj);
493:         l_c = (l/ratiok);

495:         /* 
496:            Only include those interpolation points that are truly 
497:            nonzero. Note this is very important for final grid lines
498:            in x and y directions; since they have no right/top neighbors
499:         */
500:         if (coors) {
501:           /* only access the next coors point if we know there is one */
502:           /* note this is dangerous because x may not exactly equal ZERO */
503:           x = (coors[l][j][i].x - ccoors[l_c][j_c][i_c].x);
504:           if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[l_c][j_c][i_c+1].x - ccoors[l_c][j_c][i_c].x);
505:           y = (coors[l][j][i].y - ccoors[l_c][j_c][i_c].y);
506:           if (PetscAbsScalar(y) != 0.0) y = y/(ccoors[l_c][j_c+1][i_c].y - ccoors[l_c][j_c][i_c].y);
507:           z = (coors[l][j][i].z - ccoors[l_c][j_c][i_c].z);
508:           if (PetscAbsScalar(z) != 0.0) z = z/(ccoors[l_c+1][j_c][i_c].z - ccoors[l_c][j_c][i_c].z);
509:         } else {
510:           x  = ((double)(i - i_c*ratioi))/((double)ratioi);
511:           y  = ((double)(j - j_c*ratioj))/((double)ratioj);
512:           z  = ((double)(l - l_c*ratiok))/((double)ratiok);
513:         }
514:         nc = 0;
515:         /* one left and below; or we are right on it */
516:         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));

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

521:         if (i_c*ratioi != i) {
522:           cols[nc] = idx_c[col+dof]/dof;
523:           v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
524:         }

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

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

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

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

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

551:         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
552:           cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
553:           v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
554:         }
555:         MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
556:       }
557:     }
558:   }
559:   if (vcoors) {
560:     DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
561:     DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
562:   }
563:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
564:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);

566:   MatCreateMAIJ(mat,dof,A);
567:   MatDestroy(mat);
568:   PetscLogFlops(13*m_f*n_f);
569:   return(0);
570: }

574: /*@C
575:    DAGetInterpolation - Gets an interpolation matrix that maps between 
576:    grids associated with two DAs.

578:    Collective on DA

580:    Input Parameters:
581: +  dac - the coarse grid DA
582: -  daf - the fine grid DA

584:    Output Parameters:
585: +  A - the interpolation matrix
586: -  scale - a scaling vector used to scale the coarse grid restricted vector before applying the 
587:            grid function or grid Jacobian to it.

589:    Level: intermediate

591: .keywords: interpolation, restriction, multigrid 

593: .seealso: DARefine(), DAGetInjection()
594: @*/
595: PetscErrorCode DAGetInterpolation(DA dac,DA daf,Mat *A,Vec *scale)
596: {
598:   PetscInt       dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
599:   DAPeriodicType wrapc,wrapf;
600:   DAStencilType  stc,stf;


608:   DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
609:   DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
610:   if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
611:   if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
612:   if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
613:   if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
614:   if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");
615:   if (Mc < 2 && Mf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
616:   if (dimc > 1 && Nc < 2 && Nf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
617:   if (dimc > 2 && Pc < 2 && Pf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");

619:   if (dac->interptype == DA_Q1){
620:     if (dimc == 1){
621:       DAGetInterpolation_1D_Q1(dac,daf,A);
622:     } else if (dimc == 2){
623:       DAGetInterpolation_2D_Q1(dac,daf,A);
624:     } else if (dimc == 3){
625:       DAGetInterpolation_3D_Q1(dac,daf,A);
626:     } else {
627:       SETERRQ2(PETSC_ERR_SUP,"No support for this DA dimension %D for interpolation type %d",dimc,(int)dac->interptype);
628:     }
629:   } else if (dac->interptype == DA_Q0){
630:     if (dimc == 1){
631:       DAGetInterpolation_1D_Q0(dac,daf,A);
632:     } else {
633:       SETERRQ2(PETSC_ERR_SUP,"No support for this DA dimension %D for interpolation type %d",dimc,(int)dac->interptype);
634:     }
635:   }
636:   if (scale) {
637:     DMGetInterpolationScale((DM)dac,(DM)daf,*A,scale);
638:   }
639:   return(0);
640: }

644: PetscErrorCode DAGetInjection_2D(DA dac,DA daf,VecScatter *inject)
645: {
647:   PetscInt       i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
648:   PetscInt       m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c;
649:   PetscInt       row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
650:   PetscInt       i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
651:   PetscInt       *cols;
652:   DAPeriodicType pt;
653:   Vec            vecf,vecc;
654:   IS             isf;


658:   DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
659:   DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
660:   if (DAXPeriodic(pt)){
661:     ratioi = mx/Mx;
662:     if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx  must be integer: mx %D Mx %D",mx,Mx);
663:   } else {
664:     ratioi = (mx-1)/(Mx-1);
665:     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);
666:   }
667:   if (DAYPeriodic(pt)){
668:     ratioj = my/My;
669:     if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My  must be integer: my %D My %D",my,My);
670:   } else {
671:     ratioj = (my-1)/(My-1);
672:     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);
673:   }


676:   DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
677:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
678:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

680:   DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
681:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
682:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);


685:   /* loop over local fine grid nodes setting interpolation for those*/
686:   nc = 0;
687:   PetscMalloc(n_f*m_f*sizeof(PetscInt),&cols);
688:   for (j=j_start; j<j_start+n_f; j++) {
689:     for (i=i_start; i<i_start+m_f; i++) {

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

694:       if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
695:     j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
696:       if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
697:     i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);

699:       if (i_c*ratioi == i && j_c*ratioj == j) {
700:         /* convert to local "natural" numbering and then to PETSc global numbering */
701:         row    = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
702:         cols[nc++] = row;
703:       }
704:     }
705:   }

707:   ISCreateBlock(daf->comm,dof,nc,cols,&isf);
708:   DAGetGlobalVector(dac,&vecc);
709:   DAGetGlobalVector(daf,&vecf);
710:   VecScatterCreate(vecf,isf,vecc,PETSC_NULL,inject);
711:   DARestoreGlobalVector(dac,&vecc);
712:   DARestoreGlobalVector(daf,&vecf);
713:   ISDestroy(isf);
714:   PetscFree(cols);
715:   return(0);
716: }

720: /*@C
721:    DAGetInjection - Gets an injection matrix that maps between 
722:    grids associated with two DAs.

724:    Collective on DA

726:    Input Parameters:
727: +  dac - the coarse grid DA
728: -  daf - the fine grid DA

730:    Output Parameters:
731: .  inject - the injection scatter

733:    Level: intermediate

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

737: .seealso: DARefine(), DAGetInterpolation()
738: @*/
739: PetscErrorCode DAGetInjection(DA dac,DA daf,VecScatter *inject)
740: {
742:   PetscInt       dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
743:   DAPeriodicType wrapc,wrapf;
744:   DAStencilType  stc,stf;


751:   DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
752:   DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
753:   if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
754:   if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
755:   if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
756:   if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
757:   if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");
758:   if (Mc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
759:   if (dimc > 1 && Nc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
760:   if (dimc > 2 && Pc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");

762:   if (dimc == 2){
763:     DAGetInjection_2D(dac,daf,inject);
764:   } else {
765:     SETERRQ1(PETSC_ERR_SUP,"No support for this DA dimension %D",dimc);
766:   }
767:   return(0);
768: }