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: }