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