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