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