Actual source code: dainterp.c
1: #define PETSCDM_DLL
3: /*
4: Code for interpolating between grids represented by DAs
5: */
7: #include private/daimpl.h
8: #include petscmg.h
12: /*@
13: DMGetInterpolationScale - Forms L = R*1/diag(R*1) - L.*v is like a coarse grid average of the
14: nearby fine grid points.
16: Input Parameters:
17: + dac - DM that defines a coarse mesh
18: . daf - DM that defines a fine mesh
19: - mat - the restriction (or interpolation operator) from fine to coarse
21: Output Parameter:
22: . scale - the scaled vector
24: Level: developer
26: .seealso: DMGetInterpolation()
28: @*/
29: PetscErrorCode DMGetInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
30: {
32: Vec fine;
33: PetscScalar one = 1.0;
36: DMCreateGlobalVector(daf,&fine);
37: DMCreateGlobalVector(dac,scale);
38: VecSet(fine,one);
39: MatRestrict(mat,fine,*scale);
40: VecDestroy(fine);
41: VecReciprocal(*scale);
42: return(0);
43: }
47: PetscErrorCode DAGetInterpolation_1D_Q1(DA dac,DA daf,Mat *A)
48: {
50: PetscInt i,i_start,m_f,Mx,*idx_f;
51: PetscInt m_ghost,*idx_c,m_ghost_c;
52: PetscInt row,col,i_start_ghost,mx,m_c,nc,ratio;
53: PetscInt i_c,i_start_c,i_start_ghost_c,cols[2],dof;
54: PetscScalar v[2],x,*coors = 0,*ccoors;
55: Mat mat;
56: DAPeriodicType pt;
57: Vec vcoors,cvcoors;
60: DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
61: DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
62: if (pt == DA_XPERIODIC) {
63: ratio = mx/Mx;
64: if (ratio*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx must be integer: mx %D Mx %D",mx,Mx);
65: } else {
66: ratio = (mx-1)/(Mx-1);
67: if (ratio*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
68: }
70: DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
71: DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
72: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
74: DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
75: DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
76: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
78: /* create interpolation matrix */
79: MatCreate(((PetscObject)dac)->comm,&mat);
80: MatSetSizes(mat,m_f,m_c,mx,Mx);
81: MatSetType(mat,MATAIJ);
82: MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
83: MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);
85: DAGetCoordinates(daf,&vcoors);
86: if (vcoors) {
87: DAGetGhostedCoordinates(dac,&cvcoors);
88: DAVecGetArray(daf->da_coordinates,vcoors,&coors);
89: DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
90: }
91: /* loop over local fine grid nodes setting interpolation for those*/
92: for (i=i_start; i<i_start+m_f; i++) {
93: /* convert to local "natural" numbering and then to PETSc global numbering */
94: row = idx_f[dof*(i-i_start_ghost)]/dof;
96: i_c = (i/ratio); /* coarse grid node to left of fine grid node */
97: if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
98: i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
100: /*
101: Only include those interpolation points that are truly
102: nonzero. Note this is very important for final grid lines
103: in x direction; since they have no right neighbor
104: */
105: if (coors) {
106: x = (coors[i] - ccoors[i_c]);
107: /* only access the next coors point if we know there is one */
108: /* note this is dangerous because x may not exactly equal ZERO */
109: if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[i_c+1] - ccoors[i_c]);
110: } else {
111: x = ((double)(i - i_c*ratio))/((double)ratio);
112: }
113: nc = 0;
114: /* one left and below; or we are right on it */
115: col = dof*(i_c-i_start_ghost_c);
116: cols[nc] = idx_c[col]/dof;
117: v[nc++] = - x + 1.0;
118: /* one right? */
119: if (i_c*ratio != i) {
120: cols[nc] = idx_c[col+dof]/dof;
121: v[nc++] = x;
122: }
123: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
124: }
125: if (vcoors) {
126: DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
127: DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
128: VecDestroy(cvcoors);
129: VecDestroy(vcoors);
130: }
131: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
132: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
133: MatCreateMAIJ(mat,dof,A);
134: MatDestroy(mat);
135: PetscLogFlops(5.0*m_f);
136: return(0);
137: }
141: PetscErrorCode DAGetInterpolation_1D_Q0(DA dac,DA daf,Mat *A)
142: {
144: PetscInt i,i_start,m_f,Mx,*idx_f;
145: PetscInt m_ghost,*idx_c,m_ghost_c;
146: PetscInt row,col,i_start_ghost,mx,m_c,nc,ratio;
147: PetscInt i_c,i_start_c,i_start_ghost_c,cols[2],dof;
148: PetscScalar v[2],x;
149: Mat mat;
150: DAPeriodicType pt;
153: DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
154: DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
155: if (pt == DA_XPERIODIC) {
156: ratio = mx/Mx;
157: if (ratio*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx must be integer: mx %D Mx %D",mx,Mx);
158: } else {
159: ratio = (mx-1)/(Mx-1);
160: if (ratio*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
161: }
163: DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
164: DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
165: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
167: DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
168: DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
169: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
171: /* create interpolation matrix */
172: MatCreate(((PetscObject)dac)->comm,&mat);
173: MatSetSizes(mat,m_f,m_c,mx,Mx);
174: MatSetType(mat,MATAIJ);
175: MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
176: MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);
178: /* loop over local fine grid nodes setting interpolation for those*/
179: for (i=i_start; i<i_start+m_f; i++) {
180: /* convert to local "natural" numbering and then to PETSc global numbering */
181: row = idx_f[dof*(i-i_start_ghost)]/dof;
183: i_c = (i/ratio); /* coarse grid node to left of fine grid node */
185: /*
186: Only include those interpolation points that are truly
187: nonzero. Note this is very important for final grid lines
188: in x direction; since they have no right neighbor
189: */
190: x = ((double)(i - i_c*ratio))/((double)ratio);
191: nc = 0;
192: /* one left and below; or we are right on it */
193: col = dof*(i_c-i_start_ghost_c);
194: cols[nc] = idx_c[col]/dof;
195: v[nc++] = - x + 1.0;
196: /* one right? */
197: if (i_c*ratio != i) {
198: cols[nc] = idx_c[col+dof]/dof;
199: v[nc++] = x;
200: }
201: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
202: }
203: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
204: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
205: MatCreateMAIJ(mat,dof,A);
206: MatDestroy(mat);
207: PetscLogFlops(5.0*m_f);
208: return(0);
209: }
213: PetscErrorCode DAGetInterpolation_2D_Q1(DA dac,DA daf,Mat *A)
214: {
216: PetscInt i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
217: PetscInt m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
218: PetscInt row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
219: PetscInt i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c,col_shift,col_scale;
220: PetscMPIInt size_c,size_f,rank_f;
221: PetscScalar v[4],x,y;
222: Mat mat;
223: DAPeriodicType pt;
224: DACoor2d **coors = 0,**ccoors;
225: Vec vcoors,cvcoors;
228: DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
229: DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
230: if (DAXPeriodic(pt)){
231: ratioi = mx/Mx;
232: if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx must be integer: mx %D Mx %D",mx,Mx);
233: } else {
234: ratioi = (mx-1)/(Mx-1);
235: if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
236: }
237: if (DAYPeriodic(pt)){
238: ratioj = my/My;
239: if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My must be integer: my %D My %D",my,My);
240: } else {
241: ratioj = (my-1)/(My-1);
242: if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
243: }
246: DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
247: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
248: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
250: DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
251: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
252: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
254: /*
255: Used for handling a coarse DA that lives on 1/4 the processors of the fine DA.
256: The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
257: processors). It's effective length is hence 4 times its normal length, this is
258: why the col_scale is multiplied by the interpolation matrix column sizes.
259: sol_shift allows each set of 1/4 processors do its own interpolation using ITS
260: copy of the coarse vector. A bit of a hack but you do better.
262: In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
263: */
264: MPI_Comm_size(((PetscObject)dac)->comm,&size_c);
265: MPI_Comm_size(((PetscObject)daf)->comm,&size_f);
266: MPI_Comm_rank(((PetscObject)daf)->comm,&rank_f);
267: col_scale = size_f/size_c;
268: col_shift = Mx*My*(rank_f/size_c);
270: MatPreallocateInitialize(((PetscObject)daf)->comm,m_f*n_f,col_scale*m_c*n_c,dnz,onz);
271: for (j=j_start; j<j_start+n_f; j++) {
272: for (i=i_start; i<i_start+m_f; i++) {
273: /* convert to local "natural" numbering and then to PETSc global numbering */
274: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
276: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
277: j_c = (j/ratioj); /* coarse grid node below fine grid node */
279: if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
280: j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
281: if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
282: i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
284: /*
285: Only include those interpolation points that are truly
286: nonzero. Note this is very important for final grid lines
287: in x and y directions; since they have no right/top neighbors
288: */
289: nc = 0;
290: /* one left and below; or we are right on it */
291: col = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
292: cols[nc++] = col_shift + idx_c[col]/dof;
293: /* one right and below */
294: if (i_c*ratioi != i) {
295: cols[nc++] = col_shift + idx_c[col+dof]/dof;
296: }
297: /* one left and above */
298: if (j_c*ratioj != j) {
299: cols[nc++] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
300: }
301: /* one right and above */
302: if (j_c*ratioi != j && i_c*ratioj != i) {
303: cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
304: }
305: MatPreallocateSet(row,nc,cols,dnz,onz);
306: }
307: }
308: MatCreate(((PetscObject)daf)->comm,&mat);
309: MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);
310: MatSetType(mat,MATAIJ);
311: MatSeqAIJSetPreallocation(mat,0,dnz);
312: MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
313: MatPreallocateFinalize(dnz,onz);
315: DAGetCoordinates(daf,&vcoors);
316: if (vcoors) {
317: DAGetGhostedCoordinates(dac,&cvcoors);
318: DAVecGetArray(daf->da_coordinates,vcoors,&coors);
319: DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
320: }
322: /* loop over local fine grid nodes setting interpolation for those*/
323: for (j=j_start; j<j_start+n_f; j++) {
324: for (i=i_start; i<i_start+m_f; i++) {
325: /* convert to local "natural" numbering and then to PETSc global numbering */
326: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
328: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
329: j_c = (j/ratioj); /* coarse grid node below fine grid node */
331: /*
332: Only include those interpolation points that are truly
333: nonzero. Note this is very important for final grid lines
334: in x and y directions; since they have no right/top neighbors
335: */
336: if (coors) {
337: /* only access the next coors point if we know there is one */
338: /* note this is dangerous because x may not exactly equal ZERO */
339: x = (coors[j][i].x - ccoors[j_c][i_c].x);
340: if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[j_c][i_c+1].x - ccoors[j_c][i_c].x);
341: y = (coors[j][i].y - ccoors[j_c][i_c].y);
342: if (PetscAbsScalar(y) != 0.0) y = y/(ccoors[j_c+1][i_c].y - ccoors[j_c][i_c].y);
343: } else {
344: x = ((double)(i - i_c*ratioi))/((double)ratioi);
345: y = ((double)(j - j_c*ratioj))/((double)ratioj);
346: }
347: nc = 0;
348: /* one left and below; or we are right on it */
349: col = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
350: cols[nc] = col_shift + idx_c[col]/dof;
351: v[nc++] = x*y - x - y + 1.0;
352: /* one right and below */
353: if (i_c*ratioi != i) {
354: cols[nc] = col_shift + idx_c[col+dof]/dof;
355: v[nc++] = -x*y + x;
356: }
357: /* one left and above */
358: if (j_c*ratioj != j) {
359: cols[nc] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
360: v[nc++] = -x*y + y;
361: }
362: /* one right and above */
363: if (j_c*ratioj != j && i_c*ratioi != i) {
364: cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
365: v[nc++] = x*y;
366: }
367: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
368: }
369: }
370: if (vcoors) {
371: DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
372: DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
373: VecDestroy(cvcoors);
374: VecDestroy(vcoors);
375: }
376: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
377: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
378: MatCreateMAIJ(mat,dof,A);
379: MatDestroy(mat);
380: PetscLogFlops(13.0*m_f*n_f);
381: return(0);
382: }
384: /*
385: Contributed by Andrei Draganescu <aidraga@sandia.gov>
386: */
389: PetscErrorCode DAGetInterpolation_2D_Q0(DA dac,DA daf,Mat *A)
390: {
392: PetscInt i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
393: PetscInt m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
394: PetscInt row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
395: PetscInt i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c,col_shift,col_scale;
396: PetscMPIInt size_c,size_f,rank_f;
397: PetscScalar v[4];
398: Mat mat;
399: DAPeriodicType pt;
402: DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
403: DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
404: if (DAXPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in x");
405: if (DAYPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in y");
406: ratioi = mx/Mx;
407: ratioj = my/My;
408: if (ratioi*Mx != mx) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
409: if (ratioj*My != my) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
410: if (ratioi != 2) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 2");
411: if (ratioj != 2) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 2");
413: DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
414: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
415: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
417: DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
418: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
419: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
421: /*
422: Used for handling a coarse DA that lives on 1/4 the processors of the fine DA.
423: The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
424: processors). It's effective length is hence 4 times its normal length, this is
425: why the col_scale is multiplied by the interpolation matrix column sizes.
426: sol_shift allows each set of 1/4 processors do its own interpolation using ITS
427: copy of the coarse vector. A bit of a hack but you do better.
429: In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
430: */
431: MPI_Comm_size(((PetscObject)dac)->comm,&size_c);
432: MPI_Comm_size(((PetscObject)daf)->comm,&size_f);
433: MPI_Comm_rank(((PetscObject)daf)->comm,&rank_f);
434: col_scale = size_f/size_c;
435: col_shift = Mx*My*(rank_f/size_c);
437: MatPreallocateInitialize(((PetscObject)daf)->comm,m_f*n_f,col_scale*m_c*n_c,dnz,onz);
438: for (j=j_start; j<j_start+n_f; j++) {
439: for (i=i_start; i<i_start+m_f; i++) {
440: /* convert to local "natural" numbering and then to PETSc global numbering */
441: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
443: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
444: j_c = (j/ratioj); /* coarse grid node below fine grid node */
446: if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
447: j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
448: if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
449: i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
451: /*
452: Only include those interpolation points that are truly
453: nonzero. Note this is very important for final grid lines
454: in x and y directions; since they have no right/top neighbors
455: */
456: nc = 0;
457: /* one left and below; or we are right on it */
458: col = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
459: cols[nc++] = col_shift + idx_c[col]/dof;
460: MatPreallocateSet(row,nc,cols,dnz,onz);
461: }
462: }
463: MatCreate(((PetscObject)daf)->comm,&mat);
464: MatSetSizes(mat,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My);
465: MatSetType(mat,MATAIJ);
466: MatSeqAIJSetPreallocation(mat,0,dnz);
467: MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
468: MatPreallocateFinalize(dnz,onz);
470: /* loop over local fine grid nodes setting interpolation for those*/
471: for (j=j_start; j<j_start+n_f; j++) {
472: for (i=i_start; i<i_start+m_f; i++) {
473: /* convert to local "natural" numbering and then to PETSc global numbering */
474: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
476: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
477: j_c = (j/ratioj); /* coarse grid node below fine grid node */
478: nc = 0;
479: /* one left and below; or we are right on it */
480: col = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
481: cols[nc] = col_shift + idx_c[col]/dof;
482: v[nc++] = 1.0;
483:
484: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
485: }
486: }
487: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
488: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
489: MatCreateMAIJ(mat,dof,A);
490: MatDestroy(mat);
491: PetscLogFlops(13.0*m_f*n_f);
492: return(0);
493: }
495: /*
496: Contributed by Jianming Yang <jianming-yang@uiowa.edu>
497: */
500: PetscErrorCode DAGetInterpolation_3D_Q0(DA dac,DA daf,Mat *A)
501: {
503: PetscInt i,j,l,i_start,j_start,l_start,m_f,n_f,p_f,Mx,My,Mz,*idx_f,dof;
504: PetscInt m_ghost,n_ghost,p_ghost,*idx_c,m_ghost_c,n_ghost_c,p_ghost_c,nc,*dnz,*onz;
505: PetscInt row,col,i_start_ghost,j_start_ghost,l_start_ghost,cols[8],mx,m_c,my,n_c,mz,p_c,ratioi,ratioj,ratiol;
506: PetscInt i_c,j_c,l_c,i_start_c,j_start_c,l_start_c,i_start_ghost_c,j_start_ghost_c,l_start_ghost_c,col_shift,col_scale;
507: PetscMPIInt size_c,size_f,rank_f;
508: PetscScalar v[8];
509: Mat mat;
510: DAPeriodicType pt;
513: DAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&pt,0);
514: DAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0);
515: if (DAXPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in x");
516: if (DAYPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in y");
517: if (DAZPeriodic(pt)) SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot handle periodic grid in z");
518: ratioi = mx/Mx;
519: ratioj = my/My;
520: ratiol = mz/Mz;
521: if (ratioi*Mx != mx) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in x");
522: if (ratioj*My != my) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in y");
523: if (ratiol*Mz != mz) SETERRQ(PETSC_ERR_ARG_WRONG,"Fine grid points must be multiple of coarse grid points in z");
524: if (ratioi != 2 && ratioi != 1) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in x must be 1 or 2");
525: if (ratioj != 2 && ratioj != 1) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in y must be 1 or 2");
526: if (ratiol != 2 && ratiol != 1) SETERRQ(PETSC_ERR_ARG_WRONG,"Coarsening factor in z must be 1 or 2");
528: DAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
529: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
530: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
532: DAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
533: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
534: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
535: /*
536: Used for handling a coarse DA that lives on 1/4 the processors of the fine DA.
537: The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
538: processors). It's effective length is hence 4 times its normal length, this is
539: why the col_scale is multiplied by the interpolation matrix column sizes.
540: sol_shift allows each set of 1/4 processors do its own interpolation using ITS
541: copy of the coarse vector. A bit of a hack but you do better.
543: In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
544: */
545: MPI_Comm_size(((PetscObject)dac)->comm,&size_c);
546: MPI_Comm_size(((PetscObject)daf)->comm,&size_f);
547: MPI_Comm_rank(((PetscObject)daf)->comm,&rank_f);
548: col_scale = size_f/size_c;
549: col_shift = Mx*My*Mz*(rank_f/size_c);
551: MatPreallocateInitialize(((PetscObject)daf)->comm,m_f*n_f*p_f,col_scale*m_c*n_c*p_c,dnz,onz);
552: for (l=l_start; l<l_start+p_f; l++) {
553: for (j=j_start; j<j_start+n_f; j++) {
554: for (i=i_start; i<i_start+m_f; i++) {
555: /* convert to local "natural" numbering and then to PETSc global numbering */
556: row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
558: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
559: j_c = (j/ratioj); /* coarse grid node below fine grid node */
560: l_c = (l/ratiol);
562: if (l_c < l_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
563: l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
564: if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
565: j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
566: if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
567: i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
569: /*
570: Only include those interpolation points that are truly
571: nonzero. Note this is very important for final grid lines
572: in x and y directions; since they have no right/top neighbors
573: */
574: nc = 0;
575: /* one left and below; or we are right on it */
576: col = dof*(m_ghost_c*n_ghost_c*(l_c-l_start_ghost_c) + m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
577: cols[nc++] = col_shift + idx_c[col]/dof;
578: MatPreallocateSet(row,nc,cols,dnz,onz);
579: }
580: }
581: }
582: MatCreate(((PetscObject)daf)->comm,&mat);
583: MatSetSizes(mat,m_f*n_f*p_f,col_scale*m_c*n_c*p_c,mx*my*mz,col_scale*Mx*My*Mz);
584: MatSetType(mat,MATAIJ);
585: MatSeqAIJSetPreallocation(mat,0,dnz);
586: MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
587: MatPreallocateFinalize(dnz,onz);
589: /* loop over local fine grid nodes setting interpolation for those*/
590: for (l=l_start; l<l_start+p_f; l++) {
591: for (j=j_start; j<j_start+n_f; j++) {
592: for (i=i_start; i<i_start+m_f; i++) {
593: /* convert to local "natural" numbering and then to PETSc global numbering */
594: row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
595:
596: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
597: j_c = (j/ratioj); /* coarse grid node below fine grid node */
598: l_c = (l/ratiol);
599: nc = 0;
600: /* one left and below; or we are right on it */
601: col = dof*(m_ghost_c*n_ghost_c*(l_c-l_start_ghost_c) + m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
602: cols[nc] = col_shift + idx_c[col]/dof;
603: v[nc++] = 1.0;
604:
605: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
606: }
607: }
608: }
609: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
610: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
611: MatCreateMAIJ(mat,dof,A);
612: MatDestroy(mat);
613: PetscLogFlops(13.0*m_f*n_f*p_f);
614: return(0);
615: }
619: PetscErrorCode DAGetInterpolation_3D_Q1(DA dac,DA daf,Mat *A)
620: {
622: PetscInt i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof,l;
623: PetscInt m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,Mz,mz;
624: PetscInt row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
625: PetscInt i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
626: PetscInt l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
627: PetscInt l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
628: PetscScalar v[8],x,y,z;
629: Mat mat;
630: DAPeriodicType pt;
631: DACoor3d ***coors = 0,***ccoors;
632: Vec vcoors,cvcoors;
635: DAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&pt,0);
636: DAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0);
637: if (mx == Mx) {
638: ratioi = 1;
639: } else if (DAXPeriodic(pt)){
640: ratioi = mx/Mx;
641: if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx must be integer: mx %D Mx %D",mx,Mx);
642: } else {
643: ratioi = (mx-1)/(Mx-1);
644: if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
645: }
646: if (my == My) {
647: ratioj = 1;
648: } else if (DAYPeriodic(pt)){
649: ratioj = my/My;
650: if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My must be integer: my %D My %D",my,My);
651: } else {
652: ratioj = (my-1)/(My-1);
653: if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
654: }
655: if (mz == Mz) {
656: ratiok = 1;
657: } else if (DAZPeriodic(pt)){
658: ratiok = mz/Mz;
659: if (ratiok*Mz != mz) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mz/Mz must be integer: mz %D Mz %D",mz,Mz);
660: } else {
661: ratiok = (mz-1)/(Mz-1);
662: if (ratiok*(Mz-1) != mz-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %D Mz %D",mz,Mz);
663: }
665: DAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
666: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
667: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
669: DAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
670: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
671: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
673: /* create interpolation matrix, determining exact preallocation */
674: MatPreallocateInitialize(((PetscObject)dac)->comm,m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);
675: /* loop over local fine grid nodes counting interpolating points */
676: for (l=l_start; l<l_start+p_f; l++) {
677: for (j=j_start; j<j_start+n_f; j++) {
678: for (i=i_start; i<i_start+m_f; i++) {
679: /* convert to local "natural" numbering and then to PETSc global numbering */
680: row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
681: i_c = (i/ratioi);
682: j_c = (j/ratioj);
683: l_c = (l/ratiok);
684: if (l_c < l_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
685: l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
686: if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
687: j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
688: if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
689: i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
691: /*
692: Only include those interpolation points that are truly
693: nonzero. Note this is very important for final grid lines
694: in x and y directions; since they have no right/top neighbors
695: */
696: nc = 0;
697: col = dof*(m_ghost_c*n_ghost_c*(l_c-l_start_ghost_c) + m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
698: cols[nc++] = idx_c[col]/dof;
699: if (i_c*ratioi != i) {
700: cols[nc++] = idx_c[col+dof]/dof;
701: }
702: if (j_c*ratioj != j) {
703: cols[nc++] = idx_c[col+m_ghost_c*dof]/dof;
704: }
705: if (l_c*ratiok != l) {
706: cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
707: }
708: if (j_c*ratioj != j && i_c*ratioi != i) {
709: cols[nc++] = idx_c[col+(m_ghost_c+1)*dof]/dof;
710: }
711: if (j_c*ratioj != j && l_c*ratiok != l) {
712: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
713: }
714: if (i_c*ratioi != i && l_c*ratiok != l) {
715: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
716: }
717: if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
718: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
719: }
720: MatPreallocateSet(row,nc,cols,dnz,onz);
721: }
722: }
723: }
724: MatCreate(((PetscObject)dac)->comm,&mat);
725: MatSetSizes(mat,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz);
726: MatSetType(mat,MATAIJ);
727: MatSeqAIJSetPreallocation(mat,0,dnz);
728: MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
729: MatPreallocateFinalize(dnz,onz);
731: DAGetCoordinates(daf,&vcoors);
732: if (vcoors) {
733: DAGetGhostedCoordinates(dac,&cvcoors);
734: DAVecGetArray(daf->da_coordinates,vcoors,&coors);
735: DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
736: }
738: /* loop over local fine grid nodes setting interpolation for those*/
739: for (l=l_start; l<l_start+p_f; l++) {
740: for (j=j_start; j<j_start+n_f; j++) {
741: for (i=i_start; i<i_start+m_f; i++) {
742: /* convert to local "natural" numbering and then to PETSc global numbering */
743: row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
745: i_c = (i/ratioi);
746: j_c = (j/ratioj);
747: l_c = (l/ratiok);
749: /*
750: Only include those interpolation points that are truly
751: nonzero. Note this is very important for final grid lines
752: in x and y directions; since they have no right/top neighbors
753: */
754: if (coors) {
755: /* only access the next coors point if we know there is one */
756: /* note this is dangerous because x may not exactly equal ZERO */
757: x = (coors[l][j][i].x - ccoors[l_c][j_c][i_c].x);
758: if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[l_c][j_c][i_c+1].x - ccoors[l_c][j_c][i_c].x);
759: y = (coors[l][j][i].y - ccoors[l_c][j_c][i_c].y);
760: if (PetscAbsScalar(y) != 0.0) y = y/(ccoors[l_c][j_c+1][i_c].y - ccoors[l_c][j_c][i_c].y);
761: z = (coors[l][j][i].z - ccoors[l_c][j_c][i_c].z);
762: if (PetscAbsScalar(z) != 0.0) z = z/(ccoors[l_c+1][j_c][i_c].z - ccoors[l_c][j_c][i_c].z);
763: } else {
764: x = ((double)(i - i_c*ratioi))/((double)ratioi);
765: y = ((double)(j - j_c*ratioj))/((double)ratioj);
766: z = ((double)(l - l_c*ratiok))/((double)ratiok);
767: }
768: nc = 0;
769: /* one left and below; or we are right on it */
770: col = dof*(m_ghost_c*n_ghost_c*(l_c-l_start_ghost_c)+m_ghost_c*(j_c-j_start_ghost_c)+(i_c-i_start_ghost_c));
772: cols[nc] = idx_c[col]/dof;
773: v[nc++] = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
775: if (i_c*ratioi != i) {
776: cols[nc] = idx_c[col+dof]/dof;
777: v[nc++] = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
778: }
780: if (j_c*ratioj != j) {
781: cols[nc] = idx_c[col+m_ghost_c*dof]/dof;
782: v[nc++] = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
783: }
785: if (l_c*ratiok != l) {
786: cols[nc] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
787: v[nc++] = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
788: }
790: if (j_c*ratioj != j && i_c*ratioi != i) {
791: cols[nc] = idx_c[col+(m_ghost_c+1)*dof]/dof;
792: v[nc++] = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
793: }
795: if (j_c*ratioj != j && l_c*ratiok != l) {
796: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
797: v[nc++] = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
798: }
800: if (i_c*ratioi != i && l_c*ratiok != l) {
801: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
802: v[nc++] = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
803: }
805: if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
806: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
807: v[nc++] = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
808: }
809: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
810: }
811: }
812: }
813: if (vcoors) {
814: DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
815: DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
816: VecDestroy(cvcoors);
817: VecDestroy(vcoors);
818: }
819: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
820: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
822: MatCreateMAIJ(mat,dof,A);
823: MatDestroy(mat);
824: PetscLogFlops(13.0*m_f*n_f);
825: return(0);
826: }
830: /*@C
831: DAGetInterpolation - Gets an interpolation matrix that maps between
832: grids associated with two DAs.
834: Collective on DA
836: Input Parameters:
837: + dac - the coarse grid DA
838: - daf - the fine grid DA
840: Output Parameters:
841: + A - the interpolation matrix
842: - scale - a scaling vector used to scale the coarse grid restricted vector before applying the
843: grid function or grid Jacobian to it.
845: Level: intermediate
847: .keywords: interpolation, restriction, multigrid
849: .seealso: DARefine(), DAGetInjection()
850: @*/
851: PetscErrorCode DAGetInterpolation(DA dac,DA daf,Mat *A,Vec *scale)
852: {
854: PetscInt dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
855: DAPeriodicType wrapc,wrapf;
856: DAStencilType stc,stf;
864: DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
865: DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
866: if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
867: if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
868: if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
869: if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
870: if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");
871: if (Mc < 2 && Mf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
872: if (dimc > 1 && Nc < 2 && Nf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
873: if (dimc > 2 && Pc < 2 && Pf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");
875: if (dac->interptype == DA_Q1){
876: if (dimc == 1){
877: DAGetInterpolation_1D_Q1(dac,daf,A);
878: } else if (dimc == 2){
879: DAGetInterpolation_2D_Q1(dac,daf,A);
880: } else if (dimc == 3){
881: DAGetInterpolation_3D_Q1(dac,daf,A);
882: } else {
883: SETERRQ2(PETSC_ERR_SUP,"No support for this DA dimension %D for interpolation type %d",dimc,(int)dac->interptype);
884: }
885: } else if (dac->interptype == DA_Q0){
886: if (dimc == 1){
887: DAGetInterpolation_1D_Q0(dac,daf,A);
888: } else if (dimc == 2){
889: DAGetInterpolation_2D_Q0(dac,daf,A);
890: } else if (dimc == 3){
891: DAGetInterpolation_3D_Q0(dac,daf,A);
892: } else {
893: SETERRQ2(PETSC_ERR_SUP,"No support for this DA dimension %D for interpolation type %d",dimc,(int)dac->interptype);
894: }
895: }
896: if (scale) {
897: DMGetInterpolationScale((DM)dac,(DM)daf,*A,scale);
898: }
899: return(0);
900: }
904: PetscErrorCode DAGetInjection_2D(DA dac,DA daf,VecScatter *inject)
905: {
907: PetscInt i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
908: PetscInt m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c;
909: PetscInt row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
910: PetscInt i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
911: PetscInt *cols;
912: DAPeriodicType pt;
913: Vec vecf,vecc;
914: IS isf;
918: DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
919: DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
920: if (DAXPeriodic(pt)){
921: ratioi = mx/Mx;
922: if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx must be integer: mx %D Mx %D",mx,Mx);
923: } else {
924: ratioi = (mx-1)/(Mx-1);
925: if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
926: }
927: if (DAYPeriodic(pt)){
928: ratioj = my/My;
929: if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My must be integer: my %D My %D",my,My);
930: } else {
931: ratioj = (my-1)/(My-1);
932: if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
933: }
936: DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
937: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
938: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
940: DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
941: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
942: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
945: /* loop over local fine grid nodes setting interpolation for those*/
946: nc = 0;
947: PetscMalloc(n_f*m_f*sizeof(PetscInt),&cols);
948: for (j=j_start; j<j_start+n_f; j++) {
949: for (i=i_start; i<i_start+m_f; i++) {
951: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
952: j_c = (j/ratioj); /* coarse grid node below fine grid node */
954: if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
955: j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
956: if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
957: i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
959: if (i_c*ratioi == i && j_c*ratioj == j) {
960: /* convert to local "natural" numbering and then to PETSc global numbering */
961: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
962: cols[nc++] = row;
963: }
964: }
965: }
967: ISCreateBlock(((PetscObject)daf)->comm,dof,nc,cols,&isf);
968: DAGetGlobalVector(dac,&vecc);
969: DAGetGlobalVector(daf,&vecf);
970: VecScatterCreate(vecf,isf,vecc,PETSC_NULL,inject);
971: DARestoreGlobalVector(dac,&vecc);
972: DARestoreGlobalVector(daf,&vecf);
973: ISDestroy(isf);
974: PetscFree(cols);
975: return(0);
976: }
980: /*@
981: DAGetInjection - Gets an injection matrix that maps between
982: grids associated with two DAs.
984: Collective on DA
986: Input Parameters:
987: + dac - the coarse grid DA
988: - daf - the fine grid DA
990: Output Parameters:
991: . inject - the injection scatter
993: Level: intermediate
995: .keywords: interpolation, restriction, multigrid, injection
997: .seealso: DARefine(), DAGetInterpolation()
998: @*/
999: PetscErrorCode DAGetInjection(DA dac,DA daf,VecScatter *inject)
1000: {
1002: PetscInt dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1003: DAPeriodicType wrapc,wrapf;
1004: DAStencilType stc,stf;
1011: DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
1012: DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
1013: if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
1014: if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
1015: if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
1016: if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
1017: if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");
1018: if (Mc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
1019: if (dimc > 1 && Nc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
1020: if (dimc > 2 && Pc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");
1022: if (dimc == 2){
1023: DAGetInjection_2D(dac,daf,inject);
1024: } else {
1025: SETERRQ1(PETSC_ERR_SUP,"No support for this DA dimension %D",dimc);
1026: }
1027: return(0);
1028: }
1032: /*@
1033: DAGetAggregates - Gets the aggregates that map between
1034: grids associated with two DAs.
1036: Collective on DA
1038: Input Parameters:
1039: + dac - the coarse grid DA
1040: - daf - the fine grid DA
1042: Output Parameters:
1043: . rest - the restriction matrix (transpose of the projection matrix)
1045: Level: intermediate
1047: .keywords: interpolation, restriction, multigrid
1049: .seealso: DARefine(), DAGetInjection(), DAGetInterpolation()
1050: @*/
1051: PetscErrorCode DAGetAggregates(DA dac,DA daf,Mat *rest)
1052: {
1054: PetscInt dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc;
1055: PetscInt dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
1056: DAPeriodicType wrapc,wrapf;
1057: DAStencilType stc,stf;
1058: /* PetscReal r_x, r_y, r_z; */
1060: PetscInt i,j,l;
1061: PetscInt i_start,j_start,l_start, m_f,n_f,p_f;
1062: PetscInt i_start_ghost,j_start_ghost,l_start_ghost,m_ghost,n_ghost,p_ghost;
1063: PetscInt *idx_f;
1064: PetscInt i_c,j_c,l_c;
1065: PetscInt i_start_c,j_start_c,l_start_c, m_c,n_c,p_c;
1066: PetscInt i_start_ghost_c,j_start_ghost_c,l_start_ghost_c,m_ghost_c,n_ghost_c,p_ghost_c;
1067: PetscInt *idx_c;
1068: PetscInt d;
1069: PetscInt a;
1070: PetscInt max_agg_size;
1071: PetscInt *fine_nodes;
1072: PetscScalar *one_vec;
1073: PetscInt fn_idx;
1080: DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
1081: DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
1082: if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
1083: if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
1084: if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
1085: if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
1086: if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");
1088: if( Mf < Mc ) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Mc %D, Mf %D", Mc, Mf);
1089: if( Nf < Nc ) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Nc %D, Nf %D", Nc, Nf);
1090: if( Pf < Pc ) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Coarse grid has more points than fine grid, Pc %D, Pf %D", Pc, Pf);
1092: DAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
1093: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
1094: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
1096: DAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
1097: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
1098: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
1100: /*
1101: Basic idea is as follows. Here's a 2D example, suppose r_x, r_y are the ratios
1102: for dimension 1 and 2 respectively.
1103: Let (i,j) be a coarse grid node. All the fine grid nodes between r_x*i and r_x*(i+1)
1104: and r_y*j and r_y*(j+1) will be grouped into the same coarse grid agregate.
1105: Each specific dof on the fine grid is mapped to one dof on the coarse grid.
1106: */
1108: max_agg_size = (Mf/Mc+1)*(Nf/Nc+1)*(Pf/Pc+1);
1110: /* create the matrix that will contain the restriction operator */
1111: MatCreateMPIAIJ( ((PetscObject)daf)->comm, m_c*n_c*p_c*dofc, m_f*n_f*p_f*doff, Mc*Nc*Pc*dofc, Mf*Nf*Pf*doff,
1112: max_agg_size, PETSC_NULL, max_agg_size, PETSC_NULL, rest);
1114: /* store nodes in the fine grid here */
1115: PetscMalloc2(max_agg_size,PetscScalar, &one_vec,max_agg_size,PetscInt, &fine_nodes);
1116: for(i=0; i<max_agg_size; i++) one_vec[i] = 1.0;
1117:
1118: /* loop over all coarse nodes */
1119: for (l_c=l_start_c; l_c<l_start_c+p_c; l_c++) {
1120: for (j_c=j_start_c; j_c<j_start_c+n_c; j_c++) {
1121: for (i_c=i_start_c; i_c<i_start_c+m_c; i_c++) {
1122: for(d=0; d<dofc; d++) {
1123: /* convert to local "natural" numbering and then to PETSc global numbering */
1124: a = idx_c[dofc*(m_ghost_c*n_ghost_c*(l_c-l_start_ghost_c) + m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c))] + d;
1126: fn_idx = 0;
1127: /* Corresponding fine points are all points (i_f, j_f, l_f) such that
1128: i_c*Mf/Mc <= i_f < (i_c+1)*Mf/Mc
1129: (same for other dimensions)
1130: */
1131: for (l=l_c*Pf/Pc; l<PetscMin((l_c+1)*Pf/Pc,Pf); l++) {
1132: for (j=j_c*Nf/Nc; j<PetscMin((j_c+1)*Nf/Nc,Nf); j++) {
1133: for (i=i_c*Mf/Mc; i<PetscMin((i_c+1)*Mf/Mc,Mf); i++) {
1134: fine_nodes[fn_idx] = idx_f[doff*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))] + d;
1135: fn_idx++;
1136: }
1137: }
1138: }
1139: /* add all these points to one aggregate */
1140: MatSetValues(*rest, 1, &a, fn_idx, fine_nodes, one_vec, INSERT_VALUES);
1141: }
1142: }
1143: }
1144: }
1145: PetscFree2(one_vec,fine_nodes);
1146: MatAssemblyBegin(*rest, MAT_FINAL_ASSEMBLY);
1147: MatAssemblyEnd(*rest, MAT_FINAL_ASSEMBLY);
1148: return(0);
1149: }