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