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