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