Actual source code: dainterp.c
1: /*
2: Code for interpolating between grids represented by DAs
3: */
5: #include src/dm/da/daimpl.h
6: #include petscmg.h
10: PetscErrorCode DMGetInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
11: {
13: Vec fine;
14: PetscScalar one = 1.0;
17: DMCreateGlobalVector(daf,&fine);
18: DMCreateGlobalVector(dac,scale);
19: VecSet(&one,fine);
20: MatRestrict(mat,fine,*scale);
21: VecDestroy(fine);
22: VecReciprocal(*scale);
23: return(0);
24: }
28: PetscErrorCode DAGetInterpolation_1D_Q1(DA dac,DA daf,Mat *A)
29: {
31: PetscInt i,i_start,m_f,Mx,*idx_f;
32: PetscInt m_ghost,*idx_c,m_ghost_c;
33: PetscInt row,col,i_start_ghost,mx,m_c,nc,ratio;
34: PetscInt i_c,i_start_c,i_start_ghost_c,cols[2],dof;
35: PetscScalar v[2],x,*coors = 0,*ccoors;
36: Mat mat;
37: DAPeriodicType pt;
38: Vec vcoors,cvcoors;
41: DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
42: DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
43: if (pt == DA_XPERIODIC) {
44: ratio = mx/Mx;
45: if (ratio*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx must be integer: mx %D Mx %D",mx,Mx);
46: } else {
47: ratio = (mx-1)/(Mx-1);
48: if (ratio*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
49: }
51: DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
52: DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
53: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
55: DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
56: DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
57: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
59: /* create interpolation matrix */
60: MatCreate(dac->comm,m_f,m_c,mx,Mx,&mat);
61: MatSetType(mat,MATAIJ);
62: MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
63: MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);
64: if (!DAXPeriodic(pt)){MatSetOption(mat,MAT_COLUMNS_SORTED);}
66: DAGetCoordinates(daf,&vcoors);
67: if (vcoors) {
68: DAGetGhostedCoordinates(dac,&cvcoors);
69: DAVecGetArray(daf->da_coordinates,vcoors,&coors);
70: DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
71: }
72: /* loop over local fine grid nodes setting interpolation for those*/
73: for (i=i_start; i<i_start+m_f; i++) {
74: /* convert to local "natural" numbering and then to PETSc global numbering */
75: row = idx_f[dof*(i-i_start_ghost)]/dof;
77: i_c = (i/ratio); /* coarse grid node to left of fine grid node */
78: if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
79: i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
81: /*
82: Only include those interpolation points that are truly
83: nonzero. Note this is very important for final grid lines
84: in x direction; since they have no right neighbor
85: */
86: if (coors) {
87: x = (coors[i] - ccoors[i_c]);
88: /* only access the next coors point if we know there is one */
89: /* note this is dangerous because x may not exactly equal ZERO */
90: if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[i_c+1] - ccoors[i_c]);
91: } else {
92: x = ((double)(i - i_c*ratio))/((double)ratio);
93: }
94: nc = 0;
95: /* one left and below; or we are right on it */
96: col = dof*(i_c-i_start_ghost_c);
97: cols[nc] = idx_c[col]/dof;
98: v[nc++] = - x + 1.0;
99: /* one right? */
100: if (i_c*ratio != i) {
101: cols[nc] = idx_c[col+dof]/dof;
102: v[nc++] = x;
103: }
104: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
105: }
106: if (vcoors) {
107: DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
108: DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
109: }
110: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
111: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
112: MatCreateMAIJ(mat,dof,A);
113: MatDestroy(mat);
114: PetscLogFlops(5*m_f);
115: return(0);
116: }
120: PetscErrorCode DAGetInterpolation_1D_Q0(DA dac,DA daf,Mat *A)
121: {
123: PetscInt i,i_start,m_f,Mx,*idx_f;
124: PetscInt m_ghost,*idx_c,m_ghost_c;
125: PetscInt row,col,i_start_ghost,mx,m_c,nc,ratio;
126: PetscInt i_c,i_start_c,i_start_ghost_c,cols[2],dof;
127: PetscScalar v[2],x;
128: Mat mat;
129: DAPeriodicType pt;
132: DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
133: DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
134: if (pt == DA_XPERIODIC) {
135: ratio = mx/Mx;
136: if (ratio*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx must be integer: mx %D Mx %D",mx,Mx);
137: } else {
138: ratio = (mx-1)/(Mx-1);
139: if (ratio*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
140: }
142: DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
143: DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
144: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
146: DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
147: DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
148: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
150: /* create interpolation matrix */
151: MatCreate(dac->comm,m_f,m_c,mx,Mx,&mat);
152: MatSetType(mat,MATAIJ);
153: MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
154: MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);
155: if (!DAXPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}
157: /* loop over local fine grid nodes setting interpolation for those*/
158: for (i=i_start; i<i_start+m_f; i++) {
159: /* convert to local "natural" numbering and then to PETSc global numbering */
160: row = idx_f[dof*(i-i_start_ghost)]/dof;
162: i_c = (i/ratio); /* coarse grid node to left of fine grid node */
164: /*
165: Only include those interpolation points that are truly
166: nonzero. Note this is very important for final grid lines
167: in x direction; since they have no right neighbor
168: */
169: x = ((double)(i - i_c*ratio))/((double)ratio);
170: nc = 0;
171: /* one left and below; or we are right on it */
172: col = dof*(i_c-i_start_ghost_c);
173: cols[nc] = idx_c[col]/dof;
174: v[nc++] = - x + 1.0;
175: /* one right? */
176: if (i_c*ratio != i) {
177: cols[nc] = idx_c[col+dof]/dof;
178: v[nc++] = x;
179: }
180: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
181: }
182: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
183: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
184: MatCreateMAIJ(mat,dof,A);
185: MatDestroy(mat);
186: PetscLogFlops(5*m_f);
187: return(0);
188: }
192: PetscErrorCode DAGetInterpolation_2D_Q1(DA dac,DA daf,Mat *A)
193: {
195: PetscInt i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
196: PetscInt m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
197: PetscInt row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
198: PetscInt i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c,col_shift,col_scale;
199: PetscMPIInt size_c,size_f,rank_f;
200: PetscScalar v[4],x,y;
201: Mat mat;
202: DAPeriodicType pt;
203: DACoor2d **coors = 0,**ccoors;
204: Vec vcoors,cvcoors;
207: DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
208: DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
209: if (DAXPeriodic(pt)){
210: ratioi = mx/Mx;
211: if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx must be integer: mx %D Mx %D",mx,Mx);
212: } else {
213: ratioi = (mx-1)/(Mx-1);
214: if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
215: }
216: if (DAYPeriodic(pt)){
217: ratioj = my/My;
218: if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My must be integer: my %D My %D",my,My);
219: } else {
220: ratioj = (my-1)/(My-1);
221: if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
222: }
225: DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
226: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
227: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
229: DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
230: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
231: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
233: /*
234: Used for handling a coarse DA that lives on 1/4 the processors of the fine DA.
235: The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
236: processors). It's effective length is hence 4 times its normal length, this is
237: why the col_scale is multiplied by the interpolation matrix column sizes.
238: sol_shift allows each set of 1/4 processors do its own interpolation using ITS
239: copy of the coarse vector. A bit of a hack but you do better.
241: In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
242: */
243: MPI_Comm_size(dac->comm,&size_c);
244: MPI_Comm_size(daf->comm,&size_f);
245: MPI_Comm_rank(daf->comm,&rank_f);
246: col_scale = size_f/size_c;
247: col_shift = Mx*My*(rank_f/size_c);
249: MatPreallocateInitialize(daf->comm,m_f*n_f,col_scale*m_c*n_c,dnz,onz);
250: for (j=j_start; j<j_start+n_f; j++) {
251: for (i=i_start; i<i_start+m_f; i++) {
252: /* convert to local "natural" numbering and then to PETSc global numbering */
253: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
255: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
256: j_c = (j/ratioj); /* coarse grid node below fine grid node */
258: if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
259: j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
260: if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
261: i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
263: /*
264: Only include those interpolation points that are truly
265: nonzero. Note this is very important for final grid lines
266: in x and y directions; since they have no right/top neighbors
267: */
268: nc = 0;
269: /* one left and below; or we are right on it */
270: col = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
271: cols[nc++] = col_shift + idx_c[col]/dof;
272: /* one right and below */
273: if (i_c*ratioi != i) {
274: cols[nc++] = col_shift + idx_c[col+dof]/dof;
275: }
276: /* one left and above */
277: if (j_c*ratioj != j) {
278: cols[nc++] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
279: }
280: /* one right and above */
281: if (j_c*ratioi != j && i_c*ratioj != i) {
282: cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
283: }
284: MatPreallocateSet(row,nc,cols,dnz,onz);
285: }
286: }
287: MatCreate(daf->comm,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My,&mat);
288: MatSetType(mat,MATAIJ);
289: MatSeqAIJSetPreallocation(mat,0,dnz);
290: MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
291: MatPreallocateFinalize(dnz,onz);
292: if (!DAXPeriodic(pt) && !DAYPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}
294: DAGetCoordinates(daf,&vcoors);
295: if (vcoors) {
296: DAGetGhostedCoordinates(dac,&cvcoors);
297: DAVecGetArray(daf->da_coordinates,vcoors,&coors);
298: DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
299: }
301: /* loop over local fine grid nodes setting interpolation for those*/
302: for (j=j_start; j<j_start+n_f; j++) {
303: for (i=i_start; i<i_start+m_f; i++) {
304: /* convert to local "natural" numbering and then to PETSc global numbering */
305: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
307: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
308: j_c = (j/ratioj); /* coarse grid node below fine grid node */
310: /*
311: Only include those interpolation points that are truly
312: nonzero. Note this is very important for final grid lines
313: in x and y directions; since they have no right/top neighbors
314: */
315: if (coors) {
316: /* only access the next coors point if we know there is one */
317: /* note this is dangerous because x may not exactly equal ZERO */
318: x = (coors[j][i].x - ccoors[j_c][i_c].x);
319: if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[j_c][i_c+1].x - ccoors[j_c][i_c].x);
320: y = (coors[j][i].y - ccoors[j_c][i_c].y);
321: if (PetscAbsScalar(y) != 0.0) y = y/(ccoors[j_c+1][i_c].y - ccoors[j_c][i_c].y);
322: } else {
323: x = ((double)(i - i_c*ratioi))/((double)ratioi);
324: y = ((double)(j - j_c*ratioj))/((double)ratioj);
325: }
326: nc = 0;
327: /* one left and below; or we are right on it */
328: col = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
329: cols[nc] = col_shift + idx_c[col]/dof;
330: v[nc++] = x*y - x - y + 1.0;
331: /* one right and below */
332: if (i_c*ratioi != i) {
333: cols[nc] = col_shift + idx_c[col+dof]/dof;
334: v[nc++] = -x*y + x;
335: }
336: /* one left and above */
337: if (j_c*ratioj != j) {
338: cols[nc] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
339: v[nc++] = -x*y + y;
340: }
341: /* one right and above */
342: if (j_c*ratioj != j && i_c*ratioi != i) {
343: cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
344: v[nc++] = x*y;
345: }
346: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
347: }
348: }
349: if (vcoors) {
350: DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
351: DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
352: }
353: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
354: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
355: MatCreateMAIJ(mat,dof,A);
356: MatDestroy(mat);
357: PetscLogFlops(13*m_f*n_f);
358: return(0);
359: }
362: /* dof degree of freedom per node, nonperiodic */
365: PetscErrorCode DAGetInterpolation_3D_Q1(DA dac,DA daf,Mat *A)
366: {
368: PetscInt i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof,l;
369: PetscInt m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,Mz,mz;
370: PetscInt row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
371: PetscInt i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
372: PetscInt l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
373: PetscInt l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
374: PetscScalar v[8],x,y,z;
375: Mat mat;
376: DAPeriodicType pt;
377: DACoor3d ***coors = 0,***ccoors;
378: Vec vcoors,cvcoors;
381: DAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&pt,0);
382: DAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0);
383: if (mx == My) {
384: ratioi = 1;
385: } else if (DAXPeriodic(pt)){
386: ratioi = mx/Mx;
387: if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx must be integer: mx %D Mx %D",mx,Mx);
388: } else {
389: ratioi = (mx-1)/(Mx-1);
390: if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
391: }
392: if (my == My) {
393: ratioj = 1;
394: } else if (DAYPeriodic(pt)){
395: ratioj = my/My;
396: if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My must be integer: my %D My %D",my,My);
397: } else {
398: ratioj = (my-1)/(My-1);
399: if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
400: }
401: if (mz == Mz) {
402: ratiok = 1;
403: } else if (DAZPeriodic(pt)){
404: ratiok = mz/Mz;
405: if (ratiok*Mz != mz) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mz/Mz must be integer: mz %D Mz %D",mz,Mz);
406: } else {
407: ratiok = (mz-1)/(Mz-1);
408: if (ratiok*(Mz-1) != mz-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %D Mz %D",mz,Mz);
409: }
411: DAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
412: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
413: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
415: DAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
416: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
417: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
419: /* create interpolation matrix, determining exact preallocation */
420: MatPreallocateInitialize(dac->comm,m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);
421: /* loop over local fine grid nodes counting interpolating points */
422: for (l=l_start; l<l_start+p_f; l++) {
423: for (j=j_start; j<j_start+n_f; j++) {
424: for (i=i_start; i<i_start+m_f; i++) {
425: /* convert to local "natural" numbering and then to PETSc global numbering */
426: row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
427: i_c = (i/ratioi);
428: j_c = (j/ratioj);
429: l_c = (l/ratiok);
430: if (l_c < l_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
431: l_start %D l_c %D l_start_ghost_c %D",l_start,l_c,l_start_ghost_c);
432: if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
433: j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
434: if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
435: i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
437: /*
438: Only include those interpolation points that are truly
439: nonzero. Note this is very important for final grid lines
440: in x and y directions; since they have no right/top neighbors
441: */
442: nc = 0;
443: col = dof*(m_ghost_c*n_ghost_c*(l_c-l_start_ghost_c) + m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
444: cols[nc++] = idx_c[col]/dof;
445: if (i_c*ratioi != i) {
446: cols[nc++] = idx_c[col+dof]/dof;
447: }
448: if (j_c*ratioj != j) {
449: cols[nc++] = idx_c[col+m_ghost_c*dof]/dof;
450: }
451: if (l_c*ratiok != l) {
452: cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
453: }
454: if (j_c*ratioj != j && i_c*ratioi != i) {
455: cols[nc++] = idx_c[col+(m_ghost_c+1)*dof]/dof;
456: }
457: if (j_c*ratioj != j && l_c*ratiok != l) {
458: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
459: }
460: if (i_c*ratioi != i && l_c*ratiok != l) {
461: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
462: }
463: if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
464: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
465: }
466: MatPreallocateSet(row,nc,cols,dnz,onz);
467: }
468: }
469: }
470: MatCreate(dac->comm,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz,&mat);
471: MatSetType(mat,MATAIJ);
472: MatSeqAIJSetPreallocation(mat,0,dnz);
473: MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
474: MatPreallocateFinalize(dnz,onz);
475: if (!DAXPeriodic(pt) && !DAYPeriodic(pt) && !DAZPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}
477: DAGetCoordinates(daf,&vcoors);
478: if (vcoors) {
479: DAGetGhostedCoordinates(dac,&cvcoors);
480: DAVecGetArray(daf->da_coordinates,vcoors,&coors);
481: DAVecGetArray(dac->da_coordinates,cvcoors,&ccoors);
482: }
484: /* loop over local fine grid nodes setting interpolation for those*/
485: for (l=l_start; l<l_start+p_f; l++) {
486: for (j=j_start; j<j_start+n_f; j++) {
487: for (i=i_start; i<i_start+m_f; i++) {
488: /* convert to local "natural" numbering and then to PETSc global numbering */
489: row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
491: i_c = (i/ratioi);
492: j_c = (j/ratioj);
493: l_c = (l/ratiok);
495: /*
496: Only include those interpolation points that are truly
497: nonzero. Note this is very important for final grid lines
498: in x and y directions; since they have no right/top neighbors
499: */
500: if (coors) {
501: /* only access the next coors point if we know there is one */
502: /* note this is dangerous because x may not exactly equal ZERO */
503: x = (coors[l][j][i].x - ccoors[l_c][j_c][i_c].x);
504: if (PetscAbsScalar(x) != 0.0) x = x/(ccoors[l_c][j_c][i_c+1].x - ccoors[l_c][j_c][i_c].x);
505: y = (coors[l][j][i].y - ccoors[l_c][j_c][i_c].y);
506: if (PetscAbsScalar(y) != 0.0) y = y/(ccoors[l_c][j_c+1][i_c].y - ccoors[l_c][j_c][i_c].y);
507: z = (coors[l][j][i].z - ccoors[l_c][j_c][i_c].z);
508: if (PetscAbsScalar(z) != 0.0) z = z/(ccoors[l_c+1][j_c][i_c].z - ccoors[l_c][j_c][i_c].z);
509: } else {
510: x = ((double)(i - i_c*ratioi))/((double)ratioi);
511: y = ((double)(j - j_c*ratioj))/((double)ratioj);
512: z = ((double)(l - l_c*ratiok))/((double)ratiok);
513: }
514: nc = 0;
515: /* one left and below; or we are right on it */
516: col = dof*(m_ghost_c*n_ghost_c*(l_c-l_start_ghost_c)+m_ghost_c*(j_c-j_start_ghost_c)+(i_c-i_start_ghost_c));
518: cols[nc] = idx_c[col]/dof;
519: v[nc++] = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
521: if (i_c*ratioi != i) {
522: cols[nc] = idx_c[col+dof]/dof;
523: v[nc++] = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
524: }
526: if (j_c*ratioj != j) {
527: cols[nc] = idx_c[col+m_ghost_c*dof]/dof;
528: v[nc++] = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
529: }
531: if (l_c*ratiok != l) {
532: cols[nc] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
533: v[nc++] = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
534: }
536: if (j_c*ratioj != j && i_c*ratioi != i) {
537: cols[nc] = idx_c[col+(m_ghost_c+1)*dof]/dof;
538: v[nc++] = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
539: }
541: if (j_c*ratioj != j && l_c*ratiok != l) {
542: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
543: v[nc++] = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
544: }
546: if (i_c*ratioi != i && l_c*ratiok != l) {
547: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
548: v[nc++] = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
549: }
551: if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
552: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
553: v[nc++] = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
554: }
555: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
556: }
557: }
558: }
559: if (vcoors) {
560: DAVecRestoreArray(daf->da_coordinates,vcoors,&coors);
561: DAVecRestoreArray(dac->da_coordinates,cvcoors,&ccoors);
562: }
563: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
564: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
566: MatCreateMAIJ(mat,dof,A);
567: MatDestroy(mat);
568: PetscLogFlops(13*m_f*n_f);
569: return(0);
570: }
574: /*@C
575: DAGetInterpolation - Gets an interpolation matrix that maps between
576: grids associated with two DAs.
578: Collective on DA
580: Input Parameters:
581: + dac - the coarse grid DA
582: - daf - the fine grid DA
584: Output Parameters:
585: + A - the interpolation matrix
586: - scale - a scaling vector used to scale the coarse grid restricted vector before applying the
587: grid function or grid Jacobian to it.
589: Level: intermediate
591: .keywords: interpolation, restriction, multigrid
593: .seealso: DARefine(), DAGetInjection()
594: @*/
595: PetscErrorCode DAGetInterpolation(DA dac,DA daf,Mat *A,Vec *scale)
596: {
598: PetscInt dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
599: DAPeriodicType wrapc,wrapf;
600: DAStencilType stc,stf;
608: DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
609: DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
610: if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
611: if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
612: if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
613: if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
614: if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");
615: if (Mc < 2 && Mf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
616: if (dimc > 1 && Nc < 2 && Nf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
617: if (dimc > 2 && Pc < 2 && Pf > 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");
619: if (dac->interptype == DA_Q1){
620: if (dimc == 1){
621: DAGetInterpolation_1D_Q1(dac,daf,A);
622: } else if (dimc == 2){
623: DAGetInterpolation_2D_Q1(dac,daf,A);
624: } else if (dimc == 3){
625: DAGetInterpolation_3D_Q1(dac,daf,A);
626: } else {
627: SETERRQ2(PETSC_ERR_SUP,"No support for this DA dimension %D for interpolation type %d",dimc,(int)dac->interptype);
628: }
629: } else if (dac->interptype == DA_Q0){
630: if (dimc == 1){
631: DAGetInterpolation_1D_Q0(dac,daf,A);
632: } else {
633: SETERRQ2(PETSC_ERR_SUP,"No support for this DA dimension %D for interpolation type %d",dimc,(int)dac->interptype);
634: }
635: }
636: if (scale) {
637: DMGetInterpolationScale((DM)dac,(DM)daf,*A,scale);
638: }
639: return(0);
640: }
644: PetscErrorCode DAGetInjection_2D(DA dac,DA daf,VecScatter *inject)
645: {
647: PetscInt i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
648: PetscInt m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c;
649: PetscInt row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
650: PetscInt i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
651: PetscInt *cols;
652: DAPeriodicType pt;
653: Vec vecf,vecc;
654: IS isf;
658: DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
659: DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
660: if (DAXPeriodic(pt)){
661: ratioi = mx/Mx;
662: if (ratioi*Mx != mx) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: mx/Mx must be integer: mx %D Mx %D",mx,Mx);
663: } else {
664: ratioi = (mx-1)/(Mx-1);
665: if (ratioi*(Mx-1) != mx-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %D Mx %D",mx,Mx);
666: }
667: if (DAYPeriodic(pt)){
668: ratioj = my/My;
669: if (ratioj*My != my) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: my/My must be integer: my %D My %D",my,My);
670: } else {
671: ratioj = (my-1)/(My-1);
672: if (ratioj*(My-1) != my-1) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %D My %D",my,My);
673: }
676: DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
677: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
678: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
680: DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
681: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
682: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
685: /* loop over local fine grid nodes setting interpolation for those*/
686: nc = 0;
687: PetscMalloc(n_f*m_f*sizeof(PetscInt),&cols);
688: for (j=j_start; j<j_start+n_f; j++) {
689: for (i=i_start; i<i_start+m_f; i++) {
691: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
692: j_c = (j/ratioj); /* coarse grid node below fine grid node */
694: if (j_c < j_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
695: j_start %D j_c %D j_start_ghost_c %D",j_start,j_c,j_start_ghost_c);
696: if (i_c < i_start_ghost_c) SETERRQ3(PETSC_ERR_ARG_INCOMP,"Processor's coarse DA must lie over fine DA\n\
697: i_start %D i_c %D i_start_ghost_c %D",i_start,i_c,i_start_ghost_c);
699: if (i_c*ratioi == i && j_c*ratioj == j) {
700: /* convert to local "natural" numbering and then to PETSc global numbering */
701: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
702: cols[nc++] = row;
703: }
704: }
705: }
707: ISCreateBlock(daf->comm,dof,nc,cols,&isf);
708: DAGetGlobalVector(dac,&vecc);
709: DAGetGlobalVector(daf,&vecf);
710: VecScatterCreate(vecf,isf,vecc,PETSC_NULL,inject);
711: DARestoreGlobalVector(dac,&vecc);
712: DARestoreGlobalVector(daf,&vecf);
713: ISDestroy(isf);
714: PetscFree(cols);
715: return(0);
716: }
720: /*@C
721: DAGetInjection - Gets an injection matrix that maps between
722: grids associated with two DAs.
724: Collective on DA
726: Input Parameters:
727: + dac - the coarse grid DA
728: - daf - the fine grid DA
730: Output Parameters:
731: . inject - the injection scatter
733: Level: intermediate
735: .keywords: interpolation, restriction, multigrid, injection
737: .seealso: DARefine(), DAGetInterpolation()
738: @*/
739: PetscErrorCode DAGetInjection(DA dac,DA daf,VecScatter *inject)
740: {
742: PetscInt dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
743: DAPeriodicType wrapc,wrapf;
744: DAStencilType stc,stf;
751: DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
752: DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
753: if (dimc != dimf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Dimensions of DA do not match %D %D",dimc,dimf);
754: if (dofc != doff) SETERRQ2(PETSC_ERR_ARG_INCOMP,"DOF of DA do not match %D %D",dofc,doff);
755: if (sc != sf) SETERRQ2(PETSC_ERR_ARG_INCOMP,"Stencil width of DA do not match %D %D",sc,sf);
756: if (wrapc != wrapf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Periodic type different in two DAs");
757: if (stc != stf) SETERRQ(PETSC_ERR_ARG_INCOMP,"Stencil type different in two DAs");
758: if (Mc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in x direction");
759: if (dimc > 1 && Nc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in y direction");
760: if (dimc > 2 && Pc < 2) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Coarse grid requires at least 2 points in z direction");
762: if (dimc == 2){
763: DAGetInjection_2D(dac,daf,inject);
764: } else {
765: SETERRQ1(PETSC_ERR_SUP,"No support for this DA dimension %D",dimc);
766: }
767: return(0);
768: }