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