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