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