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