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