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