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