xref: /petsc/src/dm/impls/da/dagetelem.c (revision 21e3ffae2f3b73c0bd738cf6d0a809700fc04bb0)
1 
2 #include <petsc/private/dmdaimpl.h> /*I  "petscdmda.h"   I*/
3 
4 static PetscErrorCode DMDAGetElements_1D(DM dm, PetscInt *nel, PetscInt *nen, const PetscInt *e[])
5 {
6   DM_DA   *da = (DM_DA *)dm->data;
7   PetscInt i, xs, xe, Xs, Xe;
8   PetscInt cnt = 0;
9 
10   PetscFunctionBegin;
11   if (!da->e) {
12     PetscInt corners[2];
13 
14     PetscCheck(da->s, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot get elements for DMDA with zero stencil width");
15     PetscCall(DMDAGetCorners(dm, &xs, NULL, NULL, &xe, NULL, NULL));
16     PetscCall(DMDAGetGhostCorners(dm, &Xs, NULL, NULL, &Xe, NULL, NULL));
17     xe += xs;
18     Xe += Xs;
19     if (xs != Xs) xs -= 1;
20     da->ne = 1 * (xe - xs - 1);
21     PetscCall(PetscMalloc1(1 + 2 * da->ne, &da->e));
22     for (i = xs; i < xe - 1; i++) {
23       da->e[cnt++] = (i - Xs);
24       da->e[cnt++] = (i - Xs + 1);
25     }
26     da->nen = 2;
27 
28     corners[0] = (xs - Xs);
29     corners[1] = (xe - 1 - Xs);
30     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2, corners, PETSC_COPY_VALUES, &da->ecorners));
31   }
32   *nel = da->ne;
33   *nen = da->nen;
34   *e   = da->e;
35   PetscFunctionReturn(PETSC_SUCCESS);
36 }
37 
38 static PetscErrorCode DMDAGetElements_2D(DM dm, PetscInt *nel, PetscInt *nen, const PetscInt *e[])
39 {
40   DM_DA   *da = (DM_DA *)dm->data;
41   PetscInt i, xs, xe, Xs, Xe;
42   PetscInt j, ys, ye, Ys, Ye;
43   PetscInt cnt = 0, cell[4], ns = 2;
44   PetscInt c, split[] = {0, 1, 3, 2, 3, 1};
45 
46   PetscFunctionBegin;
47   if (!da->e) {
48     PetscInt corners[4], nn = 0;
49 
50     PetscCheck(da->s, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot get elements for DMDA with zero stencil width");
51 
52     switch (da->elementtype) {
53     case DMDA_ELEMENT_Q1:
54       da->nen = 4;
55       break;
56     case DMDA_ELEMENT_P1:
57       da->nen = 3;
58       break;
59     default:
60       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown element type %d", da->elementtype);
61     }
62     nn = da->nen;
63 
64     if (da->elementtype == DMDA_ELEMENT_P1) ns = 2;
65     if (da->elementtype == DMDA_ELEMENT_Q1) ns = 1;
66     PetscCall(DMDAGetCorners(dm, &xs, &ys, NULL, &xe, &ye, NULL));
67     PetscCall(DMDAGetGhostCorners(dm, &Xs, &Ys, NULL, &Xe, &Ye, NULL));
68     xe += xs;
69     Xe += Xs;
70     if (xs != Xs) xs -= 1;
71     ye += ys;
72     Ye += Ys;
73     if (ys != Ys) ys -= 1;
74     da->ne = ns * (xe - xs - 1) * (ye - ys - 1);
75     PetscCall(PetscMalloc1(1 + nn * da->ne, &da->e));
76     for (j = ys; j < ye - 1; j++) {
77       for (i = xs; i < xe - 1; i++) {
78         cell[0] = (i - Xs) + (j - Ys) * (Xe - Xs);
79         cell[1] = (i - Xs + 1) + (j - Ys) * (Xe - Xs);
80         cell[2] = (i - Xs + 1) + (j - Ys + 1) * (Xe - Xs);
81         cell[3] = (i - Xs) + (j - Ys + 1) * (Xe - Xs);
82         if (da->elementtype == DMDA_ELEMENT_P1) {
83           for (c = 0; c < ns * nn; c++) da->e[cnt++] = cell[split[c]];
84         }
85         if (da->elementtype == DMDA_ELEMENT_Q1) {
86           for (c = 0; c < ns * nn; c++) da->e[cnt++] = cell[c];
87         }
88       }
89     }
90 
91     corners[0] = (xs - Xs) + (ys - Ys) * (Xe - Xs);
92     corners[1] = (xe - 1 - Xs) + (ys - Ys) * (Xe - Xs);
93     corners[2] = (xs - Xs) + (ye - 1 - Ys) * (Xe - Xs);
94     corners[3] = (xe - 1 - Xs) + (ye - 1 - Ys) * (Xe - Xs);
95     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 4, corners, PETSC_COPY_VALUES, &da->ecorners));
96   }
97   *nel = da->ne;
98   *nen = da->nen;
99   *e   = da->e;
100   PetscFunctionReturn(PETSC_SUCCESS);
101 }
102 
103 static PetscErrorCode DMDAGetElements_3D(DM dm, PetscInt *nel, PetscInt *nen, const PetscInt *e[])
104 {
105   DM_DA   *da = (DM_DA *)dm->data;
106   PetscInt i, xs, xe, Xs, Xe;
107   PetscInt j, ys, ye, Ys, Ye;
108   PetscInt k, zs, ze, Zs, Ze;
109   PetscInt cnt = 0, cell[8], ns = 6;
110   PetscInt c, split[] = {0, 1, 3, 7, 0, 1, 7, 4, 1, 2, 3, 7, 1, 2, 7, 6, 1, 4, 5, 7, 1, 5, 6, 7};
111 
112   PetscFunctionBegin;
113   if (!da->e) {
114     PetscInt corners[8], nn = 0;
115 
116     PetscCheck(da->s, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot get elements for DMDA with zero stencil width");
117 
118     switch (da->elementtype) {
119     case DMDA_ELEMENT_Q1:
120       da->nen = 8;
121       break;
122     case DMDA_ELEMENT_P1:
123       da->nen = 4;
124       break;
125     default:
126       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown element type %d", da->elementtype);
127     }
128     nn = da->nen;
129 
130     if (da->elementtype == DMDA_ELEMENT_P1) ns = 6;
131     if (da->elementtype == DMDA_ELEMENT_Q1) ns = 1;
132     PetscCall(DMDAGetCorners(dm, &xs, &ys, &zs, &xe, &ye, &ze));
133     PetscCall(DMDAGetGhostCorners(dm, &Xs, &Ys, &Zs, &Xe, &Ye, &Ze));
134     xe += xs;
135     Xe += Xs;
136     if (xs != Xs) xs -= 1;
137     ye += ys;
138     Ye += Ys;
139     if (ys != Ys) ys -= 1;
140     ze += zs;
141     Ze += Zs;
142     if (zs != Zs) zs -= 1;
143     da->ne = ns * (xe - xs - 1) * (ye - ys - 1) * (ze - zs - 1);
144     PetscCall(PetscMalloc1(1 + nn * da->ne, &da->e));
145     for (k = zs; k < ze - 1; k++) {
146       for (j = ys; j < ye - 1; j++) {
147         for (i = xs; i < xe - 1; i++) {
148           cell[0] = (i - Xs) + (j - Ys) * (Xe - Xs) + (k - Zs) * (Xe - Xs) * (Ye - Ys);
149           cell[1] = (i + 1 - Xs) + (j - Ys) * (Xe - Xs) + (k - Zs) * (Xe - Xs) * (Ye - Ys);
150           cell[2] = (i + 1 - Xs) + (j + 1 - Ys) * (Xe - Xs) + (k - Zs) * (Xe - Xs) * (Ye - Ys);
151           cell[3] = (i - Xs) + (j + 1 - Ys) * (Xe - Xs) + (k - Zs) * (Xe - Xs) * (Ye - Ys);
152           cell[4] = (i - Xs) + (j - Ys) * (Xe - Xs) + (k + 1 - Zs) * (Xe - Xs) * (Ye - Ys);
153           cell[5] = (i + 1 - Xs) + (j - Ys) * (Xe - Xs) + (k + 1 - Zs) * (Xe - Xs) * (Ye - Ys);
154           cell[6] = (i + 1 - Xs) + (j + 1 - Ys) * (Xe - Xs) + (k + 1 - Zs) * (Xe - Xs) * (Ye - Ys);
155           cell[7] = (i - Xs) + (j + 1 - Ys) * (Xe - Xs) + (k + 1 - Zs) * (Xe - Xs) * (Ye - Ys);
156           if (da->elementtype == DMDA_ELEMENT_P1) {
157             for (c = 0; c < ns * nn; c++) da->e[cnt++] = cell[split[c]];
158           }
159           if (da->elementtype == DMDA_ELEMENT_Q1) {
160             for (c = 0; c < ns * nn; c++) da->e[cnt++] = cell[c];
161           }
162         }
163       }
164     }
165 
166     corners[0] = (xs - Xs) + (ys - Ys) * (Xe - Xs) + (zs - Zs) * (Xe - Xs) * (Ye - Ys);
167     corners[1] = (xe - 1 - Xs) + (ys - Ys) * (Xe - Xs) + (zs - Zs) * (Xe - Xs) * (Ye - Ys);
168     corners[2] = (xs - Xs) + (ye - 1 - Ys) * (Xe - Xs) + (zs - Zs) * (Xe - Xs) * (Ye - Ys);
169     corners[3] = (xe - 1 - Xs) + (ye - 1 - Ys) * (Xe - Xs) + (zs - Zs) * (Xe - Xs) * (Ye - Ys);
170     corners[4] = (xs - Xs) + (ys - Ys) * (Xe - Xs) + (ze - 1 - Zs) * (Xe - Xs) * (Ye - Ys);
171     corners[5] = (xe - 1 - Xs) + (ys - Ys) * (Xe - Xs) + (ze - 1 - Zs) * (Xe - Xs) * (Ye - Ys);
172     corners[6] = (xs - Xs) + (ye - 1 - Ys) * (Xe - Xs) + (ze - 1 - Zs) * (Xe - Xs) * (Ye - Ys);
173     corners[7] = (xe - 1 - Xs) + (ye - 1 - Ys) * (Xe - Xs) + (ze - 1 - Zs) * (Xe - Xs) * (Ye - Ys);
174     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 8, corners, PETSC_COPY_VALUES, &da->ecorners));
175   }
176   *nel = da->ne;
177   *nen = da->nen;
178   *e   = da->e;
179   PetscFunctionReturn(PETSC_SUCCESS);
180 }
181 
182 /*@
183    DMDAGetElementsCorners - Returns the global (x,y,z) indices of the lower left
184    corner of the non-overlapping decomposition identified by `DMDAGetElements()`
185 
186     Not Collective
187 
188    Input Parameter:
189 .     da - the `DMDA` object
190 
191    Output Parameters:
192 +     gx - the x index
193 .     gy - the y index
194 -     gz - the z index
195 
196    Level: intermediate
197 
198 .seealso: `DM`, `DMDA`, `DMDAElementType`, `DMDASetElementType()`, `DMDAGetElements()`
199 @*/
200 PetscErrorCode DMDAGetElementsCorners(DM da, PetscInt *gx, PetscInt *gy, PetscInt *gz)
201 {
202   PetscInt  xs, Xs;
203   PetscInt  ys, Ys;
204   PetscInt  zs, Zs;
205   PetscBool isda;
206 
207   PetscFunctionBegin;
208   PetscValidHeaderSpecificType(da, DM_CLASSID, 1, DMDA);
209   if (gx) PetscValidIntPointer(gx, 2);
210   if (gy) PetscValidIntPointer(gy, 3);
211   if (gz) PetscValidIntPointer(gz, 4);
212   PetscCall(PetscObjectTypeCompare((PetscObject)da, DMDA, &isda));
213   PetscCheck(isda, PetscObjectComm((PetscObject)da), PETSC_ERR_USER, "Not for DM type %s", ((PetscObject)da)->type_name);
214   PetscCall(DMDAGetCorners(da, &xs, &ys, &zs, NULL, NULL, NULL));
215   PetscCall(DMDAGetGhostCorners(da, &Xs, &Ys, &Zs, NULL, NULL, NULL));
216   if (xs != Xs) xs -= 1;
217   if (ys != Ys) ys -= 1;
218   if (zs != Zs) zs -= 1;
219   if (gx) *gx = xs;
220   if (gy) *gy = ys;
221   if (gz) *gz = zs;
222   PetscFunctionReturn(PETSC_SUCCESS);
223 }
224 
225 /*@
226       DMDAGetElementsSizes - Gets the local number of elements per direction for the non-overlapping decomposition identified by `DMDAGetElements()`
227 
228     Not Collective
229 
230    Input Parameter:
231 .     da - the `DMDA` object
232 
233    Output Parameters:
234 +     mx - number of local elements in x-direction
235 .     my - number of local elements in y-direction
236 -     mz - number of local elements in z-direction
237 
238    Level: intermediate
239 
240    Note:
241     It returns the same number of elements, irrespective of the `DMDAElementType`
242 
243 .seealso: `DM`, `DMDA`, `DMDAElementType`, `DMDASetElementType()`, `DMDAGetElements`
244 @*/
245 PetscErrorCode DMDAGetElementsSizes(DM da, PetscInt *mx, PetscInt *my, PetscInt *mz)
246 {
247   PetscInt  xs, xe, Xs;
248   PetscInt  ys, ye, Ys;
249   PetscInt  zs, ze, Zs;
250   PetscInt  dim;
251   PetscBool isda;
252 
253   PetscFunctionBegin;
254   PetscValidHeaderSpecificType(da, DM_CLASSID, 1, DMDA);
255   if (mx) PetscValidIntPointer(mx, 2);
256   if (my) PetscValidIntPointer(my, 3);
257   if (mz) PetscValidIntPointer(mz, 4);
258   PetscCall(PetscObjectTypeCompare((PetscObject)da, DMDA, &isda));
259   PetscCheck(isda, PetscObjectComm((PetscObject)da), PETSC_ERR_USER, "Not for DM type %s", ((PetscObject)da)->type_name);
260   PetscCall(DMDAGetCorners(da, &xs, &ys, &zs, &xe, &ye, &ze));
261   PetscCall(DMDAGetGhostCorners(da, &Xs, &Ys, &Zs, NULL, NULL, NULL));
262   xe += xs;
263   if (xs != Xs) xs -= 1;
264   ye += ys;
265   if (ys != Ys) ys -= 1;
266   ze += zs;
267   if (zs != Zs) zs -= 1;
268   if (mx) *mx = 0;
269   if (my) *my = 0;
270   if (mz) *mz = 0;
271   PetscCall(DMGetDimension(da, &dim));
272   switch (dim) {
273   case 3:
274     if (mz) *mz = ze - zs - 1; /* fall through */
275   case 2:
276     if (my) *my = ye - ys - 1; /* fall through */
277   case 1:
278     if (mx) *mx = xe - xs - 1;
279     break;
280   }
281   PetscFunctionReturn(PETSC_SUCCESS);
282 }
283 
284 /*@
285       DMDASetElementType - Sets the element type to be returned by `DMDAGetElements()`
286 
287     Not Collective
288 
289    Input Parameter:
290 .     da - the `DMDA` object
291 
292    Output Parameters:
293 .     etype - the element type, currently either `DMDA_ELEMENT_P1` or `DMDA_ELEMENT_Q1`
294 
295    Level: intermediate
296 
297 .seealso: `DM`, `DMDA`, `DMDAElementType`, `DMDAGetElementType()`, `DMDAGetElements()`, `DMDARestoreElements()`
298 @*/
299 PetscErrorCode DMDASetElementType(DM da, DMDAElementType etype)
300 {
301   DM_DA    *dd = (DM_DA *)da->data;
302   PetscBool isda;
303 
304   PetscFunctionBegin;
305   PetscValidHeaderSpecificType(da, DM_CLASSID, 1, DMDA);
306   PetscValidLogicalCollectiveEnum(da, etype, 2);
307   PetscCall(PetscObjectTypeCompare((PetscObject)da, DMDA, &isda));
308   if (!isda) PetscFunctionReturn(PETSC_SUCCESS);
309   if (dd->elementtype != etype) {
310     PetscCall(PetscFree(dd->e));
311     PetscCall(ISDestroy(&dd->ecorners));
312 
313     dd->elementtype = etype;
314     dd->ne          = 0;
315     dd->nen         = 0;
316     dd->e           = NULL;
317   }
318   PetscFunctionReturn(PETSC_SUCCESS);
319 }
320 
321 /*@
322       DMDAGetElementType - Gets the element type to be returned by `DMDAGetElements()`
323 
324     Not Collective
325 
326    Input Parameter:
327 .     da - the `DMDA` object
328 
329    Output Parameters:
330 .     etype - the element type, currently either `DMDA_ELEMENT_P1` or `DMDA_ELEMENT_Q1`
331 
332    Level: intermediate
333 
334 .seealso: `DM`, `DMDA`, `DMDAElementType`, `DMDASetElementType()`, `DMDAGetElements()`, `DMDARestoreElements()`
335 @*/
336 PetscErrorCode DMDAGetElementType(DM da, DMDAElementType *etype)
337 {
338   DM_DA    *dd = (DM_DA *)da->data;
339   PetscBool isda;
340 
341   PetscFunctionBegin;
342   PetscValidHeaderSpecificType(da, DM_CLASSID, 1, DMDA);
343   PetscValidPointer(etype, 2);
344   PetscCall(PetscObjectTypeCompare((PetscObject)da, DMDA, &isda));
345   PetscCheck(isda, PetscObjectComm((PetscObject)da), PETSC_ERR_USER, "Not for DM type %s", ((PetscObject)da)->type_name);
346   *etype = dd->elementtype;
347   PetscFunctionReturn(PETSC_SUCCESS);
348 }
349 
350 /*@C
351       DMDAGetElements - Gets an array containing the indices (in local coordinates)
352                  of all the local elements
353 
354     Not Collective
355 
356    Input Parameter:
357 .     dm - the `DMDA` object
358 
359    Output Parameters:
360 +     nel - number of local elements
361 .     nen - number of element nodes
362 -     e - the local indices of the elements' vertices
363 
364    Level: intermediate
365 
366    Notes:
367      Call `DMDARestoreElements()` once you have finished accessing the elements.
368 
369      Each process uniquely owns a subset of the elements. That is no element is owned by two or more processes.
370 
371      If on each process you integrate over its owned elements and use `ADD_VALUES` in `Vec`/`MatSetValuesLocal()` then you'll obtain the correct result.
372 
373    Fortran Note:
374      Not supported in Fortran
375 
376 .seealso: `DM`, `DMDA`, `DMDAElementType`, `DMDASetElementType()`, `VecSetValuesLocal()`, `MatSetValuesLocal()`, `DMGlobalToLocalBegin()`, `DMLocalToGlobalBegin()`
377 @*/
378 PetscErrorCode DMDAGetElements(DM dm, PetscInt *nel, PetscInt *nen, const PetscInt *e[])
379 {
380   PetscInt  dim;
381   DM_DA    *dd = (DM_DA *)dm->data;
382   PetscBool isda;
383 
384   PetscFunctionBegin;
385   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMDA);
386   PetscValidIntPointer(nel, 2);
387   PetscValidIntPointer(nen, 3);
388   PetscValidPointer(e, 4);
389   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMDA, &isda));
390   PetscCheck(isda, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for DM type %s", ((PetscObject)dm)->type_name);
391   PetscCheck(dd->stencil_type != DMDA_STENCIL_STAR, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMDAGetElements() requires you use a stencil type of DMDA_STENCIL_BOX");
392   PetscCall(DMGetDimension(dm, &dim));
393   if (dd->e) {
394     *nel = dd->ne;
395     *nen = dd->nen;
396     *e   = dd->e;
397     PetscFunctionReturn(PETSC_SUCCESS);
398   }
399   if (dim == -1) {
400     *nel = 0;
401     *nen = 0;
402     *e   = NULL;
403   } else if (dim == 1) {
404     PetscCall(DMDAGetElements_1D(dm, nel, nen, e));
405   } else if (dim == 2) {
406     PetscCall(DMDAGetElements_2D(dm, nel, nen, e));
407   } else if (dim == 3) {
408     PetscCall(DMDAGetElements_3D(dm, nel, nen, e));
409   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "DMDA dimension not 1, 2, or 3, it is %" PetscInt_FMT, dim);
410   PetscFunctionReturn(PETSC_SUCCESS);
411 }
412 
413 /*@
414       DMDAGetSubdomainCornersIS - Gets an index set containing the corner indices (in local coordinates)
415                                  of the non-overlapping decomposition identified by `DMDAGetElements()`
416 
417     Not Collective
418 
419    Input Parameter:
420 .     dm - the `DMDA` object
421 
422    Output Parameters:
423 .     is - the index set
424 
425    Level: intermediate
426 
427    Note:
428     Call `DMDARestoreSubdomainCornersIS()` once you have finished accessing the index set.
429 
430 .seealso: `DM`, `DMDA`, `DMDAElementType`, `DMDASetElementType()`, `DMDAGetElements()`, `DMDARestoreElementsCornersIS()`
431 @*/
432 PetscErrorCode DMDAGetSubdomainCornersIS(DM dm, IS *is)
433 {
434   DM_DA    *dd = (DM_DA *)dm->data;
435   PetscBool isda;
436 
437   PetscFunctionBegin;
438   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMDA);
439   PetscValidPointer(is, 2);
440   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMDA, &isda));
441   PetscCheck(isda, PetscObjectComm((PetscObject)dm), PETSC_ERR_USER, "Not for DM type %s", ((PetscObject)dm)->type_name);
442   PetscCheck(dd->stencil_type != DMDA_STENCIL_STAR, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DMDAGetElement() requires you use a stencil type of DMDA_STENCIL_BOX");
443   if (!dd->ecorners) { /* compute elements if not yet done */
444     const PetscInt *e;
445     PetscInt        nel, nen;
446 
447     PetscCall(DMDAGetElements(dm, &nel, &nen, &e));
448     PetscCall(DMDARestoreElements(dm, &nel, &nen, &e));
449   }
450   *is = dd->ecorners;
451   PetscFunctionReturn(PETSC_SUCCESS);
452 }
453 
454 /*@C
455       DMDARestoreElements - Restores the array obtained with `DMDAGetElements()`
456 
457     Not Collective
458 
459    Input Parameters:
460 +     dm - the DM object
461 .     nel - number of local elements
462 .     nen - number of element nodes
463 -     e - the local indices of the elements' vertices
464 
465    Level: intermediate
466 
467    Note:
468    This restore signals the `DMDA` object that you no longer need access to the array information.
469 
470    Fortran Note:
471    Not supported in Fortran
472 
473 .seealso: `DM`, `DMDA`, `DMDAElementType`, `DMDASetElementType()`, `DMDAGetElements()`
474 @*/
475 PetscErrorCode DMDARestoreElements(DM dm, PetscInt *nel, PetscInt *nen, const PetscInt *e[])
476 {
477   PetscFunctionBegin;
478   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMDA);
479   PetscValidIntPointer(nel, 2);
480   PetscValidIntPointer(nen, 3);
481   PetscValidPointer(e, 4);
482   *nel = 0;
483   *nen = -1;
484   *e   = NULL;
485   PetscFunctionReturn(PETSC_SUCCESS);
486 }
487 
488 /*@
489       DMDARestoreSubdomainCornersIS - Restores the `IS` obtained with `DMDAGetSubdomainCornersIS()`
490 
491     Not Collective
492 
493    Input Parameters:
494 +     dm - the `DM` object
495 -     is - the index set
496 
497    Level: intermediate
498 
499 .seealso: `DM`, `DMDA`, `DMDAElementType`, `DMDASetElementType()`, `DMDAGetSubdomainCornersIS()`
500 @*/
501 PetscErrorCode DMDARestoreSubdomainCornersIS(DM dm, IS *is)
502 {
503   PetscFunctionBegin;
504   PetscValidHeaderSpecificType(dm, DM_CLASSID, 1, DMDA);
505   PetscValidHeaderSpecific(*is, IS_CLASSID, 2);
506   *is = NULL;
507   PetscFunctionReturn(PETSC_SUCCESS);
508 }
509