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