Actual source code: dainterp.c
1: /*$Id: dainterp.c,v 1.25 2001/08/07 03:04:39 balay Exp $*/
2:
3: /*
4: Code for interpolating between grids represented by DAs
5: */
7: #include src/dm/da/daimpl.h
8: #include petscmg.h
12: int DMGetInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
13: {
14: int ierr;
15: Vec fine;
16: PetscScalar one = 1.0;
19: DMCreateGlobalVector(daf,&fine);
20: DMCreateGlobalVector(dac,scale);
21: VecSet(&one,fine);
22: MatRestrict(mat,fine,*scale);
23: VecDestroy(fine);
24: VecReciprocal(*scale);
25: return(0);
26: }
30: int DAGetInterpolation_1D_Q1(DA dac,DA daf,Mat *A)
31: {
32: int ierr,i,i_start,m_f,Mx,*idx_f;
33: int m_ghost,*idx_c,m_ghost_c;
34: int row,col,i_start_ghost,mx,m_c,nc,ratio;
35: int i_c,i_start_c,i_start_ghost_c,cols[2],dof;
36: PetscScalar v[2],x;
37: Mat mat;
38: DAPeriodicType pt;
41: DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
42: DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
43: if (pt == DA_XPERIODIC) {
44: ratio = mx/Mx;
45: if (ratio*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx must be integer: mx %d Mx %d",mx,Mx);
46: } else {
47: ratio = (mx-1)/(Mx-1);
48: if (ratio*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
49: }
51: DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
52: DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
53: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
55: DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
56: DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
57: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
59: /* create interpolation matrix */
60: MatCreate(dac->comm,m_f,m_c,mx,Mx,&mat);
61: MatSetType(mat,MATAIJ);
62: MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
63: MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);
64: if (!DAXPeriodic(pt)){MatSetOption(mat,MAT_COLUMNS_SORTED);}
66: /* loop over local fine grid nodes setting interpolation for those*/
67: for (i=i_start; i<i_start+m_f; i++) {
68: /* convert to local "natural" numbering and then to PETSc global numbering */
69: row = idx_f[dof*(i-i_start_ghost)]/dof;
71: i_c = (i/ratio); /* coarse grid node to left of fine grid node */
72: if (i_c < i_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
73: i_start %d i_c %d i_start_ghost_c %d",i_start,i_c,i_start_ghost_c);
75: /*
76: Only include those interpolation points that are truly
77: nonzero. Note this is very important for final grid lines
78: in x direction; since they have no right neighbor
79: */
80: x = ((double)(i - i_c*ratio))/((double)ratio);
81: /* printf("i j %d %d %g %g\n",i,j,x,y); */
82: nc = 0;
83: /* one left and below; or we are right on it */
84: col = dof*(i_c-i_start_ghost_c);
85: cols[nc] = idx_c[col]/dof;
86: v[nc++] = - x + 1.0;
87: /* one right? */
88: if (i_c*ratio != i) {
89: cols[nc] = idx_c[col+dof]/dof;
90: v[nc++] = x;
91: }
92: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
93: }
94: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
95: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
96: MatCreateMAIJ(mat,dof,A);
97: MatDestroy(mat);
98: PetscLogFlops(5*m_f);
99: return(0);
100: }
104: int DAGetInterpolation_1D_Q0(DA dac,DA daf,Mat *A)
105: {
106: int ierr,i,i_start,m_f,Mx,*idx_f;
107: int m_ghost,*idx_c,m_ghost_c;
108: int row,col,i_start_ghost,mx,m_c,nc,ratio;
109: int i_c,i_start_c,i_start_ghost_c,cols[2],dof;
110: PetscScalar v[2],x;
111: Mat mat;
112: DAPeriodicType pt;
115: DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
116: DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
117: if (pt == DA_XPERIODIC) {
118: ratio = mx/Mx;
119: if (ratio*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx must be integer: mx %d Mx %d",mx,Mx);
120: } else {
121: ratio = (mx-1)/(Mx-1);
122: if (ratio*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
123: }
125: DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
126: DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
127: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
129: DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
130: DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
131: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
133: /* create interpolation matrix */
134: MatCreate(dac->comm,m_f,m_c,mx,Mx,&mat);
135: MatSetType(mat,MATAIJ);
136: MatSeqAIJSetPreallocation(mat,2,PETSC_NULL);
137: MatMPIAIJSetPreallocation(mat,2,PETSC_NULL,0,PETSC_NULL);
138: if (!DAXPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}
140: /* loop over local fine grid nodes setting interpolation for those*/
141: for (i=i_start; i<i_start+m_f; i++) {
142: /* convert to local "natural" numbering and then to PETSc global numbering */
143: row = idx_f[dof*(i-i_start_ghost)]/dof;
145: i_c = (i/ratio); /* coarse grid node to left of fine grid node */
147: /*
148: Only include those interpolation points that are truly
149: nonzero. Note this is very important for final grid lines
150: in x direction; since they have no right neighbor
151: */
152: x = ((double)(i - i_c*ratio))/((double)ratio);
153: /* printf("i j %d %d %g %g\n",i,j,x,y); */
154: nc = 0;
155: /* one left and below; or we are right on it */
156: col = dof*(i_c-i_start_ghost_c);
157: cols[nc] = idx_c[col]/dof;
158: v[nc++] = - x + 1.0;
159: /* one right? */
160: if (i_c*ratio != i) {
161: cols[nc] = idx_c[col+dof]/dof;
162: v[nc++] = x;
163: }
164: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
165: }
166: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
167: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
168: MatCreateMAIJ(mat,dof,A);
169: MatDestroy(mat);
170: PetscLogFlops(5*m_f);
171: return(0);
172: }
175: /* dof degree of freedom per node, nonperiodic */
178: int DAGetInterpolation_2D_Q1(DA dac,DA daf,Mat *A)
179: {
180: int ierr,i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
181: int m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
182: int row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
183: int i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
184: int size_c,size_f,rank_f,col_shift,col_scale;
185: PetscScalar v[4],x,y;
186: Mat mat;
187: DAPeriodicType pt;
191: DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
192: DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
193: if (DAXPeriodic(pt)){
194: ratioi = mx/Mx;
195: if (ratioi*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx must be integer: mx %d Mx %d",mx,Mx);
196: } else {
197: ratioi = (mx-1)/(Mx-1);
198: if (ratioi*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
199: }
200: if (DAYPeriodic(pt)){
201: ratioj = my/My;
202: if (ratioj*My != my) SETERRQ2(1,"Ratio between levels: my/My must be integer: my %d My %d",my,My);
203: } else {
204: ratioj = (my-1)/(My-1);
205: if (ratioj*(My-1) != my-1) SETERRQ2(1,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %d My %d",my,My);
206: }
209: DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
210: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
211: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
213: DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
214: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
215: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
217: /*
218: Used for handling a coarse DA that lives on 1/4 the processors of the fine DA.
219: The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
220: processors). It's effective length is hence 4 times its normal length, this is
221: why the col_scale is multiplied by the interpolation matrix column sizes.
222: sol_shift allows each set of 1/4 processors do its own interpolation using ITS
223: copy of the coarse vector. A bit of a hack but you do better.
225: In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
226: */
227: MPI_Comm_size(dac->comm,&size_c);
228: MPI_Comm_size(daf->comm,&size_f);
229: MPI_Comm_rank(daf->comm,&rank_f);
230: col_scale = size_f/size_c;
231: col_shift = Mx*My*(rank_f/size_c);
233: MatPreallocateInitialize(daf->comm,m_f*n_f,col_scale*m_c*n_c,dnz,onz);
234: for (j=j_start; j<j_start+n_f; j++) {
235: for (i=i_start; i<i_start+m_f; i++) {
236: /* convert to local "natural" numbering and then to PETSc global numbering */
237: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
239: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
240: j_c = (j/ratioj); /* coarse grid node below fine grid node */
242: if (j_c < j_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
243: j_start %d j_c %d j_start_ghost_c %d",j_start,j_c,j_start_ghost_c);
244: if (i_c < i_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
245: i_start %d i_c %d i_start_ghost_c %d",i_start,i_c,i_start_ghost_c);
247: /*
248: Only include those interpolation points that are truly
249: nonzero. Note this is very important for final grid lines
250: in x and y directions; since they have no right/top neighbors
251: */
252: nc = 0;
253: /* one left and below; or we are right on it */
254: col = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
255: cols[nc++] = col_shift + idx_c[col]/dof;
256: /* one right and below */
257: if (i_c*ratioi != i) {
258: cols[nc++] = col_shift + idx_c[col+dof]/dof;
259: }
260: /* one left and above */
261: if (j_c*ratioj != j) {
262: cols[nc++] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
263: }
264: /* one right and above */
265: if (j_c*ratioi != j && i_c*ratioj != i) {
266: cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
267: }
268: MatPreallocateSet(row,nc,cols,dnz,onz);
269: }
270: }
271: MatCreate(daf->comm,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My,&mat);
272: MatSetType(mat,MATAIJ);
273: MatSeqAIJSetPreallocation(mat,0,dnz);
274: MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
275: MatPreallocateFinalize(dnz,onz);
276: if (!DAXPeriodic(pt) && !DAYPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}
278: /* loop over local fine grid nodes setting interpolation for those*/
279: for (j=j_start; j<j_start+n_f; j++) {
280: for (i=i_start; i<i_start+m_f; i++) {
281: /* convert to local "natural" numbering and then to PETSc global numbering */
282: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
284: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
285: j_c = (j/ratioj); /* coarse grid node below fine grid node */
287: /*
288: Only include those interpolation points that are truly
289: nonzero. Note this is very important for final grid lines
290: in x and y directions; since they have no right/top neighbors
291: */
292: x = ((double)(i - i_c*ratioi))/((double)ratioi);
293: y = ((double)(j - j_c*ratioj))/((double)ratioj);
294: /* printf("i j %d %d %g %g\n",i,j,x,y); */
295: nc = 0;
296: /* one left and below; or we are right on it */
297: col = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
298: cols[nc] = col_shift + idx_c[col]/dof;
299: v[nc++] = x*y - x - y + 1.0;
300: /* one right and below */
301: if (i_c*ratioi != i) {
302: cols[nc] = col_shift + idx_c[col+dof]/dof;
303: v[nc++] = -x*y + x;
304: }
305: /* one left and above */
306: if (j_c*ratioj != j) {
307: cols[nc] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
308: v[nc++] = -x*y + y;
309: }
310: /* one right and above */
311: if (j_c*ratioj != j && i_c*ratioi != i) {
312: cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
313: v[nc++] = x*y;
314: }
315: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
316: }
317: }
318: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
319: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
320: MatCreateMAIJ(mat,dof,A);
321: MatDestroy(mat);
322: PetscLogFlops(13*m_f*n_f);
323: return(0);
324: }
327: /* dof degree of freedom per node, nonperiodic */
330: int DAGetInterpolation_3D_Q1(DA dac,DA daf,Mat *A)
331: {
332: int ierr,i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof,l;
333: int m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,Mz,mz;
334: int row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
335: int i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
336: int l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
337: int l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
338: PetscScalar v[8],x,y,z;
339: Mat mat;
340: DAPeriodicType pt;
343: DAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&pt,0);
344: DAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0);
345: if (DAXPeriodic(pt)){
346: ratioi = mx/Mx;
347: if (ratioi*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx must be integer: mx %d Mx %d",mx,Mx);
348: } else {
349: ratioi = (mx-1)/(Mx-1);
350: if (ratioi*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
351: }
352: if (DAYPeriodic(pt)){
353: ratioj = my/My;
354: if (ratioj*My != my) SETERRQ2(1,"Ratio between levels: my/My must be integer: my %d My %d",my,My);
355: } else {
356: ratioj = (my-1)/(My-1);
357: if (ratioj*(My-1) != my-1) SETERRQ2(1,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %d My %d",my,My);
358: }
359: if (DAZPeriodic(pt)){
360: ratiok = mz/Mz;
361: if (ratiok*Mz != mz) SETERRQ2(1,"Ratio between levels: mz/Mz must be integer: mz %d Mz %d",mz,Mz);
362: } else {
363: ratiok = (mz-1)/(Mz-1);
364: if (ratiok*(Mz-1) != mz-1) SETERRQ2(1,"Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %d Mz %d",mz,Mz);
365: }
367: DAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
368: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
369: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
371: DAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
372: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
373: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
375: /* create interpolation matrix, determining exact preallocation */
376: MatPreallocateInitialize(dac->comm,m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);
377: /* loop over local fine grid nodes counting interpolating points */
378: for (l=l_start; l<l_start+p_f; l++) {
379: for (j=j_start; j<j_start+n_f; j++) {
380: for (i=i_start; i<i_start+m_f; i++) {
381: /* convert to local "natural" numbering and then to PETSc global numbering */
382: row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
383: i_c = (i/ratioi);
384: j_c = (j/ratioj);
385: l_c = (l/ratiok);
386: if (l_c < l_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
387: l_start %d l_c %d l_start_ghost_c %d",l_start,l_c,l_start_ghost_c);
388: if (j_c < j_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
389: j_start %d j_c %d j_start_ghost_c %d",j_start,j_c,j_start_ghost_c);
390: if (i_c < i_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DA\n\
391: i_start %d i_c %d i_start_ghost_c %d",i_start,i_c,i_start_ghost_c);
393: /*
394: Only include those interpolation points that are truly
395: nonzero. Note this is very important for final grid lines
396: in x and y directions; since they have no right/top neighbors
397: */
398: nc = 0;
399: col = dof*(m_ghost_c*n_ghost_c*(l_c-l_start_ghost_c) + m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
400: cols[nc++] = idx_c[col]/dof;
401: if (i_c*ratioi != i) {
402: cols[nc++] = idx_c[col+dof]/dof;
403: }
404: if (j_c*ratioj != j) {
405: cols[nc++] = idx_c[col+m_ghost_c*dof]/dof;
406: }
407: if (l_c*ratiok != l) {
408: cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
409: }
410: if (j_c*ratioj != j && i_c*ratioi != i) {
411: cols[nc++] = idx_c[col+(m_ghost_c+1)*dof]/dof;
412: }
413: if (j_c*ratioj != j && l_c*ratiok != l) {
414: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
415: }
416: if (i_c*ratioi != i && l_c*ratiok != l) {
417: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
418: }
419: if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
420: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
421: }
422: MatPreallocateSet(row,nc,cols,dnz,onz);
423: }
424: }
425: }
426: MatCreate(dac->comm,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz,&mat);
427: MatSetType(mat,MATAIJ);
428: MatSeqAIJSetPreallocation(mat,0,dnz);
429: MatMPIAIJSetPreallocation(mat,0,dnz,0,onz);
430: MatPreallocateFinalize(dnz,onz);
431: if (!DAXPeriodic(pt) && !DAYPeriodic(pt) && !DAZPeriodic(pt)) {MatSetOption(mat,MAT_COLUMNS_SORTED);}
433: /* loop over local fine grid nodes setting interpolation for those*/
434: for (l=l_start; l<l_start+p_f; l++) {
435: for (j=j_start; j<j_start+n_f; j++) {
436: for (i=i_start; i<i_start+m_f; i++) {
437: /* convert to local "natural" numbering and then to PETSc global numbering */
438: row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
440: i_c = (i/ratioi);
441: j_c = (j/ratioj);
442: l_c = (l/ratiok);
444: /*
445: Only include those interpolation points that are truly
446: nonzero. Note this is very important for final grid lines
447: in x and y directions; since they have no right/top neighbors
448: */
449: x = ((double)(i - i_c*ratioi))/((double)ratioi);
450: y = ((double)(j - j_c*ratioj))/((double)ratioj);
451: z = ((double)(l - l_c*ratiok))/((double)ratiok);
452: /* printf("i j l %d %d %d %g %g %g\n",i,j,l,x,y,z); */
453: nc = 0;
454: /* one left and below; or we are right on it */
455: col = dof*(m_ghost_c*n_ghost_c*(l_c-l_start_ghost_c)+m_ghost_c*(j_c-j_start_ghost_c)+(i_c-i_start_ghost_c));
457: cols[nc] = idx_c[col]/dof;
458: v[nc++] = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
460: if (i_c*ratioi != i) {
461: cols[nc] = idx_c[col+dof]/dof;
462: v[nc++] = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
463: }
465: if (j_c*ratioj != j) {
466: cols[nc] = idx_c[col+m_ghost_c*dof]/dof;
467: v[nc++] = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
468: }
470: if (l_c*ratiok != l) {
471: cols[nc] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
472: v[nc++] = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
473: }
475: if (j_c*ratioj != j && i_c*ratioi != i) {
476: cols[nc] = idx_c[col+(m_ghost_c+1)*dof]/dof;
477: v[nc++] = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
478: }
480: if (j_c*ratioj != j && l_c*ratiok != l) {
481: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
482: v[nc++] = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
483: }
485: if (i_c*ratioi != i && l_c*ratiok != l) {
486: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
487: v[nc++] = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
488: }
490: if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
491: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
492: v[nc++] = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
493: }
494: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
495: }
496: }
497: }
498: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
499: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
501: MatCreateMAIJ(mat,dof,A);
502: MatDestroy(mat);
503: PetscLogFlops(13*m_f*n_f);
504: return(0);
505: }
509: /*@C
510: DAGetInterpolation - Gets an interpolation matrix that maps between
511: grids associated with two DAs.
513: Collective on DA
515: Input Parameters:
516: + dac - the coarse grid DA
517: - daf - the fine grid DA
519: Output Parameters:
520: + A - the interpolation matrix
521: - scale - a scaling vector used to scale the coarse grid restricted vector before applying the
522: grid function or grid Jacobian to it.
524: Level: intermediate
526: .keywords: interpolation, restriction, multigrid
528: .seealso: DARefine(), DAGetInjection()
529: @*/
530: int DAGetInterpolation(DA dac,DA daf,Mat *A,Vec *scale)
531: {
532: int ierr,dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
533: DAPeriodicType wrapc,wrapf;
534: DAStencilType stc,stf;
542: DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
543: DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
544: if (dimc != dimf) SETERRQ2(1,"Dimensions of DA do not match %d %d",dimc,dimf);
545: /* if (mc != mf) SETERRQ2(1,"Processor dimensions of DA in X %d %d do not match",mc,mf);
546: if (nc != nf) SETERRQ2(1,"Processor dimensions of DA in Y %d %d do not match",nc,nf);
547: if (pc != pf) SETERRQ2(1,"Processor dimensions of DA in Z %d %d do not match",pc,pf); */
548: if (dofc != doff) SETERRQ2(1,"DOF of DA do not match %d %d",dofc,doff);
549: if (sc != sf) SETERRQ2(1,"Stencil width of DA do not match %d %d",sc,sf);
550: if (wrapc != wrapf) SETERRQ(1,"Periodic type different in two DAs");
551: if (stc != stf) SETERRQ(1,"Stencil type different in two DAs");
552: if (Mc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in x direction");
553: if (dimc > 1 && Nc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in y direction");
554: if (dimc > 2 && Pc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in z direction");
556: if (dac->interptype == DA_Q1){
557: if (dimc == 1){
558: DAGetInterpolation_1D_Q1(dac,daf,A);
559: } else if (dimc == 2){
560: DAGetInterpolation_2D_Q1(dac,daf,A);
561: } else if (dimc == 3){
562: DAGetInterpolation_3D_Q1(dac,daf,A);
563: } else {
564: SETERRQ2(1,"No support for this DA dimension %d for interpolation type %d",dimc,dac->interptype);
565: }
566: } else if (dac->interptype == DA_Q0){
567: if (dimc == 1){
568: DAGetInterpolation_1D_Q0(dac,daf,A);
569: } else {
570: SETERRQ2(1,"No support for this DA dimension %d for interpolation type %d",dimc,dac->interptype);
571: }
572: }
573: if (scale) {
574: DMGetInterpolationScale((DM)dac,(DM)daf,*A,scale);
575: }
576: return(0);
577: }
581: int DAGetInjection_2D(DA dac,DA daf,VecScatter *inject)
582: {
583: int ierr,i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
584: int m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c;
585: int row,i_start_ghost,j_start_ghost,mx,m_c,my,nc,ratioi,ratioj;
586: int i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
587: int *cols;
588: DAPeriodicType pt;
589: Vec vecf,vecc;
590: IS isf;
594: DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
595: DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
596: if (DAXPeriodic(pt)){
597: ratioi = mx/Mx;
598: if (ratioi*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx must be integer: mx %d Mx %d",mx,Mx);
599: } else {
600: ratioi = (mx-1)/(Mx-1);
601: if (ratioi*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
602: }
603: if (DAYPeriodic(pt)){
604: ratioj = my/My;
605: if (ratioj*My != my) SETERRQ2(1,"Ratio between levels: my/My must be integer: my %d My %d",my,My);
606: } else {
607: ratioj = (my-1)/(My-1);
608: if (ratioj*(My-1) != my-1) SETERRQ2(1,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %d My %d",my,My);
609: }
612: DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
613: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
614: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
616: DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
617: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
618: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
621: /* loop over local fine grid nodes setting interpolation for those*/
622: nc = 0;
623: PetscMalloc(n_f*m_f*sizeof(int),&cols);
624: for (j=j_start; j<j_start+n_f; j++) {
625: for (i=i_start; i<i_start+m_f; i++) {
627: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
628: j_c = (j/ratioj); /* coarse grid node below fine grid node */
630: if (i_c*ratioi == i && j_c*ratioj == j) {
631: /* convert to local "natural" numbering and then to PETSc global numbering */
632: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))];
633: cols[nc++] = row;
634: }
635: }
636: }
638: ISCreateBlock(daf->comm,dof,nc,cols,&isf);
639: DAGetGlobalVector(dac,&vecc);
640: DAGetGlobalVector(daf,&vecf);
641: VecScatterCreate(vecf,isf,vecc,PETSC_NULL,inject);
642: DARestoreGlobalVector(dac,&vecc);
643: DARestoreGlobalVector(daf,&vecf);
644: ISDestroy(isf);
645: PetscFree(cols);
646: return(0);
647: }
651: /*@C
652: DAGetInjection - Gets an injection matrix that maps between
653: grids associated with two DAs.
655: Collective on DA
657: Input Parameters:
658: + dac - the coarse grid DA
659: - daf - the fine grid DA
661: Output Parameters:
662: . inject - the injection scatter
664: Level: intermediate
666: .keywords: interpolation, restriction, multigrid, injection
668: .seealso: DARefine(), DAGetInterpolation()
669: @*/
670: int DAGetInjection(DA dac,DA daf,VecScatter *inject)
671: {
672: int ierr,dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
673: DAPeriodicType wrapc,wrapf;
674: DAStencilType stc,stf;
681: DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
682: DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
683: if (dimc != dimf) SETERRQ2(1,"Dimensions of DA do not match %d %d",dimc,dimf);
684: /* if (mc != mf) SETERRQ2(1,"Processor dimensions of DA in X %d %d do not match",mc,mf);
685: if (nc != nf) SETERRQ2(1,"Processor dimensions of DA in Y %d %d do not match",nc,nf);
686: if (pc != pf) SETERRQ2(1,"Processor dimensions of DA in Z %d %d do not match",pc,pf); */
687: if (dofc != doff) SETERRQ2(1,"DOF of DA do not match %d %d",dofc,doff);
688: if (sc != sf) SETERRQ2(1,"Stencil width of DA do not match %d %d",sc,sf);
689: if (wrapc != wrapf) SETERRQ(1,"Periodic type different in two DAs");
690: if (stc != stf) SETERRQ(1,"Stencil type different in two DAs");
691: if (Mc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in x direction");
692: if (dimc > 1 && Nc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in y direction");
693: if (dimc > 2 && Pc < 2) SETERRQ(1,"Coarse grid requires at least 2 points in z direction");
695: if (dimc == 2){
696: DAGetInjection_2D(dac,daf,inject);
697: } else {
698: SETERRQ1(1,"No support for this DA dimension %d",dimc);
699: }
700: return(0);
701: }