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