xref: /petsc/src/dm/impls/da/dalocal.c (revision 1b37a2a7cc4a4fb30c3e967db1c694c0a1013f51)
1 /*
2   Code for manipulating distributed regular arrays in parallel.
3 */
4 
5 #include <petsc/private/dmdaimpl.h> /*I   "petscdmda.h"   I*/
6 #include <petscbt.h>
7 #include <petscsf.h>
8 #include <petscds.h>
9 #include <petscfe.h>
10 
11 /*
12    This allows the DMDA vectors to properly tell MATLAB their dimensions
13 */
14 #if defined(PETSC_HAVE_MATLAB)
15   #include <engine.h> /* MATLAB include file */
16   #include <mex.h>    /* MATLAB include file */
17 static PetscErrorCode VecMatlabEnginePut_DA2d(PetscObject obj, void *mengine)
18 {
19   PetscInt     n, m;
20   Vec          vec = (Vec)obj;
21   PetscScalar *array;
22   mxArray     *mat;
23   DM           da;
24 
25   PetscFunctionBegin;
26   PetscCall(VecGetDM(vec, &da));
27   PetscCheck(da, PetscObjectComm((PetscObject)vec), PETSC_ERR_ARG_WRONGSTATE, "Vector not associated with a DMDA");
28   PetscCall(DMDAGetGhostCorners(da, 0, 0, 0, &m, &n, 0));
29 
30   PetscCall(VecGetArray(vec, &array));
31   #if !defined(PETSC_USE_COMPLEX)
32   mat = mxCreateDoubleMatrix(m, n, mxREAL);
33   #else
34   mat = mxCreateDoubleMatrix(m, n, mxCOMPLEX);
35   #endif
36   PetscCall(PetscArraycpy(mxGetPr(mat), array, n * m));
37   PetscCall(PetscObjectName(obj));
38   engPutVariable((Engine *)mengine, obj->name, mat);
39 
40   PetscCall(VecRestoreArray(vec, &array));
41   PetscFunctionReturn(PETSC_SUCCESS);
42 }
43 #endif
44 
45 PetscErrorCode DMCreateLocalVector_DA(DM da, Vec *g)
46 {
47   DM_DA *dd = (DM_DA *)da->data;
48 
49   PetscFunctionBegin;
50   PetscValidHeaderSpecific(da, DM_CLASSID, 1);
51   PetscAssertPointer(g, 2);
52   PetscCall(VecCreate(PETSC_COMM_SELF, g));
53   PetscCall(VecSetSizes(*g, dd->nlocal, PETSC_DETERMINE));
54   PetscCall(VecSetBlockSize(*g, dd->w));
55   PetscCall(VecSetType(*g, da->vectype));
56   if (dd->nlocal < da->bind_below) {
57     PetscCall(VecSetBindingPropagates(*g, PETSC_TRUE));
58     PetscCall(VecBindToCPU(*g, PETSC_TRUE));
59   }
60   PetscCall(VecSetDM(*g, da));
61 #if defined(PETSC_HAVE_MATLAB)
62   if (dd->w == 1 && da->dim == 2) PetscCall(PetscObjectComposeFunction((PetscObject)*g, "PetscMatlabEnginePut_C", VecMatlabEnginePut_DA2d));
63 #endif
64   PetscFunctionReturn(PETSC_SUCCESS);
65 }
66 
67 /*@
68   DMDAGetNumCells - Get the number of cells (or vertices) in the local piece of the `DMDA`. This includes ghost cells.
69 
70   Input Parameter:
71 . dm - The `DMDA` object
72 
73   Output Parameters:
74 + numCellsX - The number of local cells in the x-direction
75 . numCellsY - The number of local cells in the y-direction
76 . numCellsZ - The number of local cells in the z-direction
77 - numCells  - The number of local cells
78 
79   Level: developer
80 
81 .seealso: [](sec_struct), `DM`, `DMDA`, `DMDAGetCellPoint()`
82 @*/
83 PetscErrorCode DMDAGetNumCells(DM dm, PetscInt *numCellsX, PetscInt *numCellsY, PetscInt *numCellsZ, PetscInt *numCells)
84 {
85   DM_DA         *da  = (DM_DA *)dm->data;
86   const PetscInt dim = dm->dim;
87   const PetscInt mx = (da->Xe - da->Xs) / da->w, my = da->Ye - da->Ys, mz = da->Ze - da->Zs;
88   const PetscInt nC = (mx) * (dim > 1 ? (my) * (dim > 2 ? (mz) : 1) : 1);
89 
90   PetscFunctionBegin;
91   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMDA);
92   if (numCellsX) {
93     PetscAssertPointer(numCellsX, 2);
94     *numCellsX = mx;
95   }
96   if (numCellsY) {
97     PetscAssertPointer(numCellsY, 3);
98     *numCellsY = my;
99   }
100   if (numCellsZ) {
101     PetscAssertPointer(numCellsZ, 4);
102     *numCellsZ = mz;
103   }
104   if (numCells) {
105     PetscAssertPointer(numCells, 5);
106     *numCells = nC;
107   }
108   PetscFunctionReturn(PETSC_SUCCESS);
109 }
110 
111 /*@
112   DMDAGetCellPoint - Get the `DM` point corresponding to the tuple (i, j, k) in the `DMDA`
113 
114   Input Parameters:
115 + dm - The `DMDA` object
116 . i  - The global x index for the cell
117 . j  - The global y index for the cell
118 - k  - The global z index for the cell
119 
120   Output Parameter:
121 . point - The local `DM` point
122 
123   Level: developer
124 
125 .seealso: [](sec_struct), `DM`, `DMDA`, `DMDAGetNumCells()`
126 @*/
127 PetscErrorCode DMDAGetCellPoint(DM dm, PetscInt i, PetscInt j, PetscInt k, PetscInt *point)
128 {
129   const PetscInt dim = dm->dim;
130   DMDALocalInfo  info;
131 
132   PetscFunctionBegin;
133   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMDA);
134   PetscAssertPointer(point, 5);
135   PetscCall(DMDAGetLocalInfo(dm, &info));
136   if (dim > 0) PetscCheck(!(i < info.gxs) && !(i >= info.gxs + info.gxm), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "X index %" PetscInt_FMT " not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", i, info.gxs, info.gxs + info.gxm);
137   if (dim > 1) PetscCheck(!(j < info.gys) && !(j >= info.gys + info.gym), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Y index %" PetscInt_FMT " not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", j, info.gys, info.gys + info.gym);
138   if (dim > 2) PetscCheck(!(k < info.gzs) && !(k >= info.gzs + info.gzm), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Z index %" PetscInt_FMT PetscInt_FMT " not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", k, info.gzs, info.gzs + info.gzm);
139   *point = i + (dim > 1 ? (j + (dim > 2 ? k * info.gym : 0)) * info.gxm : 0);
140   PetscFunctionReturn(PETSC_SUCCESS);
141 }
142 
143 PetscErrorCode DMDAGetNumVertices(DM dm, PetscInt *numVerticesX, PetscInt *numVerticesY, PetscInt *numVerticesZ, PetscInt *numVertices)
144 {
145   DM_DA         *da  = (DM_DA *)dm->data;
146   const PetscInt dim = dm->dim;
147   const PetscInt mx = (da->Xe - da->Xs) / da->w, my = da->Ye - da->Ys, mz = da->Ze - da->Zs;
148   const PetscInt nVx = mx + 1;
149   const PetscInt nVy = dim > 1 ? (my + 1) : 1;
150   const PetscInt nVz = dim > 2 ? (mz + 1) : 1;
151   const PetscInt nV  = nVx * nVy * nVz;
152 
153   PetscFunctionBegin;
154   if (numVerticesX) {
155     PetscAssertPointer(numVerticesX, 2);
156     *numVerticesX = nVx;
157   }
158   if (numVerticesY) {
159     PetscAssertPointer(numVerticesY, 3);
160     *numVerticesY = nVy;
161   }
162   if (numVerticesZ) {
163     PetscAssertPointer(numVerticesZ, 4);
164     *numVerticesZ = nVz;
165   }
166   if (numVertices) {
167     PetscAssertPointer(numVertices, 5);
168     *numVertices = nV;
169   }
170   PetscFunctionReturn(PETSC_SUCCESS);
171 }
172 
173 PetscErrorCode DMDAGetNumFaces(DM dm, PetscInt *numXFacesX, PetscInt *numXFaces, PetscInt *numYFacesY, PetscInt *numYFaces, PetscInt *numZFacesZ, PetscInt *numZFaces)
174 {
175   DM_DA         *da  = (DM_DA *)dm->data;
176   const PetscInt dim = dm->dim;
177   const PetscInt mx = (da->Xe - da->Xs) / da->w, my = da->Ye - da->Ys, mz = da->Ze - da->Zs;
178   const PetscInt nxF = (dim > 1 ? (my) * (dim > 2 ? (mz) : 1) : 1);
179   const PetscInt nXF = (mx + 1) * nxF;
180   const PetscInt nyF = mx * (dim > 2 ? mz : 1);
181   const PetscInt nYF = dim > 1 ? (my + 1) * nyF : 0;
182   const PetscInt nzF = mx * (dim > 1 ? my : 0);
183   const PetscInt nZF = dim > 2 ? (mz + 1) * nzF : 0;
184 
185   PetscFunctionBegin;
186   if (numXFacesX) {
187     PetscAssertPointer(numXFacesX, 2);
188     *numXFacesX = nxF;
189   }
190   if (numXFaces) {
191     PetscAssertPointer(numXFaces, 3);
192     *numXFaces = nXF;
193   }
194   if (numYFacesY) {
195     PetscAssertPointer(numYFacesY, 4);
196     *numYFacesY = nyF;
197   }
198   if (numYFaces) {
199     PetscAssertPointer(numYFaces, 5);
200     *numYFaces = nYF;
201   }
202   if (numZFacesZ) {
203     PetscAssertPointer(numZFacesZ, 6);
204     *numZFacesZ = nzF;
205   }
206   if (numZFaces) {
207     PetscAssertPointer(numZFaces, 7);
208     *numZFaces = nZF;
209   }
210   PetscFunctionReturn(PETSC_SUCCESS);
211 }
212 
213 PetscErrorCode DMDAGetHeightStratum(DM dm, PetscInt height, PetscInt *pStart, PetscInt *pEnd)
214 {
215   const PetscInt dim = dm->dim;
216   PetscInt       nC, nV, nXF, nYF, nZF;
217 
218   PetscFunctionBegin;
219   if (pStart) PetscAssertPointer(pStart, 3);
220   if (pEnd) PetscAssertPointer(pEnd, 4);
221   PetscCall(DMDAGetNumCells(dm, NULL, NULL, NULL, &nC));
222   PetscCall(DMDAGetNumVertices(dm, NULL, NULL, NULL, &nV));
223   PetscCall(DMDAGetNumFaces(dm, NULL, &nXF, NULL, &nYF, NULL, &nZF));
224   if (height == 0) {
225     /* Cells */
226     if (pStart) *pStart = 0;
227     if (pEnd) *pEnd = nC;
228   } else if (height == 1) {
229     /* Faces */
230     if (pStart) *pStart = nC + nV;
231     if (pEnd) *pEnd = nC + nV + nXF + nYF + nZF;
232   } else if (height == dim) {
233     /* Vertices */
234     if (pStart) *pStart = nC;
235     if (pEnd) *pEnd = nC + nV;
236   } else if (height < 0) {
237     /* All points */
238     if (pStart) *pStart = 0;
239     if (pEnd) *pEnd = nC + nV + nXF + nYF + nZF;
240   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No points of height %" PetscInt_FMT " in the DA", height);
241   PetscFunctionReturn(PETSC_SUCCESS);
242 }
243 
244 PetscErrorCode DMDAGetDepthStratum(DM dm, PetscInt depth, PetscInt *pStart, PetscInt *pEnd)
245 {
246   const PetscInt dim = dm->dim;
247   PetscInt       nC, nV, nXF, nYF, nZF;
248 
249   PetscFunctionBegin;
250   if (pStart) PetscAssertPointer(pStart, 3);
251   if (pEnd) PetscAssertPointer(pEnd, 4);
252   PetscCall(DMDAGetNumCells(dm, NULL, NULL, NULL, &nC));
253   PetscCall(DMDAGetNumVertices(dm, NULL, NULL, NULL, &nV));
254   PetscCall(DMDAGetNumFaces(dm, NULL, &nXF, NULL, &nYF, NULL, &nZF));
255   if (depth == dim) {
256     /* Cells */
257     if (pStart) *pStart = 0;
258     if (pEnd) *pEnd = nC;
259   } else if (depth == dim - 1) {
260     /* Faces */
261     if (pStart) *pStart = nC + nV;
262     if (pEnd) *pEnd = nC + nV + nXF + nYF + nZF;
263   } else if (depth == 0) {
264     /* Vertices */
265     if (pStart) *pStart = nC;
266     if (pEnd) *pEnd = nC + nV;
267   } else if (depth < 0) {
268     /* All points */
269     if (pStart) *pStart = 0;
270     if (pEnd) *pEnd = nC + nV + nXF + nYF + nZF;
271   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No points of depth %" PetscInt_FMT " in the DA", depth);
272   PetscFunctionReturn(PETSC_SUCCESS);
273 }
274 
275 PetscErrorCode DMDASetVertexCoordinates(DM dm, PetscReal xl, PetscReal xu, PetscReal yl, PetscReal yu, PetscReal zl, PetscReal zu)
276 {
277   DM_DA       *da = (DM_DA *)dm->data;
278   Vec          coordinates;
279   PetscSection section;
280   PetscScalar *coords;
281   PetscReal    h[3];
282   PetscInt     dim, size, M, N, P, nVx, nVy, nVz, nV, vStart, vEnd, v, i, j, k;
283 
284   PetscFunctionBegin;
285   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMDA);
286   PetscCall(DMDAGetInfo(dm, &dim, &M, &N, &P, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
287   PetscCheck(dim <= 3, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "The following code only works for dim <= 3");
288   h[0] = (xu - xl) / M;
289   h[1] = (yu - yl) / N;
290   h[2] = (zu - zl) / P;
291   PetscCall(DMDAGetDepthStratum(dm, 0, &vStart, &vEnd));
292   PetscCall(DMDAGetNumVertices(dm, &nVx, &nVy, &nVz, &nV));
293   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section));
294   PetscCall(PetscSectionSetNumFields(section, 1));
295   PetscCall(PetscSectionSetFieldComponents(section, 0, dim));
296   PetscCall(PetscSectionSetChart(section, vStart, vEnd));
297   for (v = vStart; v < vEnd; ++v) PetscCall(PetscSectionSetDof(section, v, dim));
298   PetscCall(PetscSectionSetUp(section));
299   PetscCall(PetscSectionGetStorageSize(section, &size));
300   PetscCall(VecCreateSeq(PETSC_COMM_SELF, size, &coordinates));
301   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
302   PetscCall(VecGetArray(coordinates, &coords));
303   for (k = 0; k < nVz; ++k) {
304     PetscInt ind[3], d, off;
305 
306     ind[0] = 0;
307     ind[1] = 0;
308     ind[2] = k + da->zs;
309     for (j = 0; j < nVy; ++j) {
310       ind[1] = j + da->ys;
311       for (i = 0; i < nVx; ++i) {
312         const PetscInt vertex = (k * nVy + j) * nVx + i + vStart;
313 
314         PetscCall(PetscSectionGetOffset(section, vertex, &off));
315         ind[0] = i + da->xs;
316         for (d = 0; d < dim; ++d) coords[off + d] = h[d] * ind[d];
317       }
318     }
319   }
320   PetscCall(VecRestoreArray(coordinates, &coords));
321   PetscCall(DMSetCoordinateSection(dm, PETSC_DETERMINE, section));
322   PetscCall(DMSetCoordinatesLocal(dm, coordinates));
323   PetscCall(PetscSectionDestroy(&section));
324   PetscCall(VecDestroy(&coordinates));
325   PetscFunctionReturn(PETSC_SUCCESS);
326 }
327 
328 /* ------------------------------------------------------------------- */
329 
330 /*@C
331   DMDAGetArray - Gets a work array for a `DMDA`
332 
333   Input Parameters:
334 + da      - a `DMDA`
335 - ghosted - do you want arrays for the ghosted or nonghosted patch
336 
337   Output Parameter:
338 . vptr - array data structured
339 
340   Level: advanced
341 
342   Notes:
343   The vector values are NOT initialized and may have garbage in them, so you may need
344   to zero them.
345 
346   Use `DMDARestoreArray()` to return the array
347 
348 .seealso: [](sec_struct), `DM`, `DMDA`, `DMDARestoreArray()`
349 @*/
350 PetscErrorCode DMDAGetArray(DM da, PetscBool ghosted, void *vptr)
351 {
352   PetscInt j, i, xs, ys, xm, ym, zs, zm;
353   char    *iarray_start;
354   void   **iptr = (void **)vptr;
355   DM_DA   *dd   = (DM_DA *)da->data;
356 
357   PetscFunctionBegin;
358   PetscValidHeaderSpecificType(da, DM_CLASSID, 1, DMDA);
359   if (ghosted) {
360     for (i = 0; i < DMDA_MAX_WORK_ARRAYS; i++) {
361       if (dd->arrayghostedin[i]) {
362         *iptr                 = dd->arrayghostedin[i];
363         iarray_start          = (char *)dd->startghostedin[i];
364         dd->arrayghostedin[i] = NULL;
365         dd->startghostedin[i] = NULL;
366 
367         goto done;
368       }
369     }
370     xs = dd->Xs;
371     ys = dd->Ys;
372     zs = dd->Zs;
373     xm = dd->Xe - dd->Xs;
374     ym = dd->Ye - dd->Ys;
375     zm = dd->Ze - dd->Zs;
376   } else {
377     for (i = 0; i < DMDA_MAX_WORK_ARRAYS; i++) {
378       if (dd->arrayin[i]) {
379         *iptr          = dd->arrayin[i];
380         iarray_start   = (char *)dd->startin[i];
381         dd->arrayin[i] = NULL;
382         dd->startin[i] = NULL;
383 
384         goto done;
385       }
386     }
387     xs = dd->xs;
388     ys = dd->ys;
389     zs = dd->zs;
390     xm = dd->xe - dd->xs;
391     ym = dd->ye - dd->ys;
392     zm = dd->ze - dd->zs;
393   }
394 
395   switch (da->dim) {
396   case 1: {
397     void *ptr;
398 
399     PetscCall(PetscMalloc(xm * sizeof(PetscScalar), &iarray_start));
400 
401     ptr   = (void *)(iarray_start - xs * sizeof(PetscScalar));
402     *iptr = (void *)ptr;
403     break;
404   }
405   case 2: {
406     void **ptr;
407 
408     PetscCall(PetscMalloc((ym + 1) * sizeof(void *) + xm * ym * sizeof(PetscScalar), &iarray_start));
409 
410     ptr = (void **)(iarray_start + xm * ym * sizeof(PetscScalar) - ys * sizeof(void *));
411     for (j = ys; j < ys + ym; j++) ptr[j] = iarray_start + sizeof(PetscScalar) * (xm * (j - ys) - xs);
412     *iptr = (void *)ptr;
413     break;
414   }
415   case 3: {
416     void ***ptr, **bptr;
417 
418     PetscCall(PetscMalloc((zm + 1) * sizeof(void **) + (ym * zm + 1) * sizeof(void *) + xm * ym * zm * sizeof(PetscScalar), &iarray_start));
419 
420     ptr  = (void ***)(iarray_start + xm * ym * zm * sizeof(PetscScalar) - zs * sizeof(void *));
421     bptr = (void **)(iarray_start + xm * ym * zm * sizeof(PetscScalar) + zm * sizeof(void **));
422     for (i = zs; i < zs + zm; i++) ptr[i] = bptr + ((i - zs) * ym - ys);
423     for (i = zs; i < zs + zm; i++) {
424       for (j = ys; j < ys + ym; j++) ptr[i][j] = iarray_start + sizeof(PetscScalar) * (xm * ym * (i - zs) + xm * (j - ys) - xs);
425     }
426     *iptr = (void *)ptr;
427     break;
428   }
429   default:
430     SETERRQ(PetscObjectComm((PetscObject)da), PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not supported", da->dim);
431   }
432 
433 done:
434   /* add arrays to the checked out list */
435   if (ghosted) {
436     for (i = 0; i < DMDA_MAX_WORK_ARRAYS; i++) {
437       if (!dd->arrayghostedout[i]) {
438         dd->arrayghostedout[i] = *iptr;
439         dd->startghostedout[i] = iarray_start;
440         break;
441       }
442     }
443   } else {
444     for (i = 0; i < DMDA_MAX_WORK_ARRAYS; i++) {
445       if (!dd->arrayout[i]) {
446         dd->arrayout[i] = *iptr;
447         dd->startout[i] = iarray_start;
448         break;
449       }
450     }
451   }
452   PetscFunctionReturn(PETSC_SUCCESS);
453 }
454 
455 /*@C
456   DMDARestoreArray - Restores an array for a `DMDA` obtained with  `DMDAGetArray()`
457 
458   Input Parameters:
459 + da      - information about my local patch
460 . ghosted - do you want arrays for the ghosted or nonghosted patch
461 - vptr    - array data structured
462 
463   Level: advanced
464 
465 .seealso: [](sec_struct), `DM`, `DMDA`, `DMDAGetArray()`
466 @*/
467 PetscErrorCode DMDARestoreArray(DM da, PetscBool ghosted, void *vptr)
468 {
469   PetscInt i;
470   void   **iptr = (void **)vptr, *iarray_start = NULL;
471   DM_DA   *dd = (DM_DA *)da->data;
472 
473   PetscFunctionBegin;
474   PetscValidHeaderSpecificType(da, DM_CLASSID, 1, DMDA);
475   if (ghosted) {
476     for (i = 0; i < DMDA_MAX_WORK_ARRAYS; i++) {
477       if (dd->arrayghostedout[i] == *iptr) {
478         iarray_start           = dd->startghostedout[i];
479         dd->arrayghostedout[i] = NULL;
480         dd->startghostedout[i] = NULL;
481         break;
482       }
483     }
484     for (i = 0; i < DMDA_MAX_WORK_ARRAYS; i++) {
485       if (!dd->arrayghostedin[i]) {
486         dd->arrayghostedin[i] = *iptr;
487         dd->startghostedin[i] = iarray_start;
488         break;
489       }
490     }
491   } else {
492     for (i = 0; i < DMDA_MAX_WORK_ARRAYS; i++) {
493       if (dd->arrayout[i] == *iptr) {
494         iarray_start    = dd->startout[i];
495         dd->arrayout[i] = NULL;
496         dd->startout[i] = NULL;
497         break;
498       }
499     }
500     for (i = 0; i < DMDA_MAX_WORK_ARRAYS; i++) {
501       if (!dd->arrayin[i]) {
502         dd->arrayin[i] = *iptr;
503         dd->startin[i] = iarray_start;
504         break;
505       }
506     }
507   }
508   PetscFunctionReturn(PETSC_SUCCESS);
509 }
510