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