xref: /petsc/src/dm/impls/da/dacorn.c (revision bcd3bd92eda2d5998e2f14c4bbfb33bd936bdc3e)
1 
2 /*
3   Code for manipulating distributed regular arrays in parallel.
4 */
5 
6 #include <petsc/private/dmdaimpl.h> /*I   "petscdmda.h"   I*/
7 #include <petscdmfield.h>
8 
9 PetscErrorCode DMCreateCoordinateDM_DA(DM dm, DM *cdm)
10 {
11   const char *prefix;
12 
13   PetscFunctionBegin;
14   PetscCall(DMDACreateCompatibleDMDA(dm, dm->dim, cdm));
15   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
16   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix));
17   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_"));
18   PetscFunctionReturn(PETSC_SUCCESS);
19 }
20 
21 PetscErrorCode DMCreateCoordinateField_DA(DM dm, DMField *field)
22 {
23   PetscReal   gmin[3], gmax[3];
24   PetscScalar corners[24];
25   PetscInt    dim;
26   PetscInt    i, j;
27   DM          cdm;
28 
29   PetscFunctionBegin;
30   PetscCall(DMGetDimension(dm, &dim));
31   /* TODO: this is wrong if coordinates are not rectilinear */
32   PetscCall(DMGetBoundingBox(dm, gmin, gmax));
33   for (i = 0; i < (1 << dim); i++) {
34     for (j = 0; j < dim; j++) corners[i * dim + j] = (i & (1 << j)) ? gmax[j] : gmin[j];
35   }
36   PetscCall(DMClone(dm, &cdm));
37   PetscCall(DMFieldCreateDA(cdm, dim, corners, field));
38   PetscCall(DMDestroy(&cdm));
39   PetscFunctionReturn(PETSC_SUCCESS);
40 }
41 
42 /*@C
43   DMDASetFieldName - Sets the names of individual field components in multicomponent
44   vectors associated with a `DMDA`.
45 
46   Logically Collective; name must contain a common value
47 
48   Input Parameters:
49 + da   - the distributed array
50 . nf   - field number for the `DMDA` (0, 1, ... dof-1), where dof indicates the
51         number of degrees of freedom per node within the `DMDA`
52 - name - the name of the field (component)
53 
54   Level: intermediate
55 
56   Note:
57   It must be called after having called `DMSetUp()`.
58 
59 .seealso: `DM`, `DMDA`, `DMDAGetFieldName()`, `DMDASetCoordinateName()`, `DMDAGetCoordinateName()`, `DMDASetFieldNames()`, `DMSetUp()`
60 @*/
61 PetscErrorCode DMDASetFieldName(DM da, PetscInt nf, const char name[])
62 {
63   DM_DA *dd = (DM_DA *)da->data;
64 
65   PetscFunctionBegin;
66   PetscValidHeaderSpecificType(da, DM_CLASSID, 1, DMDA);
67   PetscCheck(nf >= 0 && nf < dd->w, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid field number: %" PetscInt_FMT, nf);
68   PetscCheck(dd->fieldname, PetscObjectComm((PetscObject)da), PETSC_ERR_ORDER, "You should call DMSetUp() first");
69   PetscCall(PetscFree(dd->fieldname[nf]));
70   PetscCall(PetscStrallocpy(name, &dd->fieldname[nf]));
71   PetscFunctionReturn(PETSC_SUCCESS);
72 }
73 
74 /*@C
75   DMDAGetFieldNames - Gets the name of each component in the vector associated with the `DMDA`
76 
77   Not Collective; names will contain a common value; No Fortran Support
78 
79   Input Parameter:
80 . da - the `DMDA` object
81 
82   Output Parameter:
83 . names - the names of the components, final string is `NULL`, will have the same number of entries as the dof used in creating the `DMDA`
84 
85   Level: intermediate
86 
87   Fortran Notes:
88   Use `DMDAGetFieldName()`
89 
90 .seealso: `DM`, `DMDA`, `DMDAGetFieldName()`, `DMDASetCoordinateName()`, `DMDAGetCoordinateName()`, `DMDASetFieldName()`, `DMDASetFieldNames()`
91 @*/
92 PetscErrorCode DMDAGetFieldNames(DM da, const char *const **names)
93 {
94   DM_DA *dd = (DM_DA *)da->data;
95 
96   PetscFunctionBegin;
97   *names = (const char *const *)dd->fieldname;
98   PetscFunctionReturn(PETSC_SUCCESS);
99 }
100 
101 /*@C
102   DMDASetFieldNames - Sets the name of each component in the vector associated with the DMDA
103 
104   Logically Collective; names must contain a common value; No Fortran Support
105 
106   Input Parameters:
107 + da    - the `DMDA` object
108 - names - the names of the components, final string must be NULL, must have the same number of entries as the dof used in creating the `DMDA`
109 
110   Level: intermediate
111 
112   Note:
113   It must be called after having called `DMSetUp()`.
114 
115   Fortran Notes:
116   Use `DMDASetFieldName()`
117 
118 .seealso: `DM`, `DMDA`, `DMDAGetFieldName()`, `DMDASetCoordinateName()`, `DMDAGetCoordinateName()`, `DMDASetFieldName()`, `DMSetUp()`
119 @*/
120 PetscErrorCode DMDASetFieldNames(DM da, const char *const *names)
121 {
122   DM_DA   *dd = (DM_DA *)da->data;
123   char   **fieldname;
124   PetscInt nf = 0;
125 
126   PetscFunctionBegin;
127   PetscCheck(dd->fieldname, PetscObjectComm((PetscObject)da), PETSC_ERR_ORDER, "You should call DMSetUp() first");
128   while (names[nf++]) { }
129   PetscCheck(nf == dd->w + 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of fields %" PetscInt_FMT, nf - 1);
130   PetscCall(PetscStrArrayallocpy(names, &fieldname));
131   PetscCall(PetscStrArrayDestroy(&dd->fieldname));
132   dd->fieldname = fieldname;
133   PetscFunctionReturn(PETSC_SUCCESS);
134 }
135 
136 /*@C
137   DMDAGetFieldName - Gets the names of individual field components in multicomponent
138   vectors associated with a `DMDA`.
139 
140   Not Collective; name will contain a common value
141 
142   Input Parameters:
143 + da - the distributed array
144 - nf - field number for the `DMDA` (0, 1, ... dof-1), where dof indicates the
145         number of degrees of freedom per node within the `DMDA`
146 
147   Output Parameter:
148 . name - the name of the field (component)
149 
150   Level: intermediate
151 
152   Note:
153   It must be called after having called `DMSetUp()`.
154 
155 .seealso: `DM`, `DMDA`, `DMDASetFieldName()`, `DMDASetCoordinateName()`, `DMDAGetCoordinateName()`, `DMSetUp()`
156 @*/
157 PetscErrorCode DMDAGetFieldName(DM da, PetscInt nf, const char **name)
158 {
159   DM_DA *dd = (DM_DA *)da->data;
160 
161   PetscFunctionBegin;
162   PetscValidHeaderSpecificType(da, DM_CLASSID, 1, DMDA);
163   PetscAssertPointer(name, 3);
164   PetscCheck(nf >= 0 && nf < dd->w, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid field number: %" PetscInt_FMT, nf);
165   PetscCheck(dd->fieldname, PetscObjectComm((PetscObject)da), PETSC_ERR_ORDER, "You should call DMSetUp() first");
166   *name = dd->fieldname[nf];
167   PetscFunctionReturn(PETSC_SUCCESS);
168 }
169 
170 /*@C
171   DMDASetCoordinateName - Sets the name of the coordinate directions associated with a `DMDA`, for example "x" or "y"
172 
173   Logically Collective; name must contain a common value; No Fortran Support
174 
175   Input Parameters:
176 + dm   - the `DMDA`
177 . nf   - coordinate number for the DMDA (0, 1, ... dim-1),
178 - name - the name of the coordinate
179 
180   Level: intermediate
181 
182   Note:
183   Must be called after having called `DMSetUp()`.
184 
185 .seealso: `DM`, `DMDA`, `DMDAGetCoordinateName()`, `DMDASetFieldName()`, `DMDAGetFieldName()`, `DMSetUp()`
186 @*/
187 PetscErrorCode DMDASetCoordinateName(DM dm, PetscInt nf, const char name[])
188 {
189   DM_DA *dd = (DM_DA *)dm->data;
190 
191   PetscFunctionBegin;
192   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMDA);
193   PetscCheck(nf >= 0 && nf < dm->dim, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid coordinate number: %" PetscInt_FMT, nf);
194   PetscCheck(dd->coordinatename, PetscObjectComm((PetscObject)dm), PETSC_ERR_ORDER, "You should call DMSetUp() first");
195   PetscCall(PetscFree(dd->coordinatename[nf]));
196   PetscCall(PetscStrallocpy(name, &dd->coordinatename[nf]));
197   PetscFunctionReturn(PETSC_SUCCESS);
198 }
199 
200 /*@C
201   DMDAGetCoordinateName - Gets the name of a coordinate direction associated with a `DMDA`.
202 
203   Not Collective; name will contain a common value; No Fortran Support
204 
205   Input Parameters:
206 + dm - the `DMDA`
207 - nf - number for the `DMDA` (0, 1, ... dim-1)
208 
209   Output Parameter:
210 . name - the name of the coordinate direction
211 
212   Level: intermediate
213 
214   Note:
215   It must be called after having called `DMSetUp()`.
216 
217 .seealso: `DM`, `DMDA`, `DMDASetCoordinateName()`, `DMDASetFieldName()`, `DMDAGetFieldName()`, `DMSetUp()`
218 @*/
219 PetscErrorCode DMDAGetCoordinateName(DM dm, PetscInt nf, const char **name)
220 {
221   DM_DA *dd = (DM_DA *)dm->data;
222 
223   PetscFunctionBegin;
224   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMDA);
225   PetscAssertPointer(name, 3);
226   PetscCheck(nf >= 0 && nf < dm->dim, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid coordinate number: %" PetscInt_FMT, nf);
227   PetscCheck(dd->coordinatename, PetscObjectComm((PetscObject)dm), PETSC_ERR_ORDER, "You should call DMSetUp() first");
228   *name = dd->coordinatename[nf];
229   PetscFunctionReturn(PETSC_SUCCESS);
230 }
231 
232 /*@C
233   DMDAGetCorners - Returns the global (x,y,z) indices of the lower left
234   corner and size of the local region, excluding ghost points.
235 
236   Not Collective
237 
238   Input Parameter:
239 . da - the distributed array
240 
241   Output Parameters:
242 + x - the corner index for the first dimension
243 . y - the corner index for the second dimension (only used in 2D and 3D problems)
244 . z - the corner index for the third dimension (only used in 3D problems)
245 . m - the width in the first dimension
246 . n - the width in the second dimension (only used in 2D and 3D problems)
247 - p - the width in the third dimension (only used in 3D problems)
248 
249   Level: beginner
250 
251   Note:
252   The corner information is independent of the number of degrees of
253   freedom per node set with the `DMDACreateXX()` routine. Thus the x, y, z, and
254   m, n, p can be thought of as coordinates on a logical grid, where each
255   grid point has (potentially) several degrees of freedom.
256   Any of y, z, n, and p can be passed in as NULL if not needed.
257 
258 .seealso: `DM`, `DMDA`, `DMDAGetGhostCorners()`, `DMDAGetOwnershipRanges()`, `DMStagGetCorners()`
259 @*/
260 PetscErrorCode DMDAGetCorners(DM da, PetscInt *x, PetscInt *y, PetscInt *z, PetscInt *m, PetscInt *n, PetscInt *p)
261 {
262   PetscInt w;
263   DM_DA   *dd = (DM_DA *)da->data;
264 
265   PetscFunctionBegin;
266   PetscValidHeaderSpecificType(da, DM_CLASSID, 1, DMDA);
267   /* since the xs, xe ... have all been multiplied by the number of degrees
268      of freedom per cell, w = dd->w, we divide that out before returning.*/
269   w = dd->w;
270   if (x) *x = dd->xs / w + dd->xo;
271   /* the y and z have NOT been multiplied by w */
272   if (y) *y = dd->ys + dd->yo;
273   if (z) *z = dd->zs + dd->zo;
274   if (m) *m = (dd->xe - dd->xs) / w;
275   if (n) *n = (dd->ye - dd->ys);
276   if (p) *p = (dd->ze - dd->zs);
277   PetscFunctionReturn(PETSC_SUCCESS);
278 }
279 
280 PetscErrorCode DMGetLocalBoundingIndices_DMDA(DM dm, PetscReal lmin[], PetscReal lmax[])
281 {
282   DMDALocalInfo info;
283 
284   PetscFunctionBegin;
285   PetscCall(DMDAGetLocalInfo(dm, &info));
286   lmin[0] = info.xs;
287   lmin[1] = info.ys;
288   lmin[2] = info.zs;
289   lmax[0] = info.xs + info.xm - 1;
290   lmax[1] = info.ys + info.ym - 1;
291   lmax[2] = info.zs + info.zm - 1;
292   PetscFunctionReturn(PETSC_SUCCESS);
293 }
294 
295 /*@
296   DMDAGetReducedDMDA - Deprecated; use DMDACreateCompatibleDMDA()
297 
298   Level: deprecated
299 @*/
300 PetscErrorCode DMDAGetReducedDMDA(DM da, PetscInt nfields, DM *nda)
301 {
302   PetscFunctionBegin;
303   PetscCall(DMDACreateCompatibleDMDA(da, nfields, nda));
304   PetscFunctionReturn(PETSC_SUCCESS);
305 }
306 
307 /*@
308   DMDACreateCompatibleDMDA - Creates a `DMDA` with the same layout but with fewer or more fields
309 
310   Collective
311 
312   Input Parameters:
313 + da      - the distributed array
314 - nfields - number of fields in new `DMDA`
315 
316   Output Parameter:
317 . nda - the new `DMDA`
318 
319   Level: intermediate
320 
321 .seealso: `DM`, `DMDA`, `DMDAGetGhostCorners()`, `DMSetCoordinates()`, `DMDASetUniformCoordinates()`, `DMGetCoordinates()`, `DMDAGetGhostedCoordinates()`, `DMStagCreateCompatibleDMStag()`
322 @*/
323 PetscErrorCode DMDACreateCompatibleDMDA(DM da, PetscInt nfields, DM *nda)
324 {
325   DM_DA          *dd = (DM_DA *)da->data;
326   PetscInt        s, m, n, p, M, N, P, dim, Mo, No, Po;
327   const PetscInt *lx, *ly, *lz;
328   DMBoundaryType  bx, by, bz;
329   DMDAStencilType stencil_type;
330   Vec             coords;
331   PetscInt        ox, oy, oz;
332   PetscInt        cl, rl;
333 
334   PetscFunctionBegin;
335   dim = da->dim;
336   M   = dd->M;
337   N   = dd->N;
338   P   = dd->P;
339   m   = dd->m;
340   n   = dd->n;
341   p   = dd->p;
342   s   = dd->s;
343   bx  = dd->bx;
344   by  = dd->by;
345   bz  = dd->bz;
346 
347   stencil_type = dd->stencil_type;
348 
349   PetscCall(DMDAGetOwnershipRanges(da, &lx, &ly, &lz));
350   if (dim == 1) {
351     PetscCall(DMDACreate1d(PetscObjectComm((PetscObject)da), bx, M, nfields, s, dd->lx, nda));
352   } else if (dim == 2) {
353     PetscCall(DMDACreate2d(PetscObjectComm((PetscObject)da), bx, by, stencil_type, M, N, m, n, nfields, s, lx, ly, nda));
354   } else if (dim == 3) {
355     PetscCall(DMDACreate3d(PetscObjectComm((PetscObject)da), bx, by, bz, stencil_type, M, N, P, m, n, p, nfields, s, lx, ly, lz, nda));
356   }
357   PetscCall(DMSetUp(*nda));
358   PetscCall(DMGetCoordinates(da, &coords));
359   PetscCall(DMSetCoordinates(*nda, coords));
360 
361   /* allow for getting a reduced DA corresponding to a domain decomposition */
362   PetscCall(DMDAGetOffset(da, &ox, &oy, &oz, &Mo, &No, &Po));
363   PetscCall(DMDASetOffset(*nda, ox, oy, oz, Mo, No, Po));
364 
365   /* allow for getting a reduced DA corresponding to a coarsened DA */
366   PetscCall(DMGetCoarsenLevel(da, &cl));
367   PetscCall(DMGetRefineLevel(da, &rl));
368 
369   (*nda)->levelup   = rl;
370   (*nda)->leveldown = cl;
371   PetscFunctionReturn(PETSC_SUCCESS);
372 }
373 
374 /*@C
375   DMDAGetCoordinateArray - Gets an array containing the coordinates of the `DMDA`
376 
377   Not Collective; No Fortran Support
378 
379   Input Parameter:
380 . dm - the `DMDA`
381 
382   Output Parameter:
383 . xc - the coordinates
384 
385   Level: intermediate
386 
387 .seealso: `DM`, `DMDA`, `DMDASetCoordinateName()`, `DMDASetFieldName()`, `DMDAGetFieldName()`, `DMDARestoreCoordinateArray()`
388 @*/
389 PetscErrorCode DMDAGetCoordinateArray(DM dm, void *xc)
390 {
391   DM  cdm;
392   Vec x;
393 
394   PetscFunctionBegin;
395   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
396   PetscCall(DMGetCoordinates(dm, &x));
397   PetscCall(DMGetCoordinateDM(dm, &cdm));
398   PetscCall(DMDAVecGetArray(cdm, x, xc));
399   PetscFunctionReturn(PETSC_SUCCESS);
400 }
401 
402 /*@C
403   DMDARestoreCoordinateArray - Sets an array containing the coordinates of the `DMDA`
404 
405   Not Collective; No Fortran Support
406 
407   Input Parameters:
408 + dm - the `DMDA`
409 - xc - the coordinates
410 
411   Level: intermediate
412 
413 .seealso: `DM`, `DMDA`, `DMDASetCoordinateName()`, `DMDASetFieldName()`, `DMDAGetFieldName()`, `DMDAGetCoordinateArray()`
414 @*/
415 PetscErrorCode DMDARestoreCoordinateArray(DM dm, void *xc)
416 {
417   DM  cdm;
418   Vec x;
419 
420   PetscFunctionBegin;
421   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
422   PetscCall(DMGetCoordinates(dm, &x));
423   PetscCall(DMGetCoordinateDM(dm, &cdm));
424   PetscCall(DMDAVecRestoreArray(cdm, x, xc));
425   PetscFunctionReturn(PETSC_SUCCESS);
426 }
427