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