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