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