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