Actual source code: dainterp.c
1: /*$Id: dainterp.c,v 1.22 2001/04/10 19:37:23 bsmith Exp $*/
2:
3: /*
4: Code for interpolating between grids represented by DAs
5: */
7: #include src/dm/da/daimpl.h
8: #include petscmg.h
10: int DMGetInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
11: {
12: int ierr;
13: Vec fine;
14: Scalar 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: }
26: int DAGetInterpolation_1D_dof(DA dac,DA daf,Mat *A)
27: {
28: int ierr,i,i_start,m_f,Mx,*idx_f;
29: int m_ghost,*idx_c,m_ghost_c;
30: int row,col,i_start_ghost,mx,m_c,nc,ratio;
31: int i_c,i_start_c,i_start_ghost_c,cols[2],dof;
32: Scalar v[2],x;
33: Mat mat;
34: DAPeriodicType pt;
37: DAGetInfo(dac,0,&Mx,0,0,0,0,0,0,0,&pt,0);
38: DAGetInfo(daf,0,&mx,0,0,0,0,0,&dof,0,0,0);
39: if (pt == DA_XPERIODIC) {
40: ratio = mx/Mx;
41: if (ratio*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx must be integer: mx %d Mx %d",mx,Mx);
42: } else {
43: ratio = (mx-1)/(Mx-1);
44: if (ratio*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
45: }
47: DAGetCorners(daf,&i_start,0,0,&m_f,0,0);
48: DAGetGhostCorners(daf,&i_start_ghost,0,0,&m_ghost,0,0);
49: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
51: DAGetCorners(dac,&i_start_c,0,0,&m_c,0,0);
52: DAGetGhostCorners(dac,&i_start_ghost_c,0,0,&m_ghost_c,0,0);
53: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
55: /* create interpolation matrix */
56: MatCreateMPIAIJ(dac->comm,m_f,m_c,mx,Mx,2,0,0,0,&mat);
57: MatSetOption(mat,MAT_COLUMNS_SORTED);
59: /* loop over local fine grid nodes setting interpolation for those*/
60: for (i=i_start; i<i_start+m_f; i++) {
61: /* convert to local "natural" numbering and then to PETSc global numbering */
62: row = idx_f[dof*(i-i_start_ghost)]/dof;
64: i_c = (i/ratio); /* coarse grid node to left of fine grid node */
66: /*
67: Only include those interpolation points that are truly
68: nonzero. Note this is very important for final grid lines
69: in x direction; since they have no right neighbor
70: */
71: x = ((double)(i - i_c*ratio))/((double)ratio);
72: /* printf("i j %d %d %g %gn",i,j,x,y); */
73: nc = 0;
74: /* one left and below; or we are right on it */
75: col = dof*(i_c-i_start_ghost_c);
76: cols[nc] = idx_c[col]/dof;
77: v[nc++] = - x + 1.0;
78: /* one right? */
79: if (i_c*ratio != i) {
80: cols[nc] = idx_c[col+dof]/dof;
81: v[nc++] = x;
82: }
83: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
84: }
85: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
86: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
87: MatCreateMAIJ(mat,dof,A);
88: MatDestroy(mat);
89: PetscLogFlops(5*m_f);
90: return(0);
91: }
94: /* dof degree of freedom per node, nonperiodic */
95: int DAGetInterpolation_2D_dof(DA dac,DA daf,Mat *A)
96: {
97: int ierr,i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof;
98: int m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,*dnz,*onz;
99: int row,col,i_start_ghost,j_start_ghost,cols[4],mx,m_c,my,nc,ratioi,ratioj;
100: int i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
101: int size_c,size_f,rank_f,col_shift,col_scale;
102: Scalar v[4],x,y;
103: Mat mat;
104: DAPeriodicType pt;
108: DAGetInfo(dac,0,&Mx,&My,0,0,0,0,0,0,&pt,0);
109: DAGetInfo(daf,0,&mx,&my,0,0,0,0,&dof,0,0,0);
110: if (DAXPeriodic(pt)){
111: ratioi = mx/Mx;
112: if (ratioi*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx must be integer: mx %d Mx %d",mx,Mx);
113: } else {
114: ratioi = (mx-1)/(Mx-1);
115: if (ratioi*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
116: }
117: if (DAYPeriodic(pt)){
118: ratioj = my/My;
119: if (ratioj*My != my) SETERRQ2(1,"Ratio between levels: my/My must be integer: my %d My %d",my,My);
120: } else {
121: ratioj = (my-1)/(My-1);
122: if (ratioj*(My-1) != my-1) SETERRQ2(1,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %d My %d",my,My);
123: }
126: DAGetCorners(daf,&i_start,&j_start,0,&m_f,&n_f,0);
127: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,0,&m_ghost,&n_ghost,0);
128: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
130: DAGetCorners(dac,&i_start_c,&j_start_c,0,&m_c,&n_c,0);
131: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,0,&m_ghost_c,&n_ghost_c,0);
132: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
134: /*
135: Used for handling a coarse DA that lives on 1/4 the processors of the fine DA.
136: The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
137: processors). It's effective length is hence 4 times its normal length, this is
138: why the col_scale is multiplied by the interpolation matrix column sizes.
139: sol_shift allows each set of 1/4 processors do its own interpolation using ITS
140: copy of the coarse vector. A bit of a hack but you do better.
142: In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
143: */
144: MPI_Comm_size(dac->comm,&size_c);
145: MPI_Comm_size(daf->comm,&size_f);
146: MPI_Comm_rank(daf->comm,&rank_f);
147: col_scale = size_f/size_c;
148: col_shift = Mx*My*(rank_f/size_c);
150: MatPreallocateInitialize(daf->comm,m_f*n_f,col_scale*m_c*n_c,dnz,onz);
151: for (j=j_start; j<j_start+n_f; j++) {
152: for (i=i_start; i<i_start+m_f; i++) {
153: /* convert to local "natural" numbering and then to PETSc global numbering */
154: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
156: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
157: j_c = (j/ratioj); /* coarse grid node below fine grid node */
159: /*
160: Only include those interpolation points that are truly
161: nonzero. Note this is very important for final grid lines
162: in x and y directions; since they have no right/top neighbors
163: */
164: nc = 0;
165: /* one left and below; or we are right on it */
166: col = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
167: cols[nc++] = col_shift + idx_c[col]/dof;
168: /* one right and below */
169: if (i_c*ratioi != i) {
170: cols[nc++] = col_shift + idx_c[col+dof]/dof;
171: }
172: /* one left and above */
173: if (j_c*ratioj != j) {
174: cols[nc++] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
175: }
176: /* one right and above */
177: if (j_c*ratioi != j && i_c*ratioj != i) {
178: cols[nc++] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
179: }
180: MatPreallocateSet(row,nc,cols,dnz,onz);
181: }
182: }
183: MatCreateMPIAIJ(daf->comm,m_f*n_f,col_scale*m_c*n_c,mx*my,col_scale*Mx*My,0,dnz,0,onz,&mat);
184: MatPreallocateFinalize(dnz,onz);
185: MatSetOption(mat,MAT_COLUMNS_SORTED);
187: /* loop over local fine grid nodes setting interpolation for those*/
188: for (j=j_start; j<j_start+n_f; j++) {
189: for (i=i_start; i<i_start+m_f; i++) {
190: /* convert to local "natural" numbering and then to PETSc global numbering */
191: row = idx_f[dof*(m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
193: i_c = (i/ratioi); /* coarse grid node to left of fine grid node */
194: j_c = (j/ratioj); /* coarse grid node below fine grid node */
196: /*
197: Only include those interpolation points that are truly
198: nonzero. Note this is very important for final grid lines
199: in x and y directions; since they have no right/top neighbors
200: */
201: x = ((double)(i - i_c*ratioi))/((double)ratioi);
202: y = ((double)(j - j_c*ratioj))/((double)ratioj);
203: /* printf("i j %d %d %g %gn",i,j,x,y); */
204: nc = 0;
205: /* one left and below; or we are right on it */
206: if (j_c < j_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DAn
207: j_start %d j_c %d j_start_ghost_c %d",j_start,j_c,j_start_ghost_c);
208: if (i_c < i_start_ghost_c) SETERRQ3(1,"Processor's coarse DA must lie over fine DAn
209: i_start %d i_c %d i_start_ghost_c %d",i_start,i_c,i_start_ghost_c);
210: col = dof*(m_ghost_c*(j_c-j_start_ghost_c) + (i_c-i_start_ghost_c));
211: cols[nc] = col_shift + idx_c[col]/dof;
212: v[nc++] = x*y - x - y + 1.0;
213: /* one right and below */
214: if (i_c*ratioi != i) {
215: cols[nc] = col_shift + idx_c[col+dof]/dof;
216: v[nc++] = -x*y + x;
217: }
218: /* one left and above */
219: if (j_c*ratioj != j) {
220: cols[nc] = col_shift + idx_c[col+m_ghost_c*dof]/dof;
221: v[nc++] = -x*y + y;
222: }
223: /* one right and above */
224: if (j_c*ratioj != j && i_c*ratioi != i) {
225: cols[nc] = col_shift + idx_c[col+(m_ghost_c+1)*dof]/dof;
226: v[nc++] = x*y;
227: }
228: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
229: }
230: }
231: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
232: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
233: MatCreateMAIJ(mat,dof,A);
234: MatDestroy(mat);
235: PetscLogFlops(13*m_f*n_f);
236: return(0);
237: }
240: /* dof degree of freedom per node, nonperiodic */
241: int DAGetInterpolation_3D_dof(DA dac,DA daf,Mat *A)
242: {
243: int ierr,i,j,i_start,j_start,m_f,n_f,Mx,My,*idx_f,dof,l;
244: int m_ghost,n_ghost,*idx_c,m_ghost_c,n_ghost_c,Mz,mz;
245: int row,col,i_start_ghost,j_start_ghost,cols[8],mx,m_c,my,nc,ratioi,ratioj,ratiok;
246: int i_c,j_c,i_start_c,j_start_c,n_c,i_start_ghost_c,j_start_ghost_c;
247: int l_start,p_f,l_start_ghost,p_ghost,l_start_c,p_c;
248: int l_start_ghost_c,p_ghost_c,l_c,*dnz,*onz;
249: Scalar v[8],x,y,z;
250: Mat mat;
251: DAPeriodicType pt;
254: DAGetInfo(dac,0,&Mx,&My,&Mz,0,0,0,0,0,&pt,0);
255: DAGetInfo(daf,0,&mx,&my,&mz,0,0,0,&dof,0,0,0);
256: if (DAXPeriodic(pt)){
257: ratioi = mx/Mx;
258: if (ratioi*Mx != mx) SETERRQ2(1,"Ratio between levels: mx/Mx must be integer: mx %d Mx %d",mx,Mx);
259: } else {
260: ratioi = (mx-1)/(Mx-1);
261: if (ratioi*(Mx-1) != mx-1) SETERRQ2(1,"Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %d Mx %d",mx,Mx);
262: }
263: if (DAYPeriodic(pt)){
264: ratioj = my/My;
265: if (ratioj*My != my) SETERRQ2(1,"Ratio between levels: my/My must be integer: my %d My %d",my,My);
266: } else {
267: ratioj = (my-1)/(My-1);
268: if (ratioj*(My-1) != my-1) SETERRQ2(1,"Ratio between levels: (my - 1)/(My - 1) must be integer: my %d My %d",my,My);
269: }
270: if (DAZPeriodic(pt)){
271: ratiok = mz/Mz;
272: if (ratiok*Mz != mz) SETERRQ2(1,"Ratio between levels: mz/Mz must be integer: mz %d Mz %d",mz,Mz);
273: } else {
274: ratiok = (mz-1)/(Mz-1);
275: if (ratiok*(Mz-1) != mz-1) SETERRQ2(1,"Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %d Mz %d",mz,Mz);
276: }
278: DAGetCorners(daf,&i_start,&j_start,&l_start,&m_f,&n_f,&p_f);
279: DAGetGhostCorners(daf,&i_start_ghost,&j_start_ghost,&l_start_ghost,&m_ghost,&n_ghost,&p_ghost);
280: DAGetGlobalIndices(daf,PETSC_NULL,&idx_f);
282: DAGetCorners(dac,&i_start_c,&j_start_c,&l_start_c,&m_c,&n_c,&p_c);
283: DAGetGhostCorners(dac,&i_start_ghost_c,&j_start_ghost_c,&l_start_ghost_c,&m_ghost_c,&n_ghost_c,&p_ghost_c);
284: DAGetGlobalIndices(dac,PETSC_NULL,&idx_c);
286: /* create interpolation matrix, determining exact preallocation */
287: MatPreallocateInitialize(dac->comm,m_f*n_f*p_f,m_c*n_c*p_c,dnz,onz);
288: /* loop over local fine grid nodes counting interpolating points */
289: for (l=l_start; l<l_start+p_f; l++) {
290: for (j=j_start; j<j_start+n_f; j++) {
291: for (i=i_start; i<i_start+m_f; i++) {
292: /* convert to local "natural" numbering and then to PETSc global numbering */
293: row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
294: i_c = (i/ratioi);
295: j_c = (j/ratioj);
296: l_c = (l/ratiok);
298: /*
299: Only include those interpolation points that are truly
300: nonzero. Note this is very important for final grid lines
301: in x and y directions; since they have no right/top neighbors
302: */
303: nc = 0;
304: 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));
305: cols[nc++] = idx_c[col]/dof;
306: if (i_c*ratioi != i) {
307: cols[nc++] = idx_c[col+dof]/dof;
308: }
309: if (j_c*ratioj != j) {
310: cols[nc++] = idx_c[col+m_ghost_c*dof]/dof;
311: }
312: if (l_c*ratiok != l) {
313: cols[nc++] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
314: }
315: if (j_c*ratioj != j && i_c*ratioi != i) {
316: cols[nc++] = idx_c[col+(m_ghost_c+1)*dof]/dof;
317: }
318: if (j_c*ratioj != j && l_c*ratiok != l) {
319: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
320: }
321: if (i_c*ratioi != i && l_c*ratiok != l) {
322: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
323: }
324: if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
325: cols[nc++] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
326: }
327: MatPreallocateSet(row,nc,cols,dnz,onz);
328: }
329: }
330: }
331: MatCreateMPIAIJ(dac->comm,m_f*n_f*p_f,m_c*n_c*p_c,mx*my*mz,Mx*My*Mz,0,dnz,0,onz,&mat);
332: MatPreallocateFinalize(dnz,onz);
333: MatSetOption(mat,MAT_COLUMNS_SORTED);
335: /* loop over local fine grid nodes setting interpolation for those*/
336: for (l=l_start; l<l_start+p_f; l++) {
337: for (j=j_start; j<j_start+n_f; j++) {
338: for (i=i_start; i<i_start+m_f; i++) {
339: /* convert to local "natural" numbering and then to PETSc global numbering */
340: row = idx_f[dof*(m_ghost*n_ghost*(l-l_start_ghost) + m_ghost*(j-j_start_ghost) + (i-i_start_ghost))]/dof;
342: i_c = (i/ratioi);
343: j_c = (j/ratioj);
344: l_c = (l/ratiok);
346: /*
347: Only include those interpolation points that are truly
348: nonzero. Note this is very important for final grid lines
349: in x and y directions; since they have no right/top neighbors
350: */
351: x = ((double)(i - i_c*ratioi))/((double)ratioi);
352: y = ((double)(j - j_c*ratioj))/((double)ratioj);
353: z = ((double)(l - l_c*ratiok))/((double)ratiok);
354: /* printf("i j l %d %d %d %g %g %gn",i,j,l,x,y,z); */
355: nc = 0;
356: /* one left and below; or we are right on it */
357: 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));
359: cols[nc] = idx_c[col]/dof;
360: v[nc++] = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
362: if (i_c*ratioi != i) {
363: cols[nc] = idx_c[col+dof]/dof;
364: v[nc++] = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. - (2.0*z-1.));
365: }
367: if (j_c*ratioj != j) {
368: cols[nc] = idx_c[col+m_ghost_c*dof]/dof;
369: v[nc++] = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
370: }
372: if (l_c*ratiok != l) {
373: cols[nc] = idx_c[col+m_ghost_c*n_ghost_c*dof]/dof;
374: v[nc++] = .125*(1. - (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
375: }
377: if (j_c*ratioj != j && i_c*ratioi != i) {
378: cols[nc] = idx_c[col+(m_ghost_c+1)*dof]/dof;
379: v[nc++] = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. - (2.0*z-1.));
380: }
382: if (j_c*ratioj != j && l_c*ratiok != l) {
383: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c)*dof]/dof;
384: v[nc++] = .125*(1. - (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
385: }
387: if (i_c*ratioi != i && l_c*ratiok != l) {
388: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+1)*dof]/dof;
389: v[nc++] = .125*(1. + (2.0*x-1.))*(1. - (2.0*y-1.))*(1. + (2.0*z-1.));
390: }
392: if (i_c*ratioi != i && l_c*ratiok != l && j_c*ratioj != j) {
393: cols[nc] = idx_c[col+(m_ghost_c*n_ghost_c+m_ghost_c+1)*dof]/dof;
394: v[nc++] = .125*(1. + (2.0*x-1.))*(1. + (2.0*y-1.))*(1. + (2.0*z-1.));
395: }
396: MatSetValues(mat,1,&row,nc,cols,v,INSERT_VALUES);
397: }
398: }
399: }
400: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
401: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
403: MatCreateMAIJ(mat,dof,A);
404: MatDestroy(mat);
405: PetscLogFlops(13*m_f*n_f);
406: return(0);
407: }
409: /*@C
410: DAGetInterpolation - Gets an interpolation matrix that maps between
411: grids associated with two DAs.
413: Collective on DA
415: Input Parameters:
416: + dac - the coarse grid DA
417: - daf - the fine grid DA
419: Output Parameters:
420: + A - the interpolation matrix
421: - scale - a scaling vector used to scale the coarse grid restricted vector before applying the
422: grid function or grid Jacobian to it.
424: Level: intermediate
426: .keywords: interpolation, restriction, multigrid
428: .seealso: DARefine()
429: @*/
430: int DAGetInterpolation(DA dac,DA daf,Mat *A,Vec *scale)
431: {
432: int ierr,dimc,Mc,Nc,Pc,mc,nc,pc,dofc,sc,dimf,Mf,Nf,Pf,mf,nf,pf,doff,sf;
433: DAPeriodicType wrapc,wrapf;
434: DAStencilType stc,stf;
440: DAGetInfo(dac,&dimc,&Mc,&Nc,&Pc,&mc,&nc,&pc,&dofc,&sc,&wrapc,&stc);
441: DAGetInfo(daf,&dimf,&Mf,&Nf,&Pf,&mf,&nf,&pf,&doff,&sf,&wrapf,&stf);
442: if (dimc != dimf) SETERRQ2(1,"Dimensions of DA do not match %d %d",dimc,dimf);
443: /* if (mc != mf) SETERRQ2(1,"Processor dimensions of DA in X %d %d do not match",mc,mf);
444: if (nc != nf) SETERRQ2(1,"Processor dimensions of DA in Y %d %d do not match",nc,nf);
445: if (pc != pf) SETERRQ2(1,"Processor dimensions of DA in Z %d %d do not match",pc,pf); */
446: if (dofc != doff) SETERRQ2(1,"DOF of DA do not match %d %d",dofc,doff);
447: if (sc != sf) SETERRQ2(1,"Stencil width of DA do not match %d %d",sc,sf);
448: if (wrapc != wrapf) SETERRQ(1,"Periodic type different in two DAs");
449: if (stc != stf) SETERRQ(1,"Stencil type different in two DAs");
451: if (dimc == 1){
452: DAGetInterpolation_1D_dof(dac,daf,A);
453: } else if (dimc == 2){
454: DAGetInterpolation_2D_dof(dac,daf,A);
455: } else if (dimc == 3){
456: DAGetInterpolation_3D_dof(dac,daf,A);
457: } else {
458: SETERRQ(1,"No support for this DA yet");
459: }
461: if (scale) {
462: DMGetInterpolationScale((DM)dac,(DM)daf,*A,scale);
463: }
464: return(0);
465: }