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