xref: /petsc/src/dm/interface/dm.c (revision 11c8a98f607708dcee13afcc724c3f833fe66e89)
1 #include <petscvec.h>
2 #include <petsc/private/dmimpl.h>      /*I      "petscdm.h"          I*/
3 #include <petsc/private/dmlabelimpl.h> /*I      "petscdmlabel.h"     I*/
4 #include <petsc/private/petscdsimpl.h> /*I      "petscds.h"     I*/
5 #include <petscdmplex.h>
6 #include <petscdmceed.h>
7 #include <petscdmfield.h>
8 #include <petscsf.h>
9 #include <petscds.h>
10 
11 #ifdef PETSC_HAVE_LIBCEED
12   #include <petscfeceed.h>
13 #endif
14 
15 #if !defined(PETSC_HAVE_WINDOWS_COMPILERS)
16   #include <petsc/private/valgrind/memcheck.h>
17 #endif
18 
19 PetscClassId DM_CLASSID;
20 PetscClassId DMLABEL_CLASSID;
21 PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_CreateMassMatrix, DM_Load, DM_AdaptInterpolator, DM_ProjectFunction;
22 
23 const char *const DMBoundaryTypes[]          = {"NONE", "GHOSTED", "MIRROR", "PERIODIC", "TWIST", "DMBoundaryType", "DM_BOUNDARY_", NULL};
24 const char *const DMBoundaryConditionTypes[] = {"INVALID", "ESSENTIAL", "NATURAL", "INVALID", "INVALID", "ESSENTIAL_FIELD", "NATURAL_FIELD", "INVALID", "INVALID", "ESSENTIAL_BD_FIELD", "NATURAL_RIEMANN", "DMBoundaryConditionType", "DM_BC_", NULL};
25 const char *const DMBlockingTypes[]          = {"TOPOLOGICAL_POINT", "FIELD_NODE", "DMBlockingType", "DM_BLOCKING_", NULL};
26 const char *const DMPolytopeTypes[] =
27   {"vertex",  "segment",      "tensor_segment", "triangle", "quadrilateral",  "tensor_quad",  "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism", "pyramid", "FV_ghost_cell", "interior_ghost_cell",
28    "unknown", "unknown_cell", "unknown_face",   "invalid",  "DMPolytopeType", "DM_POLYTOPE_", NULL};
29 const char *const DMCopyLabelsModes[] = {"replace", "keep", "fail", "DMCopyLabelsMode", "DM_COPY_LABELS_", NULL};
30 
31 /*@
32   DMCreate - Creates an empty `DM` object. `DM`s are the abstract objects in PETSc that mediate between meshes and discretizations and the
33   algebraic solvers, time integrators, and optimization algorithms.
34 
35   Collective
36 
37   Input Parameter:
38 . comm - The communicator for the `DM` object
39 
40   Output Parameter:
41 . dm - The `DM` object
42 
43   Level: beginner
44 
45   Notes:
46   See `DMType` for a brief summary of available `DM`.
47 
48   The type must then be set with `DMSetType()`. If you never call `DMSetType()` it will generate an
49   error when you try to use the dm.
50 
51 .seealso: [](ch_dmbase), `DM`, `DMSetType()`, `DMType`, `DMDACreate()`, `DMDA`, `DMSLICED`, `DMCOMPOSITE`, `DMPLEX`, `DMMOAB`, `DMNETWORK`
52 @*/
53 PetscErrorCode DMCreate(MPI_Comm comm, DM *dm)
54 {
55   DM      v;
56   PetscDS ds;
57 
58   PetscFunctionBegin;
59   PetscAssertPointer(dm, 2);
60 
61   PetscCall(DMInitializePackage());
62   PetscCall(PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView));
63   ((PetscObject)v)->non_cyclic_references = &DMCountNonCyclicReferences;
64   v->setupcalled                          = PETSC_FALSE;
65   v->setfromoptionscalled                 = PETSC_FALSE;
66   v->ltogmap                              = NULL;
67   v->bind_below                           = 0;
68   v->bs                                   = 1;
69   v->coloringtype                         = IS_COLORING_GLOBAL;
70   PetscCall(PetscSFCreate(comm, &v->sf));
71   PetscCall(PetscSFCreate(comm, &v->sectionSF));
72   v->labels                    = NULL;
73   v->adjacency[0]              = PETSC_FALSE;
74   v->adjacency[1]              = PETSC_TRUE;
75   v->depthLabel                = NULL;
76   v->celltypeLabel             = NULL;
77   v->localSection              = NULL;
78   v->globalSection             = NULL;
79   v->defaultConstraint.section = NULL;
80   v->defaultConstraint.mat     = NULL;
81   v->defaultConstraint.bias    = NULL;
82   v->coordinates[0].dim        = PETSC_DEFAULT;
83   v->coordinates[1].dim        = PETSC_DEFAULT;
84   v->sparseLocalize            = PETSC_TRUE;
85   v->dim                       = PETSC_DETERMINE;
86   {
87     PetscInt i;
88     for (i = 0; i < 10; ++i) {
89       v->nullspaceConstructors[i]     = NULL;
90       v->nearnullspaceConstructors[i] = NULL;
91     }
92   }
93   PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
94   PetscCall(DMSetRegionDS(v, NULL, NULL, ds, NULL));
95   PetscCall(PetscDSDestroy(&ds));
96   PetscCall(PetscHMapAuxCreate(&v->auxData));
97   v->dmBC              = NULL;
98   v->coarseMesh        = NULL;
99   v->outputSequenceNum = -1;
100   v->outputSequenceVal = 0.0;
101   PetscCall(DMSetVecType(v, VECSTANDARD));
102   PetscCall(DMSetMatType(v, MATAIJ));
103 
104   *dm = v;
105   PetscFunctionReturn(PETSC_SUCCESS);
106 }
107 
108 /*@
109   DMClone - Creates a `DM` object with the same topology as the original.
110 
111   Collective
112 
113   Input Parameter:
114 . dm - The original `DM` object
115 
116   Output Parameter:
117 . newdm - The new `DM` object
118 
119   Level: beginner
120 
121   Notes:
122   For some `DM` implementations this is a shallow clone, the result of which may share (reference counted) information with its parent. For example,
123   `DMClone()` applied to a `DMPLEX` object will result in a new `DMPLEX` that shares the topology with the original `DMPLEX`. It does not
124   share the `PetscSection` of the original `DM`.
125 
126   The clone is considered set up if the original has been set up.
127 
128   Use `DMConvert()` for a general way to create new `DM` from a given `DM`
129 
130 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMSetType()`, `DMSetLocalSection()`, `DMSetGlobalSection()`, `DMPLEX`, `DMConvert()`
131 @*/
132 PetscErrorCode DMClone(DM dm, DM *newdm)
133 {
134   PetscSF              sf;
135   Vec                  coords;
136   void                *ctx;
137   MatOrderingType      otype;
138   DMReorderDefaultFlag flg;
139   PetscInt             dim, cdim, i;
140 
141   PetscFunctionBegin;
142   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
143   PetscAssertPointer(newdm, 2);
144   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), newdm));
145   PetscCall(DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE, DM_COPY_LABELS_FAIL));
146   (*newdm)->leveldown     = dm->leveldown;
147   (*newdm)->levelup       = dm->levelup;
148   (*newdm)->prealloc_only = dm->prealloc_only;
149   (*newdm)->prealloc_skip = dm->prealloc_skip;
150   PetscCall(PetscFree((*newdm)->vectype));
151   PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*newdm)->vectype));
152   PetscCall(PetscFree((*newdm)->mattype));
153   PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*newdm)->mattype));
154   PetscCall(DMGetDimension(dm, &dim));
155   PetscCall(DMSetDimension(*newdm, dim));
156   PetscTryTypeMethod(dm, clone, newdm);
157   (*newdm)->setupcalled = dm->setupcalled;
158   PetscCall(DMGetPointSF(dm, &sf));
159   PetscCall(DMSetPointSF(*newdm, sf));
160   PetscCall(DMGetApplicationContext(dm, &ctx));
161   PetscCall(DMSetApplicationContext(*newdm, ctx));
162   PetscCall(DMReorderSectionGetDefault(dm, &flg));
163   PetscCall(DMReorderSectionSetDefault(*newdm, flg));
164   PetscCall(DMReorderSectionGetType(dm, &otype));
165   PetscCall(DMReorderSectionSetType(*newdm, otype));
166   for (i = 0; i < 2; ++i) {
167     if (dm->coordinates[i].dm) {
168       DM           ncdm;
169       PetscSection cs;
170       PetscInt     pEnd = -1, pEndMax = -1;
171 
172       PetscCall(DMGetLocalSection(dm->coordinates[i].dm, &cs));
173       if (cs) PetscCall(PetscSectionGetChart(cs, NULL, &pEnd));
174       PetscCall(MPIU_Allreduce(&pEnd, &pEndMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
175       if (pEndMax >= 0) {
176         PetscCall(DMClone(dm->coordinates[i].dm, &ncdm));
177         PetscCall(DMCopyDisc(dm->coordinates[i].dm, ncdm));
178         PetscCall(DMSetLocalSection(ncdm, cs));
179         if (dm->coordinates[i].dm->periodic.setup) {
180           ncdm->periodic.setup = dm->coordinates[i].dm->periodic.setup;
181           PetscCall(ncdm->periodic.setup(ncdm));
182         }
183         if (i) PetscCall(DMSetCellCoordinateDM(*newdm, ncdm));
184         else PetscCall(DMSetCoordinateDM(*newdm, ncdm));
185         PetscCall(DMDestroy(&ncdm));
186       }
187     }
188   }
189   PetscCall(DMGetCoordinateDim(dm, &cdim));
190   PetscCall(DMSetCoordinateDim(*newdm, cdim));
191   PetscCall(DMGetCoordinatesLocal(dm, &coords));
192   if (coords) {
193     PetscCall(DMSetCoordinatesLocal(*newdm, coords));
194   } else {
195     PetscCall(DMGetCoordinates(dm, &coords));
196     if (coords) PetscCall(DMSetCoordinates(*newdm, coords));
197   }
198   PetscCall(DMGetCellCoordinatesLocal(dm, &coords));
199   if (coords) {
200     PetscCall(DMSetCellCoordinatesLocal(*newdm, coords));
201   } else {
202     PetscCall(DMGetCellCoordinates(dm, &coords));
203     if (coords) PetscCall(DMSetCellCoordinates(*newdm, coords));
204   }
205   {
206     const PetscReal *maxCell, *Lstart, *L;
207 
208     PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
209     PetscCall(DMSetPeriodicity(*newdm, maxCell, Lstart, L));
210   }
211   {
212     PetscBool useCone, useClosure;
213 
214     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure));
215     PetscCall(DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure));
216   }
217   PetscFunctionReturn(PETSC_SUCCESS);
218 }
219 
220 /*@
221   DMSetVecType - Sets the type of vector to be created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`
222 
223   Logically Collective
224 
225   Input Parameters:
226 + dm    - initial distributed array
227 - ctype - the vector type, for example `VECSTANDARD`, `VECCUDA`, or `VECVIENNACL`
228 
229   Options Database Key:
230 . -dm_vec_type ctype - the type of vector to create
231 
232   Level: intermediate
233 
234 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMDestroy()`, `DMDAInterpolationType`, `VecType`, `DMGetVecType()`, `DMSetMatType()`, `DMGetMatType()`,
235           `VECSTANDARD`, `VECCUDA`, `VECVIENNACL`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`
236 @*/
237 PetscErrorCode DMSetVecType(DM dm, VecType ctype)
238 {
239   char *tmp;
240 
241   PetscFunctionBegin;
242   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
243   PetscAssertPointer(ctype, 2);
244   tmp = (char *)dm->vectype;
245   PetscCall(PetscStrallocpy(ctype, (char **)&dm->vectype));
246   PetscCall(PetscFree(tmp));
247   PetscFunctionReturn(PETSC_SUCCESS);
248 }
249 
250 /*@
251   DMGetVecType - Gets the type of vector created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`
252 
253   Logically Collective
254 
255   Input Parameter:
256 . da - initial distributed array
257 
258   Output Parameter:
259 . ctype - the vector type
260 
261   Level: intermediate
262 
263 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMDestroy()`, `DMDAInterpolationType`, `VecType`, `DMSetMatType()`, `DMGetMatType()`, `DMSetVecType()`
264 @*/
265 PetscErrorCode DMGetVecType(DM da, VecType *ctype)
266 {
267   PetscFunctionBegin;
268   PetscValidHeaderSpecific(da, DM_CLASSID, 1);
269   *ctype = da->vectype;
270   PetscFunctionReturn(PETSC_SUCCESS);
271 }
272 
273 /*@
274   VecGetDM - Gets the `DM` defining the data layout of the vector
275 
276   Not Collective
277 
278   Input Parameter:
279 . v - The `Vec`
280 
281   Output Parameter:
282 . dm - The `DM`
283 
284   Level: intermediate
285 
286   Note:
287   A `Vec` may not have a `DM` associated with it.
288 
289 .seealso: [](ch_dmbase), `DM`, `VecSetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
290 @*/
291 PetscErrorCode VecGetDM(Vec v, DM *dm)
292 {
293   PetscFunctionBegin;
294   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
295   PetscAssertPointer(dm, 2);
296   PetscCall(PetscObjectQuery((PetscObject)v, "__PETSc_dm", (PetscObject *)dm));
297   PetscFunctionReturn(PETSC_SUCCESS);
298 }
299 
300 /*@
301   VecSetDM - Sets the `DM` defining the data layout of the vector.
302 
303   Not Collective
304 
305   Input Parameters:
306 + v  - The `Vec`
307 - dm - The `DM`
308 
309   Level: developer
310 
311   Notes:
312   This is rarely used, generally one uses `DMGetLocalVector()` or  `DMGetGlobalVector()` to create a vector associated with a given `DM`
313 
314   This is NOT the same as `DMCreateGlobalVector()` since it does not change the view methods or perform other customization, but merely sets the `DM` member.
315 
316 .seealso: [](ch_dmbase), `DM`, `VecGetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
317 @*/
318 PetscErrorCode VecSetDM(Vec v, DM dm)
319 {
320   PetscFunctionBegin;
321   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
322   if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
323   PetscCall(PetscObjectCompose((PetscObject)v, "__PETSc_dm", (PetscObject)dm));
324   PetscFunctionReturn(PETSC_SUCCESS);
325 }
326 
327 /*@
328   DMSetISColoringType - Sets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`
329 
330   Logically Collective
331 
332   Input Parameters:
333 + dm    - the `DM` context
334 - ctype - the matrix type
335 
336   Options Database Key:
337 . -dm_is_coloring_type - global or local
338 
339   Level: intermediate
340 
341 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
342           `DMGetISColoringType()`, `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
343 @*/
344 PetscErrorCode DMSetISColoringType(DM dm, ISColoringType ctype)
345 {
346   PetscFunctionBegin;
347   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
348   dm->coloringtype = ctype;
349   PetscFunctionReturn(PETSC_SUCCESS);
350 }
351 
352 /*@
353   DMGetISColoringType - Gets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`
354 
355   Logically Collective
356 
357   Input Parameter:
358 . dm - the `DM` context
359 
360   Output Parameter:
361 . ctype - the matrix type
362 
363   Options Database Key:
364 . -dm_is_coloring_type - global or local
365 
366   Level: intermediate
367 
368 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
369           `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
370 @*/
371 PetscErrorCode DMGetISColoringType(DM dm, ISColoringType *ctype)
372 {
373   PetscFunctionBegin;
374   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
375   *ctype = dm->coloringtype;
376   PetscFunctionReturn(PETSC_SUCCESS);
377 }
378 
379 /*@
380   DMSetMatType - Sets the type of matrix created with `DMCreateMatrix()`
381 
382   Logically Collective
383 
384   Input Parameters:
385 + dm    - the `DM` context
386 - ctype - the matrix type, for example `MATMPIAIJ`
387 
388   Options Database Key:
389 . -dm_mat_type ctype - the type of the matrix to create, for example mpiaij
390 
391   Level: intermediate
392 
393 .seealso: [](ch_dmbase), `DM`, `MatType`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMGetMatType()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
394 @*/
395 PetscErrorCode DMSetMatType(DM dm, MatType ctype)
396 {
397   char *tmp;
398 
399   PetscFunctionBegin;
400   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
401   PetscAssertPointer(ctype, 2);
402   tmp = (char *)dm->mattype;
403   PetscCall(PetscStrallocpy(ctype, (char **)&dm->mattype));
404   PetscCall(PetscFree(tmp));
405   PetscFunctionReturn(PETSC_SUCCESS);
406 }
407 
408 /*@
409   DMGetMatType - Gets the type of matrix that would be created with `DMCreateMatrix()`
410 
411   Logically Collective
412 
413   Input Parameter:
414 . dm - the `DM` context
415 
416   Output Parameter:
417 . ctype - the matrix type
418 
419   Level: intermediate
420 
421 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMSetMatType()`
422 @*/
423 PetscErrorCode DMGetMatType(DM dm, MatType *ctype)
424 {
425   PetscFunctionBegin;
426   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
427   *ctype = dm->mattype;
428   PetscFunctionReturn(PETSC_SUCCESS);
429 }
430 
431 /*@
432   MatGetDM - Gets the `DM` defining the data layout of the matrix
433 
434   Not Collective
435 
436   Input Parameter:
437 . A - The `Mat`
438 
439   Output Parameter:
440 . dm - The `DM`
441 
442   Level: intermediate
443 
444   Note:
445   A matrix may not have a `DM` associated with it
446 
447   Developer Note:
448   Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with the `Mat` through a `PetscObjectCompose()` operation
449 
450 .seealso: [](ch_dmbase), `DM`, `MatSetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
451 @*/
452 PetscErrorCode MatGetDM(Mat A, DM *dm)
453 {
454   PetscFunctionBegin;
455   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
456   PetscAssertPointer(dm, 2);
457   PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", (PetscObject *)dm));
458   PetscFunctionReturn(PETSC_SUCCESS);
459 }
460 
461 /*@
462   MatSetDM - Sets the `DM` defining the data layout of the matrix
463 
464   Not Collective
465 
466   Input Parameters:
467 + A  - The `Mat`
468 - dm - The `DM`
469 
470   Level: developer
471 
472   Note:
473   This is rarely used in practice, rather `DMCreateMatrix()` is used to create a matrix associated with a particular `DM`
474 
475   Developer Note:
476   Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with
477   the `Mat` through a `PetscObjectCompose()` operation
478 
479 .seealso: [](ch_dmbase), `DM`, `MatGetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
480 @*/
481 PetscErrorCode MatSetDM(Mat A, DM dm)
482 {
483   PetscFunctionBegin;
484   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
485   if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
486   PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_dm", (PetscObject)dm));
487   PetscFunctionReturn(PETSC_SUCCESS);
488 }
489 
490 /*@
491   DMSetOptionsPrefix - Sets the prefix prepended to all option names when searching through the options database
492 
493   Logically Collective
494 
495   Input Parameters:
496 + dm     - the `DM` context
497 - prefix - the prefix to prepend
498 
499   Level: advanced
500 
501   Note:
502   A hyphen (-) must NOT be given at the beginning of the prefix name.
503   The first character of all runtime options is AUTOMATICALLY the hyphen.
504 
505 .seealso: [](ch_dmbase), `DM`, `PetscObjectSetOptionsPrefix()`, `DMSetFromOptions()`
506 @*/
507 PetscErrorCode DMSetOptionsPrefix(DM dm, const char prefix[])
508 {
509   PetscFunctionBegin;
510   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
511   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix));
512   if (dm->sf) PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm->sf, prefix));
513   if (dm->sectionSF) PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF, prefix));
514   PetscFunctionReturn(PETSC_SUCCESS);
515 }
516 
517 /*@
518   DMAppendOptionsPrefix - Appends an additional string to an already existing prefix used for searching for
519   `DM` options in the options database.
520 
521   Logically Collective
522 
523   Input Parameters:
524 + dm     - the `DM` context
525 - prefix - the string to append to the current prefix
526 
527   Level: advanced
528 
529   Note:
530   If the `DM` does not currently have an options prefix then this value is used alone as the prefix as if `DMSetOptionsPrefix()` had been called.
531   A hyphen (-) must NOT be given at the beginning of the prefix name.
532   The first character of all runtime options is AUTOMATICALLY the hyphen.
533 
534 .seealso: [](ch_dmbase), `DM`, `DMSetOptionsPrefix()`, `DMGetOptionsPrefix()`, `PetscObjectAppendOptionsPrefix()`, `DMSetFromOptions()`
535 @*/
536 PetscErrorCode DMAppendOptionsPrefix(DM dm, const char prefix[])
537 {
538   PetscFunctionBegin;
539   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
540   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, prefix));
541   PetscFunctionReturn(PETSC_SUCCESS);
542 }
543 
544 /*@
545   DMGetOptionsPrefix - Gets the prefix used for searching for all
546   DM options in the options database.
547 
548   Not Collective
549 
550   Input Parameter:
551 . dm - the `DM` context
552 
553   Output Parameter:
554 . prefix - pointer to the prefix string used is returned
555 
556   Level: advanced
557 
558   Fortran Note:
559   Pass in a string 'prefix' of
560   sufficient length to hold the prefix.
561 
562 .seealso: [](ch_dmbase), `DM`, `DMSetOptionsPrefix()`, `DMAppendOptionsPrefix()`, `DMSetFromOptions()`
563 @*/
564 PetscErrorCode DMGetOptionsPrefix(DM dm, const char *prefix[])
565 {
566   PetscFunctionBegin;
567   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
568   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, prefix));
569   PetscFunctionReturn(PETSC_SUCCESS);
570 }
571 
572 static PetscErrorCode DMCountNonCyclicReferences_Internal(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
573 {
574   PetscInt refct = ((PetscObject)dm)->refct;
575 
576   PetscFunctionBegin;
577   *ncrefct = 0;
578   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
579     refct--;
580     if (recurseCoarse) {
581       PetscInt coarseCount;
582 
583       PetscCall(DMCountNonCyclicReferences_Internal(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE, &coarseCount));
584       refct += coarseCount;
585     }
586   }
587   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
588     refct--;
589     if (recurseFine) {
590       PetscInt fineCount;
591 
592       PetscCall(DMCountNonCyclicReferences_Internal(dm->fineMesh, PETSC_FALSE, PETSC_TRUE, &fineCount));
593       refct += fineCount;
594     }
595   }
596   *ncrefct = refct;
597   PetscFunctionReturn(PETSC_SUCCESS);
598 }
599 
600 /* Generic wrapper for DMCountNonCyclicReferences_Internal() */
601 PetscErrorCode DMCountNonCyclicReferences(PetscObject dm, PetscInt *ncrefct)
602 {
603   PetscFunctionBegin;
604   PetscCall(DMCountNonCyclicReferences_Internal((DM)dm, PETSC_TRUE, PETSC_TRUE, ncrefct));
605   PetscFunctionReturn(PETSC_SUCCESS);
606 }
607 
608 PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
609 {
610   DMLabelLink next = dm->labels;
611 
612   PetscFunctionBegin;
613   /* destroy the labels */
614   while (next) {
615     DMLabelLink tmp = next->next;
616 
617     if (next->label == dm->depthLabel) dm->depthLabel = NULL;
618     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
619     PetscCall(DMLabelDestroy(&next->label));
620     PetscCall(PetscFree(next));
621     next = tmp;
622   }
623   dm->labels = NULL;
624   PetscFunctionReturn(PETSC_SUCCESS);
625 }
626 
627 static PetscErrorCode DMDestroyCoordinates_Private(DMCoordinates *c)
628 {
629   PetscFunctionBegin;
630   c->dim = PETSC_DEFAULT;
631   PetscCall(DMDestroy(&c->dm));
632   PetscCall(VecDestroy(&c->x));
633   PetscCall(VecDestroy(&c->xl));
634   PetscCall(DMFieldDestroy(&c->field));
635   PetscFunctionReturn(PETSC_SUCCESS);
636 }
637 
638 /*@
639   DMDestroy - Destroys a `DM`.
640 
641   Collective
642 
643   Input Parameter:
644 . dm - the `DM` object to destroy
645 
646   Level: developer
647 
648 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMType`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
649 @*/
650 PetscErrorCode DMDestroy(DM *dm)
651 {
652   PetscInt cnt;
653 
654   PetscFunctionBegin;
655   if (!*dm) PetscFunctionReturn(PETSC_SUCCESS);
656   PetscValidHeaderSpecific(*dm, DM_CLASSID, 1);
657 
658   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
659   PetscCall(DMCountNonCyclicReferences_Internal(*dm, PETSC_TRUE, PETSC_TRUE, &cnt));
660   --((PetscObject)*dm)->refct;
661   if (--cnt > 0) {
662     *dm = NULL;
663     PetscFunctionReturn(PETSC_SUCCESS);
664   }
665   if (((PetscObject)*dm)->refct < 0) PetscFunctionReturn(PETSC_SUCCESS);
666   ((PetscObject)*dm)->refct = 0;
667 
668   PetscCall(DMClearGlobalVectors(*dm));
669   PetscCall(DMClearLocalVectors(*dm));
670   PetscCall(DMClearNamedGlobalVectors(*dm));
671   PetscCall(DMClearNamedLocalVectors(*dm));
672 
673   /* Destroy the list of hooks */
674   {
675     DMCoarsenHookLink link, next;
676     for (link = (*dm)->coarsenhook; link; link = next) {
677       next = link->next;
678       PetscCall(PetscFree(link));
679     }
680     (*dm)->coarsenhook = NULL;
681   }
682   {
683     DMRefineHookLink link, next;
684     for (link = (*dm)->refinehook; link; link = next) {
685       next = link->next;
686       PetscCall(PetscFree(link));
687     }
688     (*dm)->refinehook = NULL;
689   }
690   {
691     DMSubDomainHookLink link, next;
692     for (link = (*dm)->subdomainhook; link; link = next) {
693       next = link->next;
694       PetscCall(PetscFree(link));
695     }
696     (*dm)->subdomainhook = NULL;
697   }
698   {
699     DMGlobalToLocalHookLink link, next;
700     for (link = (*dm)->gtolhook; link; link = next) {
701       next = link->next;
702       PetscCall(PetscFree(link));
703     }
704     (*dm)->gtolhook = NULL;
705   }
706   {
707     DMLocalToGlobalHookLink link, next;
708     for (link = (*dm)->ltoghook; link; link = next) {
709       next = link->next;
710       PetscCall(PetscFree(link));
711     }
712     (*dm)->ltoghook = NULL;
713   }
714   /* Destroy the work arrays */
715   {
716     DMWorkLink link, next;
717     PetscCheck(!(*dm)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out %p %p", (void *)(*dm)->workout, (void *)(*dm)->workout->mem);
718     for (link = (*dm)->workin; link; link = next) {
719       next = link->next;
720       PetscCall(PetscFree(link->mem));
721       PetscCall(PetscFree(link));
722     }
723     (*dm)->workin = NULL;
724   }
725   /* destroy the labels */
726   PetscCall(DMDestroyLabelLinkList_Internal(*dm));
727   /* destroy the fields */
728   PetscCall(DMClearFields(*dm));
729   /* destroy the boundaries */
730   {
731     DMBoundary next = (*dm)->boundary;
732     while (next) {
733       DMBoundary b = next;
734 
735       next = b->next;
736       PetscCall(PetscFree(b));
737     }
738   }
739 
740   PetscCall(PetscObjectDestroy(&(*dm)->dmksp));
741   PetscCall(PetscObjectDestroy(&(*dm)->dmsnes));
742   PetscCall(PetscObjectDestroy(&(*dm)->dmts));
743 
744   if ((*dm)->ctx && (*dm)->ctxdestroy) PetscCall((*(*dm)->ctxdestroy)(&(*dm)->ctx));
745   PetscCall(MatFDColoringDestroy(&(*dm)->fd));
746   PetscCall(ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap));
747   PetscCall(PetscFree((*dm)->vectype));
748   PetscCall(PetscFree((*dm)->mattype));
749 
750   PetscCall(PetscSectionDestroy(&(*dm)->localSection));
751   PetscCall(PetscSectionDestroy(&(*dm)->globalSection));
752   PetscCall(PetscFree((*dm)->reorderSectionType));
753   PetscCall(PetscLayoutDestroy(&(*dm)->map));
754   PetscCall(PetscSectionDestroy(&(*dm)->defaultConstraint.section));
755   PetscCall(MatDestroy(&(*dm)->defaultConstraint.mat));
756   PetscCall(PetscSFDestroy(&(*dm)->sf));
757   PetscCall(PetscSFDestroy(&(*dm)->sectionSF));
758   if ((*dm)->sfNatural) PetscCall(PetscSFDestroy(&(*dm)->sfNatural));
759   PetscCall(PetscObjectDereference((PetscObject)(*dm)->sfMigration));
760   PetscCall(DMClearAuxiliaryVec(*dm));
761   PetscCall(PetscHMapAuxDestroy(&(*dm)->auxData));
762   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) PetscCall(DMSetFineDM((*dm)->coarseMesh, NULL));
763 
764   PetscCall(DMDestroy(&(*dm)->coarseMesh));
765   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) PetscCall(DMSetCoarseDM((*dm)->fineMesh, NULL));
766   PetscCall(DMDestroy(&(*dm)->fineMesh));
767   PetscCall(PetscFree((*dm)->Lstart));
768   PetscCall(PetscFree((*dm)->L));
769   PetscCall(PetscFree((*dm)->maxCell));
770   PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[0]));
771   PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[1]));
772   if ((*dm)->transformDestroy) PetscCall((*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx));
773   PetscCall(DMDestroy(&(*dm)->transformDM));
774   PetscCall(VecDestroy(&(*dm)->transform));
775   for (PetscInt i = 0; i < (*dm)->periodic.num_affines; i++) {
776     PetscCall(VecScatterDestroy(&(*dm)->periodic.affine_to_local[i]));
777     PetscCall(VecDestroy(&(*dm)->periodic.affine[i]));
778   }
779   if ((*dm)->periodic.num_affines > 0) PetscCall(PetscFree2((*dm)->periodic.affine_to_local, (*dm)->periodic.affine));
780 
781   PetscCall(DMClearDS(*dm));
782   PetscCall(DMDestroy(&(*dm)->dmBC));
783   /* if memory was published with SAWs then destroy it */
784   PetscCall(PetscObjectSAWsViewOff((PetscObject)*dm));
785 
786   PetscTryTypeMethod(*dm, destroy);
787   PetscCall(DMMonitorCancel(*dm));
788   PetscCall(DMCeedDestroy(&(*dm)->dmceed));
789 #ifdef PETSC_HAVE_LIBCEED
790   PetscCallCEED(CeedElemRestrictionDestroy(&(*dm)->ceedERestrict));
791   PetscCallCEED(CeedDestroy(&(*dm)->ceed));
792 #endif
793   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
794   PetscCall(PetscHeaderDestroy(dm));
795   PetscFunctionReturn(PETSC_SUCCESS);
796 }
797 
798 /*@
799   DMSetUp - sets up the data structures inside a `DM` object
800 
801   Collective
802 
803   Input Parameter:
804 . dm - the `DM` object to setup
805 
806   Level: intermediate
807 
808   Note:
809   This is usually called after various parameter setting operations and `DMSetFromOptions()` are called on the `DM`
810 
811 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
812 @*/
813 PetscErrorCode DMSetUp(DM dm)
814 {
815   PetscFunctionBegin;
816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
817   if (dm->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
818   PetscTryTypeMethod(dm, setup);
819   dm->setupcalled = PETSC_TRUE;
820   PetscFunctionReturn(PETSC_SUCCESS);
821 }
822 
823 /*@
824   DMSetFromOptions - sets parameters in a `DM` from the options database
825 
826   Collective
827 
828   Input Parameter:
829 . dm - the `DM` object to set options for
830 
831   Options Database Keys:
832 + -dm_preallocate_only                               - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
833 . -dm_vec_type <type>                                - type of vector to create inside `DM`
834 . -dm_mat_type <type>                                - type of matrix to create inside `DM`
835 . -dm_is_coloring_type                               - <global or local>
836 . -dm_bind_below <n>                                 - bind (force execution on CPU) for `Vec` and `Mat` objects with local size (number of vector entries or matrix rows) below n; currently only supported for `DMDA`
837 . -dm_plex_filename <str>                            - File containing a mesh
838 . -dm_plex_boundary_filename <str>                   - File containing a mesh boundary
839 . -dm_plex_name <str>                                - Name of the mesh in the file
840 . -dm_plex_shape <shape>                             - The domain shape, such as `BOX`, `SPHERE`, etc.
841 . -dm_plex_cell <ct>                                 - Cell shape
842 . -dm_plex_reference_cell_domain <bool>              - Use a reference cell domain
843 . -dm_plex_dim <dim>                                 - Set the topological dimension
844 . -dm_plex_simplex <bool>                            - `PETSC_TRUE` for simplex elements, `PETSC_FALSE` for tensor elements
845 . -dm_plex_interpolate <bool>                        - `PETSC_TRUE` turns on topological interpolation (creating edges and faces)
846 . -dm_plex_scale <sc>                                - Scale factor for mesh coordinates
847 . -dm_coord_remap <bool>                             - Map coordinates using a function
848 . -dm_coord_map <mapname>                            - Select a builtin coordinate map
849 . -dm_coord_map_params <p0,p1,p2,...>                - Set coordinate mapping parameters
850 . -dm_plex_box_faces <m,n,p>                         - Number of faces along each dimension
851 . -dm_plex_box_lower <x,y,z>                         - Specify lower-left-bottom coordinates for the box
852 . -dm_plex_box_upper <x,y,z>                         - Specify upper-right-top coordinates for the box
853 . -dm_plex_box_bd <bx,by,bz>                         - Specify the `DMBoundaryType` for each direction
854 . -dm_plex_sphere_radius <r>                         - The sphere radius
855 . -dm_plex_ball_radius <r>                           - Radius of the ball
856 . -dm_plex_cylinder_bd <bz>                          - Boundary type in the z direction
857 . -dm_plex_cylinder_num_wedges <n>                   - Number of wedges around the cylinder
858 . -dm_plex_reorder <order>                           - Reorder the mesh using the specified algorithm
859 . -dm_refine_pre <n>                                 - The number of refinements before distribution
860 . -dm_refine_uniform_pre <bool>                      - Flag for uniform refinement before distribution
861 . -dm_refine_volume_limit_pre <v>                    - The maximum cell volume after refinement before distribution
862 . -dm_refine <n>                                     - The number of refinements after distribution
863 . -dm_extrude <l>                                    - Activate extrusion and specify the number of layers to extrude
864 . -dm_plex_transform_extrude_thickness <t>           - The total thickness of extruded layers
865 . -dm_plex_transform_extrude_use_tensor <bool>       - Use tensor cells when extruding
866 . -dm_plex_transform_extrude_symmetric <bool>        - Extrude layers symmetrically about the surface
867 . -dm_plex_transform_extrude_normal <n0,...,nd>      - Specify the extrusion direction
868 . -dm_plex_transform_extrude_thicknesses <t0,...,tl> - Specify thickness of each layer
869 . -dm_plex_create_fv_ghost_cells                     - Flag to create finite volume ghost cells on the boundary
870 . -dm_plex_fv_ghost_cells_label <name>               - Label name for ghost cells boundary
871 . -dm_distribute <bool>                              - Flag to redistribute a mesh among processes
872 . -dm_distribute_overlap <n>                         - The size of the overlap halo
873 . -dm_plex_adj_cone <bool>                           - Set adjacency direction
874 . -dm_plex_adj_closure <bool>                        - Set adjacency size
875 . -dm_plex_use_ceed <bool>                           - Use LibCEED as the FEM backend
876 . -dm_plex_check_symmetry                            - Check that the adjacency information in the mesh is symmetric - `DMPlexCheckSymmetry()`
877 . -dm_plex_check_skeleton                            - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - `DMPlexCheckSkeleton()`
878 . -dm_plex_check_faces                               - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type - `DMPlexCheckFaces()`
879 . -dm_plex_check_geometry                            - Check that cells have positive volume - `DMPlexCheckGeometry()`
880 . -dm_plex_check_pointsf                             - Check some necessary conditions for `PointSF` - `DMPlexCheckPointSF()`
881 . -dm_plex_check_interface_cones                     - Check points on inter-partition interfaces have conforming order of cone points - `DMPlexCheckInterfaceCones()`
882 - -dm_plex_check_all                                 - Perform all the checks above
883 
884   Level: intermediate
885 
886   Note:
887   For some `DMType` such as `DMDA` this cannot be called after `DMSetUp()` has been called.
888 
889 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
890          `DMPlexCheckSymmetry()`, `DMPlexCheckSkeleton()`, `DMPlexCheckFaces()`, `DMPlexCheckGeometry()`, `DMPlexCheckPointSF()`, `DMPlexCheckInterfaceCones()`,
891          `DMSetOptionsPrefix()`, `DMType`, `DMPLEX`, `DMDA`, `DMSetUp()`
892 @*/
893 PetscErrorCode DMSetFromOptions(DM dm)
894 {
895   char      typeName[256];
896   PetscBool flg;
897 
898   PetscFunctionBegin;
899   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
900   dm->setfromoptionscalled = PETSC_TRUE;
901   if (dm->sf) PetscCall(PetscSFSetFromOptions(dm->sf));
902   if (dm->sectionSF) PetscCall(PetscSFSetFromOptions(dm->sectionSF));
903   if (dm->coordinates[0].dm) PetscCall(DMSetFromOptions(dm->coordinates[0].dm));
904   PetscObjectOptionsBegin((PetscObject)dm);
905   PetscCall(PetscOptionsBool("-dm_preallocate_only", "only preallocate matrix, but do not set column indices", "DMSetMatrixPreallocateOnly", dm->prealloc_only, &dm->prealloc_only, NULL));
906   PetscCall(PetscOptionsFList("-dm_vec_type", "Vector type used for created vectors", "DMSetVecType", VecList, dm->vectype, typeName, 256, &flg));
907   if (flg) PetscCall(DMSetVecType(dm, typeName));
908   PetscCall(PetscOptionsFList("-dm_mat_type", "Matrix type used for created matrices", "DMSetMatType", MatList, dm->mattype ? dm->mattype : typeName, typeName, sizeof(typeName), &flg));
909   if (flg) PetscCall(DMSetMatType(dm, typeName));
910   PetscCall(PetscOptionsEnum("-dm_blocking_type", "Topological point or field node blocking", "DMSetBlockingType", DMBlockingTypes, (PetscEnum)dm->blocking_type, (PetscEnum *)&dm->blocking_type, NULL));
911   PetscCall(PetscOptionsEnum("-dm_is_coloring_type", "Global or local coloring of Jacobian", "DMSetISColoringType", ISColoringTypes, (PetscEnum)dm->coloringtype, (PetscEnum *)&dm->coloringtype, NULL));
912   PetscCall(PetscOptionsInt("-dm_bind_below", "Set the size threshold (in entries) below which the Vec is bound to the CPU", "VecBindToCPU", dm->bind_below, &dm->bind_below, &flg));
913   PetscCall(PetscOptionsBool("-dm_ignore_perm_output", "Ignore the local section permutation on output", "DMGetOutputDM", dm->ignorePermOutput, &dm->ignorePermOutput, NULL));
914   PetscTryTypeMethod(dm, setfromoptions, PetscOptionsObject);
915   /* process any options handlers added with PetscObjectAddOptionsHandler() */
916   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)dm, PetscOptionsObject));
917   PetscOptionsEnd();
918   PetscFunctionReturn(PETSC_SUCCESS);
919 }
920 
921 /*@
922   DMViewFromOptions - View a `DM` in a particular way based on a request in the options database
923 
924   Collective
925 
926   Input Parameters:
927 + dm   - the `DM` object
928 . obj  - optional object that provides the prefix for the options database (if `NULL` then the prefix in obj is used)
929 - name - option string that is used to activate viewing
930 
931   Level: intermediate
932 
933   Note:
934   See `PetscObjectViewFromOptions()` for a list of values that can be provided in the options database to determine how the `DM` is viewed
935 
936 .seealso: [](ch_dmbase), `DM`, `DMView()`, `PetscObjectViewFromOptions()`, `DMCreate()`
937 @*/
938 PetscErrorCode DMViewFromOptions(DM dm, PetscObject obj, const char name[])
939 {
940   PetscFunctionBegin;
941   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
942   PetscCall(PetscObjectViewFromOptions((PetscObject)dm, obj, name));
943   PetscFunctionReturn(PETSC_SUCCESS);
944 }
945 
946 /*@
947   DMView - Views a `DM`. Depending on the `PetscViewer` and its `PetscViewerFormat` it may print some ASCII information about the `DM` to the screen or a file or
948   save the `DM` in a binary file to be loaded later or create a visualization of the `DM`
949 
950   Collective
951 
952   Input Parameters:
953 + dm - the `DM` object to view
954 - v  - the viewer
955 
956   Level: beginner
957 
958   Note:
959   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` as the `PetscViewerFormat` one can save multiple `DMPLEX`
960   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
961   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
962 
963 .seealso: [](ch_dmbase), `DM`, `PetscViewer`, `PetscViewerFormat`, `PetscViewerSetFormat()`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMLoad()`, `PetscObjectSetName()`
964 @*/
965 PetscErrorCode DMView(DM dm, PetscViewer v)
966 {
967   PetscBool         isbinary;
968   PetscMPIInt       size;
969   PetscViewerFormat format;
970 
971   PetscFunctionBegin;
972   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
973   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &v));
974   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
975   /* Ideally, we would like to have this test on.
976      However, it currently breaks socket viz via GLVis.
977      During DMView(parallel_mesh,glvis_viewer), each
978      process opens a sequential ASCII socket to visualize
979      the local mesh, and PetscObjectView(dm,local_socket)
980      is internally called inside VecView_GLVis, incurring
981      in an error here */
982   /* PetscCheckSameComm(dm,1,v,2); */
983   PetscCall(PetscViewerCheckWritable(v));
984 
985   PetscCall(PetscViewerGetFormat(v, &format));
986   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
987   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
988   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)dm, v));
989   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERBINARY, &isbinary));
990   if (isbinary) {
991     PetscInt classid = DM_FILE_CLASSID;
992     char     type[256];
993 
994     PetscCall(PetscViewerBinaryWrite(v, &classid, 1, PETSC_INT));
995     PetscCall(PetscStrncpy(type, ((PetscObject)dm)->type_name, sizeof(type)));
996     PetscCall(PetscViewerBinaryWrite(v, type, 256, PETSC_CHAR));
997   }
998   PetscTryTypeMethod(dm, view, v);
999   PetscFunctionReturn(PETSC_SUCCESS);
1000 }
1001 
1002 /*@
1003   DMCreateGlobalVector - Creates a global vector from a `DM` object. A global vector is a parallel vector that has no duplicate values shared between MPI ranks,
1004   that is it has no ghost locations.
1005 
1006   Collective
1007 
1008   Input Parameter:
1009 . dm - the `DM` object
1010 
1011   Output Parameter:
1012 . vec - the global vector
1013 
1014   Level: beginner
1015 
1016 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateLocalVector()`, `DMGetGlobalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
1017          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1018 @*/
1019 PetscErrorCode DMCreateGlobalVector(DM dm, Vec *vec)
1020 {
1021   PetscFunctionBegin;
1022   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1023   PetscAssertPointer(vec, 2);
1024   PetscUseTypeMethod(dm, createglobalvector, vec);
1025   if (PetscDefined(USE_DEBUG)) {
1026     DM vdm;
1027 
1028     PetscCall(VecGetDM(*vec, &vdm));
1029     PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name);
1030   }
1031   PetscFunctionReturn(PETSC_SUCCESS);
1032 }
1033 
1034 /*@
1035   DMCreateLocalVector - Creates a local vector from a `DM` object.
1036 
1037   Not Collective
1038 
1039   Input Parameter:
1040 . dm - the `DM` object
1041 
1042   Output Parameter:
1043 . vec - the local vector
1044 
1045   Level: beginner
1046 
1047   Note:
1048   A local vector usually has ghost locations that contain values that are owned by different MPI ranks. A global vector has no ghost locations.
1049 
1050 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateGlobalVector()`, `DMGetLocalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
1051          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1052 @*/
1053 PetscErrorCode DMCreateLocalVector(DM dm, Vec *vec)
1054 {
1055   PetscFunctionBegin;
1056   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1057   PetscAssertPointer(vec, 2);
1058   PetscUseTypeMethod(dm, createlocalvector, vec);
1059   if (PetscDefined(USE_DEBUG)) {
1060     DM vdm;
1061 
1062     PetscCall(VecGetDM(*vec, &vdm));
1063     PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_LIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name);
1064   }
1065   PetscFunctionReturn(PETSC_SUCCESS);
1066 }
1067 
1068 /*@
1069   DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a `DM`.
1070 
1071   Collective
1072 
1073   Input Parameter:
1074 . dm - the `DM` that provides the mapping
1075 
1076   Output Parameter:
1077 . ltog - the mapping
1078 
1079   Level: advanced
1080 
1081   Notes:
1082   The global to local mapping allows one to set values into the global vector or matrix using `VecSetValuesLocal()` and `MatSetValuesLocal()`
1083 
1084   Vectors obtained with  `DMCreateGlobalVector()` and matrices obtained with `DMCreateMatrix()` already contain the global mapping so you do
1085   need to use this function with those objects.
1086 
1087   This mapping can then be used by `VecSetLocalToGlobalMapping()` or `MatSetLocalToGlobalMapping()`.
1088 
1089 .seealso: [](ch_dmbase), `DM`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `VecSetLocalToGlobalMapping()`, `MatSetLocalToGlobalMapping()`,
1090           `DMCreateMatrix()`
1091 @*/
1092 PetscErrorCode DMGetLocalToGlobalMapping(DM dm, ISLocalToGlobalMapping *ltog)
1093 {
1094   PetscInt bs = -1, bsLocal[2], bsMinMax[2];
1095 
1096   PetscFunctionBegin;
1097   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1098   PetscAssertPointer(ltog, 2);
1099   if (!dm->ltogmap) {
1100     PetscSection section, sectionGlobal;
1101 
1102     PetscCall(DMGetLocalSection(dm, &section));
1103     if (section) {
1104       const PetscInt *cdofs;
1105       PetscInt       *ltog;
1106       PetscInt        pStart, pEnd, n, p, k, l;
1107 
1108       PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
1109       PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
1110       PetscCall(PetscSectionGetStorageSize(section, &n));
1111       PetscCall(PetscMalloc1(n, &ltog)); /* We want the local+overlap size */
1112       for (p = pStart, l = 0; p < pEnd; ++p) {
1113         PetscInt bdof, cdof, dof, off, c, cind;
1114 
1115         /* Should probably use constrained dofs */
1116         PetscCall(PetscSectionGetDof(section, p, &dof));
1117         PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1118         PetscCall(PetscSectionGetConstraintIndices(section, p, &cdofs));
1119         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &off));
1120         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1121         bdof = cdof && (dof - cdof) ? 1 : dof;
1122         if (dof) bs = bs < 0 ? bdof : PetscGCD(bs, bdof);
1123 
1124         for (c = 0, cind = 0; c < dof; ++c, ++l) {
1125           if (cind < cdof && c == cdofs[cind]) {
1126             ltog[l] = off < 0 ? off - c : -(off + c + 1);
1127             cind++;
1128           } else {
1129             ltog[l] = (off < 0 ? -(off + 1) : off) + c - cind;
1130           }
1131         }
1132       }
1133       /* Must have same blocksize on all procs (some might have no points) */
1134       bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
1135       bsLocal[1] = bs;
1136       PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
1137       if (bsMinMax[0] != bsMinMax[1]) {
1138         bs = 1;
1139       } else {
1140         bs = bsMinMax[0];
1141       }
1142       bs = bs < 0 ? 1 : bs;
1143       /* Must reduce indices by blocksize */
1144       if (bs > 1) {
1145         for (l = 0, k = 0; l < n; l += bs, ++k) {
1146           // Integer division of negative values truncates toward zero(!), not toward negative infinity
1147           ltog[k] = ltog[l] >= 0 ? ltog[l] / bs : -(-(ltog[l] + 1) / bs + 1);
1148         }
1149         n /= bs;
1150       }
1151       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap));
1152     } else PetscUseTypeMethod(dm, getlocaltoglobalmapping);
1153   }
1154   *ltog = dm->ltogmap;
1155   PetscFunctionReturn(PETSC_SUCCESS);
1156 }
1157 
1158 /*@
1159   DMGetBlockSize - Gets the inherent block size associated with a `DM`
1160 
1161   Not Collective
1162 
1163   Input Parameter:
1164 . dm - the `DM` with block structure
1165 
1166   Output Parameter:
1167 . bs - the block size, 1 implies no exploitable block structure
1168 
1169   Level: intermediate
1170 
1171   Notes:
1172   This might be the number of degrees of freedom at each grid point for a structured grid.
1173 
1174   Complex `DM` that represent multiphysics or staggered grids or mixed-methods do not generally have a single inherent block size, but
1175   rather different locations in the vectors may have a different block size.
1176 
1177 .seealso: [](ch_dmbase), `DM`, `ISCreateBlock()`, `VecSetBlockSize()`, `MatSetBlockSize()`, `DMGetLocalToGlobalMapping()`
1178 @*/
1179 PetscErrorCode DMGetBlockSize(DM dm, PetscInt *bs)
1180 {
1181   PetscFunctionBegin;
1182   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1183   PetscAssertPointer(bs, 2);
1184   PetscCheck(dm->bs >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM does not have enough information to provide a block size yet");
1185   *bs = dm->bs;
1186   PetscFunctionReturn(PETSC_SUCCESS);
1187 }
1188 
1189 /*@
1190   DMCreateInterpolation - Gets the interpolation matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1191   `DMCreateGlobalVector()` on the coarse `DM` to similar vectors on the fine grid `DM`.
1192 
1193   Collective
1194 
1195   Input Parameters:
1196 + dmc - the `DM` object
1197 - dmf - the second, finer `DM` object
1198 
1199   Output Parameters:
1200 + mat - the interpolation
1201 - vec - the scaling (optional, pass `NULL` if not needed), see `DMCreateInterpolationScale()`
1202 
1203   Level: developer
1204 
1205   Notes:
1206   For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1207   DMCoarsen(). The coordinates set into the `DMDA` are completely ignored in computing the interpolation.
1208 
1209   For `DMDA` objects you can use this interpolation (more precisely the interpolation from the `DMGetCoordinateDM()`) to interpolate the mesh coordinate
1210   vectors EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
1211 
1212 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolationScale()`
1213 @*/
1214 PetscErrorCode DMCreateInterpolation(DM dmc, DM dmf, Mat *mat, Vec *vec)
1215 {
1216   PetscFunctionBegin;
1217   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1218   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1219   PetscAssertPointer(mat, 3);
1220   PetscCall(PetscLogEventBegin(DM_CreateInterpolation, dmc, dmf, 0, 0));
1221   PetscUseTypeMethod(dmc, createinterpolation, dmf, mat, vec);
1222   PetscCall(PetscLogEventEnd(DM_CreateInterpolation, dmc, dmf, 0, 0));
1223   PetscFunctionReturn(PETSC_SUCCESS);
1224 }
1225 
1226 /*@
1227   DMCreateInterpolationScale - Forms L = 1/(R*1) where 1 is the vector of all ones, and R is
1228   the transpose of the interpolation between the `DM`.
1229 
1230   Input Parameters:
1231 + dac - `DM` that defines a coarse mesh
1232 . daf - `DM` that defines a fine mesh
1233 - mat - the restriction (or interpolation operator) from fine to coarse
1234 
1235   Output Parameter:
1236 . scale - the scaled vector
1237 
1238   Level: advanced
1239 
1240   Note:
1241   xcoarse = diag(L)*R*xfine preserves scale and is thus suitable for state (versus residual)
1242   restriction. In other words xcoarse is the coarse representation of xfine.
1243 
1244   Developer Note:
1245   If the fine-scale `DMDA` has the -dm_bind_below option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()`
1246   on the restriction/interpolation operator to set the bindingpropagates flag to true.
1247 
1248 .seealso: [](ch_dmbase), `DM`, `MatRestrict()`, `MatInterpolate()`, `DMCreateInterpolation()`, `DMCreateRestriction()`, `DMCreateGlobalVector()`
1249 @*/
1250 PetscErrorCode DMCreateInterpolationScale(DM dac, DM daf, Mat mat, Vec *scale)
1251 {
1252   Vec         fine;
1253   PetscScalar one = 1.0;
1254 #if defined(PETSC_HAVE_CUDA)
1255   PetscBool bindingpropagates, isbound;
1256 #endif
1257 
1258   PetscFunctionBegin;
1259   PetscCall(DMCreateGlobalVector(daf, &fine));
1260   PetscCall(DMCreateGlobalVector(dac, scale));
1261   PetscCall(VecSet(fine, one));
1262 #if defined(PETSC_HAVE_CUDA)
1263   /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well.
1264    * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL,
1265    * we'll need to do it for that case, too.*/
1266   PetscCall(VecGetBindingPropagates(fine, &bindingpropagates));
1267   if (bindingpropagates) {
1268     PetscCall(MatSetBindingPropagates(mat, PETSC_TRUE));
1269     PetscCall(VecBoundToCPU(fine, &isbound));
1270     PetscCall(MatBindToCPU(mat, isbound));
1271   }
1272 #endif
1273   PetscCall(MatRestrict(mat, fine, *scale));
1274   PetscCall(VecDestroy(&fine));
1275   PetscCall(VecReciprocal(*scale));
1276   PetscFunctionReturn(PETSC_SUCCESS);
1277 }
1278 
1279 /*@
1280   DMCreateRestriction - Gets restriction matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1281   `DMCreateGlobalVector()` on the fine `DM` to similar vectors on the coarse grid `DM`.
1282 
1283   Collective
1284 
1285   Input Parameters:
1286 + dmc - the `DM` object
1287 - dmf - the second, finer `DM` object
1288 
1289   Output Parameter:
1290 . mat - the restriction
1291 
1292   Level: developer
1293 
1294   Note:
1295   This only works for `DMSTAG`. For many situations either the transpose of the operator obtained with `DMCreateInterpolation()` or that
1296   matrix multiplied by the vector obtained with `DMCreateInterpolationScale()` provides the desired object.
1297 
1298 .seealso: [](ch_dmbase), `DM`, `DMRestrict()`, `DMInterpolate()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateInterpolation()`
1299 @*/
1300 PetscErrorCode DMCreateRestriction(DM dmc, DM dmf, Mat *mat)
1301 {
1302   PetscFunctionBegin;
1303   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1304   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1305   PetscAssertPointer(mat, 3);
1306   PetscCall(PetscLogEventBegin(DM_CreateRestriction, dmc, dmf, 0, 0));
1307   PetscUseTypeMethod(dmc, createrestriction, dmf, mat);
1308   PetscCall(PetscLogEventEnd(DM_CreateRestriction, dmc, dmf, 0, 0));
1309   PetscFunctionReturn(PETSC_SUCCESS);
1310 }
1311 
1312 /*@
1313   DMCreateInjection - Gets injection matrix between two `DM` objects.
1314 
1315   Collective
1316 
1317   Input Parameters:
1318 + dac - the `DM` object
1319 - daf - the second, finer `DM` object
1320 
1321   Output Parameter:
1322 . mat - the injection
1323 
1324   Level: developer
1325 
1326   Notes:
1327   This is an operator that applied to a vector obtained with `DMCreateGlobalVector()` on the
1328   fine grid maps the values to a vector on the vector on the coarse `DM` by simply selecting
1329   the values on the coarse grid points. This compares to the operator obtained by
1330   `DMCreateRestriction()` or the transpose of the operator obtained by
1331   `DMCreateInterpolation()` that uses a "local weighted average" of the values around the
1332   coarse grid point as the coarse grid value.
1333 
1334   For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1335   `DMCoarsen()`. The coordinates set into the `DMDA` are completely ignored in computing the injection.
1336 
1337 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateInterpolation()`,
1338           `DMCreateRestriction()`, `MatRestrict()`, `MatInterpolate()`
1339 @*/
1340 PetscErrorCode DMCreateInjection(DM dac, DM daf, Mat *mat)
1341 {
1342   PetscFunctionBegin;
1343   PetscValidHeaderSpecific(dac, DM_CLASSID, 1);
1344   PetscValidHeaderSpecific(daf, DM_CLASSID, 2);
1345   PetscAssertPointer(mat, 3);
1346   PetscCall(PetscLogEventBegin(DM_CreateInjection, dac, daf, 0, 0));
1347   PetscUseTypeMethod(dac, createinjection, daf, mat);
1348   PetscCall(PetscLogEventEnd(DM_CreateInjection, dac, daf, 0, 0));
1349   PetscFunctionReturn(PETSC_SUCCESS);
1350 }
1351 
1352 /*@
1353   DMCreateMassMatrix - Gets the mass matrix between two `DM` objects, M_ij = \int \phi_i \psi_j where the \phi are Galerkin basis functions for a
1354   a Galerkin finite element model on the `DM`
1355 
1356   Collective
1357 
1358   Input Parameters:
1359 + dmc - the target `DM` object
1360 - dmf - the source `DM` object, can be `NULL`
1361 
1362   Output Parameter:
1363 . mat - the mass matrix
1364 
1365   Level: developer
1366 
1367   Notes:
1368   For `DMPLEX` the finite element model for the `DM` must have been already provided.
1369 
1370   if `dmc` is `dmf` or `NULL`, then x^t M x is an approximation to the L2 norm of the vector x which is obtained by `DMCreateGlobalVector()`
1371 
1372 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrixLumped()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1373 @*/
1374 PetscErrorCode DMCreateMassMatrix(DM dmc, DM dmf, Mat *mat)
1375 {
1376   PetscFunctionBegin;
1377   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1378   if (!dmf) dmf = dmc;
1379   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1380   PetscAssertPointer(mat, 3);
1381   PetscCall(PetscLogEventBegin(DM_CreateMassMatrix, dmc, dmf, 0, 0));
1382   PetscUseTypeMethod(dmc, createmassmatrix, dmf, mat);
1383   PetscCall(PetscLogEventEnd(DM_CreateMassMatrix, dmc, dmf, 0, 0));
1384   PetscFunctionReturn(PETSC_SUCCESS);
1385 }
1386 
1387 /*@
1388   DMCreateMassMatrixLumped - Gets the lumped mass matrix for a given `DM`
1389 
1390   Collective
1391 
1392   Input Parameter:
1393 . dm - the `DM` object
1394 
1395   Output Parameter:
1396 + llm - the local lumped mass matrix, which is a diagonal matrix, represented as a vector
1397 - lm  - the global lumped mass matrix, which is a diagonal matrix, represented as a vector
1398 
1399   Level: developer
1400 
1401   Note:
1402   See `DMCreateMassMatrix()` for how to create the non-lumped version of the mass matrix.
1403 
1404 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrix()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1405 @*/
1406 PetscErrorCode DMCreateMassMatrixLumped(DM dm, Vec *llm, Vec *lm)
1407 {
1408   PetscFunctionBegin;
1409   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1410   if (llm) PetscAssertPointer(llm, 2);
1411   if (lm) PetscAssertPointer(lm, 3);
1412   if (llm || lm) PetscUseTypeMethod(dm, createmassmatrixlumped, llm, lm);
1413   PetscFunctionReturn(PETSC_SUCCESS);
1414 }
1415 
1416 /*@
1417   DMCreateColoring - Gets coloring of a graph associated with the `DM`. Often the graph represents the operator matrix associated with the discretization
1418   of a PDE on the `DM`.
1419 
1420   Collective
1421 
1422   Input Parameters:
1423 + dm    - the `DM` object
1424 - ctype - `IS_COLORING_LOCAL` or `IS_COLORING_GLOBAL`
1425 
1426   Output Parameter:
1427 . coloring - the coloring
1428 
1429   Level: developer
1430 
1431   Notes:
1432   Coloring of matrices can also be computed directly from the sparse matrix nonzero structure via the `MatColoring` object or from the mesh from which the
1433   matrix comes from (what this function provides). In general using the mesh produces a more optimal coloring (fewer colors).
1434 
1435   This produces a coloring with the distance of 2, see `MatSetColoringDistance()` which can be used for efficiently computing Jacobians with `MatFDColoringCreate()`
1436   For `DMDA` in three dimensions with periodic boundary conditions the number of grid points in each dimension must be divisible by 2*stencil_width + 1,
1437   otherwise an error will be generated.
1438 
1439 .seealso: [](ch_dmbase), `DM`, `ISColoring`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatType()`, `MatColoring`, `MatFDColoringCreate()`
1440 @*/
1441 PetscErrorCode DMCreateColoring(DM dm, ISColoringType ctype, ISColoring *coloring)
1442 {
1443   PetscFunctionBegin;
1444   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1445   PetscAssertPointer(coloring, 3);
1446   PetscUseTypeMethod(dm, getcoloring, ctype, coloring);
1447   PetscFunctionReturn(PETSC_SUCCESS);
1448 }
1449 
1450 /*@
1451   DMCreateMatrix - Gets an empty matrix for a `DM` that is most commonly used to store the Jacobian of a discrete PDE operator.
1452 
1453   Collective
1454 
1455   Input Parameter:
1456 . dm - the `DM` object
1457 
1458   Output Parameter:
1459 . mat - the empty Jacobian
1460 
1461   Options Database Key:
1462 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
1463 
1464   Level: beginner
1465 
1466   Notes:
1467   This properly preallocates the number of nonzeros in the sparse matrix so you
1468   do not need to do it yourself.
1469 
1470   By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1471   the nonzero pattern call `DMSetMatrixPreallocateOnly()`
1472 
1473   For `DMDA`, when you call `MatView()` on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1474   internally by PETSc.
1475 
1476   For `DMDA`, in general it is easiest to use `MatSetValuesStencil()` or `MatSetValuesLocal()` to put values into the matrix because
1477   `MatSetValues()` requires the indices for the global numbering for the `DMDA` which is complic`ated to compute
1478 
1479 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMSetMatType()`, `DMCreateMassMatrix()`
1480 @*/
1481 PetscErrorCode DMCreateMatrix(DM dm, Mat *mat)
1482 {
1483   PetscFunctionBegin;
1484   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1485   PetscAssertPointer(mat, 2);
1486   PetscCall(MatInitializePackage());
1487   PetscCall(PetscLogEventBegin(DM_CreateMatrix, 0, 0, 0, 0));
1488   PetscUseTypeMethod(dm, creatematrix, mat);
1489   if (PetscDefined(USE_DEBUG)) {
1490     DM mdm;
1491 
1492     PetscCall(MatGetDM(*mat, &mdm));
1493     PetscCheck(mdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the matrix", ((PetscObject)dm)->type_name);
1494   }
1495   /* Handle nullspace and near nullspace */
1496   if (dm->Nf) {
1497     MatNullSpace nullSpace;
1498     PetscInt     Nf, f;
1499 
1500     PetscCall(DMGetNumFields(dm, &Nf));
1501     for (f = 0; f < Nf; ++f) {
1502       if (dm->nullspaceConstructors[f]) {
1503         PetscCall((*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace));
1504         PetscCall(MatSetNullSpace(*mat, nullSpace));
1505         PetscCall(MatNullSpaceDestroy(&nullSpace));
1506         break;
1507       }
1508     }
1509     for (f = 0; f < Nf; ++f) {
1510       if (dm->nearnullspaceConstructors[f]) {
1511         PetscCall((*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace));
1512         PetscCall(MatSetNearNullSpace(*mat, nullSpace));
1513         PetscCall(MatNullSpaceDestroy(&nullSpace));
1514       }
1515     }
1516   }
1517   PetscCall(PetscLogEventEnd(DM_CreateMatrix, 0, 0, 0, 0));
1518   PetscFunctionReturn(PETSC_SUCCESS);
1519 }
1520 
1521 /*@
1522   DMSetMatrixPreallocateSkip - When `DMCreateMatrix()` is called the matrix sizes and
1523   `ISLocalToGlobalMapping` will be properly set, but the data structures to store values in the
1524   matrices will not be preallocated.
1525 
1526   Logically Collective
1527 
1528   Input Parameters:
1529 + dm   - the `DM`
1530 - skip - `PETSC_TRUE` to skip preallocation
1531 
1532   Level: developer
1533 
1534   Note:
1535   This is most useful to reduce initialization costs when `MatSetPreallocationCOO()` and
1536   `MatSetValuesCOO()` will be used.
1537 
1538 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateOnly()`
1539 @*/
1540 PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip)
1541 {
1542   PetscFunctionBegin;
1543   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1544   dm->prealloc_skip = skip;
1545   PetscFunctionReturn(PETSC_SUCCESS);
1546 }
1547 
1548 /*@
1549   DMSetMatrixPreallocateOnly - When `DMCreateMatrix()` is called the matrix will be properly
1550   preallocated but the nonzero structure and zero values will not be set.
1551 
1552   Logically Collective
1553 
1554   Input Parameters:
1555 + dm   - the `DM`
1556 - only - `PETSC_TRUE` if only want preallocation
1557 
1558   Options Database Key:
1559 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()`, `DMCreateMassMatrix()`, but do not fill it with zeros
1560 
1561   Level: developer
1562 
1563 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateSkip()`
1564 @*/
1565 PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1566 {
1567   PetscFunctionBegin;
1568   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1569   dm->prealloc_only = only;
1570   PetscFunctionReturn(PETSC_SUCCESS);
1571 }
1572 
1573 /*@
1574   DMSetMatrixStructureOnly - When `DMCreateMatrix()` is called, the matrix structure will be created
1575   but the array for numerical values will not be allocated.
1576 
1577   Logically Collective
1578 
1579   Input Parameters:
1580 + dm   - the `DM`
1581 - only - `PETSC_TRUE` if you only want matrix structure
1582 
1583   Level: developer
1584 
1585 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMSetMatrixPreallocateSkip()`
1586 @*/
1587 PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1588 {
1589   PetscFunctionBegin;
1590   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1591   dm->structure_only = only;
1592   PetscFunctionReturn(PETSC_SUCCESS);
1593 }
1594 
1595 /*@
1596   DMSetBlockingType - set the blocking granularity to be used for variable block size `DMCreateMatrix()` is called
1597 
1598   Logically Collective
1599 
1600   Input Parameters:
1601 + dm    - the `DM`
1602 - btype - block by topological point or field node
1603 
1604   Options Database Key:
1605 . -dm_blocking_type [topological_point, field_node] - use topological point blocking or field node blocking
1606 
1607   Level: advanced
1608 
1609 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
1610 @*/
1611 PetscErrorCode DMSetBlockingType(DM dm, DMBlockingType btype)
1612 {
1613   PetscFunctionBegin;
1614   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1615   dm->blocking_type = btype;
1616   PetscFunctionReturn(PETSC_SUCCESS);
1617 }
1618 
1619 /*@
1620   DMGetBlockingType - get the blocking granularity to be used for variable block size `DMCreateMatrix()` is called
1621 
1622   Not Collective
1623 
1624   Input Parameter:
1625 . dm - the `DM`
1626 
1627   Output Parameter:
1628 . btype - block by topological point or field node
1629 
1630   Level: advanced
1631 
1632 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
1633 @*/
1634 PetscErrorCode DMGetBlockingType(DM dm, DMBlockingType *btype)
1635 {
1636   PetscFunctionBegin;
1637   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1638   PetscAssertPointer(btype, 2);
1639   *btype = dm->blocking_type;
1640   PetscFunctionReturn(PETSC_SUCCESS);
1641 }
1642 
1643 /*@C
1644   DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with `DMRestoreWorkArray()`
1645 
1646   Not Collective
1647 
1648   Input Parameters:
1649 + dm    - the `DM` object
1650 . count - The minimum size
1651 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, or `MPIU_INT`)
1652 
1653   Output Parameter:
1654 . mem - the work array
1655 
1656   Level: developer
1657 
1658   Notes:
1659   A `DM` may stash the array between instantiations so using this routine may be more efficient than calling `PetscMalloc()`
1660 
1661   The array may contain nonzero values
1662 
1663 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMRestoreWorkArray()`, `PetscMalloc()`
1664 @*/
1665 PetscErrorCode DMGetWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1666 {
1667   DMWorkLink  link;
1668   PetscMPIInt dsize;
1669 
1670   PetscFunctionBegin;
1671   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1672   PetscAssertPointer(mem, 4);
1673   if (!count) {
1674     *(void **)mem = NULL;
1675     PetscFunctionReturn(PETSC_SUCCESS);
1676   }
1677   if (dm->workin) {
1678     link       = dm->workin;
1679     dm->workin = dm->workin->next;
1680   } else {
1681     PetscCall(PetscNew(&link));
1682   }
1683   /* Avoid MPI_Type_size for most used datatypes
1684      Get size directly */
1685   if (dtype == MPIU_INT) dsize = sizeof(PetscInt);
1686   else if (dtype == MPIU_REAL) dsize = sizeof(PetscReal);
1687 #if defined(PETSC_USE_64BIT_INDICES)
1688   else if (dtype == MPI_INT) dsize = sizeof(int);
1689 #endif
1690 #if defined(PETSC_USE_COMPLEX)
1691   else if (dtype == MPIU_SCALAR) dsize = sizeof(PetscScalar);
1692 #endif
1693   else PetscCallMPI(MPI_Type_size(dtype, &dsize));
1694 
1695   if (((size_t)dsize * count) > link->bytes) {
1696     PetscCall(PetscFree(link->mem));
1697     PetscCall(PetscMalloc(dsize * count, &link->mem));
1698     link->bytes = dsize * count;
1699   }
1700   link->next  = dm->workout;
1701   dm->workout = link;
1702 #if defined(__MEMCHECK_H) && (defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) || defined(PLAT_amd64_darwin))
1703   VALGRIND_MAKE_MEM_NOACCESS((char *)link->mem + (size_t)dsize * count, link->bytes - (size_t)dsize * count);
1704   VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize * count);
1705 #endif
1706   *(void **)mem = link->mem;
1707   PetscFunctionReturn(PETSC_SUCCESS);
1708 }
1709 
1710 /*@C
1711   DMRestoreWorkArray - Restores a work array obtained with `DMCreateWorkArray()`
1712 
1713   Not Collective
1714 
1715   Input Parameters:
1716 + dm    - the `DM` object
1717 . count - The minimum size
1718 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, `MPIU_INT`
1719 
1720   Output Parameter:
1721 . mem - the work array
1722 
1723   Level: developer
1724 
1725   Developer Note:
1726   count and dtype are ignored, they are only needed for `DMGetWorkArray()`
1727 
1728 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMGetWorkArray()`
1729 @*/
1730 PetscErrorCode DMRestoreWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1731 {
1732   DMWorkLink *p, link;
1733 
1734   PetscFunctionBegin;
1735   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1736   PetscAssertPointer(mem, 4);
1737   (void)count;
1738   (void)dtype;
1739   if (!*(void **)mem) PetscFunctionReturn(PETSC_SUCCESS);
1740   for (p = &dm->workout; (link = *p); p = &link->next) {
1741     if (link->mem == *(void **)mem) {
1742       *p            = link->next;
1743       link->next    = dm->workin;
1744       dm->workin    = link;
1745       *(void **)mem = NULL;
1746       PetscFunctionReturn(PETSC_SUCCESS);
1747     }
1748   }
1749   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out");
1750 }
1751 
1752 /*@C
1753   DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field, defined with `DMAddField()`, when function spaces
1754   are joined or split, such as in `DMCreateSubDM()`
1755 
1756   Logically Collective; No Fortran Support
1757 
1758   Input Parameters:
1759 + dm     - The `DM`
1760 . field  - The field number for the nullspace
1761 - nullsp - A callback to create the nullspace
1762 
1763   Calling sequence of `nullsp`:
1764 + dm        - The present `DM`
1765 . origField - The field number given above, in the original `DM`
1766 . field     - The field number in dm
1767 - nullSpace - The nullspace for the given field
1768 
1769   Level: intermediate
1770 
1771 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1772 @*/
1773 PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1774 {
1775   PetscFunctionBegin;
1776   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1777   PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field);
1778   dm->nullspaceConstructors[field] = nullsp;
1779   PetscFunctionReturn(PETSC_SUCCESS);
1780 }
1781 
1782 /*@C
1783   DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, defined with `DMAddField()`
1784 
1785   Not Collective; No Fortran Support
1786 
1787   Input Parameters:
1788 + dm    - The `DM`
1789 - field - The field number for the nullspace
1790 
1791   Output Parameter:
1792 . nullsp - A callback to create the nullspace
1793 
1794   Calling sequence of `nullsp`:
1795 + dm        - The present DM
1796 . origField - The field number given above, in the original DM
1797 . field     - The field number in dm
1798 - nullSpace - The nullspace for the given field
1799 
1800   Level: intermediate
1801 
1802 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMSetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1803 @*/
1804 PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1805 {
1806   PetscFunctionBegin;
1807   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1808   PetscAssertPointer(nullsp, 3);
1809   PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field);
1810   *nullsp = dm->nullspaceConstructors[field];
1811   PetscFunctionReturn(PETSC_SUCCESS);
1812 }
1813 
1814 /*@C
1815   DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`
1816 
1817   Logically Collective; No Fortran Support
1818 
1819   Input Parameters:
1820 + dm     - The `DM`
1821 . field  - The field number for the nullspace
1822 - nullsp - A callback to create the near-nullspace
1823 
1824   Calling sequence of `nullsp`:
1825 + dm        - The present `DM`
1826 . origField - The field number given above, in the original `DM`
1827 . field     - The field number in dm
1828 - nullSpace - The nullspace for the given field
1829 
1830   Level: intermediate
1831 
1832 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`,
1833           `MatNullSpace`
1834 @*/
1835 PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1836 {
1837   PetscFunctionBegin;
1838   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1839   PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field);
1840   dm->nearnullspaceConstructors[field] = nullsp;
1841   PetscFunctionReturn(PETSC_SUCCESS);
1842 }
1843 
1844 /*@C
1845   DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`
1846 
1847   Not Collective; No Fortran Support
1848 
1849   Input Parameters:
1850 + dm    - The `DM`
1851 - field - The field number for the nullspace
1852 
1853   Output Parameter:
1854 . nullsp - A callback to create the near-nullspace
1855 
1856   Calling sequence of `nullsp`:
1857 + dm        - The present `DM`
1858 . origField - The field number given above, in the original `DM`
1859 . field     - The field number in dm
1860 - nullSpace - The nullspace for the given field
1861 
1862   Level: intermediate
1863 
1864 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMSetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`,
1865           `MatNullSpace`, `DMCreateSuperDM()`
1866 @*/
1867 PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1868 {
1869   PetscFunctionBegin;
1870   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1871   PetscAssertPointer(nullsp, 3);
1872   PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field);
1873   *nullsp = dm->nearnullspaceConstructors[field];
1874   PetscFunctionReturn(PETSC_SUCCESS);
1875 }
1876 
1877 /*@C
1878   DMCreateFieldIS - Creates a set of `IS` objects with the global indices of dofs for each field defined with `DMAddField()`
1879 
1880   Not Collective; No Fortran Support
1881 
1882   Input Parameter:
1883 . dm - the `DM` object
1884 
1885   Output Parameters:
1886 + numFields  - The number of fields (or `NULL` if not requested)
1887 . fieldNames - The number of each field (or `NULL` if not requested)
1888 - fields     - The global indices for each field (or `NULL` if not requested)
1889 
1890   Level: intermediate
1891 
1892   Note:
1893   The user is responsible for freeing all requested arrays. In particular, every entry of `fieldNames` should be freed with
1894   `PetscFree()`, every entry of `fields` should be destroyed with `ISDestroy()`, and both arrays should be freed with
1895   `PetscFree()`.
1896 
1897   Developer Note:
1898   It is not clear why both this function and `DMCreateFieldDecomposition()` exist. Having two seems redundant and confusing. This function should
1899   likely be removed.
1900 
1901 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
1902           `DMCreateFieldDecomposition()`
1903 @*/
1904 PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1905 {
1906   PetscSection section, sectionGlobal;
1907 
1908   PetscFunctionBegin;
1909   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1910   if (numFields) {
1911     PetscAssertPointer(numFields, 2);
1912     *numFields = 0;
1913   }
1914   if (fieldNames) {
1915     PetscAssertPointer(fieldNames, 3);
1916     *fieldNames = NULL;
1917   }
1918   if (fields) {
1919     PetscAssertPointer(fields, 4);
1920     *fields = NULL;
1921   }
1922   PetscCall(DMGetLocalSection(dm, &section));
1923   if (section) {
1924     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1925     PetscInt  nF, f, pStart, pEnd, p;
1926 
1927     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
1928     PetscCall(PetscSectionGetNumFields(section, &nF));
1929     PetscCall(PetscMalloc3(nF, &fieldSizes, nF, &fieldNc, nF, &fieldIndices));
1930     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
1931     for (f = 0; f < nF; ++f) {
1932       fieldSizes[f] = 0;
1933       PetscCall(PetscSectionGetFieldComponents(section, f, &fieldNc[f]));
1934     }
1935     for (p = pStart; p < pEnd; ++p) {
1936       PetscInt gdof;
1937 
1938       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
1939       if (gdof > 0) {
1940         for (f = 0; f < nF; ++f) {
1941           PetscInt fdof, fcdof, fpdof;
1942 
1943           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
1944           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
1945           fpdof = fdof - fcdof;
1946           if (fpdof && fpdof != fieldNc[f]) {
1947             /* Layout does not admit a pointwise block size */
1948             fieldNc[f] = 1;
1949           }
1950           fieldSizes[f] += fpdof;
1951         }
1952       }
1953     }
1954     for (f = 0; f < nF; ++f) {
1955       PetscCall(PetscMalloc1(fieldSizes[f], &fieldIndices[f]));
1956       fieldSizes[f] = 0;
1957     }
1958     for (p = pStart; p < pEnd; ++p) {
1959       PetscInt gdof, goff;
1960 
1961       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
1962       if (gdof > 0) {
1963         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff));
1964         for (f = 0; f < nF; ++f) {
1965           PetscInt fdof, fcdof, fc;
1966 
1967           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
1968           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
1969           for (fc = 0; fc < fdof - fcdof; ++fc, ++fieldSizes[f]) fieldIndices[f][fieldSizes[f]] = goff++;
1970         }
1971       }
1972     }
1973     if (numFields) *numFields = nF;
1974     if (fieldNames) {
1975       PetscCall(PetscMalloc1(nF, fieldNames));
1976       for (f = 0; f < nF; ++f) {
1977         const char *fieldName;
1978 
1979         PetscCall(PetscSectionGetFieldName(section, f, &fieldName));
1980         PetscCall(PetscStrallocpy(fieldName, (char **)&(*fieldNames)[f]));
1981       }
1982     }
1983     if (fields) {
1984       PetscCall(PetscMalloc1(nF, fields));
1985       for (f = 0; f < nF; ++f) {
1986         PetscInt bs, in[2], out[2];
1987 
1988         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]));
1989         in[0] = -fieldNc[f];
1990         in[1] = fieldNc[f];
1991         PetscCall(MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
1992         bs = (-out[0] == out[1]) ? out[1] : 1;
1993         PetscCall(ISSetBlockSize((*fields)[f], bs));
1994       }
1995     }
1996     PetscCall(PetscFree3(fieldSizes, fieldNc, fieldIndices));
1997   } else PetscTryTypeMethod(dm, createfieldis, numFields, fieldNames, fields);
1998   PetscFunctionReturn(PETSC_SUCCESS);
1999 }
2000 
2001 /*@C
2002   DMCreateFieldDecomposition - Returns a list of `IS` objects defining a decomposition of a problem into subproblems
2003   corresponding to different fields.
2004 
2005   Not Collective; No Fortran Support
2006 
2007   Input Parameter:
2008 . dm - the `DM` object
2009 
2010   Output Parameters:
2011 + len      - The number of fields (or `NULL` if not requested)
2012 . namelist - The name for each field (or `NULL` if not requested)
2013 . islist   - The global indices for each field (or `NULL` if not requested)
2014 - dmlist   - The `DM`s for each field subproblem (or `NULL`, if not requested; if `NULL` is returned, no `DM`s are defined)
2015 
2016   Level: intermediate
2017 
2018   Notes:
2019   Each `IS` contains the global indices of the dofs of the corresponding field, defined by
2020   `DMAddField()`. The optional list of `DM`s define the `DM` for each subproblem.
2021 
2022   The same as `DMCreateFieldIS()` but also returns a `DM` for each field.
2023 
2024   The user is responsible for freeing all requested arrays. In particular, every entry of `namelist` should be freed with
2025   `PetscFree()`, every entry of `islist` should be destroyed with `ISDestroy()`, every entry of `dmlist` should be destroyed with `DMDestroy()`,
2026   and all of the arrays should be freed with `PetscFree()`.
2027 
2028   Developer Notes:
2029   It is not clear why this function and `DMCreateFieldIS()` exist. Having two seems redundant and confusing.
2030 
2031   Unlike  `DMRefine()`, `DMCoarsen()`, and `DMCreateDomainDecomposition()` this provides no mechanism to provide hooks that are called after the
2032   decomposition is computed.
2033 
2034 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMCreateFieldIS()`, `DMCreateSubDM()`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`
2035 @*/
2036 PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
2037 {
2038   PetscFunctionBegin;
2039   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2040   if (len) {
2041     PetscAssertPointer(len, 2);
2042     *len = 0;
2043   }
2044   if (namelist) {
2045     PetscAssertPointer(namelist, 3);
2046     *namelist = NULL;
2047   }
2048   if (islist) {
2049     PetscAssertPointer(islist, 4);
2050     *islist = NULL;
2051   }
2052   if (dmlist) {
2053     PetscAssertPointer(dmlist, 5);
2054     *dmlist = NULL;
2055   }
2056   /*
2057    Is it a good idea to apply the following check across all impls?
2058    Perhaps some impls can have a well-defined decomposition before DMSetUp?
2059    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2060    */
2061   PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
2062   if (!dm->ops->createfielddecomposition) {
2063     PetscSection section;
2064     PetscInt     numFields, f;
2065 
2066     PetscCall(DMGetLocalSection(dm, &section));
2067     if (section) PetscCall(PetscSectionGetNumFields(section, &numFields));
2068     if (section && numFields && dm->ops->createsubdm) {
2069       if (len) *len = numFields;
2070       if (namelist) PetscCall(PetscMalloc1(numFields, namelist));
2071       if (islist) PetscCall(PetscMalloc1(numFields, islist));
2072       if (dmlist) PetscCall(PetscMalloc1(numFields, dmlist));
2073       for (f = 0; f < numFields; ++f) {
2074         const char *fieldName;
2075 
2076         PetscCall(DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL));
2077         if (namelist) {
2078           PetscCall(PetscSectionGetFieldName(section, f, &fieldName));
2079           PetscCall(PetscStrallocpy(fieldName, (char **)&(*namelist)[f]));
2080         }
2081       }
2082     } else {
2083       PetscCall(DMCreateFieldIS(dm, len, namelist, islist));
2084       /* By default there are no DMs associated with subproblems. */
2085       if (dmlist) *dmlist = NULL;
2086     }
2087   } else PetscUseTypeMethod(dm, createfielddecomposition, len, namelist, islist, dmlist);
2088   PetscFunctionReturn(PETSC_SUCCESS);
2089 }
2090 
2091 /*@
2092   DMCreateSubDM - Returns an `IS` and `DM` encapsulating a subproblem defined by the fields passed in.
2093   The fields are defined by `DMCreateFieldIS()`.
2094 
2095   Not collective
2096 
2097   Input Parameters:
2098 + dm        - The `DM` object
2099 . numFields - The number of fields to select
2100 - fields    - The field numbers of the selected fields
2101 
2102   Output Parameters:
2103 + is    - The global indices for all the degrees of freedom in the new sub `DM`, use `NULL` if not needed
2104 - subdm - The `DM` for the subproblem, use `NULL` if not needed
2105 
2106   Level: intermediate
2107 
2108   Note:
2109   You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed
2110 
2111 .seealso: [](ch_dmbase), `DM`, `DMCreateFieldIS()`, `DMCreateFieldDecomposition()`, `DMAddField()`, `DMCreateSuperDM()`, `IS`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
2112 @*/
2113 PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2114 {
2115   PetscFunctionBegin;
2116   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2117   PetscAssertPointer(fields, 3);
2118   if (is) PetscAssertPointer(is, 4);
2119   if (subdm) PetscAssertPointer(subdm, 5);
2120   PetscUseTypeMethod(dm, createsubdm, numFields, fields, is, subdm);
2121   PetscFunctionReturn(PETSC_SUCCESS);
2122 }
2123 
2124 /*@C
2125   DMCreateSuperDM - Returns an arrays of `IS` and `DM` encapsulating a superproblem defined by multiple `DM`s passed in.
2126 
2127   Not collective
2128 
2129   Input Parameters:
2130 + dms - The `DM` objects
2131 - n   - The number of `DM`s
2132 
2133   Output Parameters:
2134 + is      - The global indices for each of subproblem within the super `DM`, or NULL
2135 - superdm - The `DM` for the superproblem
2136 
2137   Level: intermediate
2138 
2139   Note:
2140   You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed
2141 
2142 .seealso: [](ch_dmbase), `DM`, `DMCreateSubDM()`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`, `DMCreateDomainDecomposition()`
2143 @*/
2144 PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt n, IS *is[], DM *superdm)
2145 {
2146   PetscInt i;
2147 
2148   PetscFunctionBegin;
2149   PetscAssertPointer(dms, 1);
2150   for (i = 0; i < n; ++i) PetscValidHeaderSpecific(dms[i], DM_CLASSID, 1);
2151   if (is) PetscAssertPointer(is, 3);
2152   PetscAssertPointer(superdm, 4);
2153   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %" PetscInt_FMT, n);
2154   if (n) {
2155     DM dm = dms[0];
2156     PetscCheck(dm->ops->createsuperdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No method createsuperdm for DM of type %s", ((PetscObject)dm)->type_name);
2157     PetscCall((*dm->ops->createsuperdm)(dms, n, is, superdm));
2158   }
2159   PetscFunctionReturn(PETSC_SUCCESS);
2160 }
2161 
2162 /*@C
2163   DMCreateDomainDecomposition - Returns lists of `IS` objects defining a decomposition of a
2164   problem into subproblems corresponding to restrictions to pairs of nested subdomains.
2165 
2166   Not Collective
2167 
2168   Input Parameter:
2169 . dm - the `DM` object
2170 
2171   Output Parameters:
2172 + n           - The number of subproblems in the domain decomposition (or `NULL` if not requested)
2173 . namelist    - The name for each subdomain (or `NULL` if not requested)
2174 . innerislist - The global indices for each inner subdomain (or `NULL`, if not requested)
2175 . outerislist - The global indices for each outer subdomain (or `NULL`, if not requested)
2176 - dmlist      - The `DM`s for each subdomain subproblem (or `NULL`, if not requested; if `NULL` is returned, no `DM`s are defined)
2177 
2178   Level: intermediate
2179 
2180   Notes:
2181   Each `IS` contains the global indices of the dofs of the corresponding subdomains with in the
2182   dofs of the original `DM`. The inner subdomains conceptually define a nonoverlapping
2183   covering, while outer subdomains can overlap.
2184 
2185   The optional list of `DM`s define a `DM` for each subproblem.
2186 
2187   The user is responsible for freeing all requested arrays. In particular, every entry of `namelist` should be freed with
2188   `PetscFree()`, every entry of `innerislist` and `outerislist` should be destroyed with `ISDestroy()`, every entry of `dmlist` should be destroyed with `DMDestroy()`,
2189   and all of the arrays should be freed with `PetscFree()`.
2190 
2191   Developer Notes:
2192   The `dmlist` is for the inner subdomains or the outer subdomains or all subdomains?
2193 
2194   The names are inconsistent, the hooks use `DMSubDomainHook` which is nothing like `DMCreateDomainDecomposition()` while `DMRefineHook` is used for `DMRefine()`.
2195 
2196 .seealso: [](ch_dmbase), `DM`, `DMCreateFieldDecomposition()`, `DMDestroy()`, `DMCreateDomainDecompositionScatters()`, `DMView()`, `DMCreateInterpolation()`,
2197           `DMSubDomainHookAdd()`, `DMSubDomainHookRemove()`,`DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`
2198 @*/
2199 PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *n, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
2200 {
2201   DMSubDomainHookLink link;
2202   PetscInt            i, l;
2203 
2204   PetscFunctionBegin;
2205   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2206   if (n) {
2207     PetscAssertPointer(n, 2);
2208     *n = 0;
2209   }
2210   if (namelist) {
2211     PetscAssertPointer(namelist, 3);
2212     *namelist = NULL;
2213   }
2214   if (innerislist) {
2215     PetscAssertPointer(innerislist, 4);
2216     *innerislist = NULL;
2217   }
2218   if (outerislist) {
2219     PetscAssertPointer(outerislist, 5);
2220     *outerislist = NULL;
2221   }
2222   if (dmlist) {
2223     PetscAssertPointer(dmlist, 6);
2224     *dmlist = NULL;
2225   }
2226   /*
2227    Is it a good idea to apply the following check across all impls?
2228    Perhaps some impls can have a well-defined decomposition before DMSetUp?
2229    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2230    */
2231   PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
2232   if (dm->ops->createdomaindecomposition) {
2233     PetscUseTypeMethod(dm, createdomaindecomposition, &l, namelist, innerislist, outerislist, dmlist);
2234     /* copy subdomain hooks and context over to the subdomain DMs */
2235     if (dmlist && *dmlist) {
2236       for (i = 0; i < l; i++) {
2237         for (link = dm->subdomainhook; link; link = link->next) {
2238           if (link->ddhook) PetscCall((*link->ddhook)(dm, (*dmlist)[i], link->ctx));
2239         }
2240         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2241       }
2242     }
2243     if (n) *n = l;
2244   }
2245   PetscFunctionReturn(PETSC_SUCCESS);
2246 }
2247 
2248 /*@C
2249   DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector for subdomains created with
2250   `DMCreateDomainDecomposition()`
2251 
2252   Not Collective
2253 
2254   Input Parameters:
2255 + dm     - the `DM` object
2256 . n      - the number of subdomains
2257 - subdms - the local subdomains
2258 
2259   Output Parameters:
2260 + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2261 . oscat - scatter from global vector to overlapping global vector entries on subdomain
2262 - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
2263 
2264   Level: developer
2265 
2266   Note:
2267   This is an alternative to the iis and ois arguments in `DMCreateDomainDecomposition()` that allow for the solution
2268   of general nonlinear problems with overlapping subdomain methods.  While merely having index sets that enable subsets
2269   of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2270   solution and residual data.
2271 
2272   Developer Note:
2273   Can the subdms input be anything or are they exactly the `DM` obtained from
2274   `DMCreateDomainDecomposition()`?
2275 
2276 .seealso: [](ch_dmbase), `DM`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2277 @*/
2278 PetscErrorCode DMCreateDomainDecompositionScatters(DM dm, PetscInt n, DM *subdms, VecScatter *iscat[], VecScatter *oscat[], VecScatter *gscat[])
2279 {
2280   PetscFunctionBegin;
2281   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2282   PetscAssertPointer(subdms, 3);
2283   PetscUseTypeMethod(dm, createddscatters, n, subdms, iscat, oscat, gscat);
2284   PetscFunctionReturn(PETSC_SUCCESS);
2285 }
2286 
2287 /*@
2288   DMRefine - Refines a `DM` object using a standard nonadaptive refinement of the underlying mesh
2289 
2290   Collective
2291 
2292   Input Parameters:
2293 + dm   - the `DM` object
2294 - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)
2295 
2296   Output Parameter:
2297 . dmf - the refined `DM`, or `NULL`
2298 
2299   Options Database Key:
2300 . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex
2301 
2302   Level: developer
2303 
2304   Note:
2305   If no refinement was done, the return value is `NULL`
2306 
2307 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateDomainDecomposition()`,
2308           `DMRefineHookAdd()`, `DMRefineHookRemove()`
2309 @*/
2310 PetscErrorCode DMRefine(DM dm, MPI_Comm comm, DM *dmf)
2311 {
2312   DMRefineHookLink link;
2313 
2314   PetscFunctionBegin;
2315   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2316   PetscCall(PetscLogEventBegin(DM_Refine, dm, 0, 0, 0));
2317   PetscUseTypeMethod(dm, refine, comm, dmf);
2318   if (*dmf) {
2319     (*dmf)->ops->creatematrix = dm->ops->creatematrix;
2320 
2321     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmf));
2322 
2323     (*dmf)->ctx       = dm->ctx;
2324     (*dmf)->leveldown = dm->leveldown;
2325     (*dmf)->levelup   = dm->levelup + 1;
2326 
2327     PetscCall(DMSetMatType(*dmf, dm->mattype));
2328     for (link = dm->refinehook; link; link = link->next) {
2329       if (link->refinehook) PetscCall((*link->refinehook)(dm, *dmf, link->ctx));
2330     }
2331   }
2332   PetscCall(PetscLogEventEnd(DM_Refine, dm, 0, 0, 0));
2333   PetscFunctionReturn(PETSC_SUCCESS);
2334 }
2335 
2336 /*@C
2337   DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
2338 
2339   Logically Collective; No Fortran Support
2340 
2341   Input Parameters:
2342 + coarse     - `DM` on which to run a hook when interpolating to a finer level
2343 . refinehook - function to run when setting up the finer level
2344 . interphook - function to run to update data on finer levels (once per `SNESSolve()`)
2345 - ctx        - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2346 
2347   Calling sequence of `refinehook`:
2348 + coarse - coarse level `DM`
2349 . fine   - fine level `DM` to interpolate problem to
2350 - ctx    - optional user-defined function context
2351 
2352   Calling sequence of `interphook`:
2353 + coarse - coarse level `DM`
2354 . interp - matrix interpolating a coarse-level solution to the finer grid
2355 . fine   - fine level `DM` to update
2356 - ctx    - optional user-defined function context
2357 
2358   Level: advanced
2359 
2360   Notes:
2361   This function is only needed if auxiliary data that is attached to the `DM`s via, for example, `PetscObjectCompose()`, needs to be
2362   passed to fine grids while grid sequencing.
2363 
2364   The actual interpolation is done when `DMInterpolate()` is called.
2365 
2366   If this function is called multiple times, the hooks will be run in the order they are added.
2367 
2368 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2369 @*/
2370 PetscErrorCode DMRefineHookAdd(DM coarse, PetscErrorCode (*refinehook)(DM coarse, DM fine, void *ctx), PetscErrorCode (*interphook)(DM coarse, Mat interp, DM fine, void *ctx), void *ctx)
2371 {
2372   DMRefineHookLink link, *p;
2373 
2374   PetscFunctionBegin;
2375   PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2376   for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
2377     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
2378   }
2379   PetscCall(PetscNew(&link));
2380   link->refinehook = refinehook;
2381   link->interphook = interphook;
2382   link->ctx        = ctx;
2383   link->next       = NULL;
2384   *p               = link;
2385   PetscFunctionReturn(PETSC_SUCCESS);
2386 }
2387 
2388 /*@C
2389   DMRefineHookRemove - remove a callback from the list of hooks, that have been set with `DMRefineHookAdd()`, to be run when interpolating
2390   a nonlinear problem to a finer grid
2391 
2392   Logically Collective; No Fortran Support
2393 
2394   Input Parameters:
2395 + coarse     - the `DM` on which to run a hook when restricting to a coarser level
2396 . refinehook - function to run when setting up a finer level
2397 . interphook - function to run to update data on finer levels
2398 - ctx        - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2399 
2400   Level: advanced
2401 
2402   Note:
2403   This function does nothing if the hook is not in the list.
2404 
2405 .seealso: [](ch_dmbase), `DM`, `DMRefineHookAdd()`, `DMCoarsenHookRemove()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2406 @*/
2407 PetscErrorCode DMRefineHookRemove(DM coarse, PetscErrorCode (*refinehook)(DM, DM, void *), PetscErrorCode (*interphook)(DM, Mat, DM, void *), void *ctx)
2408 {
2409   DMRefineHookLink link, *p;
2410 
2411   PetscFunctionBegin;
2412   PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2413   for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Search the list of current hooks */
2414     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2415       link = *p;
2416       *p   = link->next;
2417       PetscCall(PetscFree(link));
2418       break;
2419     }
2420   }
2421   PetscFunctionReturn(PETSC_SUCCESS);
2422 }
2423 
2424 /*@
2425   DMInterpolate - interpolates user-defined problem data attached to a `DM` to a finer `DM` by running hooks registered by `DMRefineHookAdd()`
2426 
2427   Collective if any hooks are
2428 
2429   Input Parameters:
2430 + coarse - coarser `DM` to use as a base
2431 . interp - interpolation matrix, apply using `MatInterpolate()`
2432 - fine   - finer `DM` to update
2433 
2434   Level: developer
2435 
2436   Developer Note:
2437   This routine is called `DMInterpolate()` while the hook is called `DMRefineHookAdd()`. It would be better to have an
2438   an API with consistent terminology.
2439 
2440 .seealso: [](ch_dmbase), `DM`, `DMRefineHookAdd()`, `MatInterpolate()`
2441 @*/
2442 PetscErrorCode DMInterpolate(DM coarse, Mat interp, DM fine)
2443 {
2444   DMRefineHookLink link;
2445 
2446   PetscFunctionBegin;
2447   for (link = fine->refinehook; link; link = link->next) {
2448     if (link->interphook) PetscCall((*link->interphook)(coarse, interp, fine, link->ctx));
2449   }
2450   PetscFunctionReturn(PETSC_SUCCESS);
2451 }
2452 
2453 /*@
2454   DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.
2455 
2456   Collective
2457 
2458   Input Parameters:
2459 + coarse    - coarse `DM`
2460 . fine      - fine `DM`
2461 . interp    - (optional) the matrix computed by `DMCreateInterpolation()`.  Implementations may not need this, but if it
2462             is available it can avoid some recomputation.  If it is provided, `MatInterpolate()` will be used if
2463             the coarse `DM` does not have a specialized implementation.
2464 - coarseSol - solution on the coarse mesh
2465 
2466   Output Parameter:
2467 . fineSol - the interpolation of coarseSol to the fine mesh
2468 
2469   Level: developer
2470 
2471   Note:
2472   This function exists because the interpolation of a solution vector between meshes is not always a linear
2473   map.  For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed
2474   out of the solution vector.  Or if interpolation is inherently a nonlinear operation, such as a method using
2475   slope-limiting reconstruction.
2476 
2477   Developer Note:
2478   This doesn't just interpolate "solutions" so its API name is questionable.
2479 
2480 .seealso: [](ch_dmbase), `DM`, `DMInterpolate()`, `DMCreateInterpolation()`
2481 @*/
2482 PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2483 {
2484   PetscErrorCode (*interpsol)(DM, DM, Mat, Vec, Vec) = NULL;
2485 
2486   PetscFunctionBegin;
2487   PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2488   if (interp) PetscValidHeaderSpecific(interp, MAT_CLASSID, 3);
2489   PetscValidHeaderSpecific(coarseSol, VEC_CLASSID, 4);
2490   PetscValidHeaderSpecific(fineSol, VEC_CLASSID, 5);
2491 
2492   PetscCall(PetscObjectQueryFunction((PetscObject)coarse, "DMInterpolateSolution_C", &interpsol));
2493   if (interpsol) {
2494     PetscCall((*interpsol)(coarse, fine, interp, coarseSol, fineSol));
2495   } else if (interp) {
2496     PetscCall(MatInterpolate(interp, coarseSol, fineSol));
2497   } else SETERRQ(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2498   PetscFunctionReturn(PETSC_SUCCESS);
2499 }
2500 
2501 /*@
2502   DMGetRefineLevel - Gets the number of refinements that have generated this `DM` from some initial `DM`.
2503 
2504   Not Collective
2505 
2506   Input Parameter:
2507 . dm - the `DM` object
2508 
2509   Output Parameter:
2510 . level - number of refinements
2511 
2512   Level: developer
2513 
2514   Note:
2515   This can be used, by example, to set the number of coarser levels associated with this `DM` for a multigrid solver.
2516 
2517 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2518 @*/
2519 PetscErrorCode DMGetRefineLevel(DM dm, PetscInt *level)
2520 {
2521   PetscFunctionBegin;
2522   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2523   *level = dm->levelup;
2524   PetscFunctionReturn(PETSC_SUCCESS);
2525 }
2526 
2527 /*@
2528   DMSetRefineLevel - Sets the number of refinements that have generated this `DM`.
2529 
2530   Not Collective
2531 
2532   Input Parameters:
2533 + dm    - the `DM` object
2534 - level - number of refinements
2535 
2536   Level: advanced
2537 
2538   Notes:
2539   This value is used by `PCMG` to determine how many multigrid levels to use
2540 
2541   The values are usually set automatically by the process that is causing the refinements of an initial `DM` by calling this routine.
2542 
2543 .seealso: [](ch_dmbase), `DM`, `DMGetRefineLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2544 @*/
2545 PetscErrorCode DMSetRefineLevel(DM dm, PetscInt level)
2546 {
2547   PetscFunctionBegin;
2548   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2549   dm->levelup = level;
2550   PetscFunctionReturn(PETSC_SUCCESS);
2551 }
2552 
2553 /*@
2554   DMExtrude - Extrude a `DM` object from a surface
2555 
2556   Collective
2557 
2558   Input Parameters:
2559 + dm     - the `DM` object
2560 - layers - the number of extruded cell layers
2561 
2562   Output Parameter:
2563 . dme - the extruded `DM`, or `NULL`
2564 
2565   Level: developer
2566 
2567   Note:
2568   If no extrusion was done, the return value is `NULL`
2569 
2570 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`
2571 @*/
2572 PetscErrorCode DMExtrude(DM dm, PetscInt layers, DM *dme)
2573 {
2574   PetscFunctionBegin;
2575   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2576   PetscUseTypeMethod(dm, extrude, layers, dme);
2577   if (*dme) {
2578     (*dme)->ops->creatematrix = dm->ops->creatematrix;
2579     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dme));
2580     (*dme)->ctx = dm->ctx;
2581     PetscCall(DMSetMatType(*dme, dm->mattype));
2582   }
2583   PetscFunctionReturn(PETSC_SUCCESS);
2584 }
2585 
2586 PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2587 {
2588   PetscFunctionBegin;
2589   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2590   PetscAssertPointer(tdm, 2);
2591   *tdm = dm->transformDM;
2592   PetscFunctionReturn(PETSC_SUCCESS);
2593 }
2594 
2595 PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2596 {
2597   PetscFunctionBegin;
2598   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2599   PetscAssertPointer(tv, 2);
2600   *tv = dm->transform;
2601   PetscFunctionReturn(PETSC_SUCCESS);
2602 }
2603 
2604 /*@
2605   DMHasBasisTransform - Whether the `DM` employs a basis transformation from functions in global vectors to functions in local vectors
2606 
2607   Input Parameter:
2608 . dm - The `DM`
2609 
2610   Output Parameter:
2611 . flg - `PETSC_TRUE` if a basis transformation should be done
2612 
2613   Level: developer
2614 
2615 .seealso: [](ch_dmbase), `DM`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`, `DMPlexCreateBasisRotation()`
2616 @*/
2617 PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2618 {
2619   Vec tv;
2620 
2621   PetscFunctionBegin;
2622   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2623   PetscAssertPointer(flg, 2);
2624   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
2625   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2626   PetscFunctionReturn(PETSC_SUCCESS);
2627 }
2628 
2629 PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2630 {
2631   PetscSection s, ts;
2632   PetscScalar *ta;
2633   PetscInt     cdim, pStart, pEnd, p, Nf, f, Nc, dof;
2634 
2635   PetscFunctionBegin;
2636   PetscCall(DMGetCoordinateDim(dm, &cdim));
2637   PetscCall(DMGetLocalSection(dm, &s));
2638   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2639   PetscCall(PetscSectionGetNumFields(s, &Nf));
2640   PetscCall(DMClone(dm, &dm->transformDM));
2641   PetscCall(DMGetLocalSection(dm->transformDM, &ts));
2642   PetscCall(PetscSectionSetNumFields(ts, Nf));
2643   PetscCall(PetscSectionSetChart(ts, pStart, pEnd));
2644   for (f = 0; f < Nf; ++f) {
2645     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
2646     /* We could start to label fields by their transformation properties */
2647     if (Nc != cdim) continue;
2648     for (p = pStart; p < pEnd; ++p) {
2649       PetscCall(PetscSectionGetFieldDof(s, p, f, &dof));
2650       if (!dof) continue;
2651       PetscCall(PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim)));
2652       PetscCall(PetscSectionAddDof(ts, p, PetscSqr(cdim)));
2653     }
2654   }
2655   PetscCall(PetscSectionSetUp(ts));
2656   PetscCall(DMCreateLocalVector(dm->transformDM, &dm->transform));
2657   PetscCall(VecGetArray(dm->transform, &ta));
2658   for (p = pStart; p < pEnd; ++p) {
2659     for (f = 0; f < Nf; ++f) {
2660       PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof));
2661       if (dof) {
2662         PetscReal          x[3] = {0.0, 0.0, 0.0};
2663         PetscScalar       *tva;
2664         const PetscScalar *A;
2665 
2666         /* TODO Get quadrature point for this dual basis vector for coordinate */
2667         PetscCall((*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx));
2668         PetscCall(DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *)&tva));
2669         PetscCall(PetscArraycpy(tva, A, PetscSqr(cdim)));
2670       }
2671     }
2672   }
2673   PetscCall(VecRestoreArray(dm->transform, &ta));
2674   PetscFunctionReturn(PETSC_SUCCESS);
2675 }
2676 
2677 PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2678 {
2679   PetscFunctionBegin;
2680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2681   PetscValidHeaderSpecific(newdm, DM_CLASSID, 2);
2682   newdm->transformCtx       = dm->transformCtx;
2683   newdm->transformSetUp     = dm->transformSetUp;
2684   newdm->transformDestroy   = NULL;
2685   newdm->transformGetMatrix = dm->transformGetMatrix;
2686   if (newdm->transformSetUp) PetscCall(DMConstructBasisTransform_Internal(newdm));
2687   PetscFunctionReturn(PETSC_SUCCESS);
2688 }
2689 
2690 /*@C
2691   DMGlobalToLocalHookAdd - adds a callback to be run when `DMGlobalToLocal()` is called
2692 
2693   Logically Collective
2694 
2695   Input Parameters:
2696 + dm        - the `DM`
2697 . beginhook - function to run at the beginning of `DMGlobalToLocalBegin()`
2698 . endhook   - function to run after `DMGlobalToLocalEnd()` has completed
2699 - ctx       - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2700 
2701   Calling sequence of `beginhook`:
2702 + dm   - global `DM`
2703 . g    - global vector
2704 . mode - mode
2705 . l    - local vector
2706 - ctx  - optional user-defined function context
2707 
2708   Calling sequence of `endhook`:
2709 + dm   - global `DM`
2710 . g    - global vector
2711 . mode - mode
2712 . l    - local vector
2713 - ctx  - optional user-defined function context
2714 
2715   Level: advanced
2716 
2717   Note:
2718   The hook may be used to provide, for example, values that represent boundary conditions in the local vectors that do not exist on the global vector.
2719 
2720 .seealso: [](ch_dmbase), `DM`, `DMGlobalToLocal()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2721 @*/
2722 PetscErrorCode DMGlobalToLocalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM dm, Vec g, InsertMode mode, Vec l, void *ctx), PetscErrorCode (*endhook)(DM dm, Vec g, InsertMode mode, Vec l, void *ctx), void *ctx)
2723 {
2724   DMGlobalToLocalHookLink link, *p;
2725 
2726   PetscFunctionBegin;
2727   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2728   for (p = &dm->gtolhook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2729   PetscCall(PetscNew(&link));
2730   link->beginhook = beginhook;
2731   link->endhook   = endhook;
2732   link->ctx       = ctx;
2733   link->next      = NULL;
2734   *p              = link;
2735   PetscFunctionReturn(PETSC_SUCCESS);
2736 }
2737 
2738 static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2739 {
2740   Mat          cMat;
2741   Vec          cVec, cBias;
2742   PetscSection section, cSec;
2743   PetscInt     pStart, pEnd, p, dof;
2744 
2745   PetscFunctionBegin;
2746   (void)g;
2747   (void)ctx;
2748   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2749   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, &cBias));
2750   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2751     PetscInt nRows;
2752 
2753     PetscCall(MatGetSize(cMat, &nRows, NULL));
2754     if (nRows <= 0) PetscFunctionReturn(PETSC_SUCCESS);
2755     PetscCall(DMGetLocalSection(dm, &section));
2756     PetscCall(MatCreateVecs(cMat, NULL, &cVec));
2757     PetscCall(MatMult(cMat, l, cVec));
2758     if (cBias) PetscCall(VecAXPY(cVec, 1., cBias));
2759     PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
2760     for (p = pStart; p < pEnd; p++) {
2761       PetscCall(PetscSectionGetDof(cSec, p, &dof));
2762       if (dof) {
2763         PetscScalar *vals;
2764         PetscCall(VecGetValuesSection(cVec, cSec, p, &vals));
2765         PetscCall(VecSetValuesSection(l, section, p, vals, INSERT_ALL_VALUES));
2766       }
2767     }
2768     PetscCall(VecDestroy(&cVec));
2769   }
2770   PetscFunctionReturn(PETSC_SUCCESS);
2771 }
2772 
2773 /*@
2774   DMGlobalToLocal - update local vectors from global vector
2775 
2776   Neighbor-wise Collective
2777 
2778   Input Parameters:
2779 + dm   - the `DM` object
2780 . g    - the global vector
2781 . mode - `INSERT_VALUES` or `ADD_VALUES`
2782 - l    - the local vector
2783 
2784   Level: beginner
2785 
2786   Notes:
2787   The communication involved in this update can be overlapped with computation by instead using
2788   `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()`.
2789 
2790   `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.
2791 
2792 .seealso: [](ch_dmbase), `DM`, `DMGlobalToLocalHookAdd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`,
2793           `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`,
2794           `DMGlobalToLocalBegin()` `DMGlobalToLocalEnd()`
2795 @*/
2796 PetscErrorCode DMGlobalToLocal(DM dm, Vec g, InsertMode mode, Vec l)
2797 {
2798   PetscFunctionBegin;
2799   PetscCall(DMGlobalToLocalBegin(dm, g, mode, l));
2800   PetscCall(DMGlobalToLocalEnd(dm, g, mode, l));
2801   PetscFunctionReturn(PETSC_SUCCESS);
2802 }
2803 
2804 /*@
2805   DMGlobalToLocalBegin - Begins updating local vectors from global vector
2806 
2807   Neighbor-wise Collective
2808 
2809   Input Parameters:
2810 + dm   - the `DM` object
2811 . g    - the global vector
2812 . mode - `INSERT_VALUES` or `ADD_VALUES`
2813 - l    - the local vector
2814 
2815   Level: intermediate
2816 
2817   Notes:
2818   The operation is completed with `DMGlobalToLocalEnd()`
2819 
2820   One can perform local computations between the `DMGlobalToLocalBegin()` and  `DMGlobalToLocalEnd()` to overlap communication and computation
2821 
2822   `DMGlobalToLocal()` is a short form of  `DMGlobalToLocalBegin()` and  `DMGlobalToLocalEnd()`
2823 
2824   `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.
2825 
2826 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`
2827 @*/
2828 PetscErrorCode DMGlobalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
2829 {
2830   PetscSF                 sf;
2831   DMGlobalToLocalHookLink link;
2832 
2833   PetscFunctionBegin;
2834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2835   for (link = dm->gtolhook; link; link = link->next) {
2836     if (link->beginhook) PetscCall((*link->beginhook)(dm, g, mode, l, link->ctx));
2837   }
2838   PetscCall(DMGetSectionSF(dm, &sf));
2839   if (sf) {
2840     const PetscScalar *gArray;
2841     PetscScalar       *lArray;
2842     PetscMemType       lmtype, gmtype;
2843 
2844     PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode);
2845     PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype));
2846     PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype));
2847     PetscCall(PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE));
2848     PetscCall(VecRestoreArrayAndMemType(l, &lArray));
2849     PetscCall(VecRestoreArrayReadAndMemType(g, &gArray));
2850   } else {
2851     PetscUseTypeMethod(dm, globaltolocalbegin, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2852   }
2853   PetscFunctionReturn(PETSC_SUCCESS);
2854 }
2855 
2856 /*@
2857   DMGlobalToLocalEnd - Ends updating local vectors from global vector
2858 
2859   Neighbor-wise Collective
2860 
2861   Input Parameters:
2862 + dm   - the `DM` object
2863 . g    - the global vector
2864 . mode - `INSERT_VALUES` or `ADD_VALUES`
2865 - l    - the local vector
2866 
2867   Level: intermediate
2868 
2869   Note:
2870   See `DMGlobalToLocalBegin()` for details.
2871 
2872 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`
2873 @*/
2874 PetscErrorCode DMGlobalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
2875 {
2876   PetscSF                 sf;
2877   const PetscScalar      *gArray;
2878   PetscScalar            *lArray;
2879   PetscBool               transform;
2880   DMGlobalToLocalHookLink link;
2881   PetscMemType            lmtype, gmtype;
2882 
2883   PetscFunctionBegin;
2884   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2885   PetscCall(DMGetSectionSF(dm, &sf));
2886   PetscCall(DMHasBasisTransform(dm, &transform));
2887   if (sf) {
2888     PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode);
2889 
2890     PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype));
2891     PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype));
2892     PetscCall(PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray, MPI_REPLACE));
2893     PetscCall(VecRestoreArrayAndMemType(l, &lArray));
2894     PetscCall(VecRestoreArrayReadAndMemType(g, &gArray));
2895     if (transform) PetscCall(DMPlexGlobalToLocalBasis(dm, l));
2896   } else {
2897     PetscUseTypeMethod(dm, globaltolocalend, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2898   }
2899   PetscCall(DMGlobalToLocalHook_Constraints(dm, g, mode, l, NULL));
2900   for (link = dm->gtolhook; link; link = link->next) {
2901     if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx));
2902   }
2903   PetscFunctionReturn(PETSC_SUCCESS);
2904 }
2905 
2906 /*@C
2907   DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
2908 
2909   Logically Collective
2910 
2911   Input Parameters:
2912 + dm        - the `DM`
2913 . beginhook - function to run at the beginning of `DMLocalToGlobalBegin()`
2914 . endhook   - function to run after `DMLocalToGlobalEnd()` has completed
2915 - ctx       - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2916 
2917   Calling sequence of `beginhook`:
2918 + global - global `DM`
2919 . l      - local vector
2920 . mode   - mode
2921 . g      - global vector
2922 - ctx    - optional user-defined function context
2923 
2924   Calling sequence of `endhook`:
2925 + global - global `DM`
2926 . l      - local vector
2927 . mode   - mode
2928 . g      - global vector
2929 - ctx    - optional user-defined function context
2930 
2931   Level: advanced
2932 
2933 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobal()`, `DMRefineHookAdd()`, `DMGlobalToLocalHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2934 @*/
2935 PetscErrorCode DMLocalToGlobalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM global, Vec l, InsertMode mode, Vec g, void *ctx), PetscErrorCode (*endhook)(DM global, Vec l, InsertMode mode, Vec g, void *ctx), void *ctx)
2936 {
2937   DMLocalToGlobalHookLink link, *p;
2938 
2939   PetscFunctionBegin;
2940   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2941   for (p = &dm->ltoghook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2942   PetscCall(PetscNew(&link));
2943   link->beginhook = beginhook;
2944   link->endhook   = endhook;
2945   link->ctx       = ctx;
2946   link->next      = NULL;
2947   *p              = link;
2948   PetscFunctionReturn(PETSC_SUCCESS);
2949 }
2950 
2951 static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2952 {
2953   PetscFunctionBegin;
2954   (void)g;
2955   (void)ctx;
2956   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2957   if (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES) {
2958     Mat          cMat;
2959     Vec          cVec;
2960     PetscInt     nRows;
2961     PetscSection section, cSec;
2962     PetscInt     pStart, pEnd, p, dof;
2963 
2964     PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
2965     if (!cMat) PetscFunctionReturn(PETSC_SUCCESS);
2966 
2967     PetscCall(MatGetSize(cMat, &nRows, NULL));
2968     if (nRows <= 0) PetscFunctionReturn(PETSC_SUCCESS);
2969     PetscCall(DMGetLocalSection(dm, &section));
2970     PetscCall(MatCreateVecs(cMat, NULL, &cVec));
2971     PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
2972     for (p = pStart; p < pEnd; p++) {
2973       PetscCall(PetscSectionGetDof(cSec, p, &dof));
2974       if (dof) {
2975         PetscInt     d;
2976         PetscScalar *vals;
2977         PetscCall(VecGetValuesSection(l, section, p, &vals));
2978         PetscCall(VecSetValuesSection(cVec, cSec, p, vals, mode));
2979         /* for this to be the true transpose, we have to zero the values that
2980          * we just extracted */
2981         for (d = 0; d < dof; d++) vals[d] = 0.;
2982       }
2983     }
2984     PetscCall(MatMultTransposeAdd(cMat, cVec, l, l));
2985     PetscCall(VecDestroy(&cVec));
2986   }
2987   PetscFunctionReturn(PETSC_SUCCESS);
2988 }
2989 /*@
2990   DMLocalToGlobal - updates global vectors from local vectors
2991 
2992   Neighbor-wise Collective
2993 
2994   Input Parameters:
2995 + dm   - the `DM` object
2996 . l    - the local vector
2997 . mode - if `INSERT_VALUES` then no parallel communication is used, if `ADD_VALUES` then all ghost points from the same base point accumulate into that base point.
2998 - g    - the global vector
2999 
3000   Level: beginner
3001 
3002   Notes:
3003   The communication involved in this update can be overlapped with computation by using
3004   `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()`.
3005 
3006   In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.
3007 
3008   `INSERT_VALUES` is not supported for `DMDA`; in that case simply compute the values directly into a global vector instead of a local one.
3009 
3010   Use `DMLocalToGlobalHookAdd()` to add additional operations that are performed on the data during the update process
3011 
3012 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`, `DMLocalToGlobalHookAdd()`, `DMGlobaToLocallHookAdd()`
3013 @*/
3014 PetscErrorCode DMLocalToGlobal(DM dm, Vec l, InsertMode mode, Vec g)
3015 {
3016   PetscFunctionBegin;
3017   PetscCall(DMLocalToGlobalBegin(dm, l, mode, g));
3018   PetscCall(DMLocalToGlobalEnd(dm, l, mode, g));
3019   PetscFunctionReturn(PETSC_SUCCESS);
3020 }
3021 
3022 /*@
3023   DMLocalToGlobalBegin - begins updating global vectors from local vectors
3024 
3025   Neighbor-wise Collective
3026 
3027   Input Parameters:
3028 + dm   - the `DM` object
3029 . l    - the local vector
3030 . mode - if `INSERT_VALUES` then no parallel communication is used, if `ADD_VALUES` then all ghost points from the same base point accumulate into that base point.
3031 - g    - the global vector
3032 
3033   Level: intermediate
3034 
3035   Notes:
3036   In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.
3037 
3038   `INSERT_VALUES is` not supported for `DMDA`, in that case simply compute the values directly into a global vector instead of a local one.
3039 
3040   Use `DMLocalToGlobalEnd()` to complete the communication process.
3041 
3042   `DMLocalToGlobal()` is a short form of  `DMLocalToGlobalBegin()` and  `DMLocalToGlobalEnd()`
3043 
3044   `DMLocalToGlobalHookAdd()` may be used to provide additional operations that are performed during the update process.
3045 
3046 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`
3047 @*/
3048 PetscErrorCode DMLocalToGlobalBegin(DM dm, Vec l, InsertMode mode, Vec g)
3049 {
3050   PetscSF                 sf;
3051   PetscSection            s, gs;
3052   DMLocalToGlobalHookLink link;
3053   Vec                     tmpl;
3054   const PetscScalar      *lArray;
3055   PetscScalar            *gArray;
3056   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
3057   PetscMemType            lmtype = PETSC_MEMTYPE_HOST, gmtype = PETSC_MEMTYPE_HOST;
3058 
3059   PetscFunctionBegin;
3060   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3061   for (link = dm->ltoghook; link; link = link->next) {
3062     if (link->beginhook) PetscCall((*link->beginhook)(dm, l, mode, g, link->ctx));
3063   }
3064   PetscCall(DMLocalToGlobalHook_Constraints(dm, l, mode, g, NULL));
3065   PetscCall(DMGetSectionSF(dm, &sf));
3066   PetscCall(DMGetLocalSection(dm, &s));
3067   switch (mode) {
3068   case INSERT_VALUES:
3069   case INSERT_ALL_VALUES:
3070   case INSERT_BC_VALUES:
3071     isInsert = PETSC_TRUE;
3072     break;
3073   case ADD_VALUES:
3074   case ADD_ALL_VALUES:
3075   case ADD_BC_VALUES:
3076     isInsert = PETSC_FALSE;
3077     break;
3078   default:
3079     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
3080   }
3081   if ((sf && !isInsert) || (s && isInsert)) {
3082     PetscCall(DMHasBasisTransform(dm, &transform));
3083     if (transform) {
3084       PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3085       PetscCall(VecCopy(l, tmpl));
3086       PetscCall(DMPlexLocalToGlobalBasis(dm, tmpl));
3087       PetscCall(VecGetArrayRead(tmpl, &lArray));
3088     } else if (isInsert) {
3089       PetscCall(VecGetArrayRead(l, &lArray));
3090     } else {
3091       PetscCall(VecGetArrayReadAndMemType(l, &lArray, &lmtype));
3092       l_inplace = PETSC_TRUE;
3093     }
3094     if (s && isInsert) {
3095       PetscCall(VecGetArray(g, &gArray));
3096     } else {
3097       PetscCall(VecGetArrayAndMemType(g, &gArray, &gmtype));
3098       g_inplace = PETSC_TRUE;
3099     }
3100     if (sf && !isInsert) {
3101       PetscCall(PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM));
3102     } else if (s && isInsert) {
3103       PetscInt gStart, pStart, pEnd, p;
3104 
3105       PetscCall(DMGetGlobalSection(dm, &gs));
3106       PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
3107       PetscCall(VecGetOwnershipRange(g, &gStart, NULL));
3108       for (p = pStart; p < pEnd; ++p) {
3109         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
3110 
3111         PetscCall(PetscSectionGetDof(s, p, &dof));
3112         PetscCall(PetscSectionGetDof(gs, p, &gdof));
3113         PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
3114         PetscCall(PetscSectionGetConstraintDof(gs, p, &gcdof));
3115         PetscCall(PetscSectionGetOffset(s, p, &off));
3116         PetscCall(PetscSectionGetOffset(gs, p, &goff));
3117         /* Ignore off-process data and points with no global data */
3118         if (!gdof || goff < 0) continue;
3119         PetscCheck(dof == gdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof);
3120         /* If no constraints are enforced in the global vector */
3121         if (!gcdof) {
3122           for (d = 0; d < dof; ++d) gArray[goff - gStart + d] = lArray[off + d];
3123           /* If constraints are enforced in the global vector */
3124         } else if (cdof == gcdof) {
3125           const PetscInt *cdofs;
3126           PetscInt        cind = 0;
3127 
3128           PetscCall(PetscSectionGetConstraintIndices(s, p, &cdofs));
3129           for (d = 0, e = 0; d < dof; ++d) {
3130             if ((cind < cdof) && (d == cdofs[cind])) {
3131               ++cind;
3132               continue;
3133             }
3134             gArray[goff - gStart + e++] = lArray[off + d];
3135           }
3136         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof);
3137       }
3138     }
3139     if (g_inplace) {
3140       PetscCall(VecRestoreArrayAndMemType(g, &gArray));
3141     } else {
3142       PetscCall(VecRestoreArray(g, &gArray));
3143     }
3144     if (transform) {
3145       PetscCall(VecRestoreArrayRead(tmpl, &lArray));
3146       PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3147     } else if (l_inplace) {
3148       PetscCall(VecRestoreArrayReadAndMemType(l, &lArray));
3149     } else {
3150       PetscCall(VecRestoreArrayRead(l, &lArray));
3151     }
3152   } else {
3153     PetscUseTypeMethod(dm, localtoglobalbegin, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3154   }
3155   PetscFunctionReturn(PETSC_SUCCESS);
3156 }
3157 
3158 /*@
3159   DMLocalToGlobalEnd - updates global vectors from local vectors
3160 
3161   Neighbor-wise Collective
3162 
3163   Input Parameters:
3164 + dm   - the `DM` object
3165 . l    - the local vector
3166 . mode - `INSERT_VALUES` or `ADD_VALUES`
3167 - g    - the global vector
3168 
3169   Level: intermediate
3170 
3171   Note:
3172   See `DMLocalToGlobalBegin()` for full details
3173 
3174 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`
3175 @*/
3176 PetscErrorCode DMLocalToGlobalEnd(DM dm, Vec l, InsertMode mode, Vec g)
3177 {
3178   PetscSF                 sf;
3179   PetscSection            s;
3180   DMLocalToGlobalHookLink link;
3181   PetscBool               isInsert, transform;
3182 
3183   PetscFunctionBegin;
3184   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3185   PetscCall(DMGetSectionSF(dm, &sf));
3186   PetscCall(DMGetLocalSection(dm, &s));
3187   switch (mode) {
3188   case INSERT_VALUES:
3189   case INSERT_ALL_VALUES:
3190     isInsert = PETSC_TRUE;
3191     break;
3192   case ADD_VALUES:
3193   case ADD_ALL_VALUES:
3194     isInsert = PETSC_FALSE;
3195     break;
3196   default:
3197     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
3198   }
3199   if (sf && !isInsert) {
3200     const PetscScalar *lArray;
3201     PetscScalar       *gArray;
3202     Vec                tmpl;
3203 
3204     PetscCall(DMHasBasisTransform(dm, &transform));
3205     if (transform) {
3206       PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3207       PetscCall(VecGetArrayRead(tmpl, &lArray));
3208     } else {
3209       PetscCall(VecGetArrayReadAndMemType(l, &lArray, NULL));
3210     }
3211     PetscCall(VecGetArrayAndMemType(g, &gArray, NULL));
3212     PetscCall(PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM));
3213     if (transform) {
3214       PetscCall(VecRestoreArrayRead(tmpl, &lArray));
3215       PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3216     } else {
3217       PetscCall(VecRestoreArrayReadAndMemType(l, &lArray));
3218     }
3219     PetscCall(VecRestoreArrayAndMemType(g, &gArray));
3220   } else if (s && isInsert) {
3221   } else {
3222     PetscUseTypeMethod(dm, localtoglobalend, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3223   }
3224   for (link = dm->ltoghook; link; link = link->next) {
3225     if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx));
3226   }
3227   PetscFunctionReturn(PETSC_SUCCESS);
3228 }
3229 
3230 /*@
3231   DMLocalToLocalBegin - Begins the process of mapping values from a local vector (that include
3232   ghost points that contain irrelevant values) to another local vector where the ghost points
3233   in the second are set correctly from values on other MPI ranks.
3234 
3235   Neighbor-wise Collective
3236 
3237   Input Parameters:
3238 + dm   - the `DM` object
3239 . g    - the original local vector
3240 - mode - one of `INSERT_VALUES` or `ADD_VALUES`
3241 
3242   Output Parameter:
3243 . l - the local vector with correct ghost values
3244 
3245   Level: intermediate
3246 
3247   Note:
3248   Must be followed by `DMLocalToLocalEnd()`.
3249 
3250 .seealso: [](ch_dmbase), `DM`, `DMLocalToLocalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3251 @*/
3252 PetscErrorCode DMLocalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
3253 {
3254   PetscFunctionBegin;
3255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3256   PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
3257   PetscValidHeaderSpecific(l, VEC_CLASSID, 4);
3258   PetscUseTypeMethod(dm, localtolocalbegin, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3259   PetscFunctionReturn(PETSC_SUCCESS);
3260 }
3261 
3262 /*@
3263   DMLocalToLocalEnd - Maps from a local vector to another local vector where the ghost
3264   points in the second are set correctly. Must be preceded by `DMLocalToLocalBegin()`.
3265 
3266   Neighbor-wise Collective
3267 
3268   Input Parameters:
3269 + dm   - the `DM` object
3270 . g    - the original local vector
3271 - mode - one of `INSERT_VALUES` or `ADD_VALUES`
3272 
3273   Output Parameter:
3274 . l - the local vector with correct ghost values
3275 
3276   Level: intermediate
3277 
3278 .seealso: [](ch_dmbase), `DM`, `DMLocalToLocalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3279 @*/
3280 PetscErrorCode DMLocalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
3281 {
3282   PetscFunctionBegin;
3283   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3284   PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
3285   PetscValidHeaderSpecific(l, VEC_CLASSID, 4);
3286   PetscUseTypeMethod(dm, localtolocalend, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3287   PetscFunctionReturn(PETSC_SUCCESS);
3288 }
3289 
3290 /*@
3291   DMCoarsen - Coarsens a `DM` object using a standard, non-adaptive coarsening of the underlying mesh
3292 
3293   Collective
3294 
3295   Input Parameters:
3296 + dm   - the `DM` object
3297 - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)
3298 
3299   Output Parameter:
3300 . dmc - the coarsened `DM`
3301 
3302   Level: developer
3303 
3304 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateDomainDecomposition()`,
3305           `DMCoarsenHookAdd()`, `DMCoarsenHookRemove()`
3306 @*/
3307 PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3308 {
3309   DMCoarsenHookLink link;
3310 
3311   PetscFunctionBegin;
3312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3313   PetscCall(PetscLogEventBegin(DM_Coarsen, dm, 0, 0, 0));
3314   PetscUseTypeMethod(dm, coarsen, comm, dmc);
3315   if (*dmc) {
3316     (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */
3317     PetscCall(DMSetCoarseDM(dm, *dmc));
3318     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3319     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmc));
3320     (*dmc)->ctx       = dm->ctx;
3321     (*dmc)->levelup   = dm->levelup;
3322     (*dmc)->leveldown = dm->leveldown + 1;
3323     PetscCall(DMSetMatType(*dmc, dm->mattype));
3324     for (link = dm->coarsenhook; link; link = link->next) {
3325       if (link->coarsenhook) PetscCall((*link->coarsenhook)(dm, *dmc, link->ctx));
3326     }
3327   }
3328   PetscCall(PetscLogEventEnd(DM_Coarsen, dm, 0, 0, 0));
3329   PetscCheck(*dmc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3330   PetscFunctionReturn(PETSC_SUCCESS);
3331 }
3332 
3333 /*@C
3334   DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
3335 
3336   Logically Collective; No Fortran Support
3337 
3338   Input Parameters:
3339 + fine         - `DM` on which to run a hook when restricting to a coarser level
3340 . coarsenhook  - function to run when setting up a coarser level
3341 . restricthook - function to run to update data on coarser levels (called once per `SNESSolve()`)
3342 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3343 
3344   Calling sequence of `coarsenhook`:
3345 + fine   - fine level `DM`
3346 . coarse - coarse level `DM` to restrict problem to
3347 - ctx    - optional user-defined function context
3348 
3349   Calling sequence of `restricthook`:
3350 + fine      - fine level `DM`
3351 . mrestrict - matrix restricting a fine-level solution to the coarse grid, usually the transpose of the interpolation
3352 . rscale    - scaling vector for restriction
3353 . inject    - matrix restricting by injection
3354 . coarse    - coarse level DM to update
3355 - ctx       - optional user-defined function context
3356 
3357   Level: advanced
3358 
3359   Notes:
3360   This function is only needed if auxiliary data, attached to the `DM` with `PetscObjectCompose()`, needs to be set up or passed from the fine `DM` to the coarse `DM`.
3361 
3362   If this function is called multiple times, the hooks will be run in the order they are added.
3363 
3364   In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3365   extract the finest level information from its context (instead of from the `SNES`).
3366 
3367   The hooks are automatically called by `DMRestrict()`
3368 
3369 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3370 @*/
3371 PetscErrorCode DMCoarsenHookAdd(DM fine, PetscErrorCode (*coarsenhook)(DM fine, DM coarse, void *ctx), PetscErrorCode (*restricthook)(DM fine, Mat mrestrict, Vec rscale, Mat inject, DM coarse, void *ctx), void *ctx)
3372 {
3373   DMCoarsenHookLink link, *p;
3374 
3375   PetscFunctionBegin;
3376   PetscValidHeaderSpecific(fine, DM_CLASSID, 1);
3377   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3378     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
3379   }
3380   PetscCall(PetscNew(&link));
3381   link->coarsenhook  = coarsenhook;
3382   link->restricthook = restricthook;
3383   link->ctx          = ctx;
3384   link->next         = NULL;
3385   *p                 = link;
3386   PetscFunctionReturn(PETSC_SUCCESS);
3387 }
3388 
3389 /*@C
3390   DMCoarsenHookRemove - remove a callback set with `DMCoarsenHookAdd()`
3391 
3392   Logically Collective; No Fortran Support
3393 
3394   Input Parameters:
3395 + fine         - `DM` on which to run a hook when restricting to a coarser level
3396 . coarsenhook  - function to run when setting up a coarser level
3397 . restricthook - function to run to update data on coarser levels
3398 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3399 
3400   Level: advanced
3401 
3402   Notes:
3403   This function does nothing if the `coarsenhook` is not in the list.
3404 
3405   See `DMCoarsenHookAdd()` for the calling sequence of `coarsenhook` and `restricthook`
3406 
3407 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3408 @*/
3409 PetscErrorCode DMCoarsenHookRemove(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx)
3410 {
3411   DMCoarsenHookLink link, *p;
3412 
3413   PetscFunctionBegin;
3414   PetscValidHeaderSpecific(fine, DM_CLASSID, 1);
3415   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3416     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3417       link = *p;
3418       *p   = link->next;
3419       PetscCall(PetscFree(link));
3420       break;
3421     }
3422   }
3423   PetscFunctionReturn(PETSC_SUCCESS);
3424 }
3425 
3426 /*@
3427   DMRestrict - restricts user-defined problem data to a coarser `DM` by running hooks registered by `DMCoarsenHookAdd()`
3428 
3429   Collective if any hooks are
3430 
3431   Input Parameters:
3432 + fine    - finer `DM` from which the data is obtained
3433 . restrct - restriction matrix, apply using `MatRestrict()`, usually the transpose of the interpolation
3434 . rscale  - scaling vector for restriction
3435 . inject  - injection matrix, also use `MatRestrict()`
3436 - coarse  - coarser `DM` to update
3437 
3438   Level: developer
3439 
3440   Developer Note:
3441   Though this routine is called `DMRestrict()` the hooks are added with `DMCoarsenHookAdd()`, a consistent terminology would be better
3442 
3443 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `MatRestrict()`, `DMInterpolate()`, `DMRefineHookAdd()`
3444 @*/
3445 PetscErrorCode DMRestrict(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse)
3446 {
3447   DMCoarsenHookLink link;
3448 
3449   PetscFunctionBegin;
3450   for (link = fine->coarsenhook; link; link = link->next) {
3451     if (link->restricthook) PetscCall((*link->restricthook)(fine, restrct, rscale, inject, coarse, link->ctx));
3452   }
3453   PetscFunctionReturn(PETSC_SUCCESS);
3454 }
3455 
3456 /*@C
3457   DMSubDomainHookAdd - adds a callback to be run when restricting a problem to subdomain `DM`s with `DMCreateDomainDecomposition()`
3458 
3459   Logically Collective; No Fortran Support
3460 
3461   Input Parameters:
3462 + global       - global `DM`
3463 . ddhook       - function to run to pass data to the decomposition `DM` upon its creation
3464 . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3465 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3466 
3467   Calling sequence of `ddhook`:
3468 + global - global `DM`
3469 . block  - subdomain `DM`
3470 - ctx    - optional user-defined function context
3471 
3472   Calling sequence of `restricthook`:
3473 + global - global `DM`
3474 . out    - scatter to the outer (with ghost and overlap points) sub vector
3475 . in     - scatter to sub vector values only owned locally
3476 . block  - subdomain `DM`
3477 - ctx    - optional user-defined function context
3478 
3479   Level: advanced
3480 
3481   Notes:
3482   This function can be used if auxiliary data needs to be set up on subdomain `DM`s.
3483 
3484   If this function is called multiple times, the hooks will be run in the order they are added.
3485 
3486   In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3487   extract the global information from its context (instead of from the `SNES`).
3488 
3489   Developer Note:
3490   It is unclear what "block solve" means within the definition of `restricthook`
3491 
3492 .seealso: [](ch_dmbase), `DM`, `DMSubDomainHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`, `DMCreateDomainDecomposition()`
3493 @*/
3494 PetscErrorCode DMSubDomainHookAdd(DM global, PetscErrorCode (*ddhook)(DM global, DM block, void *ctx), PetscErrorCode (*restricthook)(DM global, VecScatter out, VecScatter in, DM block, void *ctx), void *ctx)
3495 {
3496   DMSubDomainHookLink link, *p;
3497 
3498   PetscFunctionBegin;
3499   PetscValidHeaderSpecific(global, DM_CLASSID, 1);
3500   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3501     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
3502   }
3503   PetscCall(PetscNew(&link));
3504   link->restricthook = restricthook;
3505   link->ddhook       = ddhook;
3506   link->ctx          = ctx;
3507   link->next         = NULL;
3508   *p                 = link;
3509   PetscFunctionReturn(PETSC_SUCCESS);
3510 }
3511 
3512 /*@C
3513   DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to subdomain `DM`s with `DMCreateDomainDecomposition()`
3514 
3515   Logically Collective; No Fortran Support
3516 
3517   Input Parameters:
3518 + global       - global `DM`
3519 . ddhook       - function to run to pass data to the decomposition `DM` upon its creation
3520 . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3521 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3522 
3523   Level: advanced
3524 
3525   Note:
3526   See `DMSubDomainHookAdd()` for the calling sequences of `ddhook` and `restricthook`
3527 
3528 .seealso: [](ch_dmbase), `DM`, `DMSubDomainHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`,
3529           `DMCreateDomainDecomposition()`
3530 @*/
3531 PetscErrorCode DMSubDomainHookRemove(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx)
3532 {
3533   DMSubDomainHookLink link, *p;
3534 
3535   PetscFunctionBegin;
3536   PetscValidHeaderSpecific(global, DM_CLASSID, 1);
3537   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3538     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3539       link = *p;
3540       *p   = link->next;
3541       PetscCall(PetscFree(link));
3542       break;
3543     }
3544   }
3545   PetscFunctionReturn(PETSC_SUCCESS);
3546 }
3547 
3548 /*@
3549   DMSubDomainRestrict - restricts user-defined problem data to a subdomain `DM` by running hooks registered by `DMSubDomainHookAdd()`
3550 
3551   Collective if any hooks are
3552 
3553   Input Parameters:
3554 + global   - The global `DM` to use as a base
3555 . oscatter - The scatter from domain global vector filling subdomain global vector with overlap
3556 . gscatter - The scatter from domain global vector filling subdomain local vector with ghosts
3557 - subdm    - The subdomain `DM` to update
3558 
3559   Level: developer
3560 
3561 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `MatRestrict()`, `DMCreateDomainDecomposition()`
3562 @*/
3563 PetscErrorCode DMSubDomainRestrict(DM global, VecScatter oscatter, VecScatter gscatter, DM subdm)
3564 {
3565   DMSubDomainHookLink link;
3566 
3567   PetscFunctionBegin;
3568   for (link = global->subdomainhook; link; link = link->next) {
3569     if (link->restricthook) PetscCall((*link->restricthook)(global, oscatter, gscatter, subdm, link->ctx));
3570   }
3571   PetscFunctionReturn(PETSC_SUCCESS);
3572 }
3573 
3574 /*@
3575   DMGetCoarsenLevel - Gets the number of coarsenings that have generated this `DM`.
3576 
3577   Not Collective
3578 
3579   Input Parameter:
3580 . dm - the `DM` object
3581 
3582   Output Parameter:
3583 . level - number of coarsenings
3584 
3585   Level: developer
3586 
3587 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMSetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3588 @*/
3589 PetscErrorCode DMGetCoarsenLevel(DM dm, PetscInt *level)
3590 {
3591   PetscFunctionBegin;
3592   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3593   PetscAssertPointer(level, 2);
3594   *level = dm->leveldown;
3595   PetscFunctionReturn(PETSC_SUCCESS);
3596 }
3597 
3598 /*@
3599   DMSetCoarsenLevel - Sets the number of coarsenings that have generated this `DM`.
3600 
3601   Collective
3602 
3603   Input Parameters:
3604 + dm    - the `DM` object
3605 - level - number of coarsenings
3606 
3607   Level: developer
3608 
3609   Note:
3610   This is rarely used directly, the information is automatically set when a `DM` is created with `DMCoarsen()`
3611 
3612 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3613 @*/
3614 PetscErrorCode DMSetCoarsenLevel(DM dm, PetscInt level)
3615 {
3616   PetscFunctionBegin;
3617   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3618   dm->leveldown = level;
3619   PetscFunctionReturn(PETSC_SUCCESS);
3620 }
3621 
3622 /*@
3623   DMRefineHierarchy - Refines a `DM` object, all levels at once
3624 
3625   Collective
3626 
3627   Input Parameters:
3628 + dm      - the `DM` object
3629 - nlevels - the number of levels of refinement
3630 
3631   Output Parameter:
3632 . dmf - the refined `DM` hierarchy
3633 
3634   Level: developer
3635 
3636 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMCoarsenHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3637 @*/
3638 PetscErrorCode DMRefineHierarchy(DM dm, PetscInt nlevels, DM dmf[])
3639 {
3640   PetscFunctionBegin;
3641   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3642   PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative");
3643   if (nlevels == 0) PetscFunctionReturn(PETSC_SUCCESS);
3644   PetscAssertPointer(dmf, 3);
3645   if (dm->ops->refine && !dm->ops->refinehierarchy) {
3646     PetscInt i;
3647 
3648     PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &dmf[0]));
3649     for (i = 1; i < nlevels; i++) PetscCall(DMRefine(dmf[i - 1], PetscObjectComm((PetscObject)dm), &dmf[i]));
3650   } else PetscUseTypeMethod(dm, refinehierarchy, nlevels, dmf);
3651   PetscFunctionReturn(PETSC_SUCCESS);
3652 }
3653 
3654 /*@
3655   DMCoarsenHierarchy - Coarsens a `DM` object, all levels at once
3656 
3657   Collective
3658 
3659   Input Parameters:
3660 + dm      - the `DM` object
3661 - nlevels - the number of levels of coarsening
3662 
3663   Output Parameter:
3664 . dmc - the coarsened `DM` hierarchy
3665 
3666   Level: developer
3667 
3668 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMRefineHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3669 @*/
3670 PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3671 {
3672   PetscFunctionBegin;
3673   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3674   PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative");
3675   if (nlevels == 0) PetscFunctionReturn(PETSC_SUCCESS);
3676   PetscAssertPointer(dmc, 3);
3677   if (dm->ops->coarsen && !dm->ops->coarsenhierarchy) {
3678     PetscInt i;
3679 
3680     PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &dmc[0]));
3681     for (i = 1; i < nlevels; i++) PetscCall(DMCoarsen(dmc[i - 1], PetscObjectComm((PetscObject)dm), &dmc[i]));
3682   } else PetscUseTypeMethod(dm, coarsenhierarchy, nlevels, dmc);
3683   PetscFunctionReturn(PETSC_SUCCESS);
3684 }
3685 
3686 /*@C
3687   DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the `DM` is destroyed
3688 
3689   Logically Collective if the function is collective
3690 
3691   Input Parameters:
3692 + dm      - the `DM` object
3693 - destroy - the destroy function
3694 
3695   Level: intermediate
3696 
3697 .seealso: [](ch_dmbase), `DM`, `DMSetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3698 @*/
3699 PetscErrorCode DMSetApplicationContextDestroy(DM dm, PetscErrorCode (*destroy)(void **))
3700 {
3701   PetscFunctionBegin;
3702   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3703   dm->ctxdestroy = destroy;
3704   PetscFunctionReturn(PETSC_SUCCESS);
3705 }
3706 
3707 /*@
3708   DMSetApplicationContext - Set a user context into a `DM` object
3709 
3710   Not Collective
3711 
3712   Input Parameters:
3713 + dm  - the `DM` object
3714 - ctx - the user context
3715 
3716   Level: intermediate
3717 
3718   Notes:
3719   A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3720   In a multilevel solver, the user context is shared by all the `DM` in the hierarchy; it is thus not advisable
3721   to store objects that represent discretized quantities inside the context.
3722 
3723 .seealso: [](ch_dmbase), `DM`, `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3724 @*/
3725 PetscErrorCode DMSetApplicationContext(DM dm, void *ctx)
3726 {
3727   PetscFunctionBegin;
3728   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3729   dm->ctx = ctx;
3730   PetscFunctionReturn(PETSC_SUCCESS);
3731 }
3732 
3733 /*@
3734   DMGetApplicationContext - Gets a user context from a `DM` object
3735 
3736   Not Collective
3737 
3738   Input Parameter:
3739 . dm - the `DM` object
3740 
3741   Output Parameter:
3742 . ctx - the user context
3743 
3744   Level: intermediate
3745 
3746   Note:
3747   A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3748 
3749 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3750 @*/
3751 PetscErrorCode DMGetApplicationContext(DM dm, void *ctx)
3752 {
3753   PetscFunctionBegin;
3754   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3755   *(void **)ctx = dm->ctx;
3756   PetscFunctionReturn(PETSC_SUCCESS);
3757 }
3758 
3759 /*@C
3760   DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for `SNESVI`.
3761 
3762   Logically Collective
3763 
3764   Input Parameters:
3765 + dm - the DM object
3766 - f  - the function that computes variable bounds used by SNESVI (use `NULL` to cancel a previous function that was set)
3767 
3768   Level: intermediate
3769 
3770 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`,
3771          `DMSetJacobian()`
3772 @*/
3773 PetscErrorCode DMSetVariableBounds(DM dm, PetscErrorCode (*f)(DM, Vec, Vec))
3774 {
3775   PetscFunctionBegin;
3776   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3777   dm->ops->computevariablebounds = f;
3778   PetscFunctionReturn(PETSC_SUCCESS);
3779 }
3780 
3781 /*@
3782   DMHasVariableBounds - does the `DM` object have a variable bounds function?
3783 
3784   Not Collective
3785 
3786   Input Parameter:
3787 . dm - the `DM` object to destroy
3788 
3789   Output Parameter:
3790 . flg - `PETSC_TRUE` if the variable bounds function exists
3791 
3792   Level: developer
3793 
3794 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3795 @*/
3796 PetscErrorCode DMHasVariableBounds(DM dm, PetscBool *flg)
3797 {
3798   PetscFunctionBegin;
3799   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3800   PetscAssertPointer(flg, 2);
3801   *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3802   PetscFunctionReturn(PETSC_SUCCESS);
3803 }
3804 
3805 /*@
3806   DMComputeVariableBounds - compute variable bounds used by `SNESVI`.
3807 
3808   Logically Collective
3809 
3810   Input Parameter:
3811 . dm - the `DM` object
3812 
3813   Output Parameters:
3814 + xl - lower bound
3815 - xu - upper bound
3816 
3817   Level: advanced
3818 
3819   Note:
3820   This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3821 
3822 .seealso: [](ch_dmbase), `DM`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3823 @*/
3824 PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3825 {
3826   PetscFunctionBegin;
3827   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3828   PetscValidHeaderSpecific(xl, VEC_CLASSID, 2);
3829   PetscValidHeaderSpecific(xu, VEC_CLASSID, 3);
3830   PetscUseTypeMethod(dm, computevariablebounds, xl, xu);
3831   PetscFunctionReturn(PETSC_SUCCESS);
3832 }
3833 
3834 /*@
3835   DMHasColoring - does the `DM` object have a method of providing a coloring?
3836 
3837   Not Collective
3838 
3839   Input Parameter:
3840 . dm - the DM object
3841 
3842   Output Parameter:
3843 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateColoring()`.
3844 
3845   Level: developer
3846 
3847 .seealso: [](ch_dmbase), `DM`, `DMCreateColoring()`
3848 @*/
3849 PetscErrorCode DMHasColoring(DM dm, PetscBool *flg)
3850 {
3851   PetscFunctionBegin;
3852   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3853   PetscAssertPointer(flg, 2);
3854   *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3855   PetscFunctionReturn(PETSC_SUCCESS);
3856 }
3857 
3858 /*@
3859   DMHasCreateRestriction - does the `DM` object have a method of providing a restriction?
3860 
3861   Not Collective
3862 
3863   Input Parameter:
3864 . dm - the `DM` object
3865 
3866   Output Parameter:
3867 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateRestriction()`.
3868 
3869   Level: developer
3870 
3871 .seealso: [](ch_dmbase), `DM`, `DMCreateRestriction()`, `DMHasCreateInterpolation()`, `DMHasCreateInjection()`
3872 @*/
3873 PetscErrorCode DMHasCreateRestriction(DM dm, PetscBool *flg)
3874 {
3875   PetscFunctionBegin;
3876   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3877   PetscAssertPointer(flg, 2);
3878   *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3879   PetscFunctionReturn(PETSC_SUCCESS);
3880 }
3881 
3882 /*@
3883   DMHasCreateInjection - does the `DM` object have a method of providing an injection?
3884 
3885   Not Collective
3886 
3887   Input Parameter:
3888 . dm - the `DM` object
3889 
3890   Output Parameter:
3891 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateInjection()`.
3892 
3893   Level: developer
3894 
3895 .seealso: [](ch_dmbase), `DM`, `DMCreateInjection()`, `DMHasCreateRestriction()`, `DMHasCreateInterpolation()`
3896 @*/
3897 PetscErrorCode DMHasCreateInjection(DM dm, PetscBool *flg)
3898 {
3899   PetscFunctionBegin;
3900   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3901   PetscAssertPointer(flg, 2);
3902   if (dm->ops->hascreateinjection) PetscUseTypeMethod(dm, hascreateinjection, flg);
3903   else *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3904   PetscFunctionReturn(PETSC_SUCCESS);
3905 }
3906 
3907 PetscFunctionList DMList              = NULL;
3908 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
3909 
3910 /*@
3911   DMSetType - Builds a `DM`, for a particular `DM` implementation.
3912 
3913   Collective
3914 
3915   Input Parameters:
3916 + dm     - The `DM` object
3917 - method - The name of the `DMType`, for example `DMDA`, `DMPLEX`
3918 
3919   Options Database Key:
3920 . -dm_type <type> - Sets the `DM` type; use -help for a list of available types
3921 
3922   Level: intermediate
3923 
3924   Note:
3925   Of the `DM` is constructed by directly calling a function to construct a particular `DM`, for example, `DMDACreate2d()` or `DMPlexCreateBoxMesh()`
3926 
3927 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMGetType()`, `DMCreate()`, `DMDACreate2d()`
3928 @*/
3929 PetscErrorCode DMSetType(DM dm, DMType method)
3930 {
3931   PetscErrorCode (*r)(DM);
3932   PetscBool match;
3933 
3934   PetscFunctionBegin;
3935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3936   PetscCall(PetscObjectTypeCompare((PetscObject)dm, method, &match));
3937   if (match) PetscFunctionReturn(PETSC_SUCCESS);
3938 
3939   PetscCall(DMRegisterAll());
3940   PetscCall(PetscFunctionListFind(DMList, method, &r));
3941   PetscCheck(r, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
3942 
3943   PetscTryTypeMethod(dm, destroy);
3944   PetscCall(PetscMemzero(dm->ops, sizeof(*dm->ops)));
3945   PetscCall(PetscObjectChangeTypeName((PetscObject)dm, method));
3946   PetscCall((*r)(dm));
3947   PetscFunctionReturn(PETSC_SUCCESS);
3948 }
3949 
3950 /*@
3951   DMGetType - Gets the `DM` type name (as a string) from the `DM`.
3952 
3953   Not Collective
3954 
3955   Input Parameter:
3956 . dm - The `DM`
3957 
3958   Output Parameter:
3959 . type - The `DMType` name
3960 
3961   Level: intermediate
3962 
3963 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMSetType()`, `DMCreate()`
3964 @*/
3965 PetscErrorCode DMGetType(DM dm, DMType *type)
3966 {
3967   PetscFunctionBegin;
3968   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3969   PetscAssertPointer(type, 2);
3970   PetscCall(DMRegisterAll());
3971   *type = ((PetscObject)dm)->type_name;
3972   PetscFunctionReturn(PETSC_SUCCESS);
3973 }
3974 
3975 /*@
3976   DMConvert - Converts a `DM` to another `DM`, either of the same or different type.
3977 
3978   Collective
3979 
3980   Input Parameters:
3981 + dm      - the `DM`
3982 - newtype - new `DM` type (use "same" for the same type)
3983 
3984   Output Parameter:
3985 . M - pointer to new `DM`
3986 
3987   Level: intermediate
3988 
3989   Note:
3990   Cannot be used to convert a sequential `DM` to a parallel or a parallel to sequential,
3991   the MPI communicator of the generated `DM` is always the same as the communicator
3992   of the input `DM`.
3993 
3994 .seealso: [](ch_dmbase), `DM`, `DMSetType()`, `DMCreate()`, `DMClone()`
3995 @*/
3996 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3997 {
3998   DM        B;
3999   char      convname[256];
4000   PetscBool sametype /*, issame */;
4001 
4002   PetscFunctionBegin;
4003   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4004   PetscValidType(dm, 1);
4005   PetscAssertPointer(M, 3);
4006   PetscCall(PetscObjectTypeCompare((PetscObject)dm, newtype, &sametype));
4007   /* PetscCall(PetscStrcmp(newtype, "same", &issame)); */
4008   if (sametype) {
4009     *M = dm;
4010     PetscCall(PetscObjectReference((PetscObject)dm));
4011     PetscFunctionReturn(PETSC_SUCCESS);
4012   } else {
4013     PetscErrorCode (*conv)(DM, DMType, DM *) = NULL;
4014 
4015     /*
4016        Order of precedence:
4017        1) See if a specialized converter is known to the current DM.
4018        2) See if a specialized converter is known to the desired DM class.
4019        3) See if a good general converter is registered for the desired class
4020        4) See if a good general converter is known for the current matrix.
4021        5) Use a really basic converter.
4022     */
4023 
4024     /* 1) See if a specialized converter is known to the current DM and the desired class */
4025     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4026     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4027     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4028     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4029     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4030     PetscCall(PetscObjectQueryFunction((PetscObject)dm, convname, &conv));
4031     if (conv) goto foundconv;
4032 
4033     /* 2)  See if a specialized converter is known to the desired DM class. */
4034     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &B));
4035     PetscCall(DMSetType(B, newtype));
4036     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4037     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4038     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4039     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4040     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4041     PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4042     if (conv) {
4043       PetscCall(DMDestroy(&B));
4044       goto foundconv;
4045     }
4046 
4047 #if 0
4048     /* 3) See if a good general converter is registered for the desired class */
4049     conv = B->ops->convertfrom;
4050     PetscCall(DMDestroy(&B));
4051     if (conv) goto foundconv;
4052 
4053     /* 4) See if a good general converter is known for the current matrix */
4054     if (dm->ops->convert) {
4055       conv = dm->ops->convert;
4056     }
4057     if (conv) goto foundconv;
4058 #endif
4059 
4060     /* 5) Use a really basic converter. */
4061     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject)dm)->type_name, newtype);
4062 
4063   foundconv:
4064     PetscCall(PetscLogEventBegin(DM_Convert, dm, 0, 0, 0));
4065     PetscCall((*conv)(dm, newtype, M));
4066     /* Things that are independent of DM type: We should consult DMClone() here */
4067     {
4068       const PetscReal *maxCell, *Lstart, *L;
4069 
4070       PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
4071       PetscCall(DMSetPeriodicity(*M, maxCell, Lstart, L));
4072       (*M)->prealloc_only = dm->prealloc_only;
4073       PetscCall(PetscFree((*M)->vectype));
4074       PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype));
4075       PetscCall(PetscFree((*M)->mattype));
4076       PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype));
4077     }
4078     PetscCall(PetscLogEventEnd(DM_Convert, dm, 0, 0, 0));
4079   }
4080   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4081   PetscFunctionReturn(PETSC_SUCCESS);
4082 }
4083 
4084 /*--------------------------------------------------------------------------------------------------------------------*/
4085 
4086 /*@C
4087   DMRegister -  Adds a new `DM` type implementation
4088 
4089   Not Collective, No Fortran Support
4090 
4091   Input Parameters:
4092 + sname    - The name of a new user-defined creation routine
4093 - function - The creation routine itself
4094 
4095   Level: advanced
4096 
4097   Note:
4098   `DMRegister()` may be called multiple times to add several user-defined `DM`s
4099 
4100   Example Usage:
4101 .vb
4102     DMRegister("my_da", MyDMCreate);
4103 .ve
4104 
4105   Then, your `DM` type can be chosen with the procedural interface via
4106 .vb
4107     DMCreate(MPI_Comm, DM *);
4108     DMSetType(DM,"my_da");
4109 .ve
4110   or at runtime via the option
4111 .vb
4112     -da_type my_da
4113 .ve
4114 
4115 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()`
4116 @*/
4117 PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM))
4118 {
4119   PetscFunctionBegin;
4120   PetscCall(DMInitializePackage());
4121   PetscCall(PetscFunctionListAdd(&DMList, sname, function));
4122   PetscFunctionReturn(PETSC_SUCCESS);
4123 }
4124 
4125 /*@
4126   DMLoad - Loads a DM that has been stored in binary  with `DMView()`.
4127 
4128   Collective
4129 
4130   Input Parameters:
4131 + newdm  - the newly loaded `DM`, this needs to have been created with `DMCreate()` or
4132            some related function before a call to `DMLoad()`.
4133 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
4134            `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()`
4135 
4136   Level: intermediate
4137 
4138   Notes:
4139   The type is determined by the data in the file, any type set into the DM before this call is ignored.
4140 
4141   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
4142   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
4143   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
4144 
4145 .seealso: [](ch_dmbase), `DM`, `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()`
4146 @*/
4147 PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
4148 {
4149   PetscBool isbinary, ishdf5;
4150 
4151   PetscFunctionBegin;
4152   PetscValidHeaderSpecific(newdm, DM_CLASSID, 1);
4153   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
4154   PetscCall(PetscViewerCheckReadable(viewer));
4155   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
4156   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
4157   PetscCall(PetscLogEventBegin(DM_Load, viewer, 0, 0, 0));
4158   if (isbinary) {
4159     PetscInt classid;
4160     char     type[256];
4161 
4162     PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT));
4163     PetscCheck(classid == DM_FILE_CLASSID, PetscObjectComm((PetscObject)newdm), PETSC_ERR_ARG_WRONG, "Not DM next in file, classid found %d", (int)classid);
4164     PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
4165     PetscCall(DMSetType(newdm, type));
4166     PetscTryTypeMethod(newdm, load, viewer);
4167   } else if (ishdf5) {
4168     PetscTryTypeMethod(newdm, load, viewer);
4169   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4170   PetscCall(PetscLogEventEnd(DM_Load, viewer, 0, 0, 0));
4171   PetscFunctionReturn(PETSC_SUCCESS);
4172 }
4173 
4174 /******************************** FEM Support **********************************/
4175 
4176 PetscErrorCode DMPrintCellIndices(PetscInt c, const char name[], PetscInt len, const PetscInt x[])
4177 {
4178   PetscInt f;
4179 
4180   PetscFunctionBegin;
4181   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4182   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %" PetscInt_FMT " |\n", x[f]));
4183   PetscFunctionReturn(PETSC_SUCCESS);
4184 }
4185 
4186 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4187 {
4188   PetscInt f;
4189 
4190   PetscFunctionBegin;
4191   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4192   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f])));
4193   PetscFunctionReturn(PETSC_SUCCESS);
4194 }
4195 
4196 PetscErrorCode DMPrintCellVectorReal(PetscInt c, const char name[], PetscInt len, const PetscReal x[])
4197 {
4198   PetscInt f;
4199 
4200   PetscFunctionBegin;
4201   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4202   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)x[f]));
4203   PetscFunctionReturn(PETSC_SUCCESS);
4204 }
4205 
4206 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4207 {
4208   PetscInt f, g;
4209 
4210   PetscFunctionBegin;
4211   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4212   for (f = 0; f < rows; ++f) {
4213     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  |"));
4214     for (g = 0; g < cols; ++g) PetscCall(PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g])));
4215     PetscCall(PetscPrintf(PETSC_COMM_SELF, " |\n"));
4216   }
4217   PetscFunctionReturn(PETSC_SUCCESS);
4218 }
4219 
4220 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4221 {
4222   PetscInt           localSize, bs;
4223   PetscMPIInt        size;
4224   Vec                x, xglob;
4225   const PetscScalar *xarray;
4226 
4227   PetscFunctionBegin;
4228   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
4229   PetscCall(VecDuplicate(X, &x));
4230   PetscCall(VecCopy(X, x));
4231   PetscCall(VecFilter(x, tol));
4232   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name));
4233   if (size > 1) {
4234     PetscCall(VecGetLocalSize(x, &localSize));
4235     PetscCall(VecGetArrayRead(x, &xarray));
4236     PetscCall(VecGetBlockSize(x, &bs));
4237     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob));
4238   } else {
4239     xglob = x;
4240   }
4241   PetscCall(VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm))));
4242   if (size > 1) {
4243     PetscCall(VecDestroy(&xglob));
4244     PetscCall(VecRestoreArrayRead(x, &xarray));
4245   }
4246   PetscCall(VecDestroy(&x));
4247   PetscFunctionReturn(PETSC_SUCCESS);
4248 }
4249 
4250 /*@
4251   DMGetSection - Get the `PetscSection` encoding the local data layout for the `DM`.   This is equivalent to `DMGetLocalSection()`. Deprecated in v3.12
4252 
4253   Input Parameter:
4254 . dm - The `DM`
4255 
4256   Output Parameter:
4257 . section - The `PetscSection`
4258 
4259   Options Database Key:
4260 . -dm_petscsection_view - View the `PetscSection` created by the `DM`
4261 
4262   Level: advanced
4263 
4264   Notes:
4265   Use `DMGetLocalSection()` in new code.
4266 
4267   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4268 
4269 .seealso: [](ch_dmbase), `DM`, `DMGetLocalSection()`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4270 @*/
4271 PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4272 {
4273   PetscFunctionBegin;
4274   PetscCall(DMGetLocalSection(dm, section));
4275   PetscFunctionReturn(PETSC_SUCCESS);
4276 }
4277 
4278 /*@
4279   DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`.
4280 
4281   Input Parameter:
4282 . dm - The `DM`
4283 
4284   Output Parameter:
4285 . section - The `PetscSection`
4286 
4287   Options Database Key:
4288 . -dm_petscsection_view - View the section created by the `DM`
4289 
4290   Level: intermediate
4291 
4292   Note:
4293   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4294 
4295 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4296 @*/
4297 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4298 {
4299   PetscFunctionBegin;
4300   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4301   PetscAssertPointer(section, 2);
4302   if (!dm->localSection && dm->ops->createlocalsection) {
4303     PetscInt d;
4304 
4305     if (dm->setfromoptionscalled) {
4306       PetscObject       obj = (PetscObject)dm;
4307       PetscViewer       viewer;
4308       PetscViewerFormat format;
4309       PetscBool         flg;
4310 
4311       PetscCall(PetscOptionsCreateViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg));
4312       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
4313       for (d = 0; d < dm->Nds; ++d) {
4314         PetscCall(PetscDSSetFromOptions(dm->probs[d].ds));
4315         if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer));
4316       }
4317       if (flg) {
4318         PetscCall(PetscViewerFlush(viewer));
4319         PetscCall(PetscViewerPopFormat(viewer));
4320         PetscCall(PetscViewerDestroy(&viewer));
4321       }
4322     }
4323     PetscUseTypeMethod(dm, createlocalsection);
4324     if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view"));
4325   }
4326   *section = dm->localSection;
4327   PetscFunctionReturn(PETSC_SUCCESS);
4328 }
4329 
4330 /*@
4331   DMSetSection - Set the `PetscSection` encoding the local data layout for the `DM`.  This is equivalent to `DMSetLocalSection()`. Deprecated in v3.12
4332 
4333   Input Parameters:
4334 + dm      - The `DM`
4335 - section - The `PetscSection`
4336 
4337   Level: advanced
4338 
4339   Notes:
4340   Use `DMSetLocalSection()` in new code.
4341 
4342   Any existing `PetscSection` will be destroyed
4343 
4344 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4345 @*/
4346 PetscErrorCode DMSetSection(DM dm, PetscSection section)
4347 {
4348   PetscFunctionBegin;
4349   PetscCall(DMSetLocalSection(dm, section));
4350   PetscFunctionReturn(PETSC_SUCCESS);
4351 }
4352 
4353 /*@
4354   DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.
4355 
4356   Input Parameters:
4357 + dm      - The `DM`
4358 - section - The `PetscSection`
4359 
4360   Level: intermediate
4361 
4362   Note:
4363   Any existing Section will be destroyed
4364 
4365 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4366 @*/
4367 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4368 {
4369   PetscInt numFields = 0;
4370   PetscInt f;
4371 
4372   PetscFunctionBegin;
4373   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4374   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4375   PetscCall(PetscObjectReference((PetscObject)section));
4376   PetscCall(PetscSectionDestroy(&dm->localSection));
4377   dm->localSection = section;
4378   if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields));
4379   if (numFields) {
4380     PetscCall(DMSetNumFields(dm, numFields));
4381     for (f = 0; f < numFields; ++f) {
4382       PetscObject disc;
4383       const char *name;
4384 
4385       PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name));
4386       PetscCall(DMGetField(dm, f, NULL, &disc));
4387       PetscCall(PetscObjectSetName(disc, name));
4388     }
4389   }
4390   /* The global section and the SectionSF will be rebuilt
4391      in the next call to DMGetGlobalSection() and DMGetSectionSF(). */
4392   PetscCall(PetscSectionDestroy(&dm->globalSection));
4393   PetscCall(PetscSFDestroy(&dm->sectionSF));
4394   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4395 
4396   /* Clear scratch vectors */
4397   PetscCall(DMClearGlobalVectors(dm));
4398   PetscCall(DMClearLocalVectors(dm));
4399   PetscCall(DMClearNamedGlobalVectors(dm));
4400   PetscCall(DMClearNamedLocalVectors(dm));
4401   PetscFunctionReturn(PETSC_SUCCESS);
4402 }
4403 
4404 /*@C
4405   DMCreateSectionPermutation - Create a permutation of the `PetscSection` chart and optionally a block structure.
4406 
4407   Input Parameter:
4408 . dm - The `DM`
4409 
4410   Output Parameters:
4411 + perm        - A permutation of the mesh points in the chart
4412 - blockStarts - A high bit is set for the point that begins every block, or `NULL` for default blocking
4413 
4414   Level: developer
4415 
4416 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4417 @*/
4418 PetscErrorCode DMCreateSectionPermutation(DM dm, IS *perm, PetscBT *blockStarts)
4419 {
4420   PetscFunctionBegin;
4421   *perm        = NULL;
4422   *blockStarts = NULL;
4423   PetscTryTypeMethod(dm, createsectionpermutation, perm, blockStarts);
4424   PetscFunctionReturn(PETSC_SUCCESS);
4425 }
4426 
4427 /*@
4428   DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation.
4429 
4430   not Collective
4431 
4432   Input Parameter:
4433 . dm - The `DM`
4434 
4435   Output Parameters:
4436 + section - The `PetscSection` describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.  Returns `NULL` if there are no local constraints.
4437 . mat     - The `Mat` that interpolates local constraints: its width should be the layout size of the default section.  Returns `NULL` if there are no local constraints.
4438 - bias    - Vector containing bias to be added to constrained dofs
4439 
4440   Level: advanced
4441 
4442   Note:
4443   This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`.
4444 
4445 .seealso: [](ch_dmbase), `DM`, `DMSetDefaultConstraints()`
4446 @*/
4447 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4448 {
4449   PetscFunctionBegin;
4450   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4451   if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4452   if (section) *section = dm->defaultConstraint.section;
4453   if (mat) *mat = dm->defaultConstraint.mat;
4454   if (bias) *bias = dm->defaultConstraint.bias;
4455   PetscFunctionReturn(PETSC_SUCCESS);
4456 }
4457 
4458 /*@
4459   DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.
4460 
4461   Collective
4462 
4463   Input Parameters:
4464 + dm      - The `DM`
4465 . section - The `PetscSection` describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4466 . mat     - The `Mat` that interpolates local constraints: its width should be the layout size of the default section:  `NULL` indicates no constraints.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4467 - bias    - A bias vector to be added to constrained values in the local vector.  `NULL` indicates no bias.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4468 
4469   Level: advanced
4470 
4471   Notes:
4472   If a constraint matrix is specified, then it is applied during `DMGlobalToLocalEnd()` when mode is `INSERT_VALUES`, `INSERT_BC_VALUES`, or `INSERT_ALL_VALUES`.  Without a constraint matrix, the local vector l returned by `DMGlobalToLocalEnd()` contains values that have been scattered from a global vector without modification; with a constraint matrix A, l is modified by computing c = A * l + bias, l[s[i]] = c[i], where the scatter s is defined by the `PetscSection` returned by `DMGetDefaultConstraints()`.
4473 
4474   If a constraint matrix is specified, then its adjoint is applied during `DMLocalToGlobalBegin()` when mode is `ADD_VALUES`, `ADD_BC_VALUES`, or `ADD_ALL_VALUES`.  Without a constraint matrix, the local vector l is accumulated into a global vector without modification; with a constraint matrix A, l is first modified by computing c[i] = l[s[i]], l[s[i]] = 0, l = l + A'*c, which is the adjoint of the operation described above.  Any bias, if specified, is ignored when accumulating.
4475 
4476   This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them.
4477 
4478 .seealso: [](ch_dmbase), `DM`, `DMGetDefaultConstraints()`
4479 @*/
4480 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4481 {
4482   PetscMPIInt result;
4483 
4484   PetscFunctionBegin;
4485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4486   if (section) {
4487     PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4488     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result));
4489     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator");
4490   }
4491   if (mat) {
4492     PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
4493     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result));
4494     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator");
4495   }
4496   if (bias) {
4497     PetscValidHeaderSpecific(bias, VEC_CLASSID, 4);
4498     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result));
4499     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator");
4500   }
4501   PetscCall(PetscObjectReference((PetscObject)section));
4502   PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section));
4503   dm->defaultConstraint.section = section;
4504   PetscCall(PetscObjectReference((PetscObject)mat));
4505   PetscCall(MatDestroy(&dm->defaultConstraint.mat));
4506   dm->defaultConstraint.mat = mat;
4507   PetscCall(PetscObjectReference((PetscObject)bias));
4508   PetscCall(VecDestroy(&dm->defaultConstraint.bias));
4509   dm->defaultConstraint.bias = bias;
4510   PetscFunctionReturn(PETSC_SUCCESS);
4511 }
4512 
4513 #if defined(PETSC_USE_DEBUG)
4514 /*
4515   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.
4516 
4517   Input Parameters:
4518 + dm - The `DM`
4519 . localSection - `PetscSection` describing the local data layout
4520 - globalSection - `PetscSection` describing the global data layout
4521 
4522   Level: intermediate
4523 
4524 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`
4525 */
4526 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4527 {
4528   MPI_Comm        comm;
4529   PetscLayout     layout;
4530   const PetscInt *ranges;
4531   PetscInt        pStart, pEnd, p, nroots;
4532   PetscMPIInt     size, rank;
4533   PetscBool       valid = PETSC_TRUE, gvalid;
4534 
4535   PetscFunctionBegin;
4536   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4537   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4538   PetscCallMPI(MPI_Comm_size(comm, &size));
4539   PetscCallMPI(MPI_Comm_rank(comm, &rank));
4540   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
4541   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
4542   PetscCall(PetscLayoutCreate(comm, &layout));
4543   PetscCall(PetscLayoutSetBlockSize(layout, 1));
4544   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
4545   PetscCall(PetscLayoutSetUp(layout));
4546   PetscCall(PetscLayoutGetRanges(layout, &ranges));
4547   for (p = pStart; p < pEnd; ++p) {
4548     PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4549 
4550     PetscCall(PetscSectionGetDof(localSection, p, &dof));
4551     PetscCall(PetscSectionGetOffset(localSection, p, &off));
4552     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
4553     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
4554     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
4555     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
4556     if (!gdof) continue; /* Censored point */
4557     if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4558       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof));
4559       valid = PETSC_FALSE;
4560     }
4561     if (gcdof && (gcdof != cdof)) {
4562       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof));
4563       valid = PETSC_FALSE;
4564     }
4565     if (gdof < 0) {
4566       gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4567       for (d = 0; d < gsize; ++d) {
4568         PetscInt offset = -(goff + 1) + d, r;
4569 
4570         PetscCall(PetscFindInt(offset, size + 1, ranges, &r));
4571         if (r < 0) r = -(r + 2);
4572         if ((r < 0) || (r >= size)) {
4573           PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff));
4574           valid = PETSC_FALSE;
4575           break;
4576         }
4577       }
4578     }
4579   }
4580   PetscCall(PetscLayoutDestroy(&layout));
4581   PetscCall(PetscSynchronizedFlush(comm, NULL));
4582   PetscCall(MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm));
4583   if (!gvalid) {
4584     PetscCall(DMView(dm, NULL));
4585     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4586   }
4587   PetscFunctionReturn(PETSC_SUCCESS);
4588 }
4589 #endif
4590 
4591 static PetscErrorCode DMGetIsoperiodicPointSF_Internal(DM dm, PetscSF *sf)
4592 {
4593   PetscErrorCode (*f)(DM, PetscSF *);
4594 
4595   PetscFunctionBegin;
4596   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4597   PetscAssertPointer(sf, 2);
4598   PetscCall(PetscObjectQueryFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", &f));
4599   if (f) PetscCall(f(dm, sf));
4600   else *sf = dm->sf;
4601   PetscFunctionReturn(PETSC_SUCCESS);
4602 }
4603 
4604 /*@
4605   DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.
4606 
4607   Collective
4608 
4609   Input Parameter:
4610 . dm - The `DM`
4611 
4612   Output Parameter:
4613 . section - The `PetscSection`
4614 
4615   Level: intermediate
4616 
4617   Note:
4618   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4619 
4620 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`
4621 @*/
4622 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4623 {
4624   PetscFunctionBegin;
4625   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4626   PetscAssertPointer(section, 2);
4627   if (!dm->globalSection) {
4628     PetscSection s;
4629     PetscSF      sf;
4630 
4631     PetscCall(DMGetLocalSection(dm, &s));
4632     PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4633     PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4634     PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &sf));
4635     PetscCall(PetscSectionCreateGlobalSection(s, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &dm->globalSection));
4636     PetscCall(PetscLayoutDestroy(&dm->map));
4637     PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map));
4638     PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view"));
4639   }
4640   *section = dm->globalSection;
4641   PetscFunctionReturn(PETSC_SUCCESS);
4642 }
4643 
4644 /*@
4645   DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.
4646 
4647   Input Parameters:
4648 + dm      - The `DM`
4649 - section - The PetscSection, or `NULL`
4650 
4651   Level: intermediate
4652 
4653   Note:
4654   Any existing `PetscSection` will be destroyed
4655 
4656 .seealso: [](ch_dmbase), `DM`, `DMGetGlobalSection()`, `DMSetLocalSection()`
4657 @*/
4658 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4659 {
4660   PetscFunctionBegin;
4661   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4662   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4663   PetscCall(PetscObjectReference((PetscObject)section));
4664   PetscCall(PetscSectionDestroy(&dm->globalSection));
4665   dm->globalSection = section;
4666 #if defined(PETSC_USE_DEBUG)
4667   if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section));
4668 #endif
4669   /* Clear global scratch vectors and sectionSF */
4670   PetscCall(PetscSFDestroy(&dm->sectionSF));
4671   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4672   PetscCall(DMClearGlobalVectors(dm));
4673   PetscCall(DMClearNamedGlobalVectors(dm));
4674   PetscFunctionReturn(PETSC_SUCCESS);
4675 }
4676 
4677 /*@
4678   DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set,
4679   it is created from the default `PetscSection` layouts in the `DM`.
4680 
4681   Input Parameter:
4682 . dm - The `DM`
4683 
4684   Output Parameter:
4685 . sf - The `PetscSF`
4686 
4687   Level: intermediate
4688 
4689   Note:
4690   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4691 
4692 .seealso: [](ch_dmbase), `DM`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4693 @*/
4694 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4695 {
4696   PetscInt nroots;
4697 
4698   PetscFunctionBegin;
4699   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4700   PetscAssertPointer(sf, 2);
4701   if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4702   PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL));
4703   if (nroots < 0) {
4704     PetscSection section, gSection;
4705 
4706     PetscCall(DMGetLocalSection(dm, &section));
4707     if (section) {
4708       PetscCall(DMGetGlobalSection(dm, &gSection));
4709       PetscCall(DMCreateSectionSF(dm, section, gSection));
4710     } else {
4711       *sf = NULL;
4712       PetscFunctionReturn(PETSC_SUCCESS);
4713     }
4714   }
4715   *sf = dm->sectionSF;
4716   PetscFunctionReturn(PETSC_SUCCESS);
4717 }
4718 
4719 /*@
4720   DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`
4721 
4722   Input Parameters:
4723 + dm - The `DM`
4724 - sf - The `PetscSF`
4725 
4726   Level: intermediate
4727 
4728   Note:
4729   Any previous `PetscSF` is destroyed
4730 
4731 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMCreateSectionSF()`
4732 @*/
4733 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4734 {
4735   PetscFunctionBegin;
4736   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4737   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4738   PetscCall(PetscObjectReference((PetscObject)sf));
4739   PetscCall(PetscSFDestroy(&dm->sectionSF));
4740   dm->sectionSF = sf;
4741   PetscFunctionReturn(PETSC_SUCCESS);
4742 }
4743 
4744 /*@
4745   DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4746   describing the data layout.
4747 
4748   Input Parameters:
4749 + dm            - The `DM`
4750 . localSection  - `PetscSection` describing the local data layout
4751 - globalSection - `PetscSection` describing the global data layout
4752 
4753   Level: developer
4754 
4755   Note:
4756   One usually uses `DMGetSectionSF()` to obtain the `PetscSF`
4757 
4758   Developer Note:
4759   Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF`
4760   directly into the `DM`, perhaps this function should not take the local and global sections as
4761   input and should just obtain them from the `DM`? Plus PETSc creation functions return the thing
4762   they create, this returns nothing
4763 
4764 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4765 @*/
4766 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4767 {
4768   PetscFunctionBegin;
4769   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4770   PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection));
4771   PetscFunctionReturn(PETSC_SUCCESS);
4772 }
4773 
4774 /*@
4775   DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.
4776 
4777   Not collective but the resulting `PetscSF` is collective
4778 
4779   Input Parameter:
4780 . dm - The `DM`
4781 
4782   Output Parameter:
4783 . sf - The `PetscSF`
4784 
4785   Level: intermediate
4786 
4787   Note:
4788   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4789 
4790 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4791 @*/
4792 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4793 {
4794   PetscFunctionBegin;
4795   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4796   PetscAssertPointer(sf, 2);
4797   *sf = dm->sf;
4798   PetscFunctionReturn(PETSC_SUCCESS);
4799 }
4800 
4801 /*@
4802   DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.
4803 
4804   Collective
4805 
4806   Input Parameters:
4807 + dm - The `DM`
4808 - sf - The `PetscSF`
4809 
4810   Level: intermediate
4811 
4812 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4813 @*/
4814 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4815 {
4816   PetscFunctionBegin;
4817   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4818   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4819   PetscCall(PetscObjectReference((PetscObject)sf));
4820   PetscCall(PetscSFDestroy(&dm->sf));
4821   dm->sf = sf;
4822   PetscFunctionReturn(PETSC_SUCCESS);
4823 }
4824 
4825 /*@
4826   DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering
4827 
4828   Input Parameter:
4829 . dm - The `DM`
4830 
4831   Output Parameter:
4832 . sf - The `PetscSF`
4833 
4834   Level: intermediate
4835 
4836   Note:
4837   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4838 
4839 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4840 @*/
4841 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4842 {
4843   PetscFunctionBegin;
4844   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4845   PetscAssertPointer(sf, 2);
4846   *sf = dm->sfNatural;
4847   PetscFunctionReturn(PETSC_SUCCESS);
4848 }
4849 
4850 /*@
4851   DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4852 
4853   Input Parameters:
4854 + dm - The DM
4855 - sf - The PetscSF
4856 
4857   Level: intermediate
4858 
4859 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4860 @*/
4861 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4862 {
4863   PetscFunctionBegin;
4864   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4865   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4866   PetscCall(PetscObjectReference((PetscObject)sf));
4867   PetscCall(PetscSFDestroy(&dm->sfNatural));
4868   dm->sfNatural = sf;
4869   PetscFunctionReturn(PETSC_SUCCESS);
4870 }
4871 
4872 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4873 {
4874   PetscClassId id;
4875 
4876   PetscFunctionBegin;
4877   PetscCall(PetscObjectGetClassId(disc, &id));
4878   if (id == PETSCFE_CLASSID) {
4879     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4880   } else if (id == PETSCFV_CLASSID) {
4881     PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE));
4882   } else {
4883     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4884   }
4885   PetscFunctionReturn(PETSC_SUCCESS);
4886 }
4887 
4888 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4889 {
4890   RegionField *tmpr;
4891   PetscInt     Nf = dm->Nf, f;
4892 
4893   PetscFunctionBegin;
4894   if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS);
4895   PetscCall(PetscMalloc1(NfNew, &tmpr));
4896   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4897   for (f = Nf; f < NfNew; ++f) {
4898     tmpr[f].disc        = NULL;
4899     tmpr[f].label       = NULL;
4900     tmpr[f].avoidTensor = PETSC_FALSE;
4901   }
4902   PetscCall(PetscFree(dm->fields));
4903   dm->Nf     = NfNew;
4904   dm->fields = tmpr;
4905   PetscFunctionReturn(PETSC_SUCCESS);
4906 }
4907 
4908 /*@
4909   DMClearFields - Remove all fields from the `DM`
4910 
4911   Logically Collective
4912 
4913   Input Parameter:
4914 . dm - The `DM`
4915 
4916   Level: intermediate
4917 
4918 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4919 @*/
4920 PetscErrorCode DMClearFields(DM dm)
4921 {
4922   PetscInt f;
4923 
4924   PetscFunctionBegin;
4925   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4926   for (f = 0; f < dm->Nf; ++f) {
4927     PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4928     PetscCall(DMLabelDestroy(&dm->fields[f].label));
4929   }
4930   PetscCall(PetscFree(dm->fields));
4931   dm->fields = NULL;
4932   dm->Nf     = 0;
4933   PetscFunctionReturn(PETSC_SUCCESS);
4934 }
4935 
4936 /*@
4937   DMGetNumFields - Get the number of fields in the `DM`
4938 
4939   Not Collective
4940 
4941   Input Parameter:
4942 . dm - The `DM`
4943 
4944   Output Parameter:
4945 . numFields - The number of fields
4946 
4947   Level: intermediate
4948 
4949 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()`
4950 @*/
4951 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4952 {
4953   PetscFunctionBegin;
4954   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4955   PetscAssertPointer(numFields, 2);
4956   *numFields = dm->Nf;
4957   PetscFunctionReturn(PETSC_SUCCESS);
4958 }
4959 
4960 /*@
4961   DMSetNumFields - Set the number of fields in the `DM`
4962 
4963   Logically Collective
4964 
4965   Input Parameters:
4966 + dm        - The `DM`
4967 - numFields - The number of fields
4968 
4969   Level: intermediate
4970 
4971 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()`
4972 @*/
4973 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4974 {
4975   PetscInt Nf, f;
4976 
4977   PetscFunctionBegin;
4978   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4979   PetscCall(DMGetNumFields(dm, &Nf));
4980   for (f = Nf; f < numFields; ++f) {
4981     PetscContainer obj;
4982 
4983     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj));
4984     PetscCall(DMAddField(dm, NULL, (PetscObject)obj));
4985     PetscCall(PetscContainerDestroy(&obj));
4986   }
4987   PetscFunctionReturn(PETSC_SUCCESS);
4988 }
4989 
4990 /*@
4991   DMGetField - Return the `DMLabel` and discretization object for a given `DM` field
4992 
4993   Not Collective
4994 
4995   Input Parameters:
4996 + dm - The `DM`
4997 - f  - The field number
4998 
4999   Output Parameters:
5000 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed)
5001 - disc  - The discretization object (pass in `NULL` if not needed)
5002 
5003   Level: intermediate
5004 
5005 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`
5006 @*/
5007 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
5008 {
5009   PetscFunctionBegin;
5010   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5011   PetscAssertPointer(disc, 4);
5012   PetscCheck((f >= 0) && (f < dm->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, dm->Nf);
5013   if (label) *label = dm->fields[f].label;
5014   if (disc) *disc = dm->fields[f].disc;
5015   PetscFunctionReturn(PETSC_SUCCESS);
5016 }
5017 
5018 /* Does not clear the DS */
5019 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5020 {
5021   PetscFunctionBegin;
5022   PetscCall(DMFieldEnlarge_Static(dm, f + 1));
5023   PetscCall(DMLabelDestroy(&dm->fields[f].label));
5024   PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
5025   dm->fields[f].label = label;
5026   dm->fields[f].disc  = disc;
5027   PetscCall(PetscObjectReference((PetscObject)label));
5028   PetscCall(PetscObjectReference((PetscObject)disc));
5029   PetscFunctionReturn(PETSC_SUCCESS);
5030 }
5031 
5032 /*@
5033   DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
5034   the field numbering.
5035 
5036   Logically Collective
5037 
5038   Input Parameters:
5039 + dm    - The `DM`
5040 . f     - The field number
5041 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5042 - disc  - The discretization object
5043 
5044   Level: intermediate
5045 
5046 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`
5047 @*/
5048 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5049 {
5050   PetscFunctionBegin;
5051   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5052   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5053   PetscValidHeader(disc, 4);
5054   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
5055   PetscCall(DMSetField_Internal(dm, f, label, disc));
5056   PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc));
5057   PetscCall(DMClearDS(dm));
5058   PetscFunctionReturn(PETSC_SUCCESS);
5059 }
5060 
5061 /*@
5062   DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
5063   and a discretization object that defines the function space associated with those points.
5064 
5065   Logically Collective
5066 
5067   Input Parameters:
5068 + dm    - The `DM`
5069 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5070 - disc  - The discretization object
5071 
5072   Level: intermediate
5073 
5074   Notes:
5075   The label already exists or will be added to the `DM` with `DMSetLabel()`.
5076 
5077   For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
5078   within each cell. Thus a specific function in the space is defined by the combination of a `Vec` containing the coefficients, a `DM` defining the
5079   geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.
5080 
5081 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
5082 @*/
5083 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
5084 {
5085   PetscInt Nf = dm->Nf;
5086 
5087   PetscFunctionBegin;
5088   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5089   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5090   PetscValidHeader(disc, 3);
5091   PetscCall(DMFieldEnlarge_Static(dm, Nf + 1));
5092   dm->fields[Nf].label = label;
5093   dm->fields[Nf].disc  = disc;
5094   PetscCall(PetscObjectReference((PetscObject)label));
5095   PetscCall(PetscObjectReference((PetscObject)disc));
5096   PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc));
5097   PetscCall(DMClearDS(dm));
5098   PetscFunctionReturn(PETSC_SUCCESS);
5099 }
5100 
5101 /*@
5102   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
5103 
5104   Logically Collective
5105 
5106   Input Parameters:
5107 + dm          - The `DM`
5108 . f           - The field index
5109 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells
5110 
5111   Level: intermediate
5112 
5113 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
5114 @*/
5115 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
5116 {
5117   PetscFunctionBegin;
5118   PetscCheck((f >= 0) && (f < dm->Nf), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", f, dm->Nf);
5119   dm->fields[f].avoidTensor = avoidTensor;
5120   PetscFunctionReturn(PETSC_SUCCESS);
5121 }
5122 
5123 /*@
5124   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
5125 
5126   Not Collective
5127 
5128   Input Parameters:
5129 + dm - The `DM`
5130 - f  - The field index
5131 
5132   Output Parameter:
5133 . avoidTensor - The flag to avoid defining the field on tensor cells
5134 
5135   Level: intermediate
5136 
5137 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`
5138 @*/
5139 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
5140 {
5141   PetscFunctionBegin;
5142   PetscCheck((f >= 0) && (f < dm->Nf), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", f, dm->Nf);
5143   *avoidTensor = dm->fields[f].avoidTensor;
5144   PetscFunctionReturn(PETSC_SUCCESS);
5145 }
5146 
5147 /*@
5148   DMCopyFields - Copy the discretizations for the `DM` into another `DM`
5149 
5150   Collective
5151 
5152   Input Parameter:
5153 . dm - The `DM`
5154 
5155   Output Parameter:
5156 . newdm - The `DM`
5157 
5158   Level: advanced
5159 
5160 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
5161 @*/
5162 PetscErrorCode DMCopyFields(DM dm, DM newdm)
5163 {
5164   PetscInt Nf, f;
5165 
5166   PetscFunctionBegin;
5167   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
5168   PetscCall(DMGetNumFields(dm, &Nf));
5169   PetscCall(DMClearFields(newdm));
5170   for (f = 0; f < Nf; ++f) {
5171     DMLabel     label;
5172     PetscObject field;
5173     PetscBool   useCone, useClosure;
5174 
5175     PetscCall(DMGetField(dm, f, &label, &field));
5176     PetscCall(DMSetField(newdm, f, label, field));
5177     PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
5178     PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure));
5179   }
5180   PetscFunctionReturn(PETSC_SUCCESS);
5181 }
5182 
5183 /*@
5184   DMGetAdjacency - Returns the flags for determining variable influence
5185 
5186   Not Collective
5187 
5188   Input Parameters:
5189 + dm - The `DM` object
5190 - f  - The field number, or `PETSC_DEFAULT` for the default adjacency
5191 
5192   Output Parameters:
5193 + useCone    - Flag for variable influence starting with the cone operation
5194 - useClosure - Flag for variable influence using transitive closure
5195 
5196   Level: developer
5197 
5198   Notes:
5199 .vb
5200      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5201      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5202      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5203 .ve
5204   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5205 
5206 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
5207 @*/
5208 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
5209 {
5210   PetscFunctionBegin;
5211   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5212   if (useCone) PetscAssertPointer(useCone, 3);
5213   if (useClosure) PetscAssertPointer(useClosure, 4);
5214   if (f < 0) {
5215     if (useCone) *useCone = dm->adjacency[0];
5216     if (useClosure) *useClosure = dm->adjacency[1];
5217   } else {
5218     PetscInt Nf;
5219 
5220     PetscCall(DMGetNumFields(dm, &Nf));
5221     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5222     if (useCone) *useCone = dm->fields[f].adjacency[0];
5223     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5224   }
5225   PetscFunctionReturn(PETSC_SUCCESS);
5226 }
5227 
5228 /*@
5229   DMSetAdjacency - Set the flags for determining variable influence
5230 
5231   Not Collective
5232 
5233   Input Parameters:
5234 + dm         - The `DM` object
5235 . f          - The field number
5236 . useCone    - Flag for variable influence starting with the cone operation
5237 - useClosure - Flag for variable influence using transitive closure
5238 
5239   Level: developer
5240 
5241   Notes:
5242 .vb
5243      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5244      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5245      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5246 .ve
5247   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5248 
5249 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
5250 @*/
5251 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5252 {
5253   PetscFunctionBegin;
5254   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5255   if (f < 0) {
5256     dm->adjacency[0] = useCone;
5257     dm->adjacency[1] = useClosure;
5258   } else {
5259     PetscInt Nf;
5260 
5261     PetscCall(DMGetNumFields(dm, &Nf));
5262     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5263     dm->fields[f].adjacency[0] = useCone;
5264     dm->fields[f].adjacency[1] = useClosure;
5265   }
5266   PetscFunctionReturn(PETSC_SUCCESS);
5267 }
5268 
5269 /*@
5270   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5271 
5272   Not collective
5273 
5274   Input Parameter:
5275 . dm - The `DM` object
5276 
5277   Output Parameters:
5278 + useCone    - Flag for variable influence starting with the cone operation
5279 - useClosure - Flag for variable influence using transitive closure
5280 
5281   Level: developer
5282 
5283   Notes:
5284 .vb
5285      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5286      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5287      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5288 .ve
5289 
5290 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5291 @*/
5292 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5293 {
5294   PetscInt Nf;
5295 
5296   PetscFunctionBegin;
5297   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5298   if (useCone) PetscAssertPointer(useCone, 2);
5299   if (useClosure) PetscAssertPointer(useClosure, 3);
5300   PetscCall(DMGetNumFields(dm, &Nf));
5301   if (!Nf) {
5302     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5303   } else {
5304     PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure));
5305   }
5306   PetscFunctionReturn(PETSC_SUCCESS);
5307 }
5308 
5309 /*@
5310   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5311 
5312   Not Collective
5313 
5314   Input Parameters:
5315 + dm         - The `DM` object
5316 . useCone    - Flag for variable influence starting with the cone operation
5317 - useClosure - Flag for variable influence using transitive closure
5318 
5319   Level: developer
5320 
5321   Notes:
5322 .vb
5323      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5324      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5325      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5326 .ve
5327 
5328 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5329 @*/
5330 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5331 {
5332   PetscInt Nf;
5333 
5334   PetscFunctionBegin;
5335   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5336   PetscCall(DMGetNumFields(dm, &Nf));
5337   if (!Nf) {
5338     PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5339   } else {
5340     PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure));
5341   }
5342   PetscFunctionReturn(PETSC_SUCCESS);
5343 }
5344 
5345 PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5346 {
5347   DM           plex;
5348   DMLabel     *labels, *glabels;
5349   const char **names;
5350   char        *sendNames, *recvNames;
5351   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5352   size_t       len;
5353   MPI_Comm     comm;
5354   PetscMPIInt  rank, size, p, *counts, *displs;
5355 
5356   PetscFunctionBegin;
5357   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5358   PetscCallMPI(MPI_Comm_size(comm, &size));
5359   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5360   PetscCall(DMGetNumDS(dm, &Nds));
5361   for (s = 0; s < Nds; ++s) {
5362     PetscDS  dsBC;
5363     PetscInt numBd;
5364 
5365     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5366     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5367     maxLabels += numBd;
5368   }
5369   PetscCall(PetscCalloc1(maxLabels, &labels));
5370   /* Get list of labels to be completed */
5371   for (s = 0; s < Nds; ++s) {
5372     PetscDS  dsBC;
5373     PetscInt numBd, bd;
5374 
5375     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5376     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5377     for (bd = 0; bd < numBd; ++bd) {
5378       DMLabel      label;
5379       PetscInt     field;
5380       PetscObject  obj;
5381       PetscClassId id;
5382 
5383       PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
5384       PetscCall(DMGetField(dm, field, NULL, &obj));
5385       PetscCall(PetscObjectGetClassId(obj, &id));
5386       if (!(id == PETSCFE_CLASSID) || !label) continue;
5387       for (l = 0; l < Nl; ++l)
5388         if (labels[l] == label) break;
5389       if (l == Nl) labels[Nl++] = label;
5390     }
5391   }
5392   /* Get label names */
5393   PetscCall(PetscMalloc1(Nl, &names));
5394   for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l]));
5395   for (l = 0; l < Nl; ++l) {
5396     PetscCall(PetscStrlen(names[l], &len));
5397     maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5398   }
5399   PetscCall(PetscFree(labels));
5400   PetscCall(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm));
5401   PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames));
5402   for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen));
5403   PetscCall(PetscFree(names));
5404   /* Put all names on all processes */
5405   PetscCall(PetscCalloc2(size, &counts, size + 1, &displs));
5406   PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm));
5407   for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5408   gNl = displs[size];
5409   for (p = 0; p < size; ++p) {
5410     counts[p] *= gmaxLen;
5411     displs[p] *= gmaxLen;
5412   }
5413   PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels));
5414   PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm));
5415   PetscCall(PetscFree2(counts, displs));
5416   PetscCall(PetscFree(sendNames));
5417   for (l = 0, gl = 0; l < gNl; ++l) {
5418     PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]));
5419     PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank);
5420     for (m = 0; m < gl; ++m)
5421       if (glabels[m] == glabels[gl]) continue;
5422     PetscCall(DMConvert(dm, DMPLEX, &plex));
5423     PetscCall(DMPlexLabelComplete(plex, glabels[gl]));
5424     PetscCall(DMDestroy(&plex));
5425     ++gl;
5426   }
5427   PetscCall(PetscFree2(recvNames, glabels));
5428   PetscFunctionReturn(PETSC_SUCCESS);
5429 }
5430 
5431 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5432 {
5433   DMSpace *tmpd;
5434   PetscInt Nds = dm->Nds, s;
5435 
5436   PetscFunctionBegin;
5437   if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS);
5438   PetscCall(PetscMalloc1(NdsNew, &tmpd));
5439   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5440   for (s = Nds; s < NdsNew; ++s) {
5441     tmpd[s].ds     = NULL;
5442     tmpd[s].label  = NULL;
5443     tmpd[s].fields = NULL;
5444   }
5445   PetscCall(PetscFree(dm->probs));
5446   dm->Nds   = NdsNew;
5447   dm->probs = tmpd;
5448   PetscFunctionReturn(PETSC_SUCCESS);
5449 }
5450 
5451 /*@
5452   DMGetNumDS - Get the number of discrete systems in the `DM`
5453 
5454   Not Collective
5455 
5456   Input Parameter:
5457 . dm - The `DM`
5458 
5459   Output Parameter:
5460 . Nds - The number of `PetscDS` objects
5461 
5462   Level: intermediate
5463 
5464 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()`
5465 @*/
5466 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5467 {
5468   PetscFunctionBegin;
5469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5470   PetscAssertPointer(Nds, 2);
5471   *Nds = dm->Nds;
5472   PetscFunctionReturn(PETSC_SUCCESS);
5473 }
5474 
5475 /*@
5476   DMClearDS - Remove all discrete systems from the `DM`
5477 
5478   Logically Collective
5479 
5480   Input Parameter:
5481 . dm - The `DM`
5482 
5483   Level: intermediate
5484 
5485 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5486 @*/
5487 PetscErrorCode DMClearDS(DM dm)
5488 {
5489   PetscInt s;
5490 
5491   PetscFunctionBegin;
5492   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5493   for (s = 0; s < dm->Nds; ++s) {
5494     PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5495     PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5496     PetscCall(DMLabelDestroy(&dm->probs[s].label));
5497     PetscCall(ISDestroy(&dm->probs[s].fields));
5498   }
5499   PetscCall(PetscFree(dm->probs));
5500   dm->probs = NULL;
5501   dm->Nds   = 0;
5502   PetscFunctionReturn(PETSC_SUCCESS);
5503 }
5504 
5505 /*@
5506   DMGetDS - Get the default `PetscDS`
5507 
5508   Not Collective
5509 
5510   Input Parameter:
5511 . dm - The `DM`
5512 
5513   Output Parameter:
5514 . ds - The default `PetscDS`
5515 
5516   Level: intermediate
5517 
5518 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()`
5519 @*/
5520 PetscErrorCode DMGetDS(DM dm, PetscDS *ds)
5521 {
5522   PetscFunctionBeginHot;
5523   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5524   PetscAssertPointer(ds, 2);
5525   PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()");
5526   *ds = dm->probs[0].ds;
5527   PetscFunctionReturn(PETSC_SUCCESS);
5528 }
5529 
5530 /*@
5531   DMGetCellDS - Get the `PetscDS` defined on a given cell
5532 
5533   Not Collective
5534 
5535   Input Parameters:
5536 + dm    - The `DM`
5537 - point - Cell for the `PetscDS`
5538 
5539   Output Parameters:
5540 + ds   - The `PetscDS` defined on the given cell
5541 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds
5542 
5543   Level: developer
5544 
5545 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()`
5546 @*/
5547 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn)
5548 {
5549   PetscDS  dsDef = NULL;
5550   PetscInt s;
5551 
5552   PetscFunctionBeginHot;
5553   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5554   if (ds) PetscAssertPointer(ds, 3);
5555   if (dsIn) PetscAssertPointer(dsIn, 4);
5556   PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5557   if (ds) *ds = NULL;
5558   if (dsIn) *dsIn = NULL;
5559   for (s = 0; s < dm->Nds; ++s) {
5560     PetscInt val;
5561 
5562     if (!dm->probs[s].label) {
5563       dsDef = dm->probs[s].ds;
5564     } else {
5565       PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5566       if (val >= 0) {
5567         if (ds) *ds = dm->probs[s].ds;
5568         if (dsIn) *dsIn = dm->probs[s].dsIn;
5569         break;
5570       }
5571     }
5572   }
5573   if (ds && !*ds) *ds = dsDef;
5574   PetscFunctionReturn(PETSC_SUCCESS);
5575 }
5576 
5577 /*@
5578   DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel`
5579 
5580   Not Collective
5581 
5582   Input Parameters:
5583 + dm    - The `DM`
5584 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5585 
5586   Output Parameters:
5587 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5588 . ds     - The `PetscDS` defined on the given region, or `NULL`
5589 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5590 
5591   Level: advanced
5592 
5593   Note:
5594   If a non-`NULL` label is given, but there is no `PetscDS` on that specific label,
5595   the `PetscDS` for the full domain (if present) is returned. Returns with
5596   fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain.
5597 
5598 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5599 @*/
5600 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5601 {
5602   PetscInt Nds = dm->Nds, s;
5603 
5604   PetscFunctionBegin;
5605   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5606   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5607   if (fields) {
5608     PetscAssertPointer(fields, 3);
5609     *fields = NULL;
5610   }
5611   if (ds) {
5612     PetscAssertPointer(ds, 4);
5613     *ds = NULL;
5614   }
5615   if (dsIn) {
5616     PetscAssertPointer(dsIn, 5);
5617     *dsIn = NULL;
5618   }
5619   for (s = 0; s < Nds; ++s) {
5620     if (dm->probs[s].label == label || !dm->probs[s].label) {
5621       if (fields) *fields = dm->probs[s].fields;
5622       if (ds) *ds = dm->probs[s].ds;
5623       if (dsIn) *dsIn = dm->probs[s].dsIn;
5624       if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS);
5625     }
5626   }
5627   PetscFunctionReturn(PETSC_SUCCESS);
5628 }
5629 
5630 /*@
5631   DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5632 
5633   Collective
5634 
5635   Input Parameters:
5636 + dm     - The `DM`
5637 . label  - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5638 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields
5639 . ds     - The `PetscDS` defined on the given region
5640 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5641 
5642   Level: advanced
5643 
5644   Note:
5645   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5646   the fields argument is ignored.
5647 
5648 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5649 @*/
5650 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5651 {
5652   PetscInt Nds = dm->Nds, s;
5653 
5654   PetscFunctionBegin;
5655   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5656   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5657   if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3);
5658   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5659   if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5);
5660   for (s = 0; s < Nds; ++s) {
5661     if (dm->probs[s].label == label) {
5662       PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5663       PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5664       dm->probs[s].ds   = ds;
5665       dm->probs[s].dsIn = dsIn;
5666       PetscFunctionReturn(PETSC_SUCCESS);
5667     }
5668   }
5669   PetscCall(DMDSEnlarge_Static(dm, Nds + 1));
5670   PetscCall(PetscObjectReference((PetscObject)label));
5671   PetscCall(PetscObjectReference((PetscObject)fields));
5672   PetscCall(PetscObjectReference((PetscObject)ds));
5673   PetscCall(PetscObjectReference((PetscObject)dsIn));
5674   if (!label) {
5675     /* Put the NULL label at the front, so it is returned as the default */
5676     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5677     Nds = 0;
5678   }
5679   dm->probs[Nds].label  = label;
5680   dm->probs[Nds].fields = fields;
5681   dm->probs[Nds].ds     = ds;
5682   dm->probs[Nds].dsIn   = dsIn;
5683   PetscFunctionReturn(PETSC_SUCCESS);
5684 }
5685 
5686 /*@
5687   DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number
5688 
5689   Not Collective
5690 
5691   Input Parameters:
5692 + dm  - The `DM`
5693 - num - The region number, in [0, Nds)
5694 
5695   Output Parameters:
5696 + label  - The region label, or `NULL`
5697 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5698 . ds     - The `PetscDS` defined on the given region, or `NULL`
5699 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5700 
5701   Level: advanced
5702 
5703 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5704 @*/
5705 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5706 {
5707   PetscInt Nds;
5708 
5709   PetscFunctionBegin;
5710   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5711   PetscCall(DMGetNumDS(dm, &Nds));
5712   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5713   if (label) {
5714     PetscAssertPointer(label, 3);
5715     *label = dm->probs[num].label;
5716   }
5717   if (fields) {
5718     PetscAssertPointer(fields, 4);
5719     *fields = dm->probs[num].fields;
5720   }
5721   if (ds) {
5722     PetscAssertPointer(ds, 5);
5723     *ds = dm->probs[num].ds;
5724   }
5725   if (dsIn) {
5726     PetscAssertPointer(dsIn, 6);
5727     *dsIn = dm->probs[num].dsIn;
5728   }
5729   PetscFunctionReturn(PETSC_SUCCESS);
5730 }
5731 
5732 /*@
5733   DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number
5734 
5735   Not Collective
5736 
5737   Input Parameters:
5738 + dm     - The `DM`
5739 . num    - The region number, in [0, Nds)
5740 . label  - The region label, or `NULL`
5741 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting
5742 . ds     - The `PetscDS` defined on the given region, or `NULL` to prevent setting
5743 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5744 
5745   Level: advanced
5746 
5747 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5748 @*/
5749 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5750 {
5751   PetscInt Nds;
5752 
5753   PetscFunctionBegin;
5754   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5755   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5756   PetscCall(DMGetNumDS(dm, &Nds));
5757   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5758   PetscCall(PetscObjectReference((PetscObject)label));
5759   PetscCall(DMLabelDestroy(&dm->probs[num].label));
5760   dm->probs[num].label = label;
5761   if (fields) {
5762     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5763     PetscCall(PetscObjectReference((PetscObject)fields));
5764     PetscCall(ISDestroy(&dm->probs[num].fields));
5765     dm->probs[num].fields = fields;
5766   }
5767   if (ds) {
5768     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5769     PetscCall(PetscObjectReference((PetscObject)ds));
5770     PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5771     dm->probs[num].ds = ds;
5772   }
5773   if (dsIn) {
5774     PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6);
5775     PetscCall(PetscObjectReference((PetscObject)dsIn));
5776     PetscCall(PetscDSDestroy(&dm->probs[num].dsIn));
5777     dm->probs[num].dsIn = dsIn;
5778   }
5779   PetscFunctionReturn(PETSC_SUCCESS);
5780 }
5781 
5782 /*@
5783   DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found.
5784 
5785   Not Collective
5786 
5787   Input Parameters:
5788 + dm - The `DM`
5789 - ds - The `PetscDS` defined on the given region
5790 
5791   Output Parameter:
5792 . num - The region number, in [0, Nds), or -1 if not found
5793 
5794   Level: advanced
5795 
5796 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5797 @*/
5798 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5799 {
5800   PetscInt Nds, n;
5801 
5802   PetscFunctionBegin;
5803   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5804   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5805   PetscAssertPointer(num, 3);
5806   PetscCall(DMGetNumDS(dm, &Nds));
5807   for (n = 0; n < Nds; ++n)
5808     if (ds == dm->probs[n].ds) break;
5809   if (n >= Nds) *num = -1;
5810   else *num = n;
5811   PetscFunctionReturn(PETSC_SUCCESS);
5812 }
5813 
5814 /*@
5815   DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5816 
5817   Not Collective
5818 
5819   Input Parameters:
5820 + dm     - The `DM`
5821 . Nc     - The number of components for the field
5822 . prefix - The options prefix for the output `PetscFE`, or `NULL`
5823 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5824 
5825   Output Parameter:
5826 . fem - The `PetscFE`
5827 
5828   Level: intermediate
5829 
5830   Note:
5831   This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5832 
5833 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5834 @*/
5835 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5836 {
5837   DMPolytopeType ct;
5838   PetscInt       dim, cStart;
5839 
5840   PetscFunctionBegin;
5841   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5842   PetscValidLogicalCollectiveInt(dm, Nc, 2);
5843   if (prefix) PetscAssertPointer(prefix, 3);
5844   PetscValidLogicalCollectiveInt(dm, qorder, 4);
5845   PetscAssertPointer(fem, 5);
5846   PetscCall(DMGetDimension(dm, &dim));
5847   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5848   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5849   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5850   PetscFunctionReturn(PETSC_SUCCESS);
5851 }
5852 
5853 /*@
5854   DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5855 
5856   Collective
5857 
5858   Input Parameter:
5859 . dm - The `DM`
5860 
5861   Options Database Key:
5862 . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5863 
5864   Level: intermediate
5865 
5866 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5867 @*/
5868 PetscErrorCode DMCreateDS(DM dm)
5869 {
5870   MPI_Comm  comm;
5871   PetscDS   dsDef;
5872   DMLabel  *labelSet;
5873   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5874   PetscBool doSetup = PETSC_TRUE, flg;
5875 
5876   PetscFunctionBegin;
5877   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5878   if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS);
5879   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5880   PetscCall(DMGetCoordinateDim(dm, &dE));
5881   /* Determine how many regions we have */
5882   PetscCall(PetscMalloc1(Nf, &labelSet));
5883   Nl   = 0;
5884   Ndef = 0;
5885   for (f = 0; f < Nf; ++f) {
5886     DMLabel  label = dm->fields[f].label;
5887     PetscInt l;
5888 
5889 #ifdef PETSC_HAVE_LIBCEED
5890     /* Move CEED context to discretizations */
5891     {
5892       PetscClassId id;
5893 
5894       PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5895       if (id == PETSCFE_CLASSID) {
5896         Ceed ceed;
5897 
5898         PetscCall(DMGetCeed(dm, &ceed));
5899         PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed));
5900       }
5901     }
5902 #endif
5903     if (!label) {
5904       ++Ndef;
5905       continue;
5906     }
5907     for (l = 0; l < Nl; ++l)
5908       if (label == labelSet[l]) break;
5909     if (l < Nl) continue;
5910     labelSet[Nl++] = label;
5911   }
5912   /* Create default DS if there are no labels to intersect with */
5913   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5914   if (!dsDef && Ndef && !Nl) {
5915     IS        fields;
5916     PetscInt *fld, nf;
5917 
5918     for (f = 0, nf = 0; f < Nf; ++f)
5919       if (!dm->fields[f].label) ++nf;
5920     PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5921     PetscCall(PetscMalloc1(nf, &fld));
5922     for (f = 0, nf = 0; f < Nf; ++f)
5923       if (!dm->fields[f].label) fld[nf++] = f;
5924     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5925     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5926     PetscCall(ISSetType(fields, ISGENERAL));
5927     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5928 
5929     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5930     PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL));
5931     PetscCall(PetscDSDestroy(&dsDef));
5932     PetscCall(ISDestroy(&fields));
5933   }
5934   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5935   if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5936   /* Intersect labels with default fields */
5937   if (Ndef && Nl) {
5938     DM              plex;
5939     DMLabel         cellLabel;
5940     IS              fieldIS, allcellIS, defcellIS = NULL;
5941     PetscInt       *fields;
5942     const PetscInt *cells;
5943     PetscInt        depth, nf = 0, n, c;
5944 
5945     PetscCall(DMConvert(dm, DMPLEX, &plex));
5946     PetscCall(DMPlexGetDepth(plex, &depth));
5947     PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
5948     if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
5949     /* TODO This looks like it only works for one label */
5950     for (l = 0; l < Nl; ++l) {
5951       DMLabel label = labelSet[l];
5952       IS      pointIS;
5953 
5954       PetscCall(ISDestroy(&defcellIS));
5955       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
5956       PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
5957       PetscCall(ISDestroy(&pointIS));
5958     }
5959     PetscCall(ISDestroy(&allcellIS));
5960 
5961     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
5962     PetscCall(ISGetLocalSize(defcellIS, &n));
5963     PetscCall(ISGetIndices(defcellIS, &cells));
5964     for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
5965     PetscCall(ISRestoreIndices(defcellIS, &cells));
5966     PetscCall(ISDestroy(&defcellIS));
5967     PetscCall(DMPlexLabelComplete(plex, cellLabel));
5968 
5969     PetscCall(PetscMalloc1(Ndef, &fields));
5970     for (f = 0; f < Nf; ++f)
5971       if (!dm->fields[f].label) fields[nf++] = f;
5972     PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
5973     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_"));
5974     PetscCall(ISSetType(fieldIS, ISGENERAL));
5975     PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
5976 
5977     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5978     PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL));
5979     PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5980     PetscCall(DMLabelDestroy(&cellLabel));
5981     PetscCall(PetscDSDestroy(&dsDef));
5982     PetscCall(ISDestroy(&fieldIS));
5983     PetscCall(DMDestroy(&plex));
5984   }
5985   /* Create label DSes
5986      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5987   */
5988   /* TODO Should check that labels are disjoint */
5989   for (l = 0; l < Nl; ++l) {
5990     DMLabel   label = labelSet[l];
5991     PetscDS   ds, dsIn = NULL;
5992     IS        fields;
5993     PetscInt *fld, nf;
5994 
5995     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
5996     for (f = 0, nf = 0; f < Nf; ++f)
5997       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5998     PetscCall(PetscMalloc1(nf, &fld));
5999     for (f = 0, nf = 0; f < Nf; ++f)
6000       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
6001     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
6002     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
6003     PetscCall(ISSetType(fields, ISGENERAL));
6004     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
6005     PetscCall(PetscDSSetCoordinateDimension(ds, dE));
6006     {
6007       DMPolytopeType ct;
6008       PetscInt       lStart, lEnd;
6009       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;
6010 
6011       PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
6012       if (lStart >= 0) {
6013         PetscCall(DMPlexGetCellType(dm, lStart, &ct));
6014         switch (ct) {
6015         case DM_POLYTOPE_POINT_PRISM_TENSOR:
6016         case DM_POLYTOPE_SEG_PRISM_TENSOR:
6017         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6018         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
6019           isCohesiveLocal = PETSC_TRUE;
6020           break;
6021         default:
6022           break;
6023         }
6024       }
6025       PetscCall(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm));
6026       if (isCohesive) {
6027         PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn));
6028         PetscCall(PetscDSSetCoordinateDimension(dsIn, dE));
6029       }
6030       for (f = 0, nf = 0; f < Nf; ++f) {
6031         if (label == dm->fields[f].label || !dm->fields[f].label) {
6032           if (label == dm->fields[f].label) {
6033             PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
6034             PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
6035             if (dsIn) {
6036               PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL));
6037               PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive));
6038             }
6039           }
6040           ++nf;
6041         }
6042       }
6043     }
6044     PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn));
6045     PetscCall(ISDestroy(&fields));
6046     PetscCall(PetscDSDestroy(&ds));
6047     PetscCall(PetscDSDestroy(&dsIn));
6048   }
6049   PetscCall(PetscFree(labelSet));
6050   /* Set fields in DSes */
6051   for (s = 0; s < dm->Nds; ++s) {
6052     PetscDS         ds     = dm->probs[s].ds;
6053     PetscDS         dsIn   = dm->probs[s].dsIn;
6054     IS              fields = dm->probs[s].fields;
6055     const PetscInt *fld;
6056     PetscInt        nf, dsnf;
6057     PetscBool       isCohesive;
6058 
6059     PetscCall(PetscDSGetNumFields(ds, &dsnf));
6060     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
6061     PetscCall(ISGetLocalSize(fields, &nf));
6062     PetscCall(ISGetIndices(fields, &fld));
6063     for (f = 0; f < nf; ++f) {
6064       PetscObject  disc = dm->fields[fld[f]].disc;
6065       PetscBool    isCohesiveField;
6066       PetscClassId id;
6067 
6068       /* Handle DS with no fields */
6069       if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
6070       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
6071       if (isCohesive) {
6072         if (!isCohesiveField) {
6073           PetscObject bdDisc;
6074 
6075           PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc));
6076           PetscCall(PetscDSSetDiscretization(ds, f, bdDisc));
6077           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6078         } else {
6079           PetscCall(PetscDSSetDiscretization(ds, f, disc));
6080           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6081         }
6082       } else {
6083         PetscCall(PetscDSSetDiscretization(ds, f, disc));
6084       }
6085       /* We allow people to have placeholder fields and construct the Section by hand */
6086       PetscCall(PetscObjectGetClassId(disc, &id));
6087       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
6088     }
6089     PetscCall(ISRestoreIndices(fields, &fld));
6090   }
6091   /* Allow k-jet tabulation */
6092   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
6093   if (flg) {
6094     for (s = 0; s < dm->Nds; ++s) {
6095       PetscDS  ds   = dm->probs[s].ds;
6096       PetscDS  dsIn = dm->probs[s].dsIn;
6097       PetscInt Nf, f;
6098 
6099       PetscCall(PetscDSGetNumFields(ds, &Nf));
6100       for (f = 0; f < Nf; ++f) {
6101         PetscCall(PetscDSSetJetDegree(ds, f, k));
6102         if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k));
6103       }
6104     }
6105   }
6106   /* Setup DSes */
6107   if (doSetup) {
6108     for (s = 0; s < dm->Nds; ++s) {
6109       if (dm->setfromoptionscalled) {
6110         PetscCall(PetscDSSetFromOptions(dm->probs[s].ds));
6111         if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn));
6112       }
6113       PetscCall(PetscDSSetUp(dm->probs[s].ds));
6114       if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn));
6115     }
6116   }
6117   PetscFunctionReturn(PETSC_SUCCESS);
6118 }
6119 
6120 /*@
6121   DMUseTensorOrder - Use a tensor product closure ordering for the default section
6122 
6123   Input Parameters:
6124 + dm     - The DM
6125 - tensor - Flag for tensor order
6126 
6127   Level: developer
6128 
6129 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()`
6130 @*/
6131 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor)
6132 {
6133   PetscInt  Nf;
6134   PetscBool reorder = PETSC_TRUE, isPlex;
6135 
6136   PetscFunctionBegin;
6137   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
6138   PetscCall(DMGetNumFields(dm, &Nf));
6139   for (PetscInt f = 0; f < Nf; ++f) {
6140     PetscObject  obj;
6141     PetscClassId id;
6142 
6143     PetscCall(DMGetField(dm, f, NULL, &obj));
6144     PetscCall(PetscObjectGetClassId(obj, &id));
6145     if (id == PETSCFE_CLASSID) {
6146       PetscSpace sp;
6147       PetscBool  tensor;
6148 
6149       PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp));
6150       PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor));
6151       reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE;
6152     } else reorder = PETSC_FALSE;
6153   }
6154   if (tensor) {
6155     if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL));
6156   } else {
6157     PetscSection s;
6158 
6159     PetscCall(DMGetLocalSection(dm, &s));
6160     if (s) PetscCall(PetscSectionResetClosurePermutation(s));
6161   }
6162   PetscFunctionReturn(PETSC_SUCCESS);
6163 }
6164 
6165 /*@
6166   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
6167 
6168   Collective
6169 
6170   Input Parameters:
6171 + dm   - The `DM`
6172 - time - The time
6173 
6174   Output Parameters:
6175 + u   - The vector will be filled with exact solution values, or `NULL`
6176 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL`
6177 
6178   Level: developer
6179 
6180   Note:
6181   The user must call `PetscDSSetExactSolution()` before using this routine
6182 
6183 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()`
6184 @*/
6185 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
6186 {
6187   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
6188   void   **ectxs;
6189   Vec      locu, locu_t;
6190   PetscInt Nf, Nds, s;
6191 
6192   PetscFunctionBegin;
6193   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6194   if (u) {
6195     PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
6196     PetscCall(DMGetLocalVector(dm, &locu));
6197     PetscCall(VecSet(locu, 0.));
6198   }
6199   if (u_t) {
6200     PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
6201     PetscCall(DMGetLocalVector(dm, &locu_t));
6202     PetscCall(VecSet(locu_t, 0.));
6203   }
6204   PetscCall(DMGetNumFields(dm, &Nf));
6205   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
6206   PetscCall(DMGetNumDS(dm, &Nds));
6207   for (s = 0; s < Nds; ++s) {
6208     PetscDS         ds;
6209     DMLabel         label;
6210     IS              fieldIS;
6211     const PetscInt *fields, id = 1;
6212     PetscInt        dsNf, f;
6213 
6214     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
6215     PetscCall(PetscDSGetNumFields(ds, &dsNf));
6216     PetscCall(ISGetIndices(fieldIS, &fields));
6217     PetscCall(PetscArrayzero(exacts, Nf));
6218     PetscCall(PetscArrayzero(ectxs, Nf));
6219     if (u) {
6220       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6221       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu));
6222       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu));
6223     }
6224     if (u_t) {
6225       PetscCall(PetscArrayzero(exacts, Nf));
6226       PetscCall(PetscArrayzero(ectxs, Nf));
6227       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6228       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6229       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6230     }
6231     PetscCall(ISRestoreIndices(fieldIS, &fields));
6232   }
6233   if (u) {
6234     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6235     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6236   }
6237   if (u_t) {
6238     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6239     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6240   }
6241   PetscCall(PetscFree2(exacts, ectxs));
6242   if (u) {
6243     PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u));
6244     PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u));
6245     PetscCall(DMRestoreLocalVector(dm, &locu));
6246   }
6247   if (u_t) {
6248     PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t));
6249     PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t));
6250     PetscCall(DMRestoreLocalVector(dm, &locu_t));
6251   }
6252   PetscFunctionReturn(PETSC_SUCCESS);
6253 }
6254 
6255 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
6256 {
6257   PetscDS dsNew, dsInNew = NULL;
6258 
6259   PetscFunctionBegin;
6260   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6261   PetscCall(PetscDSCopy(ds, dm, dsNew));
6262   if (dsIn) {
6263     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew));
6264     PetscCall(PetscDSCopy(dsIn, dm, dsInNew));
6265   }
6266   PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew));
6267   PetscCall(PetscDSDestroy(&dsNew));
6268   PetscCall(PetscDSDestroy(&dsInNew));
6269   PetscFunctionReturn(PETSC_SUCCESS);
6270 }
6271 
6272 /*@
6273   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6274 
6275   Collective
6276 
6277   Input Parameter:
6278 . dm - The `DM`
6279 
6280   Output Parameter:
6281 . newdm - The `DM`
6282 
6283   Level: advanced
6284 
6285 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6286 @*/
6287 PetscErrorCode DMCopyDS(DM dm, DM newdm)
6288 {
6289   PetscInt Nds, s;
6290 
6291   PetscFunctionBegin;
6292   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
6293   PetscCall(DMGetNumDS(dm, &Nds));
6294   PetscCall(DMClearDS(newdm));
6295   for (s = 0; s < Nds; ++s) {
6296     DMLabel  label;
6297     IS       fields;
6298     PetscDS  ds, dsIn, newds;
6299     PetscInt Nbd, bd;
6300 
6301     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn));
6302     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6303     PetscCall(DMTransferDS_Internal(newdm, label, fields, ds, dsIn));
6304     /* Complete new labels in the new DS */
6305     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL));
6306     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6307     for (bd = 0; bd < Nbd; ++bd) {
6308       PetscWeakForm wf;
6309       DMLabel       label;
6310       PetscInt      field;
6311 
6312       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6313       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6314     }
6315   }
6316   PetscCall(DMCompleteBCLabels_Internal(newdm));
6317   PetscFunctionReturn(PETSC_SUCCESS);
6318 }
6319 
6320 /*@
6321   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6322 
6323   Collective
6324 
6325   Input Parameter:
6326 . dm - The `DM`
6327 
6328   Output Parameter:
6329 . newdm - The `DM`
6330 
6331   Level: advanced
6332 
6333   Developer Note:
6334   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6335 
6336 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()`
6337 @*/
6338 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6339 {
6340   PetscFunctionBegin;
6341   PetscCall(DMCopyFields(dm, newdm));
6342   PetscCall(DMCopyDS(dm, newdm));
6343   PetscFunctionReturn(PETSC_SUCCESS);
6344 }
6345 
6346 /*@
6347   DMGetDimension - Return the topological dimension of the `DM`
6348 
6349   Not Collective
6350 
6351   Input Parameter:
6352 . dm - The `DM`
6353 
6354   Output Parameter:
6355 . dim - The topological dimension
6356 
6357   Level: beginner
6358 
6359 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()`
6360 @*/
6361 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6362 {
6363   PetscFunctionBegin;
6364   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6365   PetscAssertPointer(dim, 2);
6366   *dim = dm->dim;
6367   PetscFunctionReturn(PETSC_SUCCESS);
6368 }
6369 
6370 /*@
6371   DMSetDimension - Set the topological dimension of the `DM`
6372 
6373   Collective
6374 
6375   Input Parameters:
6376 + dm  - The `DM`
6377 - dim - The topological dimension
6378 
6379   Level: beginner
6380 
6381 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()`
6382 @*/
6383 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6384 {
6385   PetscDS  ds;
6386   PetscInt Nds, n;
6387 
6388   PetscFunctionBegin;
6389   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6390   PetscValidLogicalCollectiveInt(dm, dim, 2);
6391   dm->dim = dim;
6392   if (dm->dim >= 0) {
6393     PetscCall(DMGetNumDS(dm, &Nds));
6394     for (n = 0; n < Nds; ++n) {
6395       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL));
6396       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6397     }
6398   }
6399   PetscFunctionReturn(PETSC_SUCCESS);
6400 }
6401 
6402 /*@
6403   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6404 
6405   Collective
6406 
6407   Input Parameters:
6408 + dm  - the `DM`
6409 - dim - the dimension
6410 
6411   Output Parameters:
6412 + pStart - The first point of the given dimension
6413 - pEnd   - The first point following points of the given dimension
6414 
6415   Level: intermediate
6416 
6417   Note:
6418   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6419   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6420   then the interval is empty.
6421 
6422 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6423 @*/
6424 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6425 {
6426   PetscInt d;
6427 
6428   PetscFunctionBegin;
6429   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6430   PetscCall(DMGetDimension(dm, &d));
6431   PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6432   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6433   PetscFunctionReturn(PETSC_SUCCESS);
6434 }
6435 
6436 /*@
6437   DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6438 
6439   Collective
6440 
6441   Input Parameter:
6442 . dm - The original `DM`
6443 
6444   Output Parameter:
6445 . odm - The `DM` which provides the layout for output
6446 
6447   Level: intermediate
6448 
6449   Note:
6450   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6451   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6452   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6453 
6454 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6455 @*/
6456 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6457 {
6458   PetscSection section;
6459   IS           perm;
6460   PetscBool    hasConstraints, newDM, gnewDM;
6461 
6462   PetscFunctionBegin;
6463   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6464   PetscAssertPointer(odm, 2);
6465   PetscCall(DMGetLocalSection(dm, &section));
6466   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6467   PetscCall(PetscSectionGetPermutation(section, &perm));
6468   newDM = hasConstraints || perm ? PETSC_TRUE : PETSC_FALSE;
6469   PetscCall(MPIU_Allreduce(&newDM, &gnewDM, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6470   if (!gnewDM) {
6471     *odm = dm;
6472     PetscFunctionReturn(PETSC_SUCCESS);
6473   }
6474   if (!dm->dmBC) {
6475     PetscSection newSection, gsection;
6476     PetscSF      sf;
6477     PetscBool    usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE;
6478 
6479     PetscCall(DMClone(dm, &dm->dmBC));
6480     PetscCall(DMCopyDisc(dm, dm->dmBC));
6481     PetscCall(PetscSectionClone(section, &newSection));
6482     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6483     PetscCall(PetscSectionDestroy(&newSection));
6484     PetscCall(DMGetPointSF(dm->dmBC, &sf));
6485     PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection));
6486     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6487     PetscCall(PetscSectionDestroy(&gsection));
6488   }
6489   *odm = dm->dmBC;
6490   PetscFunctionReturn(PETSC_SUCCESS);
6491 }
6492 
6493 /*@
6494   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6495 
6496   Input Parameter:
6497 . dm - The original `DM`
6498 
6499   Output Parameters:
6500 + num - The output sequence number
6501 - val - The output sequence value
6502 
6503   Level: intermediate
6504 
6505   Note:
6506   This is intended for output that should appear in sequence, for instance
6507   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6508 
6509   Developer Note:
6510   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6511   not directly related to the `DM`.
6512 
6513 .seealso: [](ch_dmbase), `DM`, `VecView()`
6514 @*/
6515 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6516 {
6517   PetscFunctionBegin;
6518   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6519   if (num) {
6520     PetscAssertPointer(num, 2);
6521     *num = dm->outputSequenceNum;
6522   }
6523   if (val) {
6524     PetscAssertPointer(val, 3);
6525     *val = dm->outputSequenceVal;
6526   }
6527   PetscFunctionReturn(PETSC_SUCCESS);
6528 }
6529 
6530 /*@
6531   DMSetOutputSequenceNumber - Set the sequence number/value for output
6532 
6533   Input Parameters:
6534 + dm  - The original `DM`
6535 . num - The output sequence number
6536 - val - The output sequence value
6537 
6538   Level: intermediate
6539 
6540   Note:
6541   This is intended for output that should appear in sequence, for instance
6542   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6543 
6544 .seealso: [](ch_dmbase), `DM`, `VecView()`
6545 @*/
6546 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6547 {
6548   PetscFunctionBegin;
6549   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6550   dm->outputSequenceNum = num;
6551   dm->outputSequenceVal = val;
6552   PetscFunctionReturn(PETSC_SUCCESS);
6553 }
6554 
6555 /*@
6556   DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6557 
6558   Input Parameters:
6559 + dm     - The original `DM`
6560 . viewer - The `PetscViewer` to get it from
6561 . name   - The sequence name
6562 - num    - The output sequence number
6563 
6564   Output Parameter:
6565 . val - The output sequence value
6566 
6567   Level: intermediate
6568 
6569   Note:
6570   This is intended for output that should appear in sequence, for instance
6571   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6572 
6573   Developer Note:
6574   It is unclear at the user API level why a `DM` is needed as input
6575 
6576 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6577 @*/
6578 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char name[], PetscInt num, PetscReal *val)
6579 {
6580   PetscBool ishdf5;
6581 
6582   PetscFunctionBegin;
6583   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6584   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6585   PetscAssertPointer(name, 3);
6586   PetscAssertPointer(val, 5);
6587   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6588   if (ishdf5) {
6589 #if defined(PETSC_HAVE_HDF5)
6590     PetscScalar value;
6591 
6592     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6593     *val = PetscRealPart(value);
6594 #endif
6595   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6596   PetscFunctionReturn(PETSC_SUCCESS);
6597 }
6598 
6599 /*@
6600   DMGetOutputSequenceLength - Retrieve the number of sequence values from a `PetscViewer`
6601 
6602   Input Parameters:
6603 + dm     - The original `DM`
6604 . viewer - The `PetscViewer` to get it from
6605 - name   - The sequence name
6606 
6607   Output Parameter:
6608 . len - The length of the output sequence
6609 
6610   Level: intermediate
6611 
6612   Note:
6613   This is intended for output that should appear in sequence, for instance
6614   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6615 
6616   Developer Note:
6617   It is unclear at the user API level why a `DM` is needed as input
6618 
6619 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6620 @*/
6621 PetscErrorCode DMGetOutputSequenceLength(DM dm, PetscViewer viewer, const char name[], PetscInt *len)
6622 {
6623   PetscBool ishdf5;
6624 
6625   PetscFunctionBegin;
6626   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6627   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6628   PetscAssertPointer(name, 3);
6629   PetscAssertPointer(len, 4);
6630   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6631   if (ishdf5) {
6632 #if defined(PETSC_HAVE_HDF5)
6633     PetscCall(DMSequenceGetLength_HDF5_Internal(dm, name, len, viewer));
6634 #endif
6635   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6636   PetscFunctionReturn(PETSC_SUCCESS);
6637 }
6638 
6639 /*@
6640   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6641 
6642   Not Collective
6643 
6644   Input Parameter:
6645 . dm - The `DM`
6646 
6647   Output Parameter:
6648 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6649 
6650   Level: beginner
6651 
6652 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()`
6653 @*/
6654 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6655 {
6656   PetscFunctionBegin;
6657   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6658   PetscAssertPointer(useNatural, 2);
6659   *useNatural = dm->useNatural;
6660   PetscFunctionReturn(PETSC_SUCCESS);
6661 }
6662 
6663 /*@
6664   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6665 
6666   Collective
6667 
6668   Input Parameters:
6669 + dm         - The `DM`
6670 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6671 
6672   Level: beginner
6673 
6674   Note:
6675   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6676 
6677 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6678 @*/
6679 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6680 {
6681   PetscFunctionBegin;
6682   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6683   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6684   dm->useNatural = useNatural;
6685   PetscFunctionReturn(PETSC_SUCCESS);
6686 }
6687 
6688 /*@
6689   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6690 
6691   Not Collective
6692 
6693   Input Parameters:
6694 + dm   - The `DM` object
6695 - name - The label name
6696 
6697   Level: intermediate
6698 
6699 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6700 @*/
6701 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6702 {
6703   PetscBool flg;
6704   DMLabel   label;
6705 
6706   PetscFunctionBegin;
6707   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6708   PetscAssertPointer(name, 2);
6709   PetscCall(DMHasLabel(dm, name, &flg));
6710   if (!flg) {
6711     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6712     PetscCall(DMAddLabel(dm, label));
6713     PetscCall(DMLabelDestroy(&label));
6714   }
6715   PetscFunctionReturn(PETSC_SUCCESS);
6716 }
6717 
6718 /*@
6719   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6720 
6721   Not Collective
6722 
6723   Input Parameters:
6724 + dm   - The `DM` object
6725 . l    - The index for the label
6726 - name - The label name
6727 
6728   Level: intermediate
6729 
6730 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6731 @*/
6732 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6733 {
6734   DMLabelLink orig, prev = NULL;
6735   DMLabel     label;
6736   PetscInt    Nl, m;
6737   PetscBool   flg, match;
6738   const char *lname;
6739 
6740   PetscFunctionBegin;
6741   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6742   PetscAssertPointer(name, 3);
6743   PetscCall(DMHasLabel(dm, name, &flg));
6744   if (!flg) {
6745     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6746     PetscCall(DMAddLabel(dm, label));
6747     PetscCall(DMLabelDestroy(&label));
6748   }
6749   PetscCall(DMGetNumLabels(dm, &Nl));
6750   PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6751   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6752     PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6753     PetscCall(PetscStrcmp(name, lname, &match));
6754     if (match) break;
6755   }
6756   if (m == l) PetscFunctionReturn(PETSC_SUCCESS);
6757   if (!m) dm->labels = orig->next;
6758   else prev->next = orig->next;
6759   if (!l) {
6760     orig->next = dm->labels;
6761     dm->labels = orig;
6762   } else {
6763     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next);
6764     orig->next = prev->next;
6765     prev->next = orig;
6766   }
6767   PetscFunctionReturn(PETSC_SUCCESS);
6768 }
6769 
6770 /*@
6771   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6772 
6773   Not Collective
6774 
6775   Input Parameters:
6776 + dm    - The `DM` object
6777 . name  - The label name
6778 - point - The mesh point
6779 
6780   Output Parameter:
6781 . value - The label value for this point, or -1 if the point is not in the label
6782 
6783   Level: beginner
6784 
6785 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6786 @*/
6787 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6788 {
6789   DMLabel label;
6790 
6791   PetscFunctionBegin;
6792   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6793   PetscAssertPointer(name, 2);
6794   PetscCall(DMGetLabel(dm, name, &label));
6795   PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6796   PetscCall(DMLabelGetValue(label, point, value));
6797   PetscFunctionReturn(PETSC_SUCCESS);
6798 }
6799 
6800 /*@
6801   DMSetLabelValue - Add a point to a `DMLabel` with given value
6802 
6803   Not Collective
6804 
6805   Input Parameters:
6806 + dm    - The `DM` object
6807 . name  - The label name
6808 . point - The mesh point
6809 - value - The label value for this point
6810 
6811   Output Parameter:
6812 
6813   Level: beginner
6814 
6815 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6816 @*/
6817 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6818 {
6819   DMLabel label;
6820 
6821   PetscFunctionBegin;
6822   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6823   PetscAssertPointer(name, 2);
6824   PetscCall(DMGetLabel(dm, name, &label));
6825   if (!label) {
6826     PetscCall(DMCreateLabel(dm, name));
6827     PetscCall(DMGetLabel(dm, name, &label));
6828   }
6829   PetscCall(DMLabelSetValue(label, point, value));
6830   PetscFunctionReturn(PETSC_SUCCESS);
6831 }
6832 
6833 /*@
6834   DMClearLabelValue - Remove a point from a `DMLabel` with given value
6835 
6836   Not Collective
6837 
6838   Input Parameters:
6839 + dm    - The `DM` object
6840 . name  - The label name
6841 . point - The mesh point
6842 - value - The label value for this point
6843 
6844   Level: beginner
6845 
6846 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6847 @*/
6848 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6849 {
6850   DMLabel label;
6851 
6852   PetscFunctionBegin;
6853   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6854   PetscAssertPointer(name, 2);
6855   PetscCall(DMGetLabel(dm, name, &label));
6856   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6857   PetscCall(DMLabelClearValue(label, point, value));
6858   PetscFunctionReturn(PETSC_SUCCESS);
6859 }
6860 
6861 /*@
6862   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6863 
6864   Not Collective
6865 
6866   Input Parameters:
6867 + dm   - The `DM` object
6868 - name - The label name
6869 
6870   Output Parameter:
6871 . size - The number of different integer ids, or 0 if the label does not exist
6872 
6873   Level: beginner
6874 
6875   Developer Note:
6876   This should be renamed to something like `DMGetLabelNumValues()` or removed.
6877 
6878 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6879 @*/
6880 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6881 {
6882   DMLabel label;
6883 
6884   PetscFunctionBegin;
6885   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6886   PetscAssertPointer(name, 2);
6887   PetscAssertPointer(size, 3);
6888   PetscCall(DMGetLabel(dm, name, &label));
6889   *size = 0;
6890   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6891   PetscCall(DMLabelGetNumValues(label, size));
6892   PetscFunctionReturn(PETSC_SUCCESS);
6893 }
6894 
6895 /*@
6896   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6897 
6898   Not Collective
6899 
6900   Input Parameters:
6901 + dm   - The `DM` object
6902 - name - The label name
6903 
6904   Output Parameter:
6905 . ids - The integer ids, or `NULL` if the label does not exist
6906 
6907   Level: beginner
6908 
6909 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()`
6910 @*/
6911 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6912 {
6913   DMLabel label;
6914 
6915   PetscFunctionBegin;
6916   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6917   PetscAssertPointer(name, 2);
6918   PetscAssertPointer(ids, 3);
6919   PetscCall(DMGetLabel(dm, name, &label));
6920   *ids = NULL;
6921   if (label) {
6922     PetscCall(DMLabelGetValueIS(label, ids));
6923   } else {
6924     /* returning an empty IS */
6925     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
6926   }
6927   PetscFunctionReturn(PETSC_SUCCESS);
6928 }
6929 
6930 /*@
6931   DMGetStratumSize - Get the number of points in a label stratum
6932 
6933   Not Collective
6934 
6935   Input Parameters:
6936 + dm    - The `DM` object
6937 . name  - The label name of the stratum
6938 - value - The stratum value
6939 
6940   Output Parameter:
6941 . size - The number of points, also called the stratum size
6942 
6943   Level: beginner
6944 
6945 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6946 @*/
6947 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6948 {
6949   DMLabel label;
6950 
6951   PetscFunctionBegin;
6952   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6953   PetscAssertPointer(name, 2);
6954   PetscAssertPointer(size, 4);
6955   PetscCall(DMGetLabel(dm, name, &label));
6956   *size = 0;
6957   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6958   PetscCall(DMLabelGetStratumSize(label, value, size));
6959   PetscFunctionReturn(PETSC_SUCCESS);
6960 }
6961 
6962 /*@
6963   DMGetStratumIS - Get the points in a label stratum
6964 
6965   Not Collective
6966 
6967   Input Parameters:
6968 + dm    - The `DM` object
6969 . name  - The label name
6970 - value - The stratum value
6971 
6972   Output Parameter:
6973 . points - The stratum points, or `NULL` if the label does not exist or does not have that value
6974 
6975   Level: beginner
6976 
6977 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()`
6978 @*/
6979 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6980 {
6981   DMLabel label;
6982 
6983   PetscFunctionBegin;
6984   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6985   PetscAssertPointer(name, 2);
6986   PetscAssertPointer(points, 4);
6987   PetscCall(DMGetLabel(dm, name, &label));
6988   *points = NULL;
6989   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6990   PetscCall(DMLabelGetStratumIS(label, value, points));
6991   PetscFunctionReturn(PETSC_SUCCESS);
6992 }
6993 
6994 /*@
6995   DMSetStratumIS - Set the points in a label stratum
6996 
6997   Not Collective
6998 
6999   Input Parameters:
7000 + dm     - The `DM` object
7001 . name   - The label name
7002 . value  - The stratum value
7003 - points - The stratum points
7004 
7005   Level: beginner
7006 
7007 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
7008 @*/
7009 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7010 {
7011   DMLabel label;
7012 
7013   PetscFunctionBegin;
7014   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7015   PetscAssertPointer(name, 2);
7016   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
7017   PetscCall(DMGetLabel(dm, name, &label));
7018   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7019   PetscCall(DMLabelSetStratumIS(label, value, points));
7020   PetscFunctionReturn(PETSC_SUCCESS);
7021 }
7022 
7023 /*@
7024   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
7025 
7026   Not Collective
7027 
7028   Input Parameters:
7029 + dm    - The `DM` object
7030 . name  - The label name
7031 - value - The label value for this point
7032 
7033   Output Parameter:
7034 
7035   Level: beginner
7036 
7037 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
7038 @*/
7039 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7040 {
7041   DMLabel label;
7042 
7043   PetscFunctionBegin;
7044   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7045   PetscAssertPointer(name, 2);
7046   PetscCall(DMGetLabel(dm, name, &label));
7047   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7048   PetscCall(DMLabelClearStratum(label, value));
7049   PetscFunctionReturn(PETSC_SUCCESS);
7050 }
7051 
7052 /*@
7053   DMGetNumLabels - Return the number of labels defined by on the `DM`
7054 
7055   Not Collective
7056 
7057   Input Parameter:
7058 . dm - The `DM` object
7059 
7060   Output Parameter:
7061 . numLabels - the number of Labels
7062 
7063   Level: intermediate
7064 
7065 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7066 @*/
7067 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7068 {
7069   DMLabelLink next = dm->labels;
7070   PetscInt    n    = 0;
7071 
7072   PetscFunctionBegin;
7073   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7074   PetscAssertPointer(numLabels, 2);
7075   while (next) {
7076     ++n;
7077     next = next->next;
7078   }
7079   *numLabels = n;
7080   PetscFunctionReturn(PETSC_SUCCESS);
7081 }
7082 
7083 /*@
7084   DMGetLabelName - Return the name of nth label
7085 
7086   Not Collective
7087 
7088   Input Parameters:
7089 + dm - The `DM` object
7090 - n  - the label number
7091 
7092   Output Parameter:
7093 . name - the label name
7094 
7095   Level: intermediate
7096 
7097   Developer Note:
7098   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
7099 
7100 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7101 @*/
7102 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char *name[])
7103 {
7104   DMLabelLink next = dm->labels;
7105   PetscInt    l    = 0;
7106 
7107   PetscFunctionBegin;
7108   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7109   PetscAssertPointer(name, 3);
7110   while (next) {
7111     if (l == n) {
7112       PetscCall(PetscObjectGetName((PetscObject)next->label, name));
7113       PetscFunctionReturn(PETSC_SUCCESS);
7114     }
7115     ++l;
7116     next = next->next;
7117   }
7118   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7119 }
7120 
7121 /*@
7122   DMHasLabel - Determine whether the `DM` has a label of a given name
7123 
7124   Not Collective
7125 
7126   Input Parameters:
7127 + dm   - The `DM` object
7128 - name - The label name
7129 
7130   Output Parameter:
7131 . hasLabel - `PETSC_TRUE` if the label is present
7132 
7133   Level: intermediate
7134 
7135 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7136 @*/
7137 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7138 {
7139   DMLabelLink next = dm->labels;
7140   const char *lname;
7141 
7142   PetscFunctionBegin;
7143   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7144   PetscAssertPointer(name, 2);
7145   PetscAssertPointer(hasLabel, 3);
7146   *hasLabel = PETSC_FALSE;
7147   while (next) {
7148     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7149     PetscCall(PetscStrcmp(name, lname, hasLabel));
7150     if (*hasLabel) break;
7151     next = next->next;
7152   }
7153   PetscFunctionReturn(PETSC_SUCCESS);
7154 }
7155 
7156 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7157 /*@
7158   DMGetLabel - Return the label of a given name, or `NULL`, from a `DM`
7159 
7160   Not Collective
7161 
7162   Input Parameters:
7163 + dm   - The `DM` object
7164 - name - The label name
7165 
7166   Output Parameter:
7167 . label - The `DMLabel`, or `NULL` if the label is absent
7168 
7169   Default labels in a `DMPLEX`:
7170 + "depth"       - Holds the depth (co-dimension) of each mesh point
7171 . "celltype"    - Holds the topological type of each cell
7172 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7173 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7174 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7175 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7176 
7177   Level: intermediate
7178 
7179 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7180 @*/
7181 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7182 {
7183   DMLabelLink next = dm->labels;
7184   PetscBool   hasLabel;
7185   const char *lname;
7186 
7187   PetscFunctionBegin;
7188   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7189   PetscAssertPointer(name, 2);
7190   PetscAssertPointer(label, 3);
7191   *label = NULL;
7192   while (next) {
7193     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7194     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7195     if (hasLabel) {
7196       *label = next->label;
7197       break;
7198     }
7199     next = next->next;
7200   }
7201   PetscFunctionReturn(PETSC_SUCCESS);
7202 }
7203 
7204 /*@
7205   DMGetLabelByNum - Return the nth label on a `DM`
7206 
7207   Not Collective
7208 
7209   Input Parameters:
7210 + dm - The `DM` object
7211 - n  - the label number
7212 
7213   Output Parameter:
7214 . label - the label
7215 
7216   Level: intermediate
7217 
7218 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7219 @*/
7220 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7221 {
7222   DMLabelLink next = dm->labels;
7223   PetscInt    l    = 0;
7224 
7225   PetscFunctionBegin;
7226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7227   PetscAssertPointer(label, 3);
7228   while (next) {
7229     if (l == n) {
7230       *label = next->label;
7231       PetscFunctionReturn(PETSC_SUCCESS);
7232     }
7233     ++l;
7234     next = next->next;
7235   }
7236   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7237 }
7238 
7239 /*@
7240   DMAddLabel - Add the label to this `DM`
7241 
7242   Not Collective
7243 
7244   Input Parameters:
7245 + dm    - The `DM` object
7246 - label - The `DMLabel`
7247 
7248   Level: developer
7249 
7250 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7251 @*/
7252 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7253 {
7254   DMLabelLink l, *p, tmpLabel;
7255   PetscBool   hasLabel;
7256   const char *lname;
7257   PetscBool   flg;
7258 
7259   PetscFunctionBegin;
7260   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7261   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7262   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7263   PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7264   PetscCall(PetscCalloc1(1, &tmpLabel));
7265   tmpLabel->label  = label;
7266   tmpLabel->output = PETSC_TRUE;
7267   for (p = &dm->labels; (l = *p); p = &l->next) { }
7268   *p = tmpLabel;
7269   PetscCall(PetscObjectReference((PetscObject)label));
7270   PetscCall(PetscStrcmp(lname, "depth", &flg));
7271   if (flg) dm->depthLabel = label;
7272   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7273   if (flg) dm->celltypeLabel = label;
7274   PetscFunctionReturn(PETSC_SUCCESS);
7275 }
7276 
7277 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7278 /*@
7279   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7280 
7281   Not Collective
7282 
7283   Input Parameters:
7284 + dm    - The `DM` object
7285 - label - The `DMLabel`, having the same name, to substitute
7286 
7287   Default labels in a `DMPLEX`:
7288 + "depth"       - Holds the depth (co-dimension) of each mesh point
7289 . "celltype"    - Holds the topological type of each cell
7290 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7291 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7292 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7293 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7294 
7295   Level: intermediate
7296 
7297 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7298 @*/
7299 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7300 {
7301   DMLabelLink next = dm->labels;
7302   PetscBool   hasLabel, flg;
7303   const char *name, *lname;
7304 
7305   PetscFunctionBegin;
7306   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7307   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7308   PetscCall(PetscObjectGetName((PetscObject)label, &name));
7309   while (next) {
7310     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7311     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7312     if (hasLabel) {
7313       PetscCall(PetscObjectReference((PetscObject)label));
7314       PetscCall(PetscStrcmp(lname, "depth", &flg));
7315       if (flg) dm->depthLabel = label;
7316       PetscCall(PetscStrcmp(lname, "celltype", &flg));
7317       if (flg) dm->celltypeLabel = label;
7318       PetscCall(DMLabelDestroy(&next->label));
7319       next->label = label;
7320       break;
7321     }
7322     next = next->next;
7323   }
7324   PetscFunctionReturn(PETSC_SUCCESS);
7325 }
7326 
7327 /*@
7328   DMRemoveLabel - Remove the label given by name from this `DM`
7329 
7330   Not Collective
7331 
7332   Input Parameters:
7333 + dm   - The `DM` object
7334 - name - The label name
7335 
7336   Output Parameter:
7337 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the
7338           caller is responsible for calling `DMLabelDestroy()`.
7339 
7340   Level: developer
7341 
7342 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7343 @*/
7344 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7345 {
7346   DMLabelLink link, *pnext;
7347   PetscBool   hasLabel;
7348   const char *lname;
7349 
7350   PetscFunctionBegin;
7351   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7352   PetscAssertPointer(name, 2);
7353   if (label) {
7354     PetscAssertPointer(label, 3);
7355     *label = NULL;
7356   }
7357   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7358     PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7359     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7360     if (hasLabel) {
7361       *pnext = link->next; /* Remove from list */
7362       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7363       if (hasLabel) dm->depthLabel = NULL;
7364       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7365       if (hasLabel) dm->celltypeLabel = NULL;
7366       if (label) *label = link->label;
7367       else PetscCall(DMLabelDestroy(&link->label));
7368       PetscCall(PetscFree(link));
7369       break;
7370     }
7371   }
7372   PetscFunctionReturn(PETSC_SUCCESS);
7373 }
7374 
7375 /*@
7376   DMRemoveLabelBySelf - Remove the label from this `DM`
7377 
7378   Not Collective
7379 
7380   Input Parameters:
7381 + dm           - The `DM` object
7382 . label        - The `DMLabel` to be removed from the `DM`
7383 - failNotFound - Should it fail if the label is not found in the `DM`?
7384 
7385   Level: developer
7386 
7387   Note:
7388   Only exactly the same instance is removed if found, name match is ignored.
7389   If the `DM` has an exclusive reference to the label, the label gets destroyed and
7390   *label nullified.
7391 
7392 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7393 @*/
7394 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7395 {
7396   DMLabelLink link, *pnext;
7397   PetscBool   hasLabel = PETSC_FALSE;
7398 
7399   PetscFunctionBegin;
7400   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7401   PetscAssertPointer(label, 2);
7402   if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS);
7403   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7404   PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7405   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7406     if (*label == link->label) {
7407       hasLabel = PETSC_TRUE;
7408       *pnext   = link->next; /* Remove from list */
7409       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7410       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7411       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7412       PetscCall(DMLabelDestroy(&link->label));
7413       PetscCall(PetscFree(link));
7414       break;
7415     }
7416   }
7417   PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7418   PetscFunctionReturn(PETSC_SUCCESS);
7419 }
7420 
7421 /*@
7422   DMGetLabelOutput - Get the output flag for a given label
7423 
7424   Not Collective
7425 
7426   Input Parameters:
7427 + dm   - The `DM` object
7428 - name - The label name
7429 
7430   Output Parameter:
7431 . output - The flag for output
7432 
7433   Level: developer
7434 
7435 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7436 @*/
7437 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7438 {
7439   DMLabelLink next = dm->labels;
7440   const char *lname;
7441 
7442   PetscFunctionBegin;
7443   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7444   PetscAssertPointer(name, 2);
7445   PetscAssertPointer(output, 3);
7446   while (next) {
7447     PetscBool flg;
7448 
7449     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7450     PetscCall(PetscStrcmp(name, lname, &flg));
7451     if (flg) {
7452       *output = next->output;
7453       PetscFunctionReturn(PETSC_SUCCESS);
7454     }
7455     next = next->next;
7456   }
7457   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7458 }
7459 
7460 /*@
7461   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7462 
7463   Not Collective
7464 
7465   Input Parameters:
7466 + dm     - The `DM` object
7467 . name   - The label name
7468 - output - `PETSC_TRUE` to save the label to the viewer
7469 
7470   Level: developer
7471 
7472 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7473 @*/
7474 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7475 {
7476   DMLabelLink next = dm->labels;
7477   const char *lname;
7478 
7479   PetscFunctionBegin;
7480   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7481   PetscAssertPointer(name, 2);
7482   while (next) {
7483     PetscBool flg;
7484 
7485     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7486     PetscCall(PetscStrcmp(name, lname, &flg));
7487     if (flg) {
7488       next->output = output;
7489       PetscFunctionReturn(PETSC_SUCCESS);
7490     }
7491     next = next->next;
7492   }
7493   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7494 }
7495 
7496 /*@
7497   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7498 
7499   Collective
7500 
7501   Input Parameters:
7502 + dmA   - The `DM` object with initial labels
7503 . dmB   - The `DM` object to which labels are copied
7504 . mode  - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7505 . all   - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7506 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7507 
7508   Level: intermediate
7509 
7510   Note:
7511   This is typically used when interpolating or otherwise adding to a mesh, or testing.
7512 
7513 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7514 @*/
7515 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7516 {
7517   DMLabel     label, labelNew, labelOld;
7518   const char *name;
7519   PetscBool   flg;
7520   DMLabelLink link;
7521 
7522   PetscFunctionBegin;
7523   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7524   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7525   PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7526   PetscValidLogicalCollectiveBool(dmA, all, 4);
7527   PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7528   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
7529   for (link = dmA->labels; link; link = link->next) {
7530     label = link->label;
7531     PetscCall(PetscObjectGetName((PetscObject)label, &name));
7532     if (!all) {
7533       PetscCall(PetscStrcmp(name, "depth", &flg));
7534       if (flg) continue;
7535       PetscCall(PetscStrcmp(name, "dim", &flg));
7536       if (flg) continue;
7537       PetscCall(PetscStrcmp(name, "celltype", &flg));
7538       if (flg) continue;
7539     }
7540     PetscCall(DMGetLabel(dmB, name, &labelOld));
7541     if (labelOld) {
7542       switch (emode) {
7543       case DM_COPY_LABELS_KEEP:
7544         continue;
7545       case DM_COPY_LABELS_REPLACE:
7546         PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7547         break;
7548       case DM_COPY_LABELS_FAIL:
7549         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7550       default:
7551         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7552       }
7553     }
7554     if (mode == PETSC_COPY_VALUES) {
7555       PetscCall(DMLabelDuplicate(label, &labelNew));
7556     } else {
7557       labelNew = label;
7558     }
7559     PetscCall(DMAddLabel(dmB, labelNew));
7560     if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7561   }
7562   PetscFunctionReturn(PETSC_SUCCESS);
7563 }
7564 
7565 /*@C
7566   DMCompareLabels - Compare labels between two `DM` objects
7567 
7568   Collective; No Fortran Support
7569 
7570   Input Parameters:
7571 + dm0 - First `DM` object
7572 - dm1 - Second `DM` object
7573 
7574   Output Parameters:
7575 + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
7576 - message - (Optional) Message describing the difference, or `NULL` if there is no difference
7577 
7578   Level: intermediate
7579 
7580   Notes:
7581   The output flag equal will be the same on all processes.
7582 
7583   If equal is passed as `NULL` and difference is found, an error is thrown on all processes.
7584 
7585   Make sure to pass equal is `NULL` on all processes or none of them.
7586 
7587   The output message is set independently on each rank.
7588 
7589   message must be freed with `PetscFree()`
7590 
7591   If message is passed as `NULL` and a difference is found, the difference description is printed to stderr in synchronized manner.
7592 
7593   Make sure to pass message as `NULL` on all processes or no processes.
7594 
7595   Labels are matched by name. If the number of labels and their names are equal,
7596   `DMLabelCompare()` is used to compare each pair of labels with the same name.
7597 
7598   Developer Note:
7599   Can automatically generate the Fortran stub because `message` must be freed with `PetscFree()`
7600 
7601 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7602 @*/
7603 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7604 {
7605   PetscInt    n, i;
7606   char        msg[PETSC_MAX_PATH_LEN] = "";
7607   PetscBool   eq;
7608   MPI_Comm    comm;
7609   PetscMPIInt rank;
7610 
7611   PetscFunctionBegin;
7612   PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7613   PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7614   PetscCheckSameComm(dm0, 1, dm1, 2);
7615   if (equal) PetscAssertPointer(equal, 3);
7616   if (message) PetscAssertPointer(message, 4);
7617   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7618   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7619   {
7620     PetscInt n1;
7621 
7622     PetscCall(DMGetNumLabels(dm0, &n));
7623     PetscCall(DMGetNumLabels(dm1, &n1));
7624     eq = (PetscBool)(n == n1);
7625     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7626     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7627     if (!eq) goto finish;
7628   }
7629   for (i = 0; i < n; i++) {
7630     DMLabel     l0, l1;
7631     const char *name;
7632     char       *msgInner;
7633 
7634     /* Ignore label order */
7635     PetscCall(DMGetLabelByNum(dm0, i, &l0));
7636     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7637     PetscCall(DMGetLabel(dm1, name, &l1));
7638     if (!l1) {
7639       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7640       eq = PETSC_FALSE;
7641       break;
7642     }
7643     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7644     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7645     PetscCall(PetscFree(msgInner));
7646     if (!eq) break;
7647   }
7648   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7649 finish:
7650   /* If message output arg not set, print to stderr */
7651   if (message) {
7652     *message = NULL;
7653     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7654   } else {
7655     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7656     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7657   }
7658   /* If same output arg not ser and labels are not equal, throw error */
7659   if (equal) *equal = eq;
7660   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7661   PetscFunctionReturn(PETSC_SUCCESS);
7662 }
7663 
7664 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7665 {
7666   PetscFunctionBegin;
7667   PetscAssertPointer(label, 2);
7668   if (!*label) {
7669     PetscCall(DMCreateLabel(dm, name));
7670     PetscCall(DMGetLabel(dm, name, label));
7671   }
7672   PetscCall(DMLabelSetValue(*label, point, value));
7673   PetscFunctionReturn(PETSC_SUCCESS);
7674 }
7675 
7676 /*
7677   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7678   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7679   (label, id) pair in the DM.
7680 
7681   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7682   each label.
7683 */
7684 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7685 {
7686   DMUniversalLabel ul;
7687   PetscBool       *active;
7688   PetscInt         pStart, pEnd, p, Nl, l, m;
7689 
7690   PetscFunctionBegin;
7691   PetscCall(PetscMalloc1(1, &ul));
7692   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7693   PetscCall(DMGetNumLabels(dm, &Nl));
7694   PetscCall(PetscCalloc1(Nl, &active));
7695   ul->Nl = 0;
7696   for (l = 0; l < Nl; ++l) {
7697     PetscBool   isdepth, iscelltype;
7698     const char *name;
7699 
7700     PetscCall(DMGetLabelName(dm, l, &name));
7701     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7702     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7703     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7704     if (active[l]) ++ul->Nl;
7705   }
7706   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7707   ul->Nv = 0;
7708   for (l = 0, m = 0; l < Nl; ++l) {
7709     DMLabel     label;
7710     PetscInt    nv;
7711     const char *name;
7712 
7713     if (!active[l]) continue;
7714     PetscCall(DMGetLabelName(dm, l, &name));
7715     PetscCall(DMGetLabelByNum(dm, l, &label));
7716     PetscCall(DMLabelGetNumValues(label, &nv));
7717     PetscCall(PetscStrallocpy(name, &ul->names[m]));
7718     ul->indices[m] = l;
7719     ul->Nv += nv;
7720     ul->offsets[m + 1] = nv;
7721     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7722     ++m;
7723   }
7724   for (l = 1; l <= ul->Nl; ++l) {
7725     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7726     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7727   }
7728   for (l = 0; l < ul->Nl; ++l) {
7729     PetscInt b;
7730 
7731     ul->masks[l] = 0;
7732     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7733   }
7734   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7735   for (l = 0, m = 0; l < Nl; ++l) {
7736     DMLabel         label;
7737     IS              valueIS;
7738     const PetscInt *varr;
7739     PetscInt        nv, v;
7740 
7741     if (!active[l]) continue;
7742     PetscCall(DMGetLabelByNum(dm, l, &label));
7743     PetscCall(DMLabelGetNumValues(label, &nv));
7744     PetscCall(DMLabelGetValueIS(label, &valueIS));
7745     PetscCall(ISGetIndices(valueIS, &varr));
7746     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7747     PetscCall(ISRestoreIndices(valueIS, &varr));
7748     PetscCall(ISDestroy(&valueIS));
7749     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7750     ++m;
7751   }
7752   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7753   for (p = pStart; p < pEnd; ++p) {
7754     PetscInt  uval   = 0;
7755     PetscBool marked = PETSC_FALSE;
7756 
7757     for (l = 0, m = 0; l < Nl; ++l) {
7758       DMLabel  label;
7759       PetscInt val, defval, loc, nv;
7760 
7761       if (!active[l]) continue;
7762       PetscCall(DMGetLabelByNum(dm, l, &label));
7763       PetscCall(DMLabelGetValue(label, p, &val));
7764       PetscCall(DMLabelGetDefaultValue(label, &defval));
7765       if (val == defval) {
7766         ++m;
7767         continue;
7768       }
7769       nv     = ul->offsets[m + 1] - ul->offsets[m];
7770       marked = PETSC_TRUE;
7771       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7772       PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7773       uval += (loc + 1) << ul->bits[m];
7774       ++m;
7775     }
7776     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7777   }
7778   PetscCall(PetscFree(active));
7779   *universal = ul;
7780   PetscFunctionReturn(PETSC_SUCCESS);
7781 }
7782 
7783 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7784 {
7785   PetscInt l;
7786 
7787   PetscFunctionBegin;
7788   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7789   PetscCall(DMLabelDestroy(&(*universal)->label));
7790   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7791   PetscCall(PetscFree((*universal)->values));
7792   PetscCall(PetscFree(*universal));
7793   *universal = NULL;
7794   PetscFunctionReturn(PETSC_SUCCESS);
7795 }
7796 
7797 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7798 {
7799   PetscFunctionBegin;
7800   PetscAssertPointer(ulabel, 2);
7801   *ulabel = ul->label;
7802   PetscFunctionReturn(PETSC_SUCCESS);
7803 }
7804 
7805 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7806 {
7807   PetscInt Nl = ul->Nl, l;
7808 
7809   PetscFunctionBegin;
7810   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7811   for (l = 0; l < Nl; ++l) {
7812     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7813     else PetscCall(DMCreateLabel(dm, ul->names[l]));
7814   }
7815   if (preserveOrder) {
7816     for (l = 0; l < ul->Nl; ++l) {
7817       const char *name;
7818       PetscBool   match;
7819 
7820       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7821       PetscCall(PetscStrcmp(name, ul->names[l], &match));
7822       PetscCheck(match, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %" PetscInt_FMT " name %s does not match new name %s", l, name, ul->names[l]);
7823     }
7824   }
7825   PetscFunctionReturn(PETSC_SUCCESS);
7826 }
7827 
7828 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7829 {
7830   PetscInt l;
7831 
7832   PetscFunctionBegin;
7833   for (l = 0; l < ul->Nl; ++l) {
7834     DMLabel  label;
7835     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7836 
7837     if (lval) {
7838       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7839       else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7840       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7841     }
7842   }
7843   PetscFunctionReturn(PETSC_SUCCESS);
7844 }
7845 
7846 /*@
7847   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7848 
7849   Not Collective
7850 
7851   Input Parameter:
7852 . dm - The `DM` object
7853 
7854   Output Parameter:
7855 . cdm - The coarse `DM`
7856 
7857   Level: intermediate
7858 
7859 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()`
7860 @*/
7861 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7862 {
7863   PetscFunctionBegin;
7864   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7865   PetscAssertPointer(cdm, 2);
7866   *cdm = dm->coarseMesh;
7867   PetscFunctionReturn(PETSC_SUCCESS);
7868 }
7869 
7870 /*@
7871   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7872 
7873   Input Parameters:
7874 + dm  - The `DM` object
7875 - cdm - The coarse `DM`
7876 
7877   Level: intermediate
7878 
7879   Note:
7880   Normally this is set automatically by `DMRefine()`
7881 
7882 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7883 @*/
7884 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7885 {
7886   PetscFunctionBegin;
7887   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7888   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7889   if (dm == cdm) cdm = NULL;
7890   PetscCall(PetscObjectReference((PetscObject)cdm));
7891   PetscCall(DMDestroy(&dm->coarseMesh));
7892   dm->coarseMesh = cdm;
7893   PetscFunctionReturn(PETSC_SUCCESS);
7894 }
7895 
7896 /*@
7897   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7898 
7899   Input Parameter:
7900 . dm - The `DM` object
7901 
7902   Output Parameter:
7903 . fdm - The fine `DM`
7904 
7905   Level: intermediate
7906 
7907 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7908 @*/
7909 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7910 {
7911   PetscFunctionBegin;
7912   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7913   PetscAssertPointer(fdm, 2);
7914   *fdm = dm->fineMesh;
7915   PetscFunctionReturn(PETSC_SUCCESS);
7916 }
7917 
7918 /*@
7919   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7920 
7921   Input Parameters:
7922 + dm  - The `DM` object
7923 - fdm - The fine `DM`
7924 
7925   Level: developer
7926 
7927   Note:
7928   Normally this is set automatically by `DMCoarsen()`
7929 
7930 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7931 @*/
7932 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7933 {
7934   PetscFunctionBegin;
7935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7936   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7937   if (dm == fdm) fdm = NULL;
7938   PetscCall(PetscObjectReference((PetscObject)fdm));
7939   PetscCall(DMDestroy(&dm->fineMesh));
7940   dm->fineMesh = fdm;
7941   PetscFunctionReturn(PETSC_SUCCESS);
7942 }
7943 
7944 /*@C
7945   DMAddBoundary - Add a boundary condition to a model represented by a `DM`
7946 
7947   Collective
7948 
7949   Input Parameters:
7950 + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
7951 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7952 . name     - The BC name
7953 . label    - The label defining constrained points
7954 . Nv       - The number of `DMLabel` values for constrained points
7955 . values   - An array of values for constrained points
7956 . field    - The field to constrain
7957 . Nc       - The number of constrained field components (0 will constrain all fields)
7958 . comps    - An array of constrained component numbers
7959 . bcFunc   - A pointwise function giving boundary values
7960 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7961 - ctx      - An optional user context for bcFunc
7962 
7963   Output Parameter:
7964 . bd - (Optional) Boundary number
7965 
7966   Options Database Keys:
7967 + -bc_<boundary name> <num>      - Overrides the boundary ids
7968 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7969 
7970   Level: intermediate
7971 
7972   Notes:
7973   Both bcFunc and bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:
7974 .vb
7975  void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
7976 .ve
7977 
7978   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
7979 
7980 .vb
7981   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7982               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7983               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7984               PetscReal time, const PetscReal x[], PetscScalar bcval[])
7985 .ve
7986 + dim - the spatial dimension
7987 . Nf - the number of fields
7988 . uOff - the offset into u[] and u_t[] for each field
7989 . uOff_x - the offset into u_x[] for each field
7990 . u - each field evaluated at the current point
7991 . u_t - the time derivative of each field evaluated at the current point
7992 . u_x - the gradient of each field evaluated at the current point
7993 . aOff - the offset into a[] and a_t[] for each auxiliary field
7994 . aOff_x - the offset into a_x[] for each auxiliary field
7995 . a - each auxiliary field evaluated at the current point
7996 . a_t - the time derivative of each auxiliary field evaluated at the current point
7997 . a_x - the gradient of auxiliary each field evaluated at the current point
7998 . t - current time
7999 . x - coordinates of the current point
8000 . numConstants - number of constant parameters
8001 . constants - constant parameters
8002 - bcval - output values at the current point
8003 
8004 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()`
8005 @*/
8006 PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd)
8007 {
8008   PetscDS ds;
8009 
8010   PetscFunctionBegin;
8011   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8012   PetscValidLogicalCollectiveEnum(dm, type, 2);
8013   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
8014   PetscValidLogicalCollectiveInt(dm, Nv, 5);
8015   PetscValidLogicalCollectiveInt(dm, field, 7);
8016   PetscValidLogicalCollectiveInt(dm, Nc, 8);
8017   PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
8018   PetscCall(DMGetDS(dm, &ds));
8019   /* Complete label */
8020   if (label) {
8021     PetscObject  obj;
8022     PetscClassId id;
8023 
8024     PetscCall(DMGetField(dm, field, NULL, &obj));
8025     PetscCall(PetscObjectGetClassId(obj, &id));
8026     if (id == PETSCFE_CLASSID) {
8027       DM plex;
8028 
8029       PetscCall(DMConvert(dm, DMPLEX, &plex));
8030       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
8031       PetscCall(DMDestroy(&plex));
8032     }
8033   }
8034   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
8035   PetscFunctionReturn(PETSC_SUCCESS);
8036 }
8037 
8038 /* TODO Remove this since now the structures are the same */
8039 static PetscErrorCode DMPopulateBoundary(DM dm)
8040 {
8041   PetscDS     ds;
8042   DMBoundary *lastnext;
8043   DSBoundary  dsbound;
8044 
8045   PetscFunctionBegin;
8046   PetscCall(DMGetDS(dm, &ds));
8047   dsbound = ds->boundary;
8048   if (dm->boundary) {
8049     DMBoundary next = dm->boundary;
8050 
8051     /* quick check to see if the PetscDS has changed */
8052     if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS);
8053     /* the PetscDS has changed: tear down and rebuild */
8054     while (next) {
8055       DMBoundary b = next;
8056 
8057       next = b->next;
8058       PetscCall(PetscFree(b));
8059     }
8060     dm->boundary = NULL;
8061   }
8062 
8063   lastnext = &dm->boundary;
8064   while (dsbound) {
8065     DMBoundary dmbound;
8066 
8067     PetscCall(PetscNew(&dmbound));
8068     dmbound->dsboundary = dsbound;
8069     dmbound->label      = dsbound->label;
8070     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8071     *lastnext = dmbound;
8072     lastnext  = &dmbound->next;
8073     dsbound   = dsbound->next;
8074   }
8075   PetscFunctionReturn(PETSC_SUCCESS);
8076 }
8077 
8078 /* TODO: missing manual page */
8079 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8080 {
8081   DMBoundary b;
8082 
8083   PetscFunctionBegin;
8084   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8085   PetscAssertPointer(isBd, 3);
8086   *isBd = PETSC_FALSE;
8087   PetscCall(DMPopulateBoundary(dm));
8088   b = dm->boundary;
8089   while (b && !(*isBd)) {
8090     DMLabel    label = b->label;
8091     DSBoundary dsb   = b->dsboundary;
8092     PetscInt   i;
8093 
8094     if (label) {
8095       for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
8096     }
8097     b = b->next;
8098   }
8099   PetscFunctionReturn(PETSC_SUCCESS);
8100 }
8101 
8102 /*@C
8103   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
8104 
8105   Collective
8106 
8107   Input Parameters:
8108 + dm    - The `DM`
8109 . time  - The time
8110 . funcs - The coordinate functions to evaluate, one per field
8111 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8112 - mode  - The insertion mode for values
8113 
8114   Output Parameter:
8115 . X - vector
8116 
8117   Calling sequence of `funcs`:
8118 + dim  - The spatial dimension
8119 . time - The time at which to sample
8120 . x    - The coordinates
8121 . Nc   - The number of components
8122 . u    - The output field values
8123 - ctx  - optional user-defined function context
8124 
8125   Level: developer
8126 
8127   Developer Notes:
8128   This API is specific to only particular usage of `DM`
8129 
8130   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8131 
8132 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8133 @*/
8134 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx), void **ctxs, InsertMode mode, Vec X)
8135 {
8136   Vec localX;
8137 
8138   PetscFunctionBegin;
8139   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8140   PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0));
8141   PetscCall(DMGetLocalVector(dm, &localX));
8142   PetscCall(VecSet(localX, 0.));
8143   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
8144   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8145   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8146   PetscCall(DMRestoreLocalVector(dm, &localX));
8147   PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0));
8148   PetscFunctionReturn(PETSC_SUCCESS);
8149 }
8150 
8151 /*@C
8152   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
8153 
8154   Not Collective
8155 
8156   Input Parameters:
8157 + dm    - The `DM`
8158 . time  - The time
8159 . funcs - The coordinate functions to evaluate, one per field
8160 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8161 - mode  - The insertion mode for values
8162 
8163   Output Parameter:
8164 . localX - vector
8165 
8166   Calling sequence of `funcs`:
8167 + dim  - The spatial dimension
8168 . time - The current timestep
8169 . x    - The coordinates
8170 . Nc   - The number of components
8171 . u    - The output field values
8172 - ctx  - optional user-defined function context
8173 
8174   Level: developer
8175 
8176   Developer Notes:
8177   This API is specific to only particular usage of `DM`
8178 
8179   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8180 
8181 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8182 @*/
8183 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx), void **ctxs, InsertMode mode, Vec localX)
8184 {
8185   PetscFunctionBegin;
8186   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8187   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8188   PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX);
8189   PetscFunctionReturn(PETSC_SUCCESS);
8190 }
8191 
8192 /*@C
8193   DMProjectFunctionLabel - This projects the given function into the function space provided by the `DM`, putting the coefficients in a global vector, setting values only for points in the given label.
8194 
8195   Collective
8196 
8197   Input Parameters:
8198 + dm     - The `DM`
8199 . time   - The time
8200 . numIds - The number of ids
8201 . ids    - The ids
8202 . Nc     - The number of components
8203 . comps  - The components
8204 . label  - The `DMLabel` selecting the portion of the mesh for projection
8205 . funcs  - The coordinate functions to evaluate, one per field
8206 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
8207 - mode   - The insertion mode for values
8208 
8209   Output Parameter:
8210 . X - vector
8211 
8212   Calling sequence of `funcs`:
8213 + dim  - The spatial dimension
8214 . time - The current timestep
8215 . x    - The coordinates
8216 . Nc   - The number of components
8217 . u    - The output field values
8218 - ctx  - optional user-defined function context
8219 
8220   Level: developer
8221 
8222   Developer Notes:
8223   This API is specific to only particular usage of `DM`
8224 
8225   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8226 
8227 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8228 @*/
8229 PetscErrorCode DMProjectFunctionLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx), void **ctxs, InsertMode mode, Vec X)
8230 {
8231   Vec localX;
8232 
8233   PetscFunctionBegin;
8234   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8235   PetscCall(DMGetLocalVector(dm, &localX));
8236   PetscCall(VecSet(localX, 0.));
8237   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8238   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8239   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8240   PetscCall(DMRestoreLocalVector(dm, &localX));
8241   PetscFunctionReturn(PETSC_SUCCESS);
8242 }
8243 
8244 /*@C
8245   DMProjectFunctionLabelLocal - This projects the given function into the function space provided by the `DM`, putting the coefficients in a local vector, setting values only for points in the given label.
8246 
8247   Not Collective
8248 
8249   Input Parameters:
8250 + dm     - The `DM`
8251 . time   - The time
8252 . label  - The `DMLabel` selecting the portion of the mesh for projection
8253 . numIds - The number of ids
8254 . ids    - The ids
8255 . Nc     - The number of components
8256 . comps  - The components
8257 . funcs  - The coordinate functions to evaluate, one per field
8258 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8259 - mode   - The insertion mode for values
8260 
8261   Output Parameter:
8262 . localX - vector
8263 
8264   Calling sequence of `funcs`:
8265 + dim  - The spatial dimension
8266 . time - The current time
8267 . x    - The coordinates
8268 . Nc   - The number of components
8269 . u    - The output field values
8270 - ctx  - optional user-defined function context
8271 
8272   Level: developer
8273 
8274   Developer Notes:
8275   This API is specific to only particular usage of `DM`
8276 
8277   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8278 
8279 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8280 @*/
8281 PetscErrorCode DMProjectFunctionLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx), void **ctxs, InsertMode mode, Vec localX)
8282 {
8283   PetscFunctionBegin;
8284   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8285   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8286   PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8287   PetscFunctionReturn(PETSC_SUCCESS);
8288 }
8289 
8290 /*@C
8291   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided by the `DM`, putting the coefficients in a local vector.
8292 
8293   Not Collective
8294 
8295   Input Parameters:
8296 + dm     - The `DM`
8297 . time   - The time
8298 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates
8299 . funcs  - The functions to evaluate, one per field
8300 - mode   - The insertion mode for values
8301 
8302   Output Parameter:
8303 . localX - The output vector
8304 
8305   Calling sequence of `funcs`:
8306 + dim          - The spatial dimension
8307 . Nf           - The number of input fields
8308 . NfAux        - The number of input auxiliary fields
8309 . uOff         - The offset of each field in u[]
8310 . uOff_x       - The offset of each field in u_x[]
8311 . u            - The field values at this point in space
8312 . u_t          - The field time derivative at this point in space (or NULL)
8313 . u_x          - The field derivatives at this point in space
8314 . aOff         - The offset of each auxiliary field in u[]
8315 . aOff_x       - The offset of each auxiliary field in u_x[]
8316 . a            - The auxiliary field values at this point in space
8317 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8318 . a_x          - The auxiliary field derivatives at this point in space
8319 . t            - The current time
8320 . x            - The coordinates of this point
8321 . numConstants - The number of constants
8322 . constants    - The value of each constant
8323 - f            - The value of the function at this point in space
8324 
8325   Level: intermediate
8326 
8327   Note:
8328   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8329   The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8330   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8331   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8332 
8333   Developer Notes:
8334   This API is specific to only particular usage of `DM`
8335 
8336   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8337 
8338 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`,
8339 `DMProjectFunction()`, `DMComputeL2Diff()`
8340 @*/
8341 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec localX)
8342 {
8343   PetscFunctionBegin;
8344   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8345   if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8346   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8347   PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX);
8348   PetscFunctionReturn(PETSC_SUCCESS);
8349 }
8350 
8351 /*@C
8352   DMProjectFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain specified by the label.
8353 
8354   Not Collective
8355 
8356   Input Parameters:
8357 + dm     - The `DM`
8358 . time   - The time
8359 . label  - The `DMLabel` marking the portion of the domain to output
8360 . numIds - The number of label ids to use
8361 . ids    - The label ids to use for marking
8362 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8363 . comps  - The components to set in the output, or `NULL` for all components
8364 . localU - The input field vector
8365 . funcs  - The functions to evaluate, one per field
8366 - mode   - The insertion mode for values
8367 
8368   Output Parameter:
8369 . localX - The output vector
8370 
8371   Calling sequence of `funcs`:
8372 + dim          - The spatial dimension
8373 . Nf           - The number of input fields
8374 . NfAux        - The number of input auxiliary fields
8375 . uOff         - The offset of each field in u[]
8376 . uOff_x       - The offset of each field in u_x[]
8377 . u            - The field values at this point in space
8378 . u_t          - The field time derivative at this point in space (or NULL)
8379 . u_x          - The field derivatives at this point in space
8380 . aOff         - The offset of each auxiliary field in u[]
8381 . aOff_x       - The offset of each auxiliary field in u_x[]
8382 . a            - The auxiliary field values at this point in space
8383 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8384 . a_x          - The auxiliary field derivatives at this point in space
8385 . t            - The current time
8386 . x            - The coordinates of this point
8387 . numConstants - The number of constants
8388 . constants    - The value of each constant
8389 - f            - The value of the function at this point in space
8390 
8391   Level: intermediate
8392 
8393   Note:
8394   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8395   The input `DM`, attached to localU, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8396   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8397   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8398 
8399   Developer Notes:
8400   This API is specific to only particular usage of `DM`
8401 
8402   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8403 
8404 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8405 @*/
8406 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec localX)
8407 {
8408   PetscFunctionBegin;
8409   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8410   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8411   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8412   PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8413   PetscFunctionReturn(PETSC_SUCCESS);
8414 }
8415 
8416 /*@C
8417   DMProjectFieldLabel - This projects the given function of the input fields into the function space provided, putting the coefficients in a global vector, calculating only over the portion of the domain specified by the label.
8418 
8419   Not Collective
8420 
8421   Input Parameters:
8422 + dm     - The `DM`
8423 . time   - The time
8424 . label  - The `DMLabel` marking the portion of the domain to output
8425 . numIds - The number of label ids to use
8426 . ids    - The label ids to use for marking
8427 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8428 . comps  - The components to set in the output, or `NULL` for all components
8429 . U      - The input field vector
8430 . funcs  - The functions to evaluate, one per field
8431 - mode   - The insertion mode for values
8432 
8433   Output Parameter:
8434 . X - The output vector
8435 
8436   Calling sequence of `funcs`:
8437 + dim          - The spatial dimension
8438 . Nf           - The number of input fields
8439 . NfAux        - The number of input auxiliary fields
8440 . uOff         - The offset of each field in u[]
8441 . uOff_x       - The offset of each field in u_x[]
8442 . u            - The field values at this point in space
8443 . u_t          - The field time derivative at this point in space (or NULL)
8444 . u_x          - The field derivatives at this point in space
8445 . aOff         - The offset of each auxiliary field in u[]
8446 . aOff_x       - The offset of each auxiliary field in u_x[]
8447 . a            - The auxiliary field values at this point in space
8448 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8449 . a_x          - The auxiliary field derivatives at this point in space
8450 . t            - The current time
8451 . x            - The coordinates of this point
8452 . numConstants - The number of constants
8453 . constants    - The value of each constant
8454 - f            - The value of the function at this point in space
8455 
8456   Level: intermediate
8457 
8458   Note:
8459   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8460   The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8461   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8462   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8463 
8464   Developer Notes:
8465   This API is specific to only particular usage of `DM`
8466 
8467   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8468 
8469 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8470 @*/
8471 PetscErrorCode DMProjectFieldLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec U, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec X)
8472 {
8473   DM  dmIn;
8474   Vec localU, localX;
8475 
8476   PetscFunctionBegin;
8477   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8478   PetscCall(VecGetDM(U, &dmIn));
8479   PetscCall(DMGetLocalVector(dmIn, &localU));
8480   PetscCall(DMGetLocalVector(dm, &localX));
8481   PetscCall(VecSet(localX, 0.));
8482   PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8483   PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8484   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8485   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8486   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8487   PetscCall(DMRestoreLocalVector(dm, &localX));
8488   PetscCall(DMRestoreLocalVector(dmIn, &localU));
8489   PetscFunctionReturn(PETSC_SUCCESS);
8490 }
8491 
8492 /*@C
8493   DMProjectBdFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain boundary specified by the label.
8494 
8495   Not Collective
8496 
8497   Input Parameters:
8498 + dm     - The `DM`
8499 . time   - The time
8500 . label  - The `DMLabel` marking the portion of the domain boundary to output
8501 . numIds - The number of label ids to use
8502 . ids    - The label ids to use for marking
8503 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8504 . comps  - The components to set in the output, or `NULL` for all components
8505 . localU - The input field vector
8506 . funcs  - The functions to evaluate, one per field
8507 - mode   - The insertion mode for values
8508 
8509   Output Parameter:
8510 . localX - The output vector
8511 
8512   Calling sequence of `funcs`:
8513 + dim          - The spatial dimension
8514 . Nf           - The number of input fields
8515 . NfAux        - The number of input auxiliary fields
8516 . uOff         - The offset of each field in u[]
8517 . uOff_x       - The offset of each field in u_x[]
8518 . u            - The field values at this point in space
8519 . u_t          - The field time derivative at this point in space (or NULL)
8520 . u_x          - The field derivatives at this point in space
8521 . aOff         - The offset of each auxiliary field in u[]
8522 . aOff_x       - The offset of each auxiliary field in u_x[]
8523 . a            - The auxiliary field values at this point in space
8524 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8525 . a_x          - The auxiliary field derivatives at this point in space
8526 . t            - The current time
8527 . x            - The coordinates of this point
8528 . n            - The face normal
8529 . numConstants - The number of constants
8530 . constants    - The value of each constant
8531 - f            - The value of the function at this point in space
8532 
8533   Level: intermediate
8534 
8535   Note:
8536   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8537   The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8538   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8539   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8540 
8541   Developer Notes:
8542   This API is specific to only particular usage of `DM`
8543 
8544   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8545 
8546 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8547 @*/
8548 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec localX)
8549 {
8550   PetscFunctionBegin;
8551   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8552   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8553   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8554   PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8555   PetscFunctionReturn(PETSC_SUCCESS);
8556 }
8557 
8558 /*@C
8559   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8560 
8561   Collective
8562 
8563   Input Parameters:
8564 + dm    - The `DM`
8565 . time  - The time
8566 . funcs - The functions to evaluate for each field component
8567 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8568 - X     - The coefficient vector u_h, a global vector
8569 
8570   Output Parameter:
8571 . diff - The diff ||u - u_h||_2
8572 
8573   Level: developer
8574 
8575   Developer Notes:
8576   This API is specific to only particular usage of `DM`
8577 
8578   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8579 
8580 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8581 @*/
8582 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8583 {
8584   PetscFunctionBegin;
8585   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8586   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8587   PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff);
8588   PetscFunctionReturn(PETSC_SUCCESS);
8589 }
8590 
8591 /*@C
8592   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8593 
8594   Collective
8595 
8596   Input Parameters:
8597 + dm    - The `DM`
8598 . time  - The time
8599 . funcs - The gradient functions to evaluate for each field component
8600 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8601 . X     - The coefficient vector u_h, a global vector
8602 - n     - The vector to project along
8603 
8604   Output Parameter:
8605 . diff - The diff ||(grad u - grad u_h) . n||_2
8606 
8607   Level: developer
8608 
8609   Developer Notes:
8610   This API is specific to only particular usage of `DM`
8611 
8612   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8613 
8614 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8615 @*/
8616 PetscErrorCode DMComputeL2GradientDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
8617 {
8618   PetscFunctionBegin;
8619   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8620   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8621   PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff);
8622   PetscFunctionReturn(PETSC_SUCCESS);
8623 }
8624 
8625 /*@C
8626   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8627 
8628   Collective
8629 
8630   Input Parameters:
8631 + dm    - The `DM`
8632 . time  - The time
8633 . funcs - The functions to evaluate for each field component
8634 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8635 - X     - The coefficient vector u_h, a global vector
8636 
8637   Output Parameter:
8638 . diff - The array of differences, ||u^f - u^f_h||_2
8639 
8640   Level: developer
8641 
8642   Developer Notes:
8643   This API is specific to only particular usage of `DM`
8644 
8645   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8646 
8647 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()`
8648 @*/
8649 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8650 {
8651   PetscFunctionBegin;
8652   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8653   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8654   PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff);
8655   PetscFunctionReturn(PETSC_SUCCESS);
8656 }
8657 
8658 /*@C
8659   DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8660 
8661   Not Collective
8662 
8663   Input Parameter:
8664 . dm - The `DM`
8665 
8666   Output Parameters:
8667 + nranks - the number of neighbours
8668 - ranks  - the neighbors ranks
8669 
8670   Level: beginner
8671 
8672   Note:
8673   Do not free the array, it is freed when the `DM` is destroyed.
8674 
8675 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8676 @*/
8677 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8678 {
8679   PetscFunctionBegin;
8680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8681   PetscUseTypeMethod(dm, getneighbors, nranks, ranks);
8682   PetscFunctionReturn(PETSC_SUCCESS);
8683 }
8684 
8685 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8686 
8687 /*
8688     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8689     This must be a different function because it requires DM which is not defined in the Mat library
8690 */
8691 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8692 {
8693   PetscFunctionBegin;
8694   if (coloring->ctype == IS_COLORING_LOCAL) {
8695     Vec x1local;
8696     DM  dm;
8697     PetscCall(MatGetDM(J, &dm));
8698     PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8699     PetscCall(DMGetLocalVector(dm, &x1local));
8700     PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8701     PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8702     x1 = x1local;
8703   }
8704   PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8705   if (coloring->ctype == IS_COLORING_LOCAL) {
8706     DM dm;
8707     PetscCall(MatGetDM(J, &dm));
8708     PetscCall(DMRestoreLocalVector(dm, &x1));
8709   }
8710   PetscFunctionReturn(PETSC_SUCCESS);
8711 }
8712 
8713 /*@
8714   MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8715 
8716   Input Parameters:
8717 + coloring   - The matrix to get the `DM` from
8718 - fdcoloring - the `MatFDColoring` object
8719 
8720   Level: advanced
8721 
8722   Developer Note:
8723   This routine exists because the PETSc `Mat` library does not know about the `DM` objects
8724 
8725 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8726 @*/
8727 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8728 {
8729   PetscFunctionBegin;
8730   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8731   PetscFunctionReturn(PETSC_SUCCESS);
8732 }
8733 
8734 /*@
8735   DMGetCompatibility - determine if two `DM`s are compatible
8736 
8737   Collective
8738 
8739   Input Parameters:
8740 + dm1 - the first `DM`
8741 - dm2 - the second `DM`
8742 
8743   Output Parameters:
8744 + compatible - whether or not the two `DM`s are compatible
8745 - set        - whether or not the compatible value was actually determined and set
8746 
8747   Level: advanced
8748 
8749   Notes:
8750   Two `DM`s are deemed compatible if they represent the same parallel decomposition
8751   of the same topology. This implies that the section (field data) on one
8752   "makes sense" with respect to the topology and parallel decomposition of the other.
8753   Loosely speaking, compatible `DM`s represent the same domain and parallel
8754   decomposition, but hold different data.
8755 
8756   Typically, one would confirm compatibility if intending to simultaneously iterate
8757   over a pair of vectors obtained from different `DM`s.
8758 
8759   For example, two `DMDA` objects are compatible if they have the same local
8760   and global sizes and the same stencil width. They can have different numbers
8761   of degrees of freedom per node. Thus, one could use the node numbering from
8762   either `DM` in bounds for a loop over vectors derived from either `DM`.
8763 
8764   Consider the operation of summing data living on a 2-dof `DMDA` to data living
8765   on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8766 .vb
8767   ...
8768   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8769   if (set && compatible)  {
8770     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8771     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8772     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8773     for (j=y; j<y+n; ++j) {
8774       for (i=x; i<x+m, ++i) {
8775         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8776       }
8777     }
8778     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8779     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8780   } else {
8781     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8782   }
8783   ...
8784 .ve
8785 
8786   Checking compatibility might be expensive for a given implementation of `DM`,
8787   or might be impossible to unambiguously confirm or deny. For this reason,
8788   this function may decline to determine compatibility, and hence users should
8789   always check the "set" output parameter.
8790 
8791   A `DM` is always compatible with itself.
8792 
8793   In the current implementation, `DM`s which live on "unequal" communicators
8794   (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8795   incompatible.
8796 
8797   This function is labeled "Collective," as information about all subdomains
8798   is required on each rank. However, in `DM` implementations which store all this
8799   information locally, this function may be merely "Logically Collective".
8800 
8801   Developer Note:
8802   Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8803   iff B is compatible with A. Thus, this function checks the implementations
8804   of both dm and dmc (if they are of different types), attempting to determine
8805   compatibility. It is left to `DM` implementers to ensure that symmetry is
8806   preserved. The simplest way to do this is, when implementing type-specific
8807   logic for this function, is to check for existing logic in the implementation
8808   of other `DM` types and let *set = PETSC_FALSE if found.
8809 
8810 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8811 @*/
8812 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8813 {
8814   PetscMPIInt compareResult;
8815   DMType      type, type2;
8816   PetscBool   sameType;
8817 
8818   PetscFunctionBegin;
8819   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8820   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8821 
8822   /* Declare a DM compatible with itself */
8823   if (dm1 == dm2) {
8824     *set        = PETSC_TRUE;
8825     *compatible = PETSC_TRUE;
8826     PetscFunctionReturn(PETSC_SUCCESS);
8827   }
8828 
8829   /* Declare a DM incompatible with a DM that lives on an "unequal"
8830      communicator. Note that this does not preclude compatibility with
8831      DMs living on "congruent" or "similar" communicators, but this must be
8832      determined by the implementation-specific logic */
8833   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8834   if (compareResult == MPI_UNEQUAL) {
8835     *set        = PETSC_TRUE;
8836     *compatible = PETSC_FALSE;
8837     PetscFunctionReturn(PETSC_SUCCESS);
8838   }
8839 
8840   /* Pass to the implementation-specific routine, if one exists. */
8841   if (dm1->ops->getcompatibility) {
8842     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8843     if (*set) PetscFunctionReturn(PETSC_SUCCESS);
8844   }
8845 
8846   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8847      with an implementation of this function from dm2 */
8848   PetscCall(DMGetType(dm1, &type));
8849   PetscCall(DMGetType(dm2, &type2));
8850   PetscCall(PetscStrcmp(type, type2, &sameType));
8851   if (!sameType && dm2->ops->getcompatibility) {
8852     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8853   } else {
8854     *set = PETSC_FALSE;
8855   }
8856   PetscFunctionReturn(PETSC_SUCCESS);
8857 }
8858 
8859 /*@C
8860   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8861 
8862   Logically Collective
8863 
8864   Input Parameters:
8865 + dm             - the `DM`
8866 . f              - the monitor function
8867 . mctx           - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
8868 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`)
8869 
8870   Options Database Key:
8871 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8872                             does not cancel those set via the options database.
8873 
8874   Level: intermediate
8875 
8876   Note:
8877   Several different monitoring routines may be set by calling
8878   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8879   order in which they were set.
8880 
8881   Fortran Note:
8882   Only a single monitor function can be set for each `DM` object
8883 
8884   Developer Note:
8885   This API has a generic name but seems specific to a very particular aspect of the use of `DM`
8886 
8887 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8888 @*/
8889 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **))
8890 {
8891   PetscInt m;
8892 
8893   PetscFunctionBegin;
8894   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8895   for (m = 0; m < dm->numbermonitors; ++m) {
8896     PetscBool identical;
8897 
8898     PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
8899     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
8900   }
8901   PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8902   dm->monitor[dm->numbermonitors]          = f;
8903   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8904   dm->monitorcontext[dm->numbermonitors++] = (void *)mctx;
8905   PetscFunctionReturn(PETSC_SUCCESS);
8906 }
8907 
8908 /*@
8909   DMMonitorCancel - Clears all the monitor functions for a `DM` object.
8910 
8911   Logically Collective
8912 
8913   Input Parameter:
8914 . dm - the DM
8915 
8916   Options Database Key:
8917 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8918   into a code by calls to `DMonitorSet()`, but does not cancel those
8919   set via the options database
8920 
8921   Level: intermediate
8922 
8923   Note:
8924   There is no way to clear one specific monitor from a `DM` object.
8925 
8926 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8927 @*/
8928 PetscErrorCode DMMonitorCancel(DM dm)
8929 {
8930   PetscInt m;
8931 
8932   PetscFunctionBegin;
8933   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8934   for (m = 0; m < dm->numbermonitors; ++m) {
8935     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
8936   }
8937   dm->numbermonitors = 0;
8938   PetscFunctionReturn(PETSC_SUCCESS);
8939 }
8940 
8941 /*@C
8942   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8943 
8944   Collective
8945 
8946   Input Parameters:
8947 + dm           - `DM` object you wish to monitor
8948 . name         - the monitor type one is seeking
8949 . help         - message indicating what monitoring is done
8950 . manual       - manual page for the monitor
8951 . monitor      - the monitor function
8952 - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `DM` or `PetscViewer` objects
8953 
8954   Output Parameter:
8955 . flg - Flag set if the monitor was created
8956 
8957   Level: developer
8958 
8959 .seealso: [](ch_dmbase), `DM`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8960           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8961           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
8962           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8963           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8964           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8965           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8966 @*/
8967 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8968 {
8969   PetscViewer       viewer;
8970   PetscViewerFormat format;
8971 
8972   PetscFunctionBegin;
8973   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8974   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
8975   if (*flg) {
8976     PetscViewerAndFormat *vf;
8977 
8978     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
8979     PetscCall(PetscViewerDestroy(&viewer));
8980     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
8981     PetscCall(DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy));
8982   }
8983   PetscFunctionReturn(PETSC_SUCCESS);
8984 }
8985 
8986 /*@
8987   DMMonitor - runs the user provided monitor routines, if they exist
8988 
8989   Collective
8990 
8991   Input Parameter:
8992 . dm - The `DM`
8993 
8994   Level: developer
8995 
8996   Developer Note:
8997   Note should indicate when during the life of the `DM` the monitor is run. It appears to be
8998   related to the discretization process seems rather specialized since some `DM` have no
8999   concept of discretization.
9000 
9001 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`
9002 @*/
9003 PetscErrorCode DMMonitor(DM dm)
9004 {
9005   PetscInt m;
9006 
9007   PetscFunctionBegin;
9008   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
9009   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9010   for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
9011   PetscFunctionReturn(PETSC_SUCCESS);
9012 }
9013 
9014 /*@
9015   DMComputeError - Computes the error assuming the user has provided the exact solution functions
9016 
9017   Collective
9018 
9019   Input Parameters:
9020 + dm  - The `DM`
9021 - sol - The solution vector
9022 
9023   Input/Output Parameter:
9024 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output
9025            contains the error in each field
9026 
9027   Output Parameter:
9028 . errorVec - A vector to hold the cellwise error (may be `NULL`)
9029 
9030   Level: developer
9031 
9032   Note:
9033   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
9034 
9035 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
9036 @*/
9037 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9038 {
9039   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9040   void    **ctxs;
9041   PetscReal time;
9042   PetscInt  Nf, f, Nds, s;
9043 
9044   PetscFunctionBegin;
9045   PetscCall(DMGetNumFields(dm, &Nf));
9046   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
9047   PetscCall(DMGetNumDS(dm, &Nds));
9048   for (s = 0; s < Nds; ++s) {
9049     PetscDS         ds;
9050     DMLabel         label;
9051     IS              fieldIS;
9052     const PetscInt *fields;
9053     PetscInt        dsNf;
9054 
9055     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
9056     PetscCall(PetscDSGetNumFields(ds, &dsNf));
9057     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
9058     for (f = 0; f < dsNf; ++f) {
9059       const PetscInt field = fields[f];
9060       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
9061     }
9062     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
9063   }
9064   for (f = 0; f < Nf; ++f) PetscCheck(exactSol[f], PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DS must contain exact solution functions in order to calculate error, missing for field %" PetscInt_FMT, f);
9065   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
9066   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
9067   if (errorVec) {
9068     DM             edm;
9069     DMPolytopeType ct;
9070     PetscBool      simplex;
9071     PetscInt       dim, cStart, Nf;
9072 
9073     PetscCall(DMClone(dm, &edm));
9074     PetscCall(DMGetDimension(edm, &dim));
9075     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
9076     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9077     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
9078     PetscCall(DMGetNumFields(dm, &Nf));
9079     for (f = 0; f < Nf; ++f) {
9080       PetscFE         fe, efe;
9081       PetscQuadrature q;
9082       const char     *name;
9083 
9084       PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
9085       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
9086       PetscCall(PetscObjectGetName((PetscObject)fe, &name));
9087       PetscCall(PetscObjectSetName((PetscObject)efe, name));
9088       PetscCall(PetscFEGetQuadrature(fe, &q));
9089       PetscCall(PetscFESetQuadrature(efe, q));
9090       PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
9091       PetscCall(PetscFEDestroy(&efe));
9092     }
9093     PetscCall(DMCreateDS(edm));
9094 
9095     PetscCall(DMCreateGlobalVector(edm, errorVec));
9096     PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
9097     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
9098     PetscCall(DMDestroy(&edm));
9099   }
9100   PetscCall(PetscFree2(exactSol, ctxs));
9101   PetscFunctionReturn(PETSC_SUCCESS);
9102 }
9103 
9104 /*@
9105   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
9106 
9107   Not Collective
9108 
9109   Input Parameter:
9110 . dm - The `DM`
9111 
9112   Output Parameter:
9113 . numAux - The number of auxiliary data vectors
9114 
9115   Level: advanced
9116 
9117 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`
9118 @*/
9119 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9120 {
9121   PetscFunctionBegin;
9122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9123   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
9124   PetscFunctionReturn(PETSC_SUCCESS);
9125 }
9126 
9127 /*@
9128   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
9129 
9130   Not Collective
9131 
9132   Input Parameters:
9133 + dm    - The `DM`
9134 . label - The `DMLabel`
9135 . value - The label value indicating the region
9136 - part  - The equation part, or 0 if unused
9137 
9138   Output Parameter:
9139 . aux - The `Vec` holding auxiliary field data
9140 
9141   Level: advanced
9142 
9143   Note:
9144   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
9145 
9146 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
9147 @*/
9148 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
9149 {
9150   PetscHashAuxKey key, wild = {NULL, 0, 0};
9151   PetscBool       has;
9152 
9153   PetscFunctionBegin;
9154   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9155   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9156   key.label = label;
9157   key.value = value;
9158   key.part  = part;
9159   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
9160   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
9161   else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
9162   PetscFunctionReturn(PETSC_SUCCESS);
9163 }
9164 
9165 /*@
9166   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
9167 
9168   Not Collective because auxiliary vectors are not parallel
9169 
9170   Input Parameters:
9171 + dm    - The `DM`
9172 . label - The `DMLabel`
9173 . value - The label value indicating the region
9174 . part  - The equation part, or 0 if unused
9175 - aux   - The `Vec` holding auxiliary field data
9176 
9177   Level: advanced
9178 
9179 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
9180 @*/
9181 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
9182 {
9183   Vec             old;
9184   PetscHashAuxKey key;
9185 
9186   PetscFunctionBegin;
9187   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9188   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9189   key.label = label;
9190   key.value = value;
9191   key.part  = part;
9192   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9193   PetscCall(PetscObjectReference((PetscObject)aux));
9194   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9195   else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9196   PetscCall(VecDestroy(&old));
9197   PetscFunctionReturn(PETSC_SUCCESS);
9198 }
9199 
9200 /*@
9201   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
9202 
9203   Not Collective
9204 
9205   Input Parameter:
9206 . dm - The `DM`
9207 
9208   Output Parameters:
9209 + labels - The `DMLabel`s for each `Vec`
9210 . values - The label values for each `Vec`
9211 - parts  - The equation parts for each `Vec`
9212 
9213   Level: advanced
9214 
9215   Note:
9216   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
9217 
9218 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()`
9219 @*/
9220 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9221 {
9222   PetscHashAuxKey *keys;
9223   PetscInt         n, i, off = 0;
9224 
9225   PetscFunctionBegin;
9226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9227   PetscAssertPointer(labels, 2);
9228   PetscAssertPointer(values, 3);
9229   PetscAssertPointer(parts, 4);
9230   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9231   PetscCall(PetscMalloc1(n, &keys));
9232   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9233   for (i = 0; i < n; ++i) {
9234     labels[i] = keys[i].label;
9235     values[i] = keys[i].value;
9236     parts[i]  = keys[i].part;
9237   }
9238   PetscCall(PetscFree(keys));
9239   PetscFunctionReturn(PETSC_SUCCESS);
9240 }
9241 
9242 /*@
9243   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
9244 
9245   Not Collective
9246 
9247   Input Parameter:
9248 . dm - The `DM`
9249 
9250   Output Parameter:
9251 . dmNew - The new `DM`, now with the same auxiliary data
9252 
9253   Level: advanced
9254 
9255   Note:
9256   This is a shallow copy of the auxiliary vectors
9257 
9258 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9259 @*/
9260 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9261 {
9262   PetscFunctionBegin;
9263   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9264   PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2);
9265   if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS);
9266   PetscCall(DMClearAuxiliaryVec(dmNew));
9267 
9268   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9269   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9270   {
9271     Vec     *auxData;
9272     PetscInt n, i, off = 0;
9273 
9274     PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n));
9275     PetscCall(PetscMalloc1(n, &auxData));
9276     PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData));
9277     for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i]));
9278     PetscCall(PetscFree(auxData));
9279   }
9280   PetscFunctionReturn(PETSC_SUCCESS);
9281 }
9282 
9283 /*@
9284   DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one
9285 
9286   Not Collective
9287 
9288   Input Parameter:
9289 . dm - The `DM`
9290 
9291   Level: advanced
9292 
9293 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9294 @*/
9295 PetscErrorCode DMClearAuxiliaryVec(DM dm)
9296 {
9297   Vec     *auxData;
9298   PetscInt n, i, off = 0;
9299 
9300   PetscFunctionBegin;
9301   PetscCall(PetscHMapAuxGetSize(dm->auxData, &n));
9302   PetscCall(PetscMalloc1(n, &auxData));
9303   PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData));
9304   for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i]));
9305   PetscCall(PetscFree(auxData));
9306   PetscCall(PetscHMapAuxDestroy(&dm->auxData));
9307   PetscCall(PetscHMapAuxCreate(&dm->auxData));
9308   PetscFunctionReturn(PETSC_SUCCESS);
9309 }
9310 
9311 /*@
9312   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9313 
9314   Not Collective
9315 
9316   Input Parameters:
9317 + ct         - The `DMPolytopeType`
9318 . sourceCone - The source arrangement of faces
9319 - targetCone - The target arrangement of faces
9320 
9321   Output Parameters:
9322 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9323 - found - Flag indicating that a suitable orientation was found
9324 
9325   Level: advanced
9326 
9327   Note:
9328   An arrangement is a face order combined with an orientation for each face
9329 
9330   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9331   that labels each arrangement (face ordering plus orientation for each face).
9332 
9333   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9334 
9335 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9336 @*/
9337 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9338 {
9339   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9340   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9341   PetscInt       o, c;
9342 
9343   PetscFunctionBegin;
9344   if (!nO) {
9345     *ornt  = 0;
9346     *found = PETSC_TRUE;
9347     PetscFunctionReturn(PETSC_SUCCESS);
9348   }
9349   for (o = -nO; o < nO; ++o) {
9350     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
9351 
9352     for (c = 0; c < cS; ++c)
9353       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9354     if (c == cS) {
9355       *ornt = o;
9356       break;
9357     }
9358   }
9359   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9360   PetscFunctionReturn(PETSC_SUCCESS);
9361 }
9362 
9363 /*@
9364   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9365 
9366   Not Collective
9367 
9368   Input Parameters:
9369 + ct         - The `DMPolytopeType`
9370 . sourceCone - The source arrangement of faces
9371 - targetCone - The target arrangement of faces
9372 
9373   Output Parameter:
9374 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9375 
9376   Level: advanced
9377 
9378   Note:
9379   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9380 
9381   Developer Note:
9382   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9383 
9384 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9385 @*/
9386 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9387 {
9388   PetscBool found;
9389 
9390   PetscFunctionBegin;
9391   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9392   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9393   PetscFunctionReturn(PETSC_SUCCESS);
9394 }
9395 
9396 /*@
9397   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9398 
9399   Not Collective
9400 
9401   Input Parameters:
9402 + ct         - The `DMPolytopeType`
9403 . sourceVert - The source arrangement of vertices
9404 - targetVert - The target arrangement of vertices
9405 
9406   Output Parameters:
9407 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9408 - found - Flag indicating that a suitable orientation was found
9409 
9410   Level: advanced
9411 
9412   Notes:
9413   An arrangement is a vertex order
9414 
9415   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9416   that labels each arrangement (vertex ordering).
9417 
9418   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9419 
9420 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()`
9421 @*/
9422 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9423 {
9424   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9425   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9426   PetscInt       o, c;
9427 
9428   PetscFunctionBegin;
9429   if (!nO) {
9430     *ornt  = 0;
9431     *found = PETSC_TRUE;
9432     PetscFunctionReturn(PETSC_SUCCESS);
9433   }
9434   for (o = -nO; o < nO; ++o) {
9435     const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o);
9436 
9437     for (c = 0; c < cS; ++c)
9438       if (sourceVert[arr[c]] != targetVert[c]) break;
9439     if (c == cS) {
9440       *ornt = o;
9441       break;
9442     }
9443   }
9444   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9445   PetscFunctionReturn(PETSC_SUCCESS);
9446 }
9447 
9448 /*@
9449   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9450 
9451   Not Collective
9452 
9453   Input Parameters:
9454 + ct         - The `DMPolytopeType`
9455 . sourceCone - The source arrangement of vertices
9456 - targetCone - The target arrangement of vertices
9457 
9458   Output Parameter:
9459 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9460 
9461   Level: advanced
9462 
9463   Note:
9464   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9465 
9466   Developer Note:
9467   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9468 
9469 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9470 @*/
9471 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9472 {
9473   PetscBool found;
9474 
9475   PetscFunctionBegin;
9476   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9477   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9478   PetscFunctionReturn(PETSC_SUCCESS);
9479 }
9480 
9481 /*@
9482   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9483 
9484   Not Collective
9485 
9486   Input Parameters:
9487 + ct    - The `DMPolytopeType`
9488 - point - Coordinates of the point
9489 
9490   Output Parameter:
9491 . inside - Flag indicating whether the point is inside the reference cell of given type
9492 
9493   Level: advanced
9494 
9495 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()`
9496 @*/
9497 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9498 {
9499   PetscReal sum = 0.0;
9500   PetscInt  d;
9501 
9502   PetscFunctionBegin;
9503   *inside = PETSC_TRUE;
9504   switch (ct) {
9505   case DM_POLYTOPE_TRIANGLE:
9506   case DM_POLYTOPE_TETRAHEDRON:
9507     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9508       if (point[d] < -1.0) {
9509         *inside = PETSC_FALSE;
9510         break;
9511       }
9512       sum += point[d];
9513     }
9514     if (sum > PETSC_SMALL) {
9515       *inside = PETSC_FALSE;
9516       break;
9517     }
9518     break;
9519   case DM_POLYTOPE_QUADRILATERAL:
9520   case DM_POLYTOPE_HEXAHEDRON:
9521     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9522       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9523         *inside = PETSC_FALSE;
9524         break;
9525       }
9526     break;
9527   default:
9528     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9529   }
9530   PetscFunctionReturn(PETSC_SUCCESS);
9531 }
9532 
9533 /*@
9534   DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default
9535 
9536   Logically collective
9537 
9538   Input Parameters:
9539 + dm      - The DM
9540 - reorder - Flag for reordering
9541 
9542   Level: intermediate
9543 
9544 .seealso: `DMReorderSectionGetDefault()`
9545 @*/
9546 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder)
9547 {
9548   PetscFunctionBegin;
9549   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9550   PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder));
9551   PetscFunctionReturn(PETSC_SUCCESS);
9552 }
9553 
9554 /*@
9555   DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default
9556 
9557   Not collective
9558 
9559   Input Parameter:
9560 . dm - The DM
9561 
9562   Output Parameter:
9563 . reorder - Flag for reordering
9564 
9565   Level: intermediate
9566 
9567 .seealso: `DMReorderSetDefault()`
9568 @*/
9569 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder)
9570 {
9571   PetscFunctionBegin;
9572   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9573   PetscAssertPointer(reorder, 2);
9574   *reorder = DM_REORDER_DEFAULT_NOTSET;
9575   PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder));
9576   PetscFunctionReturn(PETSC_SUCCESS);
9577 }
9578 
9579 /*@
9580   DMReorderSectionSetType - Set the type of local section reordering
9581 
9582   Logically collective
9583 
9584   Input Parameters:
9585 + dm      - The DM
9586 - reorder - The reordering method
9587 
9588   Level: intermediate
9589 
9590 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()`
9591 @*/
9592 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder)
9593 {
9594   PetscFunctionBegin;
9595   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9596   PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder));
9597   PetscFunctionReturn(PETSC_SUCCESS);
9598 }
9599 
9600 /*@
9601   DMReorderSectionGetType - Get the reordering type for the local section
9602 
9603   Not collective
9604 
9605   Input Parameter:
9606 . dm - The DM
9607 
9608   Output Parameter:
9609 . reorder - The reordering method
9610 
9611   Level: intermediate
9612 
9613 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()`
9614 @*/
9615 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder)
9616 {
9617   PetscFunctionBegin;
9618   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9619   PetscAssertPointer(reorder, 2);
9620   *reorder = NULL;
9621   PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder));
9622   PetscFunctionReturn(PETSC_SUCCESS);
9623 }
9624