Actual source code: dainterp.c

  1: /*$Id: dainterp.c,v 1.25 2001/08/07 03:04:39 balay Exp $*/
  2: 
  3: /*
  4:   Code for interpolating between grids represented by DAs
  5: */

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

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

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

 30: int DAGetInterpolation_1D_Q1(DA dac,DA daf,Mat *A)
 31: {
 32:   int            ierr,i,i_start,m_f,Mx,*idx_f;
 33:   int            m_ghost,*idx_c,m_ghost_c;
 34:   int            row,col,i_start_ghost,mx,m_c,nc,ratio;
 35:   int            i_c,i_start_c,i_start_ghost_c,cols[2],dof;
 36:   PetscScalar    v[2],x;
 37:   Mat            mat;
 38:   DAPeriodicType pt;

 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(1,"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(1,"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:   /* loop over local fine grid nodes setting interpolation for those*/
 67:   for (i=i_start; i<i_start+m_f; i++) {
 68:     /* convert to local "natural" numbering and then to PETSc global numbering */
 69:     row    = idx_f[dof*(i-i_start_ghost)]/dof;

 71:     i_c = (i/ratio);    /* coarse grid node to left of fine grid node */
 72:     if (i_c < i_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
 73:     i_start %d i_c %d i_start_ghost_c %d",i_start,i_c,i_start_ghost_c);

 75:     /* 
 76:          Only include those interpolation points that are truly 
 77:          nonzero. Note this is very important for final grid lines
 78:          in x direction; since they have no right neighbor
 79:     */
 80:     x  = ((double)(i - i_c*ratio))/((double)ratio);
 81:     /* printf("i j %d %d %g %g\n",i,j,x,y); */
 82:     nc = 0;
 83:       /* one left and below; or we are right on it */
 84:     col      = dof*(i_c-i_start_ghost_c);
 85:     cols[nc] = idx_c[col]/dof;
 86:     v[nc++]  = - x + 1.0;
 87:     /* one right? */
 88:     if (i_c*ratio != i) {
 89:       cols[nc] = idx_c[col+dof]/dof;
 90:       v[nc++]  = x;
 91:     }
 92:     MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
 93:   }
 94:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
 95:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
 96:   MatCreateMAIJ(mat,dof,A);
 97:   MatDestroy(mat);
 98:   PetscLogFlops(5*m_f);
 99:   return(0);
100: }

104: int DAGetInterpolation_1D_Q0(DA dac,DA daf,Mat *A)
105: {
106:   int            ierr,i,i_start,m_f,Mx,*idx_f;
107:   int            m_ghost,*idx_c,m_ghost_c;
108:   int            row,col,i_start_ghost,mx,m_c,nc,ratio;
109:   int            i_c,i_start_c,i_start_ghost_c,cols[2],dof;
110:   PetscScalar    v[2],x;
111:   Mat            mat;
112:   DAPeriodicType pt;

115:   DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
116:   DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
117:   if (pt == DA_XPERIODIC) {
118:     ratio = mx/Mx;
119:     if (ratio*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx  must be integer: mx %d Mx %d",mx,Mx);
120:   } else {
121:     ratio = (mx-1)/(Mx-1);
122:     if (ratio*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
123:   }

125:   DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
126:   DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
127:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

129:   DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
130:   DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
131:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

133:   /* create interpolation matrix */
134:   MatCreate(dac->comm,m_f,m_c,mx,Mx,&mat);
135:   MatSetType(mat,MATAIJ);
136:   MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
137:   MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);
138:   if (!DAXPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}

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

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

147:     /* 
148:          Only include those interpolation points that are truly 
149:          nonzero. Note this is very important for final grid lines
150:          in x direction; since they have no right neighbor
151:     */
152:     x  = ((double)(i - i_c*ratio))/((double)ratio);
153:     /* printf("i j %d %d %g %g\n",i,j,x,y); */
154:     nc = 0;
155:       /* one left and below; or we are right on it */
156:     col      = dof*(i_c-i_start_ghost_c);
157:     cols[nc] = idx_c[col]/dof;
158:     v[nc++]  = - x + 1.0;
159:     /* one right? */
160:     if (i_c*ratio != i) {
161:       cols[nc] = idx_c[col+dof]/dof;
162:       v[nc++]  = x;
163:     }
164:     MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
165:   }
166:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
167:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
168:   MatCreateMAIJ(mat,dof,A);
169:   MatDestroy(mat);
170:   PetscLogFlops(5*m_f);
171:   return(0);
172: }


175: /*   dof degree of freedom per node, nonperiodic */
178: int DAGetInterpolation_2D_Q1(DA dac,DA daf,Mat *A)
179: {
180:   int            ierr,i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
181:   int            m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
182:   int            row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
183:   int            i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
184:   int            size_c,size_f,rank_f,col_shift,col_scale;
185:   PetscScalar    v[4],x,y;
186:   Mat            mat;
187:   DAPeriodicType pt;


191:   DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
192:   DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
193:   if (DAXPeriodic(pt)){
194:     ratioi = mx/Mx;
195:     if (ratioi*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx  must be integer: mx %d Mx %d",mx,Mx);
196:   } else {
197:     ratioi = (mx-1)/(Mx-1);
198:     if (ratioi*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
199:   }
200:   if (DAYPeriodic(pt)){
201:     ratioj = my/My;
202:     if (ratioj*My != my) SETERRQ2(1,"Ratio between levels: my/My  must be integer: my %d My %d",my,My);
203:   } else {
204:     ratioj = (my-1)/(My-1);
205:     if (ratioj*(My-1) != my-1) SETERRQ2(1,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %d My %d",my,My);
206:   }


209:   DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
210:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
211:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

213:   DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
214:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
215:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);

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

225:      In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
226:   */
227:   MPI_Comm_size(dac->comm,&size_c);
228:   MPI_Comm_size(daf->comm,&size_f);
229:   MPI_Comm_rank(daf->comm,&rank_f);
230:   col_scale = size_f/size_c;
231:   col_shift = Mx*My*(rank_f/size_c);

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

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

242:       if (j_c < j_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
243:     j_start %d j_c %d j_start_ghost_c %d",j_start,j_c,j_start_ghost_c);
244:       if (i_c < i_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
245:     i_start %d i_c %d i_start_ghost_c %d",i_start,i_c,i_start_ghost_c);

247:       /* 
248:          Only include those interpolation points that are truly 
249:          nonzero. Note this is very important for final grid lines
250:          in x and y directions; since they have no right/top neighbors
251:       */
252:       nc = 0;
253:       /* one left and below; or we are right on it */
254:       col        = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
255:       cols[nc++] = col_shift + idx_c[col]/dof;
256:       /* one right and below */
257:       if (i_c*ratioi != i) {
258:         cols[nc++] = col_shift + idx_c[col+dof]/dof;
259:       }
260:       /* one left and above */
261:       if (j_c*ratioj != j) {
262:         cols[nc++] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
263:       }
264:       /* one right and above */
265:       if (j_c*ratioi != j && i_c*ratioj != i) {
266:         cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
267:       }
268:       MatPreallocateSet(row,nc,cols,dnz,onz);
269:     }
270:   }
271:   MatCreate(daf->comm,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My,&mat);
272:   MatSetType(mat,MATAIJ);
273:   MatSeqAIJSetPreallocation(mat,0,dnz);
274:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
275:   MatPreallocateFinalize(dnz,onz);
276:   if (!DAXPeriodic(pt) && !DAYPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}

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

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

287:       /* 
288:          Only include those interpolation points that are truly 
289:          nonzero. Note this is very important for final grid lines
290:          in x and y directions; since they have no right/top neighbors
291:       */
292:       x  = ((double)(i - i_c*ratioi))/((double)ratioi);
293:       y  = ((double)(j - j_c*ratioj))/((double)ratioj);
294:       /* printf("i j %d %d %g %g\n",i,j,x,y); */
295:       nc = 0;
296:       /* one left and below; or we are right on it */
297:       col      = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
298:       cols[nc] = col_shift + idx_c[col]/dof;
299:       v[nc++]  = x*y - x - y + 1.0;
300:       /* one right and below */
301:       if (i_c*ratioi != i) {
302:         cols[nc] = col_shift + idx_c[col+dof]/dof;
303:         v[nc++]  = -x*y + x;
304:       }
305:       /* one left and above */
306:       if (j_c*ratioj != j) {
307:         cols[nc] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
308:         v[nc++]  = -x*y + y;
309:       }
310:       /* one right and above */
311:       if (j_c*ratioj != j && i_c*ratioi != i) {
312:         cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
313:         v[nc++]  = x*y;
314:       }
315:       MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
316:     }
317:   }
318:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
319:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
320:   MatCreateMAIJ(mat,dof,A);
321:   MatDestroy(mat);
322:   PetscLogFlops(13*m_f*n_f);
323:   return(0);
324: }


327: /*   dof degree of freedom per node, nonperiodic */
330: int DAGetInterpolation_3D_Q1(DA dac,DA daf,Mat *A)
331: {
332:   int            ierr,i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof,l;
333:   int            m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,Mz,mz;
334:   int            row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
335:   int            i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
336:   int            l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
337:   int            l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
338:   PetscScalar    v[8],x,y,z;
339:   Mat            mat;
340:   DAPeriodicType pt;

343:   DAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&pt,0);
344:   DAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0);
345:   if (DAXPeriodic(pt)){
346:     ratioi = mx/Mx;
347:     if (ratioi*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx  must be integer: mx %d Mx %d",mx,Mx);
348:   } else {
349:     ratioi = (mx-1)/(Mx-1);
350:     if (ratioi*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
351:   }
352:   if (DAYPeriodic(pt)){
353:     ratioj = my/My;
354:     if (ratioj*My != my) SETERRQ2(1,"Ratio between levels: my/My  must be integer: my %d My %d",my,My);
355:   } else {
356:     ratioj = (my-1)/(My-1);
357:     if (ratioj*(My-1) != my-1) SETERRQ2(1,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %d My %d",my,My);
358:   }
359:   if (DAZPeriodic(pt)){
360:     ratiok = mz/Mz;
361:     if (ratiok*Mz != mz) SETERRQ2(1,"Ratio between levels: mz/Mz  must be integer: mz %d Mz %d",mz,Mz);
362:   } else {
363:     ratiok = (mz-1)/(Mz-1);
364:     if (ratiok*(Mz-1) != mz-1) SETERRQ2(1,"Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %d Mz %d",mz,Mz);
365:   }

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

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

375:   /* create interpolation matrix, determining exact preallocation */
376:   MatPreallocateInitialize(dac->comm,m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);
377:   /* loop over local fine grid nodes counting interpolating points */
378:   for (l=l_start; l<l_start+p_f; l++) {
379:     for (j=j_start; j<j_start+n_f; j++) {
380:       for (i=i_start; i<i_start+m_f; i++) {
381:         /* convert to local "natural" numbering and then to PETSc global numbering */
382:         row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
383:         i_c = (i/ratioi);
384:         j_c = (j/ratioj);
385:         l_c = (l/ratiok);
386:         if (l_c < l_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
387:           l_start %d l_c %d l_start_ghost_c %d",l_start,l_c,l_start_ghost_c);
388:         if (j_c < j_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
389:           j_start %d j_c %d j_start_ghost_c %d",j_start,j_c,j_start_ghost_c);
390:         if (i_c < i_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
391:           i_start %d i_c %d i_start_ghost_c %d",i_start,i_c,i_start_ghost_c);

393:         /* 
394:          Only include those interpolation points that are truly 
395:          nonzero. Note this is very important for final grid lines
396:          in x and y directions; since they have no right/top neighbors
397:         */
398:         nc       = 0;
399:         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));
400:         cols[nc++] = idx_c[col]/dof;
401:         if (i_c*ratioi != i) {
402:           cols[nc++] = idx_c[col+dof]/dof;
403:         }
404:         if (j_c*ratioj != j) {
405:           cols[nc++] = idx_c[col+m_ghost_c*dof]/dof;
406:         }
407:         if (l_c*ratiok != l) {
408:           cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
409:         }
410:         if (j_c*ratioj != j && i_c*ratioi != i) {
411:           cols[nc++] = idx_c[col+(m_ghost_c+1)*dof]/dof;
412:         }
413:         if (j_c*ratioj != j && l_c*ratiok != l) {
414:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
415:         }
416:         if (i_c*ratioi != i && l_c*ratiok != l) {
417:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
418:         }
419:         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
420:           cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
421:         }
422:         MatPreallocateSet(row,nc,cols,dnz,onz);
423:       }
424:     }
425:   }
426:   MatCreate(dac->comm,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz,&mat);
427:   MatSetType(mat,MATAIJ);
428:   MatSeqAIJSetPreallocation(mat,0,dnz);
429:   MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
430:   MatPreallocateFinalize(dnz,onz);
431:   if (!DAXPeriodic(pt) && !DAYPeriodic(pt) && !DAZPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}

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

440:         i_c = (i/ratioi);
441:         j_c = (j/ratioj);
442:         l_c = (l/ratiok);

444:         /* 
445:            Only include those interpolation points that are truly 
446:            nonzero. Note this is very important for final grid lines
447:            in x and y directions; since they have no right/top neighbors
448:         */
449:         x  = ((double)(i - i_c*ratioi))/((double)ratioi);
450:         y  = ((double)(j - j_c*ratioj))/((double)ratioj);
451:         z  = ((double)(l - l_c*ratiok))/((double)ratiok);
452:         /* printf("i j l %d %d %d %g %g %g\n",i,j,l,x,y,z); */
453:         nc = 0;
454:         /* one left and below; or we are right on it */
455:         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));

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

460:         if (i_c*ratioi != i) {
461:           cols[nc] = idx_c[col+dof]/dof;
462:           v[nc++]  = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
463:         }

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

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

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

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

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

490:         if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
491:           cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
492:           v[nc++]  = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
493:         }
494:         MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
495:       }
496:     }
497:   }
498:   MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
499:   MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);

501:   MatCreateMAIJ(mat,dof,A);
502:   MatDestroy(mat);
503:   PetscLogFlops(13*m_f*n_f);
504:   return(0);
505: }

509: /*@C
510:    DAGetInterpolation - Gets an interpolation matrix that maps between 
511:    grids associated with two DAs.

513:    Collective on DA

515:    Input Parameters:
516: +  dac - the coarse grid DA
517: -  daf - the fine grid DA

519:    Output Parameters:
520: +  A - the interpolation matrix
521: -  scale - a scaling vector used to scale the coarse grid restricted vector before applying the 
522:            grid function or grid Jacobian to it.

524:    Level: intermediate

526: .keywords: interpolation, restriction, multigrid 

528: .seealso: DARefine(), DAGetInjection()
529: @*/
530: int DAGetInterpolation(DA dac,DA daf,Mat *A,Vec *scale)
531: {
532:   int            ierr,dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
533:   DAPeriodicType wrapc,wrapf;
534:   DAStencilType  stc,stf;


542:   DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
543:   DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
544:   if (dimc != dimf) SETERRQ2(1,"Dimensions of DA do not match %d %d",dimc,dimf);
545:   /* if (mc != mf) SETERRQ2(1,"Processor dimensions of DA in X %d %d do not match",mc,mf);
546:      if (nc != nf) SETERRQ2(1,"Processor dimensions of DA in Y %d %d do not match",nc,nf);
547:      if (pc != pf) SETERRQ2(1,"Processor dimensions of DA in Z %d %d do not match",pc,pf); */
548:   if (dofc != doff) SETERRQ2(1,"DOF of DA do not match %d %d",dofc,doff);
549:   if (sc != sf) SETERRQ2(1,"Stencil width of DA do not match %d %d",sc,sf);
550:   if (wrapc != wrapf) SETERRQ(1,"Periodic type different in two DAs");
551:   if (stc != stf) SETERRQ(1,"Stencil type different in two DAs");
552:   if (Mc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in x direction");
553:   if (dimc > 1 && Nc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in y direction");
554:   if (dimc > 2 && Pc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in z direction");

556:   if (dac->interptype == DA_Q1){
557:     if (dimc == 1){
558:       DAGetInterpolation_1D_Q1(dac,daf,A);
559:     } else if (dimc == 2){
560:       DAGetInterpolation_2D_Q1(dac,daf,A);
561:     } else if (dimc == 3){
562:       DAGetInterpolation_3D_Q1(dac,daf,A);
563:     } else {
564:       SETERRQ2(1,"No support for this DA dimension %d for interpolation type %d",dimc,dac->interptype);
565:     }
566:   } else if (dac->interptype == DA_Q0){
567:     if (dimc == 1){
568:       DAGetInterpolation_1D_Q0(dac,daf,A);
569:     } else {
570:       SETERRQ2(1,"No support for this DA dimension %d for interpolation type %d",dimc,dac->interptype);
571:     }
572:   }
573:   if (scale) {
574:     DMGetInterpolationScale((DM)dac,(DM)daf,*A,scale);
575:   }
576:   return(0);
577: }

581: int DAGetInjection_2D(DA dac,DA daf,VecScatter *inject)
582: {
583:   int            ierr,i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
584:   int            m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c;
585:   int            row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
586:   int            i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
587:   int            *cols;
588:   DAPeriodicType pt;
589:   Vec            vecf,vecc;
590:   IS             isf;


594:   DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
595:   DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
596:   if (DAXPeriodic(pt)){
597:     ratioi = mx/Mx;
598:     if (ratioi*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx  must be integer: mx %d Mx %d",mx,Mx);
599:   } else {
600:     ratioi = (mx-1)/(Mx-1);
601:     if (ratioi*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
602:   }
603:   if (DAYPeriodic(pt)){
604:     ratioj = my/My;
605:     if (ratioj*My != my) SETERRQ2(1,"Ratio between levels: my/My  must be integer: my %d My %d",my,My);
606:   } else {
607:     ratioj = (my-1)/(My-1);
608:     if (ratioj*(My-1) != my-1) SETERRQ2(1,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %d My %d",my,My);
609:   }


612:   DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
613:   DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
614:   DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);

616:   DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
617:   DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
618:   DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);


621:   /* loop over local fine grid nodes setting interpolation for those*/
622:   nc = 0;
623:   PetscMalloc(n_f*m_f*sizeof(int),&cols);
624:   for (j=j_start; j<j_start+n_f; j++) {
625:     for (i=i_start; i<i_start+m_f; i++) {

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

630:       if (i_c*ratioi == i && j_c*ratioj == j) {
631:         /* convert to local "natural" numbering and then to PETSc global numbering */
632:         row    = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
633:         cols[nc++] = row;
634:       }
635:     }
636:   }

638:   ISCreateBlock(daf->comm,dof,nc,cols,&isf);
639:   DAGetGlobalVector(dac,&vecc);
640:   DAGetGlobalVector(daf,&vecf);
641:   VecScatterCreate(vecf,isf,vecc,PETSC_NULL,inject);
642:   DARestoreGlobalVector(dac,&vecc);
643:   DARestoreGlobalVector(daf,&vecf);
644:   ISDestroy(isf);
645:   PetscFree(cols);
646:   return(0);
647: }

651: /*@C
652:    DAGetInjection - Gets an injection matrix that maps between 
653:    grids associated with two DAs.

655:    Collective on DA

657:    Input Parameters:
658: +  dac - the coarse grid DA
659: -  daf - the fine grid DA

661:    Output Parameters:
662: .  inject - the injection scatter

664:    Level: intermediate

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

668: .seealso: DARefine(), DAGetInterpolation()
669: @*/
670: int DAGetInjection(DA dac,DA daf,VecScatter *inject)
671: {
672:   int            ierr,dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
673:   DAPeriodicType wrapc,wrapf;
674:   DAStencilType  stc,stf;


681:   DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
682:   DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
683:   if (dimc != dimf) SETERRQ2(1,"Dimensions of DA do not match %d %d",dimc,dimf);
684:   /* if (mc != mf) SETERRQ2(1,"Processor dimensions of DA in X %d %d do not match",mc,mf);
685:      if (nc != nf) SETERRQ2(1,"Processor dimensions of DA in Y %d %d do not match",nc,nf);
686:      if (pc != pf) SETERRQ2(1,"Processor dimensions of DA in Z %d %d do not match",pc,pf); */
687:   if (dofc != doff) SETERRQ2(1,"DOF of DA do not match %d %d",dofc,doff);
688:   if (sc != sf) SETERRQ2(1,"Stencil width of DA do not match %d %d",sc,sf);
689:   if (wrapc != wrapf) SETERRQ(1,"Periodic type different in two DAs");
690:   if (stc != stf) SETERRQ(1,"Stencil type different in two DAs");
691:   if (Mc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in x direction");
692:   if (dimc > 1 && Nc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in y direction");
693:   if (dimc > 2 && Pc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in z direction");

695:   if (dimc == 2){
696:     DAGetInjection_2D(dac,daf,inject);
697:   } else {
698:     SETERRQ1(1,"No support for this DA dimension %d",dimc);
699:   }
700:   return(0);
701: }