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