Actual source code: dainterp.c
1: /*
2: Code for interpolating between grids represented by DMDAs
3: */
5: /*
6: For linear elements there are two branches of code to compute the interpolation. They should compute the same results but may not. The "new version" does
7: not work for periodic domains, the old does. Change NEWVERSION to 1 to compile in the new version. Eventually when we are sure the two produce identical results
8: we will remove/merge the new version. Based on current tests, these both produce the same results. We are leaving NEWVERSION for now in the code since some
9: consider it cleaner, but old version is turned on since it handles periodic case.
10: */
11: #define NEWVERSION 0
13: #include <petsc/private/dmdaimpl.h>
15: /*
16: Since the interpolation uses MATMAIJ for dof > 0 we convert request for non-MATAIJ baseded matrices to MATAIJ.
17: This is a bit of a hack, the reason for it is partially because -dm_mat_type defines the
18: matrix type for both the operator matrices and the interpolation matrices so that users
19: can select matrix types of base MATAIJ for accelerators
20: */
21: static PetscErrorCode ConvertToAIJ(MatType intype, MatType *outtype)
22: {
23: PetscInt i;
24: char const *types[3] = {MATAIJ, MATSEQAIJ, MATMPIAIJ};
25: PetscBool flg;
27: PetscFunctionBegin;
28: *outtype = MATAIJ;
29: for (i = 0; i < 3; i++) {
30: PetscCall(PetscStrbeginswith(intype, types[i], &flg));
31: if (flg) {
32: *outtype = intype;
33: PetscFunctionReturn(PETSC_SUCCESS);
34: }
35: }
36: PetscFunctionReturn(PETSC_SUCCESS);
37: }
39: static PetscErrorCode DMCreateInterpolation_DA_1D_Q1(DM dac, DM daf, Mat *A)
40: {
41: PetscInt i, i_start, m_f, Mx;
42: const PetscInt *idx_f, *idx_c;
43: PetscInt m_ghost, m_ghost_c;
44: PetscInt row, col, i_start_ghost, mx, m_c, nc, ratio;
45: PetscInt i_c, i_start_c, i_start_ghost_c, cols[2], dof;
46: PetscScalar v[2], x;
47: Mat mat;
48: DMBoundaryType bx;
49: ISLocalToGlobalMapping ltog_f, ltog_c;
50: MatType mattype;
52: PetscFunctionBegin;
53: PetscCall(DMDAGetInfo(dac, NULL, &Mx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &bx, NULL, NULL, NULL));
54: PetscCall(DMDAGetInfo(daf, NULL, &mx, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
55: if (bx == DM_BOUNDARY_PERIODIC) {
56: ratio = mx / Mx;
57: PetscCheck(ratio * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
58: } else {
59: ratio = (mx - 1) / (Mx - 1);
60: PetscCheck(ratio * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
61: }
63: PetscCall(DMDAGetCorners(daf, &i_start, NULL, NULL, &m_f, NULL, NULL));
64: PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, NULL, NULL, &m_ghost, NULL, NULL));
65: PetscCall(DMGetLocalToGlobalMapping(daf, <og_f));
66: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
68: PetscCall(DMDAGetCorners(dac, &i_start_c, NULL, NULL, &m_c, NULL, NULL));
69: PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, NULL, NULL, &m_ghost_c, NULL, NULL));
70: PetscCall(DMGetLocalToGlobalMapping(dac, <og_c));
71: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
73: /* create interpolation matrix */
74: PetscCall(MatCreate(PetscObjectComm((PetscObject)dac), &mat));
75: #if defined(PETSC_HAVE_CUDA)
76: /*
77: Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
78: we don't want the original unconverted matrix copied to the GPU
79: */
80: if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
81: #endif
82: PetscCall(MatSetSizes(mat, m_f, m_c, mx, Mx));
83: PetscCall(ConvertToAIJ(dac->mattype, &mattype));
84: PetscCall(MatSetType(mat, mattype));
85: PetscCall(MatSeqAIJSetPreallocation(mat, 2, NULL));
86: PetscCall(MatMPIAIJSetPreallocation(mat, 2, NULL, 1, NULL));
88: /* loop over local fine grid nodes setting interpolation for those*/
89: if (!NEWVERSION) {
90: for (i = i_start; i < i_start + m_f; i++) {
91: /* convert to local "natural" numbering and then to PETSc global numbering */
92: row = idx_f[i - i_start_ghost];
94: i_c = (i / ratio); /* coarse grid node to left of fine grid node */
95: PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT, i_start, i_c, i_start_ghost_c);
97: /*
98: Only include those interpolation points that are truly
99: nonzero. Note this is very important for final grid lines
100: in x direction; since they have no right neighbor
101: */
102: x = ((PetscReal)(i - i_c * ratio)) / ((PetscReal)ratio);
103: nc = 0;
104: /* one left and below; or we are right on it */
105: col = (i_c - i_start_ghost_c);
106: cols[nc] = idx_c[col];
107: v[nc++] = -x + 1.0;
108: /* one right? */
109: if (i_c * ratio != i) {
110: cols[nc] = idx_c[col + 1];
111: v[nc++] = x;
112: }
113: PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
114: }
116: } else {
117: PetscScalar *xi;
118: PetscInt li, nxi, n;
119: PetscScalar Ni[2];
121: /* compute local coordinate arrays */
122: nxi = ratio + 1;
123: PetscCall(PetscMalloc1(nxi, &xi));
124: for (li = 0; li < nxi; li++) xi[li] = -1.0 + (PetscScalar)li * (2.0 / (PetscScalar)(nxi - 1));
126: for (i = i_start; i < i_start + m_f; i++) {
127: /* convert to local "natural" numbering and then to PETSc global numbering */
128: row = idx_f[i - i_start_ghost];
130: i_c = (i / ratio); /* coarse grid node to left of fine grid node */
131: PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT, i_start, i_c, i_start_ghost_c); /* remainders */
132: li = i - ratio * (i / ratio);
133: if (i == mx - 1) li = nxi - 1;
135: /* corners */
136: col = (i_c - i_start_ghost_c);
137: cols[0] = idx_c[col];
138: Ni[0] = 1.0;
139: if ((li == 0) || (li == nxi - 1)) {
140: PetscCall(MatSetValue(mat, row, cols[0], Ni[0], INSERT_VALUES));
141: continue;
142: }
144: /* edges + interior */
145: /* remainders */
146: if (i == mx - 1) i_c--;
148: col = (i_c - i_start_ghost_c);
149: cols[0] = idx_c[col]; /* one left and below; or we are right on it */
150: cols[1] = idx_c[col + 1];
152: Ni[0] = 0.5 * (1.0 - xi[li]);
153: Ni[1] = 0.5 * (1.0 + xi[li]);
154: for (n = 0; n < 2; n++) {
155: if (PetscAbsScalar(Ni[n]) < 1.0e-32) cols[n] = -1;
156: }
157: PetscCall(MatSetValues(mat, 1, &row, 2, cols, Ni, INSERT_VALUES));
158: }
159: PetscCall(PetscFree(xi));
160: }
161: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
162: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
163: PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
164: PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
165: PetscCall(MatCreateMAIJ(mat, dof, A));
166: PetscCall(MatDestroy(&mat));
167: PetscFunctionReturn(PETSC_SUCCESS);
168: }
170: static PetscErrorCode DMCreateInterpolation_DA_1D_Q0(DM dac, DM daf, Mat *A)
171: {
172: PetscInt i, i_start, m_f, Mx;
173: const PetscInt *idx_f, *idx_c;
174: ISLocalToGlobalMapping ltog_f, ltog_c;
175: PetscInt m_ghost, m_ghost_c;
176: PetscInt row, col, i_start_ghost, mx, m_c, nc, ratio;
177: PetscInt i_c, i_start_c, i_start_ghost_c, cols[2], dof;
178: PetscScalar v[2], x;
179: Mat mat;
180: DMBoundaryType bx;
181: MatType mattype;
183: PetscFunctionBegin;
184: PetscCall(DMDAGetInfo(dac, NULL, &Mx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &bx, NULL, NULL, NULL));
185: PetscCall(DMDAGetInfo(daf, NULL, &mx, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
186: if (bx == DM_BOUNDARY_PERIODIC) {
187: PetscCheck(Mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be positive", Mx);
188: ratio = mx / Mx;
189: PetscCheck(ratio * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
190: } else {
191: PetscCheck(Mx >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be greater than 1", Mx);
192: ratio = (mx - 1) / (Mx - 1);
193: PetscCheck(ratio * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
194: }
196: PetscCall(DMDAGetCorners(daf, &i_start, NULL, NULL, &m_f, NULL, NULL));
197: PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, NULL, NULL, &m_ghost, NULL, NULL));
198: PetscCall(DMGetLocalToGlobalMapping(daf, <og_f));
199: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
201: PetscCall(DMDAGetCorners(dac, &i_start_c, NULL, NULL, &m_c, NULL, NULL));
202: PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, NULL, NULL, &m_ghost_c, NULL, NULL));
203: PetscCall(DMGetLocalToGlobalMapping(dac, <og_c));
204: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
206: /* create interpolation matrix */
207: PetscCall(MatCreate(PetscObjectComm((PetscObject)dac), &mat));
208: #if defined(PETSC_HAVE_CUDA)
209: /*
210: Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
211: we don't want the original unconverted matrix copied to the GPU
212: */
213: if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
214: #endif
215: PetscCall(MatSetSizes(mat, m_f, m_c, mx, Mx));
216: PetscCall(ConvertToAIJ(dac->mattype, &mattype));
217: PetscCall(MatSetType(mat, mattype));
218: PetscCall(MatSeqAIJSetPreallocation(mat, 2, NULL));
219: PetscCall(MatMPIAIJSetPreallocation(mat, 2, NULL, 0, NULL));
221: /* loop over local fine grid nodes setting interpolation for those*/
222: for (i = i_start; i < i_start + m_f; i++) {
223: /* convert to local "natural" numbering and then to PETSc global numbering */
224: row = idx_f[i - i_start_ghost];
226: i_c = (i / ratio); /* coarse grid node to left of fine grid node */
228: /*
229: Only include those interpolation points that are truly
230: nonzero. Note this is very important for final grid lines
231: in x direction; since they have no right neighbor
232: */
233: x = ((PetscReal)(i - i_c * ratio)) / ((PetscReal)ratio);
234: nc = 0;
235: /* one left and below; or we are right on it */
236: col = (i_c - i_start_ghost_c);
237: cols[nc] = idx_c[col];
238: v[nc++] = -x + 1.0;
239: /* one right? */
240: if (i_c * ratio != i) {
241: cols[nc] = idx_c[col + 1];
242: v[nc++] = x;
243: }
244: PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
245: }
246: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
247: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
248: PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
249: PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
250: PetscCall(MatCreateMAIJ(mat, dof, A));
251: PetscCall(MatDestroy(&mat));
252: PetscCall(PetscLogFlops(5.0 * m_f));
253: PetscFunctionReturn(PETSC_SUCCESS);
254: }
256: static PetscErrorCode DMCreateInterpolation_DA_2D_Q1(DM dac, DM daf, Mat *A)
257: {
258: PetscInt i, j, i_start, j_start, m_f, n_f, Mx, My, dof;
259: const PetscInt *idx_c, *idx_f;
260: ISLocalToGlobalMapping ltog_f, ltog_c;
261: PetscInt m_ghost, n_ghost, m_ghost_c, n_ghost_c, *dnz, *onz;
262: PetscInt row, col, i_start_ghost, j_start_ghost, cols[4], mx, m_c, my, nc, ratioi, ratioj;
263: 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;
264: PetscMPIInt size_c, size_f, rank_f;
265: PetscScalar v[4], x, y;
266: Mat mat;
267: DMBoundaryType bx, by;
268: MatType mattype;
270: PetscFunctionBegin;
271: PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, NULL, NULL, NULL, NULL, NULL, NULL, &bx, &by, NULL, NULL));
272: PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
273: if (bx == DM_BOUNDARY_PERIODIC) {
274: PetscCheck(Mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be positive", Mx);
275: ratioi = mx / Mx;
276: PetscCheck(ratioi * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
277: } else {
278: PetscCheck(Mx >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be greater than 1", Mx);
279: ratioi = (mx - 1) / (Mx - 1);
280: PetscCheck(ratioi * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
281: }
282: if (by == DM_BOUNDARY_PERIODIC) {
283: PetscCheck(My, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be positive", My);
284: ratioj = my / My;
285: PetscCheck(ratioj * My == my, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: my/My must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
286: } else {
287: PetscCheck(My >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be greater than 1", My);
288: ratioj = (my - 1) / (My - 1);
289: PetscCheck(ratioj * (My - 1) == my - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (my - 1)/(My - 1) must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
290: }
292: PetscCall(DMDAGetCorners(daf, &i_start, &j_start, NULL, &m_f, &n_f, NULL));
293: PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, NULL, &m_ghost, &n_ghost, NULL));
294: PetscCall(DMGetLocalToGlobalMapping(daf, <og_f));
295: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
297: PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, NULL, &m_c, &n_c, NULL));
298: PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, NULL, &m_ghost_c, &n_ghost_c, NULL));
299: PetscCall(DMGetLocalToGlobalMapping(dac, <og_c));
300: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
302: /*
303: Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
304: The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
305: processors). It's effective length is hence 4 times its normal length, this is
306: why the col_scale is multiplied by the interpolation matrix column sizes.
307: sol_shift allows each set of 1/4 processors do its own interpolation using ITS
308: copy of the coarse vector. A bit of a hack but you do better.
310: In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
311: */
312: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dac), &size_c));
313: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)daf), &size_f));
314: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)daf), &rank_f));
315: col_scale = size_f / size_c;
316: col_shift = Mx * My * (rank_f / size_c);
318: MatPreallocateBegin(PetscObjectComm((PetscObject)daf), m_f * n_f, col_scale * m_c * n_c, dnz, onz);
319: for (j = j_start; j < j_start + n_f; j++) {
320: for (i = i_start; i < i_start + m_f; i++) {
321: /* convert to local "natural" numbering and then to PETSc global numbering */
322: row = idx_f[(m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
324: i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
325: j_c = (j / ratioj); /* coarse grid node below fine grid node */
327: PetscCheck(j_c >= j_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, j_start %" PetscInt_FMT " j_c %" PetscInt_FMT " j_start_ghost_c %" PetscInt_FMT, j_start, j_c, j_start_ghost_c);
328: PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT, i_start, i_c, i_start_ghost_c);
330: /*
331: Only include those interpolation points that are truly
332: nonzero. Note this is very important for final grid lines
333: in x and y directions; since they have no right/top neighbors
334: */
335: nc = 0;
336: /* one left and below; or we are right on it */
337: col = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
338: cols[nc++] = col_shift + idx_c[col];
339: /* one right and below */
340: if (i_c * ratioi != i) cols[nc++] = col_shift + idx_c[col + 1];
341: /* one left and above */
342: if (j_c * ratioj != j) cols[nc++] = col_shift + idx_c[col + m_ghost_c];
343: /* one right and above */
344: if (i_c * ratioi != i && j_c * ratioj != j) cols[nc++] = col_shift + idx_c[col + (m_ghost_c + 1)];
345: PetscCall(MatPreallocateSet(row, nc, cols, dnz, onz));
346: }
347: }
348: PetscCall(MatCreate(PetscObjectComm((PetscObject)daf), &mat));
349: #if defined(PETSC_HAVE_CUDA)
350: /*
351: Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
352: we don't want the original unconverted matrix copied to the GPU
353: */
354: if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
355: #endif
356: PetscCall(MatSetSizes(mat, m_f * n_f, col_scale * m_c * n_c, mx * my, col_scale * Mx * My));
357: PetscCall(ConvertToAIJ(dac->mattype, &mattype));
358: PetscCall(MatSetType(mat, mattype));
359: PetscCall(MatSeqAIJSetPreallocation(mat, 0, dnz));
360: PetscCall(MatMPIAIJSetPreallocation(mat, 0, dnz, 0, onz));
361: MatPreallocateEnd(dnz, onz);
363: /* loop over local fine grid nodes setting interpolation for those*/
364: if (!NEWVERSION) {
365: for (j = j_start; j < j_start + n_f; j++) {
366: for (i = i_start; i < i_start + m_f; i++) {
367: /* convert to local "natural" numbering and then to PETSc global numbering */
368: row = idx_f[(m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
370: i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
371: j_c = (j / ratioj); /* coarse grid node below fine grid node */
373: /*
374: Only include those interpolation points that are truly
375: nonzero. Note this is very important for final grid lines
376: in x and y directions; since they have no right/top neighbors
377: */
378: x = ((PetscReal)(i - i_c * ratioi)) / ((PetscReal)ratioi);
379: y = ((PetscReal)(j - j_c * ratioj)) / ((PetscReal)ratioj);
381: nc = 0;
382: /* one left and below; or we are right on it */
383: col = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
384: cols[nc] = col_shift + idx_c[col];
385: v[nc++] = x * y - x - y + 1.0;
386: /* one right and below */
387: if (i_c * ratioi != i) {
388: cols[nc] = col_shift + idx_c[col + 1];
389: v[nc++] = -x * y + x;
390: }
391: /* one left and above */
392: if (j_c * ratioj != j) {
393: cols[nc] = col_shift + idx_c[col + m_ghost_c];
394: v[nc++] = -x * y + y;
395: }
396: /* one right and above */
397: if (j_c * ratioj != j && i_c * ratioi != i) {
398: cols[nc] = col_shift + idx_c[col + (m_ghost_c + 1)];
399: v[nc++] = x * y;
400: }
401: PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
402: }
403: }
405: } else {
406: PetscScalar Ni[4];
407: PetscScalar *xi, *eta;
408: PetscInt li, nxi, lj, neta;
410: /* compute local coordinate arrays */
411: nxi = ratioi + 1;
412: neta = ratioj + 1;
413: PetscCall(PetscMalloc1(nxi, &xi));
414: PetscCall(PetscMalloc1(neta, &eta));
415: for (li = 0; li < nxi; li++) xi[li] = -1.0 + (PetscScalar)li * (2.0 / (PetscScalar)(nxi - 1));
416: for (lj = 0; lj < neta; lj++) eta[lj] = -1.0 + (PetscScalar)lj * (2.0 / (PetscScalar)(neta - 1));
418: /* loop over local fine grid nodes setting interpolation for those*/
419: for (j = j_start; j < j_start + n_f; j++) {
420: for (i = i_start; i < i_start + m_f; i++) {
421: /* convert to local "natural" numbering and then to PETSc global numbering */
422: row = idx_f[(m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
424: i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
425: j_c = (j / ratioj); /* coarse grid node below fine grid node */
427: /* remainders */
428: li = i - ratioi * (i / ratioi);
429: if (i == mx - 1) li = nxi - 1;
430: lj = j - ratioj * (j / ratioj);
431: if (j == my - 1) lj = neta - 1;
433: /* corners */
434: col = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
435: cols[0] = col_shift + idx_c[col]; /* left, below */
436: Ni[0] = 1.0;
437: if ((li == 0) || (li == nxi - 1)) {
438: if ((lj == 0) || (lj == neta - 1)) {
439: PetscCall(MatSetValue(mat, row, cols[0], Ni[0], INSERT_VALUES));
440: continue;
441: }
442: }
444: /* edges + interior */
445: /* remainders */
446: if (i == mx - 1) i_c--;
447: if (j == my - 1) j_c--;
449: col = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
450: cols[0] = col_shift + idx_c[col]; /* left, below */
451: cols[1] = col_shift + idx_c[col + 1]; /* right, below */
452: cols[2] = col_shift + idx_c[col + m_ghost_c]; /* left, above */
453: cols[3] = col_shift + idx_c[col + (m_ghost_c + 1)]; /* right, above */
455: Ni[0] = 0.25 * (1.0 - xi[li]) * (1.0 - eta[lj]);
456: Ni[1] = 0.25 * (1.0 + xi[li]) * (1.0 - eta[lj]);
457: Ni[2] = 0.25 * (1.0 - xi[li]) * (1.0 + eta[lj]);
458: Ni[3] = 0.25 * (1.0 + xi[li]) * (1.0 + eta[lj]);
460: nc = 0;
461: if (PetscAbsScalar(Ni[0]) < 1.0e-32) cols[0] = -1;
462: if (PetscAbsScalar(Ni[1]) < 1.0e-32) cols[1] = -1;
463: if (PetscAbsScalar(Ni[2]) < 1.0e-32) cols[2] = -1;
464: if (PetscAbsScalar(Ni[3]) < 1.0e-32) cols[3] = -1;
466: PetscCall(MatSetValues(mat, 1, &row, 4, cols, Ni, INSERT_VALUES));
467: }
468: }
469: PetscCall(PetscFree(xi));
470: PetscCall(PetscFree(eta));
471: }
472: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
473: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
474: PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
475: PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
476: PetscCall(MatCreateMAIJ(mat, dof, A));
477: PetscCall(MatDestroy(&mat));
478: PetscFunctionReturn(PETSC_SUCCESS);
479: }
481: /*
482: Contributed by Andrei Draganescu <aidraga@sandia.gov>
483: */
484: static PetscErrorCode DMCreateInterpolation_DA_2D_Q0(DM dac, DM daf, Mat *A)
485: {
486: PetscInt i, j, i_start, j_start, m_f, n_f, Mx, My, dof;
487: const PetscInt *idx_c, *idx_f;
488: ISLocalToGlobalMapping ltog_f, ltog_c;
489: PetscInt m_ghost, n_ghost, m_ghost_c, n_ghost_c, *dnz, *onz;
490: PetscInt row, col, i_start_ghost, j_start_ghost, cols[4], mx, m_c, my, nc, ratioi, ratioj;
491: 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;
492: PetscMPIInt size_c, size_f, rank_f;
493: PetscScalar v[4];
494: Mat mat;
495: DMBoundaryType bx, by;
496: MatType mattype;
498: PetscFunctionBegin;
499: PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, NULL, NULL, NULL, NULL, NULL, NULL, &bx, &by, NULL, NULL));
500: PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
501: PetscCheck(Mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be positive", Mx);
502: PetscCheck(My, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be positive", My);
503: ratioi = mx / Mx;
504: ratioj = my / My;
505: PetscCheck(ratioi * Mx == mx, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Fine grid points must be multiple of coarse grid points in x");
506: PetscCheck(ratioj * My == my, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Fine grid points must be multiple of coarse grid points in y");
507: PetscCheck(ratioi == 2, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Coarsening factor in x must be 2");
508: PetscCheck(ratioj == 2, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Coarsening factor in y must be 2");
510: PetscCall(DMDAGetCorners(daf, &i_start, &j_start, NULL, &m_f, &n_f, NULL));
511: PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, NULL, &m_ghost, &n_ghost, NULL));
512: PetscCall(DMGetLocalToGlobalMapping(daf, <og_f));
513: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
515: PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, NULL, &m_c, &n_c, NULL));
516: PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, NULL, &m_ghost_c, &n_ghost_c, NULL));
517: PetscCall(DMGetLocalToGlobalMapping(dac, <og_c));
518: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
520: /*
521: Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
522: The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
523: processors). It's effective length is hence 4 times its normal length, this is
524: why the col_scale is multiplied by the interpolation matrix column sizes.
525: sol_shift allows each set of 1/4 processors do its own interpolation using ITS
526: copy of the coarse vector. A bit of a hack but you do better.
528: In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
529: */
530: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dac), &size_c));
531: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)daf), &size_f));
532: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)daf), &rank_f));
533: col_scale = size_f / size_c;
534: col_shift = Mx * My * (rank_f / size_c);
536: MatPreallocateBegin(PetscObjectComm((PetscObject)daf), m_f * n_f, col_scale * m_c * n_c, dnz, onz);
537: for (j = j_start; j < j_start + n_f; j++) {
538: for (i = i_start; i < i_start + m_f; i++) {
539: /* convert to local "natural" numbering and then to PETSc global numbering */
540: row = idx_f[(m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
542: i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
543: j_c = (j / ratioj); /* coarse grid node below fine grid node */
545: PetscCheck(j_c >= j_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, j_start %" PetscInt_FMT " j_c %" PetscInt_FMT " j_start_ghost_c %" PetscInt_FMT, j_start, j_c, j_start_ghost_c);
546: PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT, i_start, i_c, i_start_ghost_c);
548: /*
549: Only include those interpolation points that are truly
550: nonzero. Note this is very important for final grid lines
551: in x and y directions; since they have no right/top neighbors
552: */
553: nc = 0;
554: /* one left and below; or we are right on it */
555: col = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
556: cols[nc++] = col_shift + idx_c[col];
557: PetscCall(MatPreallocateSet(row, nc, cols, dnz, onz));
558: }
559: }
560: PetscCall(MatCreate(PetscObjectComm((PetscObject)daf), &mat));
561: #if defined(PETSC_HAVE_CUDA)
562: /*
563: Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
564: we don't want the original unconverted matrix copied to the GPU
565: */
566: if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
567: #endif
568: PetscCall(MatSetSizes(mat, m_f * n_f, col_scale * m_c * n_c, mx * my, col_scale * Mx * My));
569: PetscCall(ConvertToAIJ(dac->mattype, &mattype));
570: PetscCall(MatSetType(mat, mattype));
571: PetscCall(MatSeqAIJSetPreallocation(mat, 0, dnz));
572: PetscCall(MatMPIAIJSetPreallocation(mat, 0, dnz, 0, onz));
573: MatPreallocateEnd(dnz, onz);
575: /* loop over local fine grid nodes setting interpolation for those*/
576: for (j = j_start; j < j_start + n_f; j++) {
577: for (i = i_start; i < i_start + m_f; i++) {
578: /* convert to local "natural" numbering and then to PETSc global numbering */
579: row = idx_f[(m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
581: i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
582: j_c = (j / ratioj); /* coarse grid node below fine grid node */
583: nc = 0;
584: /* one left and below; or we are right on it */
585: col = (m_ghost_c * (j_c - j_start_ghost_c) + (i_c - i_start_ghost_c));
586: cols[nc] = col_shift + idx_c[col];
587: v[nc++] = 1.0;
589: PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
590: }
591: }
592: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
593: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
594: PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
595: PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
596: PetscCall(MatCreateMAIJ(mat, dof, A));
597: PetscCall(MatDestroy(&mat));
598: PetscCall(PetscLogFlops(13.0 * m_f * n_f));
599: PetscFunctionReturn(PETSC_SUCCESS);
600: }
602: /*
603: Contributed by Jianming Yang <jianming-yang@uiowa.edu>
604: */
605: static PetscErrorCode DMCreateInterpolation_DA_3D_Q0(DM dac, DM daf, Mat *A)
606: {
607: PetscInt i, j, l, i_start, j_start, l_start, m_f, n_f, p_f, Mx, My, Mz, dof;
608: const PetscInt *idx_c, *idx_f;
609: ISLocalToGlobalMapping ltog_f, ltog_c;
610: PetscInt m_ghost, n_ghost, p_ghost, m_ghost_c, n_ghost_c, p_ghost_c, nc, *dnz, *onz;
611: 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;
612: 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;
613: PetscMPIInt size_c, size_f, rank_f;
614: PetscScalar v[8];
615: Mat mat;
616: DMBoundaryType bx, by, bz;
617: MatType mattype;
619: PetscFunctionBegin;
620: PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, &Mz, NULL, NULL, NULL, NULL, NULL, &bx, &by, &bz, NULL));
621: PetscCheck(Mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be positive", Mx);
622: PetscCheck(My, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be positive", My);
623: PetscCheck(Mz, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of z coarse grid points %" PetscInt_FMT " must be positive", Mz);
624: PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, &mz, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
625: ratioi = mx / Mx;
626: ratioj = my / My;
627: ratiol = mz / Mz;
628: PetscCheck(ratioi * Mx == mx, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Fine grid points must be multiple of coarse grid points in x");
629: PetscCheck(ratioj * My == my, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Fine grid points must be multiple of coarse grid points in y");
630: PetscCheck(ratiol * Mz == mz, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Fine grid points must be multiple of coarse grid points in z");
631: PetscCheck(ratioi == 2 || ratioi == 1, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Coarsening factor in x must be 1 or 2");
632: PetscCheck(ratioj == 2 || ratioj == 1, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Coarsening factor in y must be 1 or 2");
633: PetscCheck(ratiol == 2 || ratiol == 1, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_WRONG, "Coarsening factor in z must be 1 or 2");
635: PetscCall(DMDAGetCorners(daf, &i_start, &j_start, &l_start, &m_f, &n_f, &p_f));
636: PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, &l_start_ghost, &m_ghost, &n_ghost, &p_ghost));
637: PetscCall(DMGetLocalToGlobalMapping(daf, <og_f));
638: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
640: PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, &l_start_c, &m_c, &n_c, &p_c));
641: PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, &l_start_ghost_c, &m_ghost_c, &n_ghost_c, &p_ghost_c));
642: PetscCall(DMGetLocalToGlobalMapping(dac, <og_c));
643: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
645: /*
646: Used for handling a coarse DMDA that lives on 1/4 the processors of the fine DMDA.
647: The coarse vector is then duplicated 4 times (each time it lives on 1/4 of the
648: processors). It's effective length is hence 4 times its normal length, this is
649: why the col_scale is multiplied by the interpolation matrix column sizes.
650: sol_shift allows each set of 1/4 processors do its own interpolation using ITS
651: copy of the coarse vector. A bit of a hack but you do better.
653: In the standard case when size_f == size_c col_scale == 1 and col_shift == 0
654: */
655: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dac), &size_c));
656: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)daf), &size_f));
657: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)daf), &rank_f));
658: col_scale = size_f / size_c;
659: col_shift = Mx * My * Mz * (rank_f / size_c);
661: MatPreallocateBegin(PetscObjectComm((PetscObject)daf), m_f * n_f * p_f, col_scale * m_c * n_c * p_c, dnz, onz);
662: for (l = l_start; l < l_start + p_f; l++) {
663: for (j = j_start; j < j_start + n_f; j++) {
664: for (i = i_start; i < i_start + m_f; i++) {
665: /* convert to local "natural" numbering and then to PETSc global numbering */
666: row = idx_f[(m_ghost * n_ghost * (l - l_start_ghost) + m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
668: i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
669: j_c = (j / ratioj); /* coarse grid node below fine grid node */
670: l_c = (l / ratiol);
672: PetscCheck(l_c >= l_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, l_start %" PetscInt_FMT " l_c %" PetscInt_FMT " l_start_ghost_c %" PetscInt_FMT, l_start, l_c, l_start_ghost_c);
673: PetscCheck(j_c >= j_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, j_start %" PetscInt_FMT " j_c %" PetscInt_FMT " j_start_ghost_c %" PetscInt_FMT, j_start, j_c, j_start_ghost_c);
674: PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT, i_start, i_c, i_start_ghost_c);
676: /*
677: Only include those interpolation points that are truly
678: nonzero. Note this is very important for final grid lines
679: in x and y directions; since they have no right/top neighbors
680: */
681: nc = 0;
682: /* one left and below; or we are right on it */
683: col = (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));
684: cols[nc++] = col_shift + idx_c[col];
685: PetscCall(MatPreallocateSet(row, nc, cols, dnz, onz));
686: }
687: }
688: }
689: PetscCall(MatCreate(PetscObjectComm((PetscObject)daf), &mat));
690: #if defined(PETSC_HAVE_CUDA)
691: /*
692: Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
693: we don't want the original unconverted matrix copied to the GPU
694: */
695: if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
696: #endif
697: PetscCall(MatSetSizes(mat, m_f * n_f * p_f, col_scale * m_c * n_c * p_c, mx * my * mz, col_scale * Mx * My * Mz));
698: PetscCall(ConvertToAIJ(dac->mattype, &mattype));
699: PetscCall(MatSetType(mat, mattype));
700: PetscCall(MatSeqAIJSetPreallocation(mat, 0, dnz));
701: PetscCall(MatMPIAIJSetPreallocation(mat, 0, dnz, 0, onz));
702: MatPreallocateEnd(dnz, onz);
704: /* loop over local fine grid nodes setting interpolation for those*/
705: for (l = l_start; l < l_start + p_f; l++) {
706: for (j = j_start; j < j_start + n_f; j++) {
707: for (i = i_start; i < i_start + m_f; i++) {
708: /* convert to local "natural" numbering and then to PETSc global numbering */
709: row = idx_f[(m_ghost * n_ghost * (l - l_start_ghost) + m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
711: i_c = (i / ratioi); /* coarse grid node to left of fine grid node */
712: j_c = (j / ratioj); /* coarse grid node below fine grid node */
713: l_c = (l / ratiol);
714: nc = 0;
715: /* one left and below; or we are right on it */
716: col = (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));
717: cols[nc] = col_shift + idx_c[col];
718: v[nc++] = 1.0;
720: PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
721: }
722: }
723: }
724: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
725: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
726: PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
727: PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
728: PetscCall(MatCreateMAIJ(mat, dof, A));
729: PetscCall(MatDestroy(&mat));
730: PetscCall(PetscLogFlops(13.0 * m_f * n_f * p_f));
731: PetscFunctionReturn(PETSC_SUCCESS);
732: }
734: static PetscErrorCode DMCreateInterpolation_DA_3D_Q1(DM dac, DM daf, Mat *A)
735: {
736: PetscInt i, j, i_start, j_start, m_f, n_f, Mx, My, dof, l;
737: const PetscInt *idx_c, *idx_f;
738: ISLocalToGlobalMapping ltog_f, ltog_c;
739: PetscInt m_ghost, n_ghost, m_ghost_c, n_ghost_c, Mz, mz;
740: PetscInt row, col, i_start_ghost, j_start_ghost, cols[8], mx, m_c, my, nc, ratioi, ratioj, ratiok;
741: PetscInt i_c, j_c, i_start_c, j_start_c, n_c, i_start_ghost_c, j_start_ghost_c;
742: PetscInt l_start, p_f, l_start_ghost, p_ghost, l_start_c, p_c;
743: PetscInt l_start_ghost_c, p_ghost_c, l_c, *dnz, *onz;
744: PetscScalar v[8], x, y, z;
745: Mat mat;
746: DMBoundaryType bx, by, bz;
747: MatType mattype;
749: PetscFunctionBegin;
750: PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, &Mz, NULL, NULL, NULL, NULL, NULL, &bx, &by, &bz, NULL));
751: PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, &mz, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
752: if (mx == Mx) {
753: ratioi = 1;
754: } else if (bx == DM_BOUNDARY_PERIODIC) {
755: PetscCheck(Mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be positive", Mx);
756: ratioi = mx / Mx;
757: PetscCheck(ratioi * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
758: } else {
759: PetscCheck(Mx >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of x coarse grid points %" PetscInt_FMT " must be greater than 1", Mx);
760: ratioi = (mx - 1) / (Mx - 1);
761: PetscCheck(ratioi * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
762: }
763: if (my == My) {
764: ratioj = 1;
765: } else if (by == DM_BOUNDARY_PERIODIC) {
766: PetscCheck(My, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be positive", My);
767: ratioj = my / My;
768: PetscCheck(ratioj * My == my, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: my/My must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
769: } else {
770: PetscCheck(My >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of y coarse grid points %" PetscInt_FMT " must be greater than 1", My);
771: ratioj = (my - 1) / (My - 1);
772: PetscCheck(ratioj * (My - 1) == my - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (my - 1)/(My - 1) must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
773: }
774: if (mz == Mz) {
775: ratiok = 1;
776: } else if (bz == DM_BOUNDARY_PERIODIC) {
777: PetscCheck(Mz, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of z coarse grid points %" PetscInt_FMT " must be positive", Mz);
778: ratiok = mz / Mz;
779: PetscCheck(ratiok * Mz == mz, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mz/Mz must be integer: mz %" PetscInt_FMT " Mz %" PetscInt_FMT, mz, Mz);
780: } else {
781: PetscCheck(Mz >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of z coarse grid points %" PetscInt_FMT " must be greater than 1", Mz);
782: ratiok = (mz - 1) / (Mz - 1);
783: PetscCheck(ratiok * (Mz - 1) == mz - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %" PetscInt_FMT " Mz %" PetscInt_FMT, mz, Mz);
784: }
786: PetscCall(DMDAGetCorners(daf, &i_start, &j_start, &l_start, &m_f, &n_f, &p_f));
787: PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, &l_start_ghost, &m_ghost, &n_ghost, &p_ghost));
788: PetscCall(DMGetLocalToGlobalMapping(daf, <og_f));
789: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
791: PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, &l_start_c, &m_c, &n_c, &p_c));
792: PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, &l_start_ghost_c, &m_ghost_c, &n_ghost_c, &p_ghost_c));
793: PetscCall(DMGetLocalToGlobalMapping(dac, <og_c));
794: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
796: /* create interpolation matrix, determining exact preallocation */
797: MatPreallocateBegin(PetscObjectComm((PetscObject)dac), m_f * n_f * p_f, m_c * n_c * p_c, dnz, onz);
798: /* loop over local fine grid nodes counting interpolating points */
799: for (l = l_start; l < l_start + p_f; l++) {
800: for (j = j_start; j < j_start + n_f; j++) {
801: for (i = i_start; i < i_start + m_f; i++) {
802: /* convert to local "natural" numbering and then to PETSc global numbering */
803: row = idx_f[(m_ghost * n_ghost * (l - l_start_ghost) + m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
804: i_c = (i / ratioi);
805: j_c = (j / ratioj);
806: l_c = (l / ratiok);
807: PetscCheck(l_c >= l_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, l_start %" PetscInt_FMT " l_c %" PetscInt_FMT " l_start_ghost_c %" PetscInt_FMT, l_start, l_c, l_start_ghost_c);
808: PetscCheck(j_c >= j_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, j_start %" PetscInt_FMT " j_c %" PetscInt_FMT " j_start_ghost_c %" PetscInt_FMT, j_start, j_c, j_start_ghost_c);
809: PetscCheck(i_c >= i_start_ghost_c, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, i_start %" PetscInt_FMT " i_c %" PetscInt_FMT " i_start_ghost_c %" PetscInt_FMT, i_start, i_c, i_start_ghost_c);
811: /*
812: Only include those interpolation points that are truly
813: nonzero. Note this is very important for final grid lines
814: in x and y directions; since they have no right/top neighbors
815: */
816: nc = 0;
817: col = (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));
818: cols[nc++] = idx_c[col];
819: if (i_c * ratioi != i) cols[nc++] = idx_c[col + 1];
820: if (j_c * ratioj != j) cols[nc++] = idx_c[col + m_ghost_c];
821: if (l_c * ratiok != l) cols[nc++] = idx_c[col + m_ghost_c * n_ghost_c];
822: if (j_c * ratioj != j && i_c * ratioi != i) cols[nc++] = idx_c[col + (m_ghost_c + 1)];
823: if (j_c * ratioj != j && l_c * ratiok != l) cols[nc++] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c)];
824: if (i_c * ratioi != i && l_c * ratiok != l) cols[nc++] = idx_c[col + (m_ghost_c * n_ghost_c + 1)];
825: if (i_c * ratioi != i && l_c * ratiok != l && j_c * ratioj != j) cols[nc++] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c + 1)];
826: PetscCall(MatPreallocateSet(row, nc, cols, dnz, onz));
827: }
828: }
829: }
830: PetscCall(MatCreate(PetscObjectComm((PetscObject)dac), &mat));
831: #if defined(PETSC_HAVE_CUDA)
832: /*
833: Temporary hack: Since the MAIJ matrix must be converted to AIJ before being used by the GPU
834: we don't want the original unconverted matrix copied to the GPU
835: */
836: if (dof > 1) PetscCall(MatBindToCPU(mat, PETSC_TRUE));
837: #endif
838: PetscCall(MatSetSizes(mat, m_f * n_f * p_f, m_c * n_c * p_c, mx * my * mz, Mx * My * Mz));
839: PetscCall(ConvertToAIJ(dac->mattype, &mattype));
840: PetscCall(MatSetType(mat, mattype));
841: PetscCall(MatSeqAIJSetPreallocation(mat, 0, dnz));
842: PetscCall(MatMPIAIJSetPreallocation(mat, 0, dnz, 0, onz));
843: MatPreallocateEnd(dnz, onz);
845: /* loop over local fine grid nodes setting interpolation for those*/
846: if (!NEWVERSION) {
847: for (l = l_start; l < l_start + p_f; l++) {
848: for (j = j_start; j < j_start + n_f; j++) {
849: for (i = i_start; i < i_start + m_f; i++) {
850: /* convert to local "natural" numbering and then to PETSc global numbering */
851: row = idx_f[(m_ghost * n_ghost * (l - l_start_ghost) + m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
853: i_c = (i / ratioi);
854: j_c = (j / ratioj);
855: l_c = (l / ratiok);
857: /*
858: Only include those interpolation points that are truly
859: nonzero. Note this is very important for final grid lines
860: in x and y directions; since they have no right/top neighbors
861: */
862: x = ((PetscReal)(i - i_c * ratioi)) / ((PetscReal)ratioi);
863: y = ((PetscReal)(j - j_c * ratioj)) / ((PetscReal)ratioj);
864: z = ((PetscReal)(l - l_c * ratiok)) / ((PetscReal)ratiok);
866: nc = 0;
867: /* one left and below; or we are right on it */
868: col = (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));
870: cols[nc] = idx_c[col];
871: v[nc++] = .125 * (1. - (2.0 * x - 1.)) * (1. - (2.0 * y - 1.)) * (1. - (2.0 * z - 1.));
873: if (i_c * ratioi != i) {
874: cols[nc] = idx_c[col + 1];
875: v[nc++] = .125 * (1. + (2.0 * x - 1.)) * (1. - (2.0 * y - 1.)) * (1. - (2.0 * z - 1.));
876: }
878: if (j_c * ratioj != j) {
879: cols[nc] = idx_c[col + m_ghost_c];
880: v[nc++] = .125 * (1. - (2.0 * x - 1.)) * (1. + (2.0 * y - 1.)) * (1. - (2.0 * z - 1.));
881: }
883: if (l_c * ratiok != l) {
884: cols[nc] = idx_c[col + m_ghost_c * n_ghost_c];
885: v[nc++] = .125 * (1. - (2.0 * x - 1.)) * (1. - (2.0 * y - 1.)) * (1. + (2.0 * z - 1.));
886: }
888: if (j_c * ratioj != j && i_c * ratioi != i) {
889: cols[nc] = idx_c[col + (m_ghost_c + 1)];
890: v[nc++] = .125 * (1. + (2.0 * x - 1.)) * (1. + (2.0 * y - 1.)) * (1. - (2.0 * z - 1.));
891: }
893: if (j_c * ratioj != j && l_c * ratiok != l) {
894: cols[nc] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c)];
895: v[nc++] = .125 * (1. - (2.0 * x - 1.)) * (1. + (2.0 * y - 1.)) * (1. + (2.0 * z - 1.));
896: }
898: if (i_c * ratioi != i && l_c * ratiok != l) {
899: cols[nc] = idx_c[col + (m_ghost_c * n_ghost_c + 1)];
900: v[nc++] = .125 * (1. + (2.0 * x - 1.)) * (1. - (2.0 * y - 1.)) * (1. + (2.0 * z - 1.));
901: }
903: if (i_c * ratioi != i && l_c * ratiok != l && j_c * ratioj != j) {
904: cols[nc] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c + 1)];
905: v[nc++] = .125 * (1. + (2.0 * x - 1.)) * (1. + (2.0 * y - 1.)) * (1. + (2.0 * z - 1.));
906: }
907: PetscCall(MatSetValues(mat, 1, &row, nc, cols, v, INSERT_VALUES));
908: }
909: }
910: }
912: } else {
913: PetscScalar *xi, *eta, *zeta;
914: PetscInt li, nxi, lj, neta, lk, nzeta, n;
915: PetscScalar Ni[8];
917: /* compute local coordinate arrays */
918: nxi = ratioi + 1;
919: neta = ratioj + 1;
920: nzeta = ratiok + 1;
921: PetscCall(PetscMalloc1(nxi, &xi));
922: PetscCall(PetscMalloc1(neta, &eta));
923: PetscCall(PetscMalloc1(nzeta, &zeta));
924: for (li = 0; li < nxi; li++) xi[li] = -1.0 + (PetscScalar)li * (2.0 / (PetscScalar)(nxi - 1));
925: for (lj = 0; lj < neta; lj++) eta[lj] = -1.0 + (PetscScalar)lj * (2.0 / (PetscScalar)(neta - 1));
926: for (lk = 0; lk < nzeta; lk++) zeta[lk] = -1.0 + (PetscScalar)lk * (2.0 / (PetscScalar)(nzeta - 1));
928: for (l = l_start; l < l_start + p_f; l++) {
929: for (j = j_start; j < j_start + n_f; j++) {
930: for (i = i_start; i < i_start + m_f; i++) {
931: /* convert to local "natural" numbering and then to PETSc global numbering */
932: row = idx_f[(m_ghost * n_ghost * (l - l_start_ghost) + m_ghost * (j - j_start_ghost) + (i - i_start_ghost))];
934: i_c = (i / ratioi);
935: j_c = (j / ratioj);
936: l_c = (l / ratiok);
938: /* remainders */
939: li = i - ratioi * (i / ratioi);
940: if (i == mx - 1) li = nxi - 1;
941: lj = j - ratioj * (j / ratioj);
942: if (j == my - 1) lj = neta - 1;
943: lk = l - ratiok * (l / ratiok);
944: if (l == mz - 1) lk = nzeta - 1;
946: /* corners */
947: col = (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));
948: cols[0] = idx_c[col];
949: Ni[0] = 1.0;
950: if ((li == 0) || (li == nxi - 1)) {
951: if ((lj == 0) || (lj == neta - 1)) {
952: if ((lk == 0) || (lk == nzeta - 1)) {
953: PetscCall(MatSetValue(mat, row, cols[0], Ni[0], INSERT_VALUES));
954: continue;
955: }
956: }
957: }
959: /* edges + interior */
960: /* remainders */
961: if (i == mx - 1) i_c--;
962: if (j == my - 1) j_c--;
963: if (l == mz - 1) l_c--;
965: col = (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));
966: cols[0] = idx_c[col]; /* one left and below; or we are right on it */
967: cols[1] = idx_c[col + 1]; /* one right and below */
968: cols[2] = idx_c[col + m_ghost_c]; /* one left and above */
969: cols[3] = idx_c[col + (m_ghost_c + 1)]; /* one right and above */
971: cols[4] = idx_c[col + m_ghost_c * n_ghost_c]; /* one left and below and front; or we are right on it */
972: cols[5] = idx_c[col + (m_ghost_c * n_ghost_c + 1)]; /* one right and below, and front */
973: cols[6] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c)]; /* one left and above and front*/
974: cols[7] = idx_c[col + (m_ghost_c * n_ghost_c + m_ghost_c + 1)]; /* one right and above and front */
976: Ni[0] = 0.125 * (1.0 - xi[li]) * (1.0 - eta[lj]) * (1.0 - zeta[lk]);
977: Ni[1] = 0.125 * (1.0 + xi[li]) * (1.0 - eta[lj]) * (1.0 - zeta[lk]);
978: Ni[2] = 0.125 * (1.0 - xi[li]) * (1.0 + eta[lj]) * (1.0 - zeta[lk]);
979: Ni[3] = 0.125 * (1.0 + xi[li]) * (1.0 + eta[lj]) * (1.0 - zeta[lk]);
981: Ni[4] = 0.125 * (1.0 - xi[li]) * (1.0 - eta[lj]) * (1.0 + zeta[lk]);
982: Ni[5] = 0.125 * (1.0 + xi[li]) * (1.0 - eta[lj]) * (1.0 + zeta[lk]);
983: Ni[6] = 0.125 * (1.0 - xi[li]) * (1.0 + eta[lj]) * (1.0 + zeta[lk]);
984: Ni[7] = 0.125 * (1.0 + xi[li]) * (1.0 + eta[lj]) * (1.0 + zeta[lk]);
986: for (n = 0; n < 8; n++) {
987: if (PetscAbsScalar(Ni[n]) < 1.0e-32) cols[n] = -1;
988: }
989: PetscCall(MatSetValues(mat, 1, &row, 8, cols, Ni, INSERT_VALUES));
990: }
991: }
992: }
993: PetscCall(PetscFree(xi));
994: PetscCall(PetscFree(eta));
995: PetscCall(PetscFree(zeta));
996: }
997: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
998: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
999: PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY));
1000: PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY));
1002: PetscCall(MatCreateMAIJ(mat, dof, A));
1003: PetscCall(MatDestroy(&mat));
1004: PetscFunctionReturn(PETSC_SUCCESS);
1005: }
1007: PetscErrorCode DMCreateInterpolation_DA(DM dac, DM daf, Mat *A, Vec *scale)
1008: {
1009: PetscInt dimc, Mc, Nc, Pc, mc, nc, pc, dofc, sc, dimf, Mf, Nf, Pf, mf, nf, pf, doff, sf;
1010: DMBoundaryType bxc, byc, bzc, bxf, byf, bzf;
1011: DMDAStencilType stc, stf;
1012: DM_DA *ddc = (DM_DA *)dac->data;
1014: PetscFunctionBegin;
1017: PetscAssertPointer(A, 3);
1018: if (scale) PetscAssertPointer(scale, 4);
1020: PetscCall(DMDAGetInfo(dac, &dimc, &Mc, &Nc, &Pc, &mc, &nc, &pc, &dofc, &sc, &bxc, &byc, &bzc, &stc));
1021: PetscCall(DMDAGetInfo(daf, &dimf, &Mf, &Nf, &Pf, &mf, &nf, &pf, &doff, &sf, &bxf, &byf, &bzf, &stf));
1022: PetscCheck(dimc == dimf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Dimensions of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dimc, dimf);
1023: PetscCheck(dofc == doff, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "DOF of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dofc, doff);
1024: PetscCheck(sc == sf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil width of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, sc, sf);
1025: PetscCheck(bxc == bxf && byc == byf && bzc == bzf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Boundary type different in two DMDAs");
1026: PetscCheck(stc == stf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil type different in two DMDAs");
1027: PetscCheck(Mc >= 2 || Mf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in x direction");
1028: PetscCheck(dimc <= 1 || Nc >= 2 || Nf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in y direction");
1029: PetscCheck(dimc <= 2 || Pc >= 2 || Pf <= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in z direction");
1031: if (ddc->interptype == DMDA_Q1) {
1032: if (dimc == 1) {
1033: PetscCall(DMCreateInterpolation_DA_1D_Q1(dac, daf, A));
1034: } else if (dimc == 2) {
1035: PetscCall(DMCreateInterpolation_DA_2D_Q1(dac, daf, A));
1036: } else if (dimc == 3) {
1037: PetscCall(DMCreateInterpolation_DA_3D_Q1(dac, daf, A));
1038: } else SETERRQ(PetscObjectComm((PetscObject)daf), PETSC_ERR_SUP, "No support for this DMDA dimension %" PetscInt_FMT " for interpolation type %d", dimc, (int)ddc->interptype);
1039: } else if (ddc->interptype == DMDA_Q0) {
1040: if (dimc == 1) {
1041: PetscCall(DMCreateInterpolation_DA_1D_Q0(dac, daf, A));
1042: } else if (dimc == 2) {
1043: PetscCall(DMCreateInterpolation_DA_2D_Q0(dac, daf, A));
1044: } else if (dimc == 3) {
1045: PetscCall(DMCreateInterpolation_DA_3D_Q0(dac, daf, A));
1046: } else SETERRQ(PetscObjectComm((PetscObject)daf), PETSC_ERR_SUP, "No support for this DMDA dimension %" PetscInt_FMT " for interpolation type %d", dimc, (int)ddc->interptype);
1047: }
1048: if (scale) PetscCall(DMCreateInterpolationScale(dac, daf, *A, scale));
1049: PetscFunctionReturn(PETSC_SUCCESS);
1050: }
1052: static PetscErrorCode DMCreateInjection_DA_1D(DM dac, DM daf, VecScatter *inject)
1053: {
1054: PetscInt i, i_start, m_f, Mx, dof;
1055: const PetscInt *idx_f;
1056: ISLocalToGlobalMapping ltog_f;
1057: PetscInt m_ghost, m_ghost_c;
1058: PetscInt row, i_start_ghost, mx, m_c, nc, ratioi;
1059: PetscInt i_start_c, i_start_ghost_c;
1060: PetscInt *cols;
1061: DMBoundaryType bx;
1062: Vec vecf, vecc;
1063: IS isf;
1065: PetscFunctionBegin;
1066: PetscCall(DMDAGetInfo(dac, NULL, &Mx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &bx, NULL, NULL, NULL));
1067: PetscCall(DMDAGetInfo(daf, NULL, &mx, NULL, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
1068: if (bx == DM_BOUNDARY_PERIODIC) {
1069: ratioi = mx / Mx;
1070: PetscCheck(ratioi * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
1071: } else {
1072: ratioi = (mx - 1) / (Mx - 1);
1073: PetscCheck(ratioi * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
1074: }
1076: PetscCall(DMDAGetCorners(daf, &i_start, NULL, NULL, &m_f, NULL, NULL));
1077: PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, NULL, NULL, &m_ghost, NULL, NULL));
1078: PetscCall(DMGetLocalToGlobalMapping(daf, <og_f));
1079: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
1081: PetscCall(DMDAGetCorners(dac, &i_start_c, NULL, NULL, &m_c, NULL, NULL));
1082: PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, NULL, NULL, &m_ghost_c, NULL, NULL));
1084: /* loop over local fine grid nodes setting interpolation for those*/
1085: nc = 0;
1086: PetscCall(PetscMalloc1(m_f, &cols));
1088: for (i = i_start_c; i < i_start_c + m_c; i++) {
1089: PetscInt i_f = i * ratioi;
1091: PetscCheck(i_f >= i_start_ghost && i_f < i_start_ghost + m_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, i_c %" PetscInt_FMT " i_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]", i, i_f, i_start_ghost, i_start_ghost + m_ghost);
1093: row = idx_f[i_f - i_start_ghost];
1094: cols[nc++] = row;
1095: }
1097: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
1098: PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)daf), dof, nc, cols, PETSC_OWN_POINTER, &isf));
1099: PetscCall(DMGetGlobalVector(dac, &vecc));
1100: PetscCall(DMGetGlobalVector(daf, &vecf));
1101: PetscCall(VecScatterCreate(vecf, isf, vecc, NULL, inject));
1102: PetscCall(DMRestoreGlobalVector(dac, &vecc));
1103: PetscCall(DMRestoreGlobalVector(daf, &vecf));
1104: PetscCall(ISDestroy(&isf));
1105: PetscFunctionReturn(PETSC_SUCCESS);
1106: }
1108: static PetscErrorCode DMCreateInjection_DA_2D(DM dac, DM daf, VecScatter *inject)
1109: {
1110: PetscInt i, j, i_start, j_start, m_f, n_f, Mx, My, dof;
1111: const PetscInt *idx_c, *idx_f;
1112: ISLocalToGlobalMapping ltog_f, ltog_c;
1113: PetscInt m_ghost, n_ghost, m_ghost_c, n_ghost_c;
1114: PetscInt row, i_start_ghost, j_start_ghost, mx, m_c, my, nc, ratioi, ratioj;
1115: PetscInt i_start_c, j_start_c, n_c, i_start_ghost_c, j_start_ghost_c;
1116: PetscInt *cols;
1117: DMBoundaryType bx, by;
1118: Vec vecf, vecc;
1119: IS isf;
1121: PetscFunctionBegin;
1122: PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, NULL, NULL, NULL, NULL, NULL, NULL, &bx, &by, NULL, NULL));
1123: PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, NULL, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
1124: if (bx == DM_BOUNDARY_PERIODIC) {
1125: ratioi = mx / Mx;
1126: PetscCheck(ratioi * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
1127: } else {
1128: ratioi = (mx - 1) / (Mx - 1);
1129: PetscCheck(ratioi * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
1130: }
1131: if (by == DM_BOUNDARY_PERIODIC) {
1132: ratioj = my / My;
1133: PetscCheck(ratioj * My == my, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: my/My must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
1134: } else {
1135: ratioj = (my - 1) / (My - 1);
1136: PetscCheck(ratioj * (My - 1) == my - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (my - 1)/(My - 1) must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
1137: }
1139: PetscCall(DMDAGetCorners(daf, &i_start, &j_start, NULL, &m_f, &n_f, NULL));
1140: PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, NULL, &m_ghost, &n_ghost, NULL));
1141: PetscCall(DMGetLocalToGlobalMapping(daf, <og_f));
1142: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
1144: PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, NULL, &m_c, &n_c, NULL));
1145: PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, NULL, &m_ghost_c, &n_ghost_c, NULL));
1146: PetscCall(DMGetLocalToGlobalMapping(dac, <og_c));
1147: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
1149: /* loop over local fine grid nodes setting interpolation for those*/
1150: nc = 0;
1151: PetscCall(PetscMalloc1(n_f * m_f, &cols));
1152: for (j = j_start_c; j < j_start_c + n_c; j++) {
1153: for (i = i_start_c; i < i_start_c + m_c; i++) {
1154: PetscInt i_f = i * ratioi, j_f = j * ratioj;
1155: PetscCheck(j_f >= j_start_ghost && j_f < j_start_ghost + n_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, j_c %" PetscInt_FMT " j_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]", j, j_f, j_start_ghost, j_start_ghost + n_ghost);
1156: PetscCheck(i_f >= i_start_ghost && i_f < i_start_ghost + m_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Processor's coarse DMDA must lie over fine DMDA, i_c %" PetscInt_FMT " i_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]", i, i_f, i_start_ghost, i_start_ghost + m_ghost);
1157: row = idx_f[(m_ghost * (j_f - j_start_ghost) + (i_f - i_start_ghost))];
1158: cols[nc++] = row;
1159: }
1160: }
1161: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
1162: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
1164: PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)daf), dof, nc, cols, PETSC_OWN_POINTER, &isf));
1165: PetscCall(DMGetGlobalVector(dac, &vecc));
1166: PetscCall(DMGetGlobalVector(daf, &vecf));
1167: PetscCall(VecScatterCreate(vecf, isf, vecc, NULL, inject));
1168: PetscCall(DMRestoreGlobalVector(dac, &vecc));
1169: PetscCall(DMRestoreGlobalVector(daf, &vecf));
1170: PetscCall(ISDestroy(&isf));
1171: PetscFunctionReturn(PETSC_SUCCESS);
1172: }
1174: static PetscErrorCode DMCreateInjection_DA_3D(DM dac, DM daf, VecScatter *inject)
1175: {
1176: PetscInt i, j, k, i_start, j_start, k_start, m_f, n_f, p_f, Mx, My, Mz;
1177: PetscInt m_ghost, n_ghost, p_ghost, m_ghost_c, n_ghost_c, p_ghost_c;
1178: PetscInt i_start_ghost, j_start_ghost, k_start_ghost;
1179: PetscInt mx, my, mz, ratioi, ratioj, ratiok;
1180: PetscInt i_start_c, j_start_c, k_start_c;
1181: PetscInt m_c, n_c, p_c;
1182: PetscInt i_start_ghost_c, j_start_ghost_c, k_start_ghost_c;
1183: PetscInt row, nc, dof;
1184: const PetscInt *idx_c, *idx_f;
1185: ISLocalToGlobalMapping ltog_f, ltog_c;
1186: PetscInt *cols;
1187: DMBoundaryType bx, by, bz;
1188: Vec vecf, vecc;
1189: IS isf;
1191: PetscFunctionBegin;
1192: PetscCall(DMDAGetInfo(dac, NULL, &Mx, &My, &Mz, NULL, NULL, NULL, NULL, NULL, &bx, &by, &bz, NULL));
1193: PetscCall(DMDAGetInfo(daf, NULL, &mx, &my, &mz, NULL, NULL, NULL, &dof, NULL, NULL, NULL, NULL, NULL));
1195: if (bx == DM_BOUNDARY_PERIODIC) {
1196: ratioi = mx / Mx;
1197: PetscCheck(ratioi * Mx == mx, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mx/Mx must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
1198: } else {
1199: ratioi = (mx - 1) / (Mx - 1);
1200: PetscCheck(ratioi * (Mx - 1) == mx - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mx - 1)/(Mx - 1) must be integer: mx %" PetscInt_FMT " Mx %" PetscInt_FMT, mx, Mx);
1201: }
1202: if (by == DM_BOUNDARY_PERIODIC) {
1203: ratioj = my / My;
1204: PetscCheck(ratioj * My == my, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: my/My must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
1205: } else {
1206: ratioj = (my - 1) / (My - 1);
1207: PetscCheck(ratioj * (My - 1) == my - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (my - 1)/(My - 1) must be integer: my %" PetscInt_FMT " My %" PetscInt_FMT, my, My);
1208: }
1209: if (bz == DM_BOUNDARY_PERIODIC) {
1210: ratiok = mz / Mz;
1211: PetscCheck(ratiok * Mz == mz, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: mz/Mz must be integer: mz %" PetscInt_FMT " My %" PetscInt_FMT, mz, Mz);
1212: } else {
1213: ratiok = (mz - 1) / (Mz - 1);
1214: PetscCheck(ratiok * (Mz - 1) == mz - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Ratio between levels: (mz - 1)/(Mz - 1) must be integer: mz %" PetscInt_FMT " Mz %" PetscInt_FMT, mz, Mz);
1215: }
1217: PetscCall(DMDAGetCorners(daf, &i_start, &j_start, &k_start, &m_f, &n_f, &p_f));
1218: PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, &k_start_ghost, &m_ghost, &n_ghost, &p_ghost));
1219: PetscCall(DMGetLocalToGlobalMapping(daf, <og_f));
1220: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_f, &idx_f));
1222: PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, &k_start_c, &m_c, &n_c, &p_c));
1223: PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, &k_start_ghost_c, &m_ghost_c, &n_ghost_c, &p_ghost_c));
1224: PetscCall(DMGetLocalToGlobalMapping(dac, <og_c));
1225: PetscCall(ISLocalToGlobalMappingGetBlockIndices(ltog_c, &idx_c));
1227: /* loop over local fine grid nodes setting interpolation for those*/
1228: nc = 0;
1229: PetscCall(PetscMalloc1(n_f * m_f * p_f, &cols));
1230: for (k = k_start_c; k < k_start_c + p_c; k++) {
1231: for (j = j_start_c; j < j_start_c + n_c; j++) {
1232: for (i = i_start_c; i < i_start_c + m_c; i++) {
1233: PetscInt i_f = i * ratioi, j_f = j * ratioj, k_f = k * ratiok;
1234: PetscCheck(k_f >= k_start_ghost && k_f < k_start_ghost + p_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP,
1235: "Processor's coarse DMDA must lie over fine DMDA "
1236: "k_c %" PetscInt_FMT " k_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]",
1237: k, k_f, k_start_ghost, k_start_ghost + p_ghost);
1238: PetscCheck(j_f >= j_start_ghost && j_f < j_start_ghost + n_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP,
1239: "Processor's coarse DMDA must lie over fine DMDA "
1240: "j_c %" PetscInt_FMT " j_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]",
1241: j, j_f, j_start_ghost, j_start_ghost + n_ghost);
1242: PetscCheck(i_f >= i_start_ghost && i_f < i_start_ghost + m_ghost, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP,
1243: "Processor's coarse DMDA must lie over fine DMDA "
1244: "i_c %" PetscInt_FMT " i_f %" PetscInt_FMT " fine ghost range [%" PetscInt_FMT ",%" PetscInt_FMT "]",
1245: i, i_f, i_start_ghost, i_start_ghost + m_ghost);
1246: row = idx_f[(m_ghost * n_ghost * (k_f - k_start_ghost) + m_ghost * (j_f - j_start_ghost) + (i_f - i_start_ghost))];
1247: cols[nc++] = row;
1248: }
1249: }
1250: }
1251: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_f, &idx_f));
1252: PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(ltog_c, &idx_c));
1254: PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)daf), dof, nc, cols, PETSC_OWN_POINTER, &isf));
1255: PetscCall(DMGetGlobalVector(dac, &vecc));
1256: PetscCall(DMGetGlobalVector(daf, &vecf));
1257: PetscCall(VecScatterCreate(vecf, isf, vecc, NULL, inject));
1258: PetscCall(DMRestoreGlobalVector(dac, &vecc));
1259: PetscCall(DMRestoreGlobalVector(daf, &vecf));
1260: PetscCall(ISDestroy(&isf));
1261: PetscFunctionReturn(PETSC_SUCCESS);
1262: }
1264: PetscErrorCode DMCreateInjection_DA(DM dac, DM daf, Mat *mat)
1265: {
1266: PetscInt dimc, Mc, Nc, Pc, mc, nc, pc, dofc, sc, dimf, Mf, Nf, Pf, mf, nf, pf, doff, sf;
1267: DMBoundaryType bxc, byc, bzc, bxf, byf, bzf;
1268: DMDAStencilType stc, stf;
1269: VecScatter inject = NULL;
1271: PetscFunctionBegin;
1274: PetscAssertPointer(mat, 3);
1276: PetscCall(DMDAGetInfo(dac, &dimc, &Mc, &Nc, &Pc, &mc, &nc, &pc, &dofc, &sc, &bxc, &byc, &bzc, &stc));
1277: PetscCall(DMDAGetInfo(daf, &dimf, &Mf, &Nf, &Pf, &mf, &nf, &pf, &doff, &sf, &bxf, &byf, &bzf, &stf));
1278: PetscCheck(dimc == dimf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Dimensions of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dimc, dimf);
1279: PetscCheck(dofc == doff, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "DOF of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dofc, doff);
1280: PetscCheck(sc == sf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil width of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, sc, sf);
1281: PetscCheck(bxc == bxf && byc == byf && bzc == bzf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Boundary type different in two DMDAs");
1282: PetscCheck(stc == stf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil type different in two DMDAs");
1283: PetscCheck(Mc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in x direction");
1284: PetscCheck(dimc <= 1 || Nc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in y direction");
1285: PetscCheck(dimc <= 2 || Pc >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coarse grid requires at least 2 points in z direction");
1287: if (dimc == 1) {
1288: PetscCall(DMCreateInjection_DA_1D(dac, daf, &inject));
1289: } else if (dimc == 2) {
1290: PetscCall(DMCreateInjection_DA_2D(dac, daf, &inject));
1291: } else if (dimc == 3) {
1292: PetscCall(DMCreateInjection_DA_3D(dac, daf, &inject));
1293: }
1294: PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)inject), inject, mat));
1295: PetscCall(VecScatterDestroy(&inject));
1296: PetscFunctionReturn(PETSC_SUCCESS);
1297: }
1299: // PetscClangLinter pragma ignore: -fdoc-*
1300: /*@
1301: DMCreateAggregates - Deprecated, see DMDACreateAggregates.
1303: Level: intermediate
1304: @*/
1305: PetscErrorCode DMCreateAggregates(DM dac, DM daf, Mat *mat)
1306: {
1307: return DMDACreateAggregates(dac, daf, mat);
1308: }
1310: /*@
1311: DMDACreateAggregates - Gets the aggregates that map between
1312: grids associated with two `DMDA`
1314: Collective
1316: Input Parameters:
1317: + dac - the coarse grid `DMDA`
1318: - daf - the fine grid `DMDA`
1320: Output Parameter:
1321: . rest - the restriction matrix (transpose of the projection matrix)
1323: Level: intermediate
1325: Note:
1326: This routine is not used by PETSc.
1327: It is not clear what its use case is and it may be removed in a future release.
1328: Users should contact petsc-maint@mcs.anl.gov if they plan to use it.
1330: .seealso: [](sec_struct), `DMRefine()`, `DMCreateInjection()`, `DMCreateInterpolation()`
1331: @*/
1332: PetscErrorCode DMDACreateAggregates(DM dac, DM daf, Mat *rest)
1333: {
1334: PetscInt dimc, Mc, Nc, Pc, mc, nc, pc, dofc, sc;
1335: PetscInt dimf, Mf, Nf, Pf, mf, nf, pf, doff, sf;
1336: DMBoundaryType bxc, byc, bzc, bxf, byf, bzf;
1337: DMDAStencilType stc, stf;
1338: PetscInt i, j, l;
1339: PetscInt i_start, j_start, l_start, m_f, n_f, p_f;
1340: PetscInt i_start_ghost, j_start_ghost, l_start_ghost, m_ghost, n_ghost, p_ghost;
1341: const PetscInt *idx_f;
1342: PetscInt i_c, j_c, l_c;
1343: PetscInt i_start_c, j_start_c, l_start_c, m_c, n_c, p_c;
1344: PetscInt i_start_ghost_c, j_start_ghost_c, l_start_ghost_c, m_ghost_c, n_ghost_c, p_ghost_c;
1345: const PetscInt *idx_c;
1346: PetscInt d;
1347: PetscInt a;
1348: PetscInt max_agg_size;
1349: PetscInt *fine_nodes;
1350: PetscScalar *one_vec;
1351: PetscInt fn_idx;
1352: ISLocalToGlobalMapping ltogmf, ltogmc;
1354: PetscFunctionBegin;
1357: PetscAssertPointer(rest, 3);
1359: PetscCall(DMDAGetInfo(dac, &dimc, &Mc, &Nc, &Pc, &mc, &nc, &pc, &dofc, &sc, &bxc, &byc, &bzc, &stc));
1360: PetscCall(DMDAGetInfo(daf, &dimf, &Mf, &Nf, &Pf, &mf, &nf, &pf, &doff, &sf, &bxf, &byf, &bzf, &stf));
1361: PetscCheck(dimc == dimf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Dimensions of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dimc, dimf);
1362: PetscCheck(dofc == doff, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "DOF of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, dofc, doff);
1363: PetscCheck(sc == sf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil width of DMDA do not match %" PetscInt_FMT " %" PetscInt_FMT, sc, sf);
1364: PetscCheck(bxc == bxf && byc == byf && bzc == bzf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Boundary type different in two DMDAs");
1365: PetscCheck(stc == stf, PetscObjectComm((PetscObject)daf), PETSC_ERR_ARG_INCOMP, "Stencil type different in two DMDAs");
1367: PetscCheck(Mf >= Mc, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Coarse grid has more points than fine grid, Mc %" PetscInt_FMT ", Mf %" PetscInt_FMT, Mc, Mf);
1368: PetscCheck(Nf >= Nc, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Coarse grid has more points than fine grid, Nc %" PetscInt_FMT ", Nf %" PetscInt_FMT, Nc, Nf);
1369: PetscCheck(Pf >= Pc, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Coarse grid has more points than fine grid, Pc %" PetscInt_FMT ", Pf %" PetscInt_FMT, Pc, Pf);
1371: if (Pc < 0) Pc = 1;
1372: if (Pf < 0) Pf = 1;
1373: if (Nc < 0) Nc = 1;
1374: if (Nf < 0) Nf = 1;
1376: PetscCall(DMDAGetCorners(daf, &i_start, &j_start, &l_start, &m_f, &n_f, &p_f));
1377: PetscCall(DMDAGetGhostCorners(daf, &i_start_ghost, &j_start_ghost, &l_start_ghost, &m_ghost, &n_ghost, &p_ghost));
1379: PetscCall(DMGetLocalToGlobalMapping(daf, <ogmf));
1380: PetscCall(ISLocalToGlobalMappingGetIndices(ltogmf, &idx_f));
1382: PetscCall(DMDAGetCorners(dac, &i_start_c, &j_start_c, &l_start_c, &m_c, &n_c, &p_c));
1383: PetscCall(DMDAGetGhostCorners(dac, &i_start_ghost_c, &j_start_ghost_c, &l_start_ghost_c, &m_ghost_c, &n_ghost_c, &p_ghost_c));
1385: PetscCall(DMGetLocalToGlobalMapping(dac, <ogmc));
1386: PetscCall(ISLocalToGlobalMappingGetIndices(ltogmc, &idx_c));
1388: /*
1389: Basic idea is as follows. Here's a 2D example, suppose r_x, r_y are the ratios
1390: for dimension 1 and 2 respectively.
1391: Let (i,j) be a coarse grid node. All the fine grid nodes between r_x*i and r_x*(i+1)
1392: and r_y*j and r_y*(j+1) will be grouped into the same coarse grid aggregate.
1393: Each specific dof on the fine grid is mapped to one dof on the coarse grid.
1394: */
1396: max_agg_size = (Mf / Mc + 1) * (Nf / Nc + 1) * (Pf / Pc + 1);
1398: /* create the matrix that will contain the restriction operator */
1399: PetscCall(MatCreateAIJ(PetscObjectComm((PetscObject)daf), m_c * n_c * p_c * dofc, m_f * n_f * p_f * doff, Mc * Nc * Pc * dofc, Mf * Nf * Pf * doff, max_agg_size, NULL, max_agg_size, NULL, rest));
1401: /* store nodes in the fine grid here */
1402: PetscCall(PetscMalloc2(max_agg_size, &one_vec, max_agg_size, &fine_nodes));
1403: for (i = 0; i < max_agg_size; i++) one_vec[i] = 1.0;
1405: /* loop over all coarse nodes */
1406: for (l_c = l_start_c; l_c < l_start_c + p_c; l_c++) {
1407: for (j_c = j_start_c; j_c < j_start_c + n_c; j_c++) {
1408: for (i_c = i_start_c; i_c < i_start_c + m_c; i_c++) {
1409: for (d = 0; d < dofc; d++) {
1410: /* convert to local "natural" numbering and then to PETSc global numbering */
1411: 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;
1413: fn_idx = 0;
1414: /* Corresponding fine points are all points (i_f, j_f, l_f) such that
1415: i_c*Mf/Mc <= i_f < (i_c+1)*Mf/Mc
1416: (same for other dimensions)
1417: */
1418: for (l = l_c * Pf / Pc; l < PetscMin((l_c + 1) * Pf / Pc, Pf); l++) {
1419: for (j = j_c * Nf / Nc; j < PetscMin((j_c + 1) * Nf / Nc, Nf); j++) {
1420: for (i = i_c * Mf / Mc; i < PetscMin((i_c + 1) * Mf / Mc, Mf); i++) {
1421: 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;
1422: fn_idx++;
1423: }
1424: }
1425: }
1426: /* add all these points to one aggregate */
1427: PetscCall(MatSetValues(*rest, 1, &a, fn_idx, fine_nodes, one_vec, INSERT_VALUES));
1428: }
1429: }
1430: }
1431: }
1432: PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogmf, &idx_f));
1433: PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogmc, &idx_c));
1434: PetscCall(PetscFree2(one_vec, fine_nodes));
1435: PetscCall(MatAssemblyBegin(*rest, MAT_FINAL_ASSEMBLY));
1436: PetscCall(MatAssemblyEnd(*rest, MAT_FINAL_ASSEMBLY));
1437: PetscFunctionReturn(PETSC_SUCCESS);
1438: }