xref: /petsc/src/dm/interface/dm.c (revision 2126a61d222f4ba29a8a0187aa8dff219df55633)
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   PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
3215   PetscValidHeaderSpecific(l, VEC_CLASSID, 4);
3216   PetscUseTypeMethod(dm, localtolocalbegin, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3217   PetscFunctionReturn(0);
3218 }
3219 
3220 /*@
3221    DMLocalToLocalEnd - Maps from a local vector to another local vector where the ghost
3222    points in the second are set correctly. Must be preceded by `DMLocalToLocalBegin()`.
3223 
3224    Neighbor-wise Collective on dm
3225 
3226    Input Parameters:
3227 +  da - the `DM` object
3228 .  g - the original local vector
3229 -  mode - one of `INSERT_VALUES` or `ADD_VALUES`
3230 
3231    Output Parameter:
3232 .  l  - the local vector with correct ghost values
3233 
3234    Level: intermediate
3235 
3236 .seealso: `DMLocalToLocalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMLocalToLocalBegin()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3237 
3238 @*/
3239 PetscErrorCode DMLocalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
3240 {
3241   PetscFunctionBegin;
3242   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3243   PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
3244   PetscValidHeaderSpecific(l, VEC_CLASSID, 4);
3245   PetscUseTypeMethod(dm, localtolocalend, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3246   PetscFunctionReturn(0);
3247 }
3248 
3249 /*@
3250     DMCoarsen - Coarsens a `DM` object using a standard, non-adaptive coarsening of the underlying mesh
3251 
3252     Collective on dm
3253 
3254     Input Parameters:
3255 +   dm - the `DM` object
3256 -   comm - the communicator to contain the new `DM` object (or MPI_COMM_NULL)
3257 
3258     Output Parameter:
3259 .   dmc - the coarsened `DM`
3260 
3261     Level: developer
3262 
3263 .seealso: `DM`, `DMRefine()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3264 
3265 @*/
3266 PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3267 {
3268   DMCoarsenHookLink link;
3269 
3270   PetscFunctionBegin;
3271   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3272   PetscCall(PetscLogEventBegin(DM_Coarsen, dm, 0, 0, 0));
3273   PetscUseTypeMethod(dm, coarsen, comm, dmc);
3274   if (*dmc) {
3275     (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */
3276     PetscCall(DMSetCoarseDM(dm, *dmc));
3277     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3278     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmc));
3279     (*dmc)->ctx       = dm->ctx;
3280     (*dmc)->levelup   = dm->levelup;
3281     (*dmc)->leveldown = dm->leveldown + 1;
3282     PetscCall(DMSetMatType(*dmc, dm->mattype));
3283     for (link = dm->coarsenhook; link; link = link->next) {
3284       if (link->coarsenhook) PetscCall((*link->coarsenhook)(dm, *dmc, link->ctx));
3285     }
3286   }
3287   PetscCall(PetscLogEventEnd(DM_Coarsen, dm, 0, 0, 0));
3288   PetscCheck(*dmc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3289   PetscFunctionReturn(0);
3290 }
3291 
3292 /*@C
3293    DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
3294 
3295    Logically Collective on fine
3296 
3297    Input Parameters:
3298 +  fine - `DM` on which to run a hook when restricting to a coarser level
3299 .  coarsenhook - function to run when setting up a coarser level
3300 .  restricthook - function to run to update data on coarser levels (called once per `SNESSolve()`)
3301 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3302 
3303    Calling sequence of coarsenhook:
3304 $    coarsenhook(DM fine,DM coarse,void *ctx);
3305 
3306 +  fine - fine level `DM`
3307 .  coarse - coarse level `DM` to restrict problem to
3308 -  ctx - optional user-defined function context
3309 
3310    Calling sequence for restricthook:
3311 $    restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
3312 $
3313 +  fine - fine level `DM`
3314 .  mrestrict - matrix restricting a fine-level solution to the coarse grid, usually the transpose of the interpolation
3315 .  rscale - scaling vector for restriction
3316 .  inject - matrix restricting by injection
3317 .  coarse - coarse level DM to update
3318 -  ctx - optional user-defined function context
3319 
3320    Level: advanced
3321 
3322    Notes:
3323    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`.
3324 
3325    If this function is called multiple times, the hooks will be run in the order they are added.
3326 
3327    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3328    extract the finest level information from its context (instead of from the `SNES`).
3329 
3330    The hooks are automatically called by `DMRestrict()`
3331 
3332    Fortran Note:
3333    This function is not available from Fortran.
3334 
3335 .seealso: `DMCoarsenHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3336 @*/
3337 PetscErrorCode DMCoarsenHookAdd(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx)
3338 {
3339   DMCoarsenHookLink link, *p;
3340 
3341   PetscFunctionBegin;
3342   PetscValidHeaderSpecific(fine, DM_CLASSID, 1);
3343   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3344     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(0);
3345   }
3346   PetscCall(PetscNew(&link));
3347   link->coarsenhook  = coarsenhook;
3348   link->restricthook = restricthook;
3349   link->ctx          = ctx;
3350   link->next         = NULL;
3351   *p                 = link;
3352   PetscFunctionReturn(0);
3353 }
3354 
3355 /*@C
3356    DMCoarsenHookRemove - remove a callback set with `DMCoarsenHookAdd()`
3357 
3358    Logically Collective on fine
3359 
3360    Input Parameters:
3361 +  fine - `DM` on which to run a hook when restricting to a coarser level
3362 .  coarsenhook - function to run when setting up a coarser level
3363 .  restricthook - function to run to update data on coarser levels
3364 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3365 
3366    Level: advanced
3367 
3368    Note:
3369    This function does nothing if the hook is not in the list.
3370 
3371    Fortran Note:
3372    This function is not available from Fortran.
3373 
3374 .seealso: `DMCoarsenHookAdd()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3375 @*/
3376 PetscErrorCode DMCoarsenHookRemove(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx)
3377 {
3378   DMCoarsenHookLink link, *p;
3379 
3380   PetscFunctionBegin;
3381   PetscValidHeaderSpecific(fine, DM_CLASSID, 1);
3382   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3383     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3384       link = *p;
3385       *p   = link->next;
3386       PetscCall(PetscFree(link));
3387       break;
3388     }
3389   }
3390   PetscFunctionReturn(0);
3391 }
3392 
3393 /*@
3394    DMRestrict - restricts user-defined problem data to a coarser `DM` by running hooks registered by `DMCoarsenHookAdd()`
3395 
3396    Collective if any hooks are
3397 
3398    Input Parameters:
3399 +  fine - finer `DM` from which the data is obtained
3400 .  restrct - restriction matrix, apply using `MatRestrict()`, usually the transpose of the interpolation
3401 .  rscale - scaling vector for restriction
3402 .  inject - injection matrix, also use `MatRestrict()`
3403 -  coarse - coarser DM to update
3404 
3405    Level: developer
3406 
3407    Developer Note:
3408    Though this routine is called `DMRestrict()` the hooks are added with `DMCoarsenHookAdd()`, a consistent terminology would be better
3409 
3410 .seealso: `DMCoarsenHookAdd()`, `MatRestrict()`, `DMInterpolate()`, `DMRefineHookAdd()`
3411 @*/
3412 PetscErrorCode DMRestrict(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse)
3413 {
3414   DMCoarsenHookLink link;
3415 
3416   PetscFunctionBegin;
3417   for (link = fine->coarsenhook; link; link = link->next) {
3418     if (link->restricthook) PetscCall((*link->restricthook)(fine, restrct, rscale, inject, coarse, link->ctx));
3419   }
3420   PetscFunctionReturn(0);
3421 }
3422 
3423 /*@C
3424    DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
3425 
3426    Logically Collective on global
3427 
3428    Input Parameters:
3429 +  global - global `DM`
3430 .  ddhook - function to run to pass data to the decomposition `DM` upon its creation
3431 .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
3432 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3433 
3434    Calling sequence for ddhook:
3435 $    ddhook(DM global,DM block,void *ctx)
3436 
3437 +  global - global `DM`
3438 .  block  - block `DM`
3439 -  ctx - optional user-defined function context
3440 
3441    Calling sequence for restricthook:
3442 $    restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
3443 
3444 +  global - global `DM`
3445 .  out    - scatter to the outer (with ghost and overlap points) block vector
3446 .  in     - scatter to block vector values only owned locally
3447 .  block  - block `DM`
3448 -  ctx - optional user-defined function context
3449 
3450    Level: advanced
3451 
3452    Notes:
3453    This function is only needed if auxiliary data needs to be set up on subdomain `DM`s.
3454 
3455    If this function is called multiple times, the hooks will be run in the order they are added.
3456 
3457    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3458    extract the global information from its context (instead of from the `SNES`).
3459 
3460    Fortran Note:
3461    This function is not available from Fortran.
3462 
3463 .seealso: `DMSubDomainHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3464 @*/
3465 PetscErrorCode DMSubDomainHookAdd(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx)
3466 {
3467   DMSubDomainHookLink link, *p;
3468 
3469   PetscFunctionBegin;
3470   PetscValidHeaderSpecific(global, DM_CLASSID, 1);
3471   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3472     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(0);
3473   }
3474   PetscCall(PetscNew(&link));
3475   link->restricthook = restricthook;
3476   link->ddhook       = ddhook;
3477   link->ctx          = ctx;
3478   link->next         = NULL;
3479   *p                 = link;
3480   PetscFunctionReturn(0);
3481 }
3482 
3483 /*@C
3484    DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to the coarse grid
3485 
3486    Logically Collective on global
3487 
3488    Input Parameters:
3489 +  global - global `DM`
3490 .  ddhook - function to run to pass data to the decomposition `DM` upon its creation
3491 .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
3492 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
3493 
3494    Level: advanced
3495 
3496    Fortran Note:
3497    This function is not available from Fortran.
3498 
3499 .seealso: `DMSubDomainHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3500 @*/
3501 PetscErrorCode DMSubDomainHookRemove(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx)
3502 {
3503   DMSubDomainHookLink link, *p;
3504 
3505   PetscFunctionBegin;
3506   PetscValidHeaderSpecific(global, DM_CLASSID, 1);
3507   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3508     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3509       link = *p;
3510       *p   = link->next;
3511       PetscCall(PetscFree(link));
3512       break;
3513     }
3514   }
3515   PetscFunctionReturn(0);
3516 }
3517 
3518 /*@
3519    DMSubDomainRestrict - restricts user-defined problem data to a block `DM` by running hooks registered by `DMSubDomainHookAdd()`
3520 
3521    Collective if any hooks are
3522 
3523    Input Parameters:
3524 +  fine - finer `DM` to use as a base
3525 .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3526 .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3527 -  coarse - coarser `DM` to update
3528 
3529    Level: developer
3530 
3531 .seealso: `DMCoarsenHookAdd()`, `MatRestrict()`
3532 @*/
3533 PetscErrorCode DMSubDomainRestrict(DM global, VecScatter oscatter, VecScatter gscatter, DM subdm)
3534 {
3535   DMSubDomainHookLink link;
3536 
3537   PetscFunctionBegin;
3538   for (link = global->subdomainhook; link; link = link->next) {
3539     if (link->restricthook) PetscCall((*link->restricthook)(global, oscatter, gscatter, subdm, link->ctx));
3540   }
3541   PetscFunctionReturn(0);
3542 }
3543 
3544 /*@
3545     DMGetCoarsenLevel - Gets the number of coarsenings that have generated this `DM`.
3546 
3547     Not Collective
3548 
3549     Input Parameter:
3550 .   dm - the `DM` object
3551 
3552     Output Parameter:
3553 .   level - number of coarsenings
3554 
3555     Level: developer
3556 
3557 .seealso: `DMCoarsen()`, `DMSetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3558 
3559 @*/
3560 PetscErrorCode DMGetCoarsenLevel(DM dm, PetscInt *level)
3561 {
3562   PetscFunctionBegin;
3563   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3564   PetscValidIntPointer(level, 2);
3565   *level = dm->leveldown;
3566   PetscFunctionReturn(0);
3567 }
3568 
3569 /*@
3570     DMSetCoarsenLevel - Sets the number of coarsenings that have generated this `DM`.
3571 
3572     Collective on dm
3573 
3574     Input Parameters:
3575 +   dm - the `DM` object
3576 -   level - number of coarsenings
3577 
3578     Level: developer
3579 
3580     Note:
3581     This is rarely used directly, the information is automatically set when a `DM` is created with `DMCoarsen()`
3582 
3583 .seealso: `DMSetCoarsenLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3584 @*/
3585 PetscErrorCode DMSetCoarsenLevel(DM dm, PetscInt level)
3586 {
3587   PetscFunctionBegin;
3588   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3589   dm->leveldown = level;
3590   PetscFunctionReturn(0);
3591 }
3592 
3593 /*@C
3594     DMRefineHierarchy - Refines a `DM` object, all levels at once
3595 
3596     Collective on dm
3597 
3598     Input Parameters:
3599 +   dm - the `DM` object
3600 -   nlevels - the number of levels of refinement
3601 
3602     Output Parameter:
3603 .   dmf - the refined `DM` hierarchy
3604 
3605     Level: developer
3606 
3607 .seealso: `DMCoarsen()`, `DMCoarsenHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3608 
3609 @*/
3610 PetscErrorCode DMRefineHierarchy(DM dm, PetscInt nlevels, DM dmf[])
3611 {
3612   PetscFunctionBegin;
3613   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3614   PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative");
3615   if (nlevels == 0) PetscFunctionReturn(0);
3616   PetscValidPointer(dmf, 3);
3617   if (dm->ops->refinehierarchy) {
3618     PetscUseTypeMethod(dm, refinehierarchy, nlevels, dmf);
3619   } else if (dm->ops->refine) {
3620     PetscInt i;
3621 
3622     PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &dmf[0]));
3623     for (i = 1; i < nlevels; i++) PetscCall(DMRefine(dmf[i - 1], PetscObjectComm((PetscObject)dm), &dmf[i]));
3624   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No RefineHierarchy for this DM yet");
3625   PetscFunctionReturn(0);
3626 }
3627 
3628 /*@C
3629     DMCoarsenHierarchy - Coarsens a `DM` object, all levels at once
3630 
3631     Collective on dm
3632 
3633     Input Parameters:
3634 +   dm - the `DM` object
3635 -   nlevels - the number of levels of coarsening
3636 
3637     Output Parameter:
3638 .   dmc - the coarsened `DM` hierarchy
3639 
3640     Level: developer
3641 
3642 .seealso: `DMCoarsen()`, `DMRefineHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3643 
3644 @*/
3645 PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3646 {
3647   PetscFunctionBegin;
3648   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3649   PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative");
3650   if (nlevels == 0) PetscFunctionReturn(0);
3651   PetscValidPointer(dmc, 3);
3652   if (dm->ops->coarsenhierarchy) {
3653     PetscUseTypeMethod(dm, coarsenhierarchy, nlevels, dmc);
3654   } else if (dm->ops->coarsen) {
3655     PetscInt i;
3656 
3657     PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &dmc[0]));
3658     for (i = 1; i < nlevels; i++) PetscCall(DMCoarsen(dmc[i - 1], PetscObjectComm((PetscObject)dm), &dmc[i]));
3659   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No CoarsenHierarchy for this DM yet");
3660   PetscFunctionReturn(0);
3661 }
3662 
3663 /*@C
3664     DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the `DM` is destroyed
3665 
3666     Logically Collective if the function is collective
3667 
3668     Input Parameters:
3669 +   dm - the `DM` object
3670 -   destroy - the destroy function
3671 
3672     Level: intermediate
3673 
3674 .seealso: `DMSetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3675 
3676 @*/
3677 PetscErrorCode DMSetApplicationContextDestroy(DM dm, PetscErrorCode (*destroy)(void **))
3678 {
3679   PetscFunctionBegin;
3680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3681   dm->ctxdestroy = destroy;
3682   PetscFunctionReturn(0);
3683 }
3684 
3685 /*@
3686     DMSetApplicationContext - Set a user context into a `DM` object
3687 
3688     Not Collective
3689 
3690     Input Parameters:
3691 +   dm - the `DM` object
3692 -   ctx - the user context
3693 
3694     Level: intermediate
3695 
3696     Note:
3697     A user context is a way to pass problem specific information that is accessable whenever the `DM` is available
3698 
3699 .seealso: `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3700 
3701 @*/
3702 PetscErrorCode DMSetApplicationContext(DM dm, void *ctx)
3703 {
3704   PetscFunctionBegin;
3705   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3706   dm->ctx = ctx;
3707   PetscFunctionReturn(0);
3708 }
3709 
3710 /*@
3711     DMGetApplicationContext - Gets a user context from a `DM` object
3712 
3713     Not Collective
3714 
3715     Input Parameter:
3716 .   dm - the `DM` object
3717 
3718     Output Parameter:
3719 .   ctx - the user context
3720 
3721     Level: intermediate
3722 
3723     Note:
3724     A user context is a way to pass problem specific information that is accessable whenever the `DM` is available
3725 
3726 .seealso: `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3727 
3728 @*/
3729 PetscErrorCode DMGetApplicationContext(DM dm, void *ctx)
3730 {
3731   PetscFunctionBegin;
3732   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3733   *(void **)ctx = dm->ctx;
3734   PetscFunctionReturn(0);
3735 }
3736 
3737 /*@C
3738     DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for `SNESVI`.
3739 
3740     Logically Collective on dm
3741 
3742     Input Parameters:
3743 +   dm - the DM object
3744 -   f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
3745 
3746     Level: intermediate
3747 
3748 .seealso: `DMComputeVariableBounds()`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`,
3749          `DMSetJacobian()`
3750 
3751 @*/
3752 PetscErrorCode DMSetVariableBounds(DM dm, PetscErrorCode (*f)(DM, Vec, Vec))
3753 {
3754   PetscFunctionBegin;
3755   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3756   dm->ops->computevariablebounds = f;
3757   PetscFunctionReturn(0);
3758 }
3759 
3760 /*@
3761     DMHasVariableBounds - does the `DM` object have a variable bounds function?
3762 
3763     Not Collective
3764 
3765     Input Parameter:
3766 .   dm - the `DM` object to destroy
3767 
3768     Output Parameter:
3769 .   flg - `PETSC_TRUE` if the variable bounds function exists
3770 
3771     Level: developer
3772 
3773 .seealso: `DMComputeVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3774 
3775 @*/
3776 PetscErrorCode DMHasVariableBounds(DM dm, PetscBool *flg)
3777 {
3778   PetscFunctionBegin;
3779   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3780   PetscValidBoolPointer(flg, 2);
3781   *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3782   PetscFunctionReturn(0);
3783 }
3784 
3785 /*@C
3786     DMComputeVariableBounds - compute variable bounds used by `SNESVI`.
3787 
3788     Logically Collective on dm
3789 
3790     Input Parameter:
3791 .   dm - the `DM` object
3792 
3793     Output parameters:
3794 +   xl - lower bound
3795 -   xu - upper bound
3796 
3797     Level: advanced
3798 
3799     Notes:
3800     This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3801 
3802 .seealso: `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3803 
3804 @*/
3805 PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3806 {
3807   PetscFunctionBegin;
3808   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3809   PetscValidHeaderSpecific(xl, VEC_CLASSID, 2);
3810   PetscValidHeaderSpecific(xu, VEC_CLASSID, 3);
3811   PetscUseTypeMethod(dm, computevariablebounds, xl, xu);
3812   PetscFunctionReturn(0);
3813 }
3814 
3815 /*@
3816     DMHasColoring - does the `DM` object have a method of providing a coloring?
3817 
3818     Not Collective
3819 
3820     Input Parameter:
3821 .   dm - the DM object
3822 
3823     Output Parameter:
3824 .   flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateColoring()`.
3825 
3826     Level: developer
3827 
3828 .seealso: `DMCreateColoring()`
3829 
3830 @*/
3831 PetscErrorCode DMHasColoring(DM dm, PetscBool *flg)
3832 {
3833   PetscFunctionBegin;
3834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3835   PetscValidBoolPointer(flg, 2);
3836   *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3837   PetscFunctionReturn(0);
3838 }
3839 
3840 /*@
3841     DMHasCreateRestriction - does the `DM` object have a method of providing a restriction?
3842 
3843     Not Collective
3844 
3845     Input Parameter:
3846 .   dm - the `DM` object
3847 
3848     Output Parameter:
3849 .   flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateRestriction()`.
3850 
3851     Level: developer
3852 
3853 .seealso: `DMCreateRestriction()`, `DMHasCreateInterpolation()`, `DMHasCreateInjection()`
3854 
3855 @*/
3856 PetscErrorCode DMHasCreateRestriction(DM dm, PetscBool *flg)
3857 {
3858   PetscFunctionBegin;
3859   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3860   PetscValidBoolPointer(flg, 2);
3861   *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3862   PetscFunctionReturn(0);
3863 }
3864 
3865 /*@
3866     DMHasCreateInjection - does the `DM` object have a method of providing an injection?
3867 
3868     Not Collective
3869 
3870     Input Parameter:
3871 .   dm - the `DM` object
3872 
3873     Output Parameter:
3874 .   flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateInjection()`.
3875 
3876     Level: developer
3877 
3878 .seealso: `DMCreateInjection()`, `DMHasCreateRestriction()`, `DMHasCreateInterpolation()`
3879 
3880 @*/
3881 PetscErrorCode DMHasCreateInjection(DM dm, PetscBool *flg)
3882 {
3883   PetscFunctionBegin;
3884   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3885   PetscValidBoolPointer(flg, 2);
3886   if (dm->ops->hascreateinjection) PetscUseTypeMethod(dm, hascreateinjection, flg);
3887   else *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3888   PetscFunctionReturn(0);
3889 }
3890 
3891 PetscFunctionList DMList              = NULL;
3892 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
3893 
3894 /*@C
3895   DMSetType - Builds a `DM`, for a particular `DM` implementation.
3896 
3897   Collective on dm
3898 
3899   Input Parameters:
3900 + dm     - The `DM` object
3901 - method - The name of the `DMType`, for example `DMDA`, `DMPLEX`
3902 
3903   Options Database Key:
3904 . -dm_type <type> - Sets the `DM` type; use -help for a list of available types
3905 
3906   Level: intermediate
3907 
3908   Note:
3909   Of the `DM` is constructed by directly calling a function to construct a particular `DM`, for example, `DMDACreate2d()` or `DMPLEXCreateBoxMesh()`
3910 
3911 .seealso: `DMType`, `DMDA`, `DMPLEX`, `DMGetType()`, `DMCreate()`, `DMDACreate2d()`
3912 @*/
3913 PetscErrorCode DMSetType(DM dm, DMType method)
3914 {
3915   PetscErrorCode (*r)(DM);
3916   PetscBool match;
3917 
3918   PetscFunctionBegin;
3919   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3920   PetscCall(PetscObjectTypeCompare((PetscObject)dm, method, &match));
3921   if (match) PetscFunctionReturn(0);
3922 
3923   PetscCall(DMRegisterAll());
3924   PetscCall(PetscFunctionListFind(DMList, method, &r));
3925   PetscCheck(r, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
3926 
3927   PetscTryTypeMethod(dm, destroy);
3928   PetscCall(PetscMemzero(dm->ops, sizeof(*dm->ops)));
3929   PetscCall(PetscObjectChangeTypeName((PetscObject)dm, method));
3930   PetscCall((*r)(dm));
3931   PetscFunctionReturn(0);
3932 }
3933 
3934 /*@C
3935   DMGetType - Gets the `DM` type name (as a string) from the `DM`.
3936 
3937   Not Collective
3938 
3939   Input Parameter:
3940 . dm  - The `DM`
3941 
3942   Output Parameter:
3943 . type - The `DMType` name
3944 
3945   Level: intermediate
3946 
3947 .seealso: `DMType`, `DMDA`, `DMPLEX`, `DMSetType()`, `DMCreate()`
3948 @*/
3949 PetscErrorCode DMGetType(DM dm, DMType *type)
3950 {
3951   PetscFunctionBegin;
3952   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3953   PetscValidPointer(type, 2);
3954   PetscCall(DMRegisterAll());
3955   *type = ((PetscObject)dm)->type_name;
3956   PetscFunctionReturn(0);
3957 }
3958 
3959 /*@C
3960   DMConvert - Converts a `DM` to another `DM`, either of the same or different type.
3961 
3962   Collective on dm
3963 
3964   Input Parameters:
3965 + dm - the `DM`
3966 - newtype - new `DM` type (use "same" for the same type)
3967 
3968   Output Parameter:
3969 . M - pointer to new `DM`
3970 
3971   Notes:
3972   Cannot be used to convert a sequential `DM` to a parallel or a parallel to sequential,
3973   the MPI communicator of the generated `DM` is always the same as the communicator
3974   of the input `DM`.
3975 
3976   Level: intermediate
3977 
3978 .seealso: `DM`, `DMSetType()`, `DMCreate()`, `DMClone()`
3979 @*/
3980 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3981 {
3982   DM        B;
3983   char      convname[256];
3984   PetscBool sametype /*, issame */;
3985 
3986   PetscFunctionBegin;
3987   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3988   PetscValidType(dm, 1);
3989   PetscValidPointer(M, 3);
3990   PetscCall(PetscObjectTypeCompare((PetscObject)dm, newtype, &sametype));
3991   /* PetscCall(PetscStrcmp(newtype, "same", &issame)); */
3992   if (sametype) {
3993     *M = dm;
3994     PetscCall(PetscObjectReference((PetscObject)dm));
3995     PetscFunctionReturn(0);
3996   } else {
3997     PetscErrorCode (*conv)(DM, DMType, DM *) = NULL;
3998 
3999     /*
4000        Order of precedence:
4001        1) See if a specialized converter is known to the current DM.
4002        2) See if a specialized converter is known to the desired DM class.
4003        3) See if a good general converter is registered for the desired class
4004        4) See if a good general converter is known for the current matrix.
4005        5) Use a really basic converter.
4006     */
4007 
4008     /* 1) See if a specialized converter is known to the current DM and the desired class */
4009     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4010     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4011     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4012     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4013     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4014     PetscCall(PetscObjectQueryFunction((PetscObject)dm, convname, &conv));
4015     if (conv) goto foundconv;
4016 
4017     /* 2)  See if a specialized converter is known to the desired DM class. */
4018     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &B));
4019     PetscCall(DMSetType(B, newtype));
4020     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4021     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4022     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4023     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4024     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4025     PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4026     if (conv) {
4027       PetscCall(DMDestroy(&B));
4028       goto foundconv;
4029     }
4030 
4031 #if 0
4032     /* 3) See if a good general converter is registered for the desired class */
4033     conv = B->ops->convertfrom;
4034     PetscCall(DMDestroy(&B));
4035     if (conv) goto foundconv;
4036 
4037     /* 4) See if a good general converter is known for the current matrix */
4038     if (dm->ops->convert) {
4039       conv = dm->ops->convert;
4040     }
4041     if (conv) goto foundconv;
4042 #endif
4043 
4044     /* 5) Use a really basic converter. */
4045     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject)dm)->type_name, newtype);
4046 
4047   foundconv:
4048     PetscCall(PetscLogEventBegin(DM_Convert, dm, 0, 0, 0));
4049     PetscCall((*conv)(dm, newtype, M));
4050     /* Things that are independent of DM type: We should consult DMClone() here */
4051     {
4052       const PetscReal *maxCell, *Lstart, *L;
4053 
4054       PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
4055       PetscCall(DMSetPeriodicity(*M, maxCell, Lstart, L));
4056       (*M)->prealloc_only = dm->prealloc_only;
4057       PetscCall(PetscFree((*M)->vectype));
4058       PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype));
4059       PetscCall(PetscFree((*M)->mattype));
4060       PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype));
4061     }
4062     PetscCall(PetscLogEventEnd(DM_Convert, dm, 0, 0, 0));
4063   }
4064   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4065   PetscFunctionReturn(0);
4066 }
4067 
4068 /*--------------------------------------------------------------------------------------------------------------------*/
4069 
4070 /*@C
4071   DMRegister -  Adds a new `DM` type implementation
4072 
4073   Not Collective
4074 
4075   Input Parameters:
4076 + name        - The name of a new user-defined creation routine
4077 - create_func - The creation routine itself
4078 
4079   Notes:
4080   DMRegister() may be called multiple times to add several user-defined `DM`s
4081 
4082   Sample usage:
4083 .vb
4084     DMRegister("my_da", MyDMCreate);
4085 .ve
4086 
4087   Then, your DM type can be chosen with the procedural interface via
4088 .vb
4089     DMCreate(MPI_Comm, DM *);
4090     DMSetType(DM,"my_da");
4091 .ve
4092    or at runtime via the option
4093 .vb
4094     -da_type my_da
4095 .ve
4096 
4097   Level: advanced
4098 
4099 .seealso: `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()`
4100 
4101 @*/
4102 PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM))
4103 {
4104   PetscFunctionBegin;
4105   PetscCall(DMInitializePackage());
4106   PetscCall(PetscFunctionListAdd(&DMList, sname, function));
4107   PetscFunctionReturn(0);
4108 }
4109 
4110 /*@C
4111   DMLoad - Loads a DM that has been stored in binary  with `DMView()`.
4112 
4113   Collective on viewer
4114 
4115   Input Parameters:
4116 + newdm - the newly loaded `DM`, this needs to have been created with `DMCreate()` or
4117            some related function before a call to `DMLoad()`.
4118 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
4119            `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()`
4120 
4121    Level: intermediate
4122 
4123   Notes:
4124   The type is determined by the data in the file, any type set into the DM before this call is ignored.
4125 
4126   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
4127   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
4128   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
4129 
4130   Notes for advanced users:
4131   Most users should not need to know the details of the binary storage
4132   format, since `DMLoad()` and `DMView()` completely hide these details.
4133   But for anyone who's interested, the standard binary matrix storage
4134   format is
4135 .vb
4136      has not yet been determined
4137 .ve
4138 
4139 .seealso: `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()`
4140 @*/
4141 PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
4142 {
4143   PetscBool isbinary, ishdf5;
4144 
4145   PetscFunctionBegin;
4146   PetscValidHeaderSpecific(newdm, DM_CLASSID, 1);
4147   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
4148   PetscCall(PetscViewerCheckReadable(viewer));
4149   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
4150   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
4151   PetscCall(PetscLogEventBegin(DM_Load, viewer, 0, 0, 0));
4152   if (isbinary) {
4153     PetscInt classid;
4154     char     type[256];
4155 
4156     PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT));
4157     PetscCheck(classid == DM_FILE_CLASSID, PetscObjectComm((PetscObject)newdm), PETSC_ERR_ARG_WRONG, "Not DM next in file, classid found %d", (int)classid);
4158     PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
4159     PetscCall(DMSetType(newdm, type));
4160     PetscTryTypeMethod(newdm, load, viewer);
4161   } else if (ishdf5) {
4162     PetscTryTypeMethod(newdm, load, viewer);
4163   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4164   PetscCall(PetscLogEventEnd(DM_Load, viewer, 0, 0, 0));
4165   PetscFunctionReturn(0);
4166 }
4167 
4168 /******************************** FEM Support **********************************/
4169 
4170 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4171 {
4172   PetscInt f;
4173 
4174   PetscFunctionBegin;
4175   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4176   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f])));
4177   PetscFunctionReturn(0);
4178 }
4179 
4180 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4181 {
4182   PetscInt f, g;
4183 
4184   PetscFunctionBegin;
4185   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4186   for (f = 0; f < rows; ++f) {
4187     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  |"));
4188     for (g = 0; g < cols; ++g) PetscCall(PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g])));
4189     PetscCall(PetscPrintf(PETSC_COMM_SELF, " |\n"));
4190   }
4191   PetscFunctionReturn(0);
4192 }
4193 
4194 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4195 {
4196   PetscInt           localSize, bs;
4197   PetscMPIInt        size;
4198   Vec                x, xglob;
4199   const PetscScalar *xarray;
4200 
4201   PetscFunctionBegin;
4202   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
4203   PetscCall(VecDuplicate(X, &x));
4204   PetscCall(VecCopy(X, x));
4205   PetscCall(VecChop(x, tol));
4206   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name));
4207   if (size > 1) {
4208     PetscCall(VecGetLocalSize(x, &localSize));
4209     PetscCall(VecGetArrayRead(x, &xarray));
4210     PetscCall(VecGetBlockSize(x, &bs));
4211     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob));
4212   } else {
4213     xglob = x;
4214   }
4215   PetscCall(VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm))));
4216   if (size > 1) {
4217     PetscCall(VecDestroy(&xglob));
4218     PetscCall(VecRestoreArrayRead(x, &xarray));
4219   }
4220   PetscCall(VecDestroy(&x));
4221   PetscFunctionReturn(0);
4222 }
4223 
4224 /*@
4225   DMGetSection - Get the `PetscSection` encoding the local data layout for the `DM`.   This is equivalent to `DMGetLocalSection()`. Deprecated in v3.12
4226 
4227   Input Parameter:
4228 . dm - The `DM`
4229 
4230   Output Parameter:
4231 . section - The `PetscSection`
4232 
4233   Options Database Keys:
4234 . -dm_petscsection_view - View the `PetscSection` created by the `DM`
4235 
4236   Level: advanced
4237 
4238   Notes:
4239   Use `DMGetLocalSection()` in new code.
4240 
4241   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4242 
4243 .seealso: `DMGetLocalSection()`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4244 @*/
4245 PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4246 {
4247   PetscFunctionBegin;
4248   PetscCall(DMGetLocalSection(dm, section));
4249   PetscFunctionReturn(0);
4250 }
4251 
4252 /*@
4253   DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`.
4254 
4255   Input Parameter:
4256 . dm - The `DM`
4257 
4258   Output Parameter:
4259 . section - The `PetscSection`
4260 
4261   Options Database Keys:
4262 . -dm_petscsection_view - View the section created by the `DM`
4263 
4264   Level: intermediate
4265 
4266   Note:
4267   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4268 
4269 .seealso: `DMSetLocalSection()`, `DMGetGlobalSection()`
4270 @*/
4271 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4272 {
4273   PetscFunctionBegin;
4274   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4275   PetscValidPointer(section, 2);
4276   if (!dm->localSection && dm->ops->createlocalsection) {
4277     PetscInt d;
4278 
4279     if (dm->setfromoptionscalled) {
4280       PetscObject       obj = (PetscObject)dm;
4281       PetscViewer       viewer;
4282       PetscViewerFormat format;
4283       PetscBool         flg;
4284 
4285       PetscCall(PetscOptionsGetViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg));
4286       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
4287       for (d = 0; d < dm->Nds; ++d) {
4288         PetscCall(PetscDSSetFromOptions(dm->probs[d].ds));
4289         if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer));
4290       }
4291       if (flg) {
4292         PetscCall(PetscViewerFlush(viewer));
4293         PetscCall(PetscViewerPopFormat(viewer));
4294         PetscCall(PetscViewerDestroy(&viewer));
4295       }
4296     }
4297     PetscUseTypeMethod(dm, createlocalsection);
4298     if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view"));
4299   }
4300   *section = dm->localSection;
4301   PetscFunctionReturn(0);
4302 }
4303 
4304 /*@
4305   DMSetSection - Set the `PetscSection` encoding the local data layout for the `DM`.  This is equivalent to `DMSetLocalSection()`. Deprecated in v3.12
4306 
4307   Input Parameters:
4308 + dm - The `DM`
4309 - section - The `PetscSection`
4310 
4311   Level: advanced
4312 
4313   Notes:
4314   Use `DMSetLocalSection()` in new code.
4315 
4316   Any existing `PetscSection` will be destroyed
4317 
4318 .seealso: `DMSetLocalSection()`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4319 @*/
4320 PetscErrorCode DMSetSection(DM dm, PetscSection section)
4321 {
4322   PetscFunctionBegin;
4323   PetscCall(DMSetLocalSection(dm, section));
4324   PetscFunctionReturn(0);
4325 }
4326 
4327 /*@
4328   DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.
4329 
4330   Input Parameters:
4331 + dm - The `DM`
4332 - section - The `PetscSection`
4333 
4334   Level: intermediate
4335 
4336   Note:
4337   Any existing Section will be destroyed
4338 
4339 .seealso: `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4340 @*/
4341 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4342 {
4343   PetscInt numFields = 0;
4344   PetscInt f;
4345 
4346   PetscFunctionBegin;
4347   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4348   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4349   PetscCall(PetscObjectReference((PetscObject)section));
4350   PetscCall(PetscSectionDestroy(&dm->localSection));
4351   dm->localSection = section;
4352   if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields));
4353   if (numFields) {
4354     PetscCall(DMSetNumFields(dm, numFields));
4355     for (f = 0; f < numFields; ++f) {
4356       PetscObject disc;
4357       const char *name;
4358 
4359       PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name));
4360       PetscCall(DMGetField(dm, f, NULL, &disc));
4361       PetscCall(PetscObjectSetName(disc, name));
4362     }
4363   }
4364   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4365   PetscCall(PetscSectionDestroy(&dm->globalSection));
4366   PetscFunctionReturn(0);
4367 }
4368 
4369 /*@
4370   DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation.
4371 
4372   not collective
4373 
4374   Input Parameter:
4375 . dm - The `DM`
4376 
4377   Output Parameters:
4378 + 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.
4379 . 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.
4380 - bias - Vector containing bias to be added to constrained dofs
4381 
4382   Level: advanced
4383 
4384   Note:
4385   This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`.
4386 
4387 .seealso: `DMSetDefaultConstraints()`
4388 @*/
4389 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4390 {
4391   PetscFunctionBegin;
4392   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4393   if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4394   if (section) *section = dm->defaultConstraint.section;
4395   if (mat) *mat = dm->defaultConstraint.mat;
4396   if (bias) *bias = dm->defaultConstraint.bias;
4397   PetscFunctionReturn(0);
4398 }
4399 
4400 /*@
4401   DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.
4402 
4403   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()`.
4404 
4405   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.
4406 
4407   collective on dm
4408 
4409   Input Parameters:
4410 + dm - The `DM`
4411 . 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).
4412 . 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).
4413 - 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).
4414 
4415   Level: advanced
4416 
4417   Note:
4418   This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them.
4419 
4420 .seealso: `DMGetDefaultConstraints()`
4421 @*/
4422 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4423 {
4424   PetscMPIInt result;
4425 
4426   PetscFunctionBegin;
4427   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4428   if (section) {
4429     PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4430     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result));
4431     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator");
4432   }
4433   if (mat) {
4434     PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
4435     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result));
4436     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator");
4437   }
4438   if (bias) {
4439     PetscValidHeaderSpecific(bias, VEC_CLASSID, 4);
4440     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result));
4441     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator");
4442   }
4443   PetscCall(PetscObjectReference((PetscObject)section));
4444   PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section));
4445   dm->defaultConstraint.section = section;
4446   PetscCall(PetscObjectReference((PetscObject)mat));
4447   PetscCall(MatDestroy(&dm->defaultConstraint.mat));
4448   dm->defaultConstraint.mat = mat;
4449   PetscCall(PetscObjectReference((PetscObject)bias));
4450   PetscCall(VecDestroy(&dm->defaultConstraint.bias));
4451   dm->defaultConstraint.bias = bias;
4452   PetscFunctionReturn(0);
4453 }
4454 
4455 #if defined(PETSC_USE_DEBUG)
4456 /*
4457   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.
4458 
4459   Input Parameters:
4460 + dm - The `DM`
4461 . localSection - `PetscSection` describing the local data layout
4462 - globalSection - `PetscSection` describing the global data layout
4463 
4464   Level: intermediate
4465 
4466 .seealso: `DMGetSectionSF()`, `DMSetSectionSF()`
4467 */
4468 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4469 {
4470   MPI_Comm        comm;
4471   PetscLayout     layout;
4472   const PetscInt *ranges;
4473   PetscInt        pStart, pEnd, p, nroots;
4474   PetscMPIInt     size, rank;
4475   PetscBool       valid = PETSC_TRUE, gvalid;
4476 
4477   PetscFunctionBegin;
4478   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4479   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4480   PetscCallMPI(MPI_Comm_size(comm, &size));
4481   PetscCallMPI(MPI_Comm_rank(comm, &rank));
4482   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
4483   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
4484   PetscCall(PetscLayoutCreate(comm, &layout));
4485   PetscCall(PetscLayoutSetBlockSize(layout, 1));
4486   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
4487   PetscCall(PetscLayoutSetUp(layout));
4488   PetscCall(PetscLayoutGetRanges(layout, &ranges));
4489   for (p = pStart; p < pEnd; ++p) {
4490     PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4491 
4492     PetscCall(PetscSectionGetDof(localSection, p, &dof));
4493     PetscCall(PetscSectionGetOffset(localSection, p, &off));
4494     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
4495     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
4496     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
4497     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
4498     if (!gdof) continue; /* Censored point */
4499     if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4500       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof));
4501       valid = PETSC_FALSE;
4502     }
4503     if (gcdof && (gcdof != cdof)) {
4504       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof));
4505       valid = PETSC_FALSE;
4506     }
4507     if (gdof < 0) {
4508       gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4509       for (d = 0; d < gsize; ++d) {
4510         PetscInt offset = -(goff + 1) + d, r;
4511 
4512         PetscCall(PetscFindInt(offset, size + 1, ranges, &r));
4513         if (r < 0) r = -(r + 2);
4514         if ((r < 0) || (r >= size)) {
4515           PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff));
4516           valid = PETSC_FALSE;
4517           break;
4518         }
4519       }
4520     }
4521   }
4522   PetscCall(PetscLayoutDestroy(&layout));
4523   PetscCall(PetscSynchronizedFlush(comm, NULL));
4524   PetscCall(MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm));
4525   if (!gvalid) {
4526     PetscCall(DMView(dm, NULL));
4527     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4528   }
4529   PetscFunctionReturn(0);
4530 }
4531 #endif
4532 
4533 /*@
4534   DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.
4535 
4536   Collective on dm
4537 
4538   Input Parameter:
4539 . dm - The `DM`
4540 
4541   Output Parameter:
4542 . section - The `PetscSection`
4543 
4544   Level: intermediate
4545 
4546   Note:
4547   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4548 
4549 .seealso: `DMSetLocalSection()`, `DMGetLocalSection()`
4550 @*/
4551 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4552 {
4553   PetscFunctionBegin;
4554   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4555   PetscValidPointer(section, 2);
4556   if (!dm->globalSection) {
4557     PetscSection s;
4558 
4559     PetscCall(DMGetLocalSection(dm, &s));
4560     PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4561     PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4562     PetscCall(PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection));
4563     PetscCall(PetscLayoutDestroy(&dm->map));
4564     PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map));
4565     PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view"));
4566   }
4567   *section = dm->globalSection;
4568   PetscFunctionReturn(0);
4569 }
4570 
4571 /*@
4572   DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.
4573 
4574   Input Parameters:
4575 + dm - The `DM`
4576 - section - The PetscSection, or NULL
4577 
4578   Level: intermediate
4579 
4580   Note:
4581   Any existing `PetscSection` will be destroyed
4582 
4583 .seealso: `DMGetGlobalSection()`, `DMSetLocalSection()`
4584 @*/
4585 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4586 {
4587   PetscFunctionBegin;
4588   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4589   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4590   PetscCall(PetscObjectReference((PetscObject)section));
4591   PetscCall(PetscSectionDestroy(&dm->globalSection));
4592   dm->globalSection = section;
4593 #if defined(PETSC_USE_DEBUG)
4594   if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section));
4595 #endif
4596   PetscFunctionReturn(0);
4597 }
4598 
4599 /*@
4600   DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set,
4601   it is created from the default `PetscSection` layouts in the `DM`.
4602 
4603   Input Parameter:
4604 . dm - The `DM`
4605 
4606   Output Parameter:
4607 . sf - The `PetscSF`
4608 
4609   Level: intermediate
4610 
4611   Note:
4612   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4613 
4614 .seealso: `DMSetSectionSF()`, `DMCreateSectionSF()`
4615 @*/
4616 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4617 {
4618   PetscInt nroots;
4619 
4620   PetscFunctionBegin;
4621   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4622   PetscValidPointer(sf, 2);
4623   if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4624   PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL));
4625   if (nroots < 0) {
4626     PetscSection section, gSection;
4627 
4628     PetscCall(DMGetLocalSection(dm, &section));
4629     if (section) {
4630       PetscCall(DMGetGlobalSection(dm, &gSection));
4631       PetscCall(DMCreateSectionSF(dm, section, gSection));
4632     } else {
4633       *sf = NULL;
4634       PetscFunctionReturn(0);
4635     }
4636   }
4637   *sf = dm->sectionSF;
4638   PetscFunctionReturn(0);
4639 }
4640 
4641 /*@
4642   DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`
4643 
4644   Input Parameters:
4645 + dm - The `DM`
4646 - sf - The `PetscSF`
4647 
4648   Level: intermediate
4649 
4650   Note:
4651   Any previous `PetscSF` is destroyed
4652 
4653 .seealso: `DMGetSectionSF()`, `DMCreateSectionSF()`
4654 @*/
4655 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4656 {
4657   PetscFunctionBegin;
4658   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4659   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4660   PetscCall(PetscObjectReference((PetscObject)sf));
4661   PetscCall(PetscSFDestroy(&dm->sectionSF));
4662   dm->sectionSF = sf;
4663   PetscFunctionReturn(0);
4664 }
4665 
4666 /*@C
4667   DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4668   describing the data layout.
4669 
4670   Input Parameters:
4671 + dm - The `DM`
4672 . localSection - `PetscSection` describing the local data layout
4673 - globalSection - `PetscSection` describing the global data layout
4674 
4675   Level: developer
4676 
4677   Note:
4678   One usually uses `DMGetSectionSF()` to obtain the `PetscSF`
4679 
4680   Developer Note:
4681   Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF`
4682   directly into the `DM`, perhaps this function should not take the local and global sections as
4683   input and should just obtain them from the `DM`?
4684 
4685 .seealso: `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4686 @*/
4687 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4688 {
4689   PetscFunctionBegin;
4690   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4691   PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection));
4692   PetscFunctionReturn(0);
4693 }
4694 
4695 /*@
4696   DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.
4697 
4698   Not collective but the resulting `PetscSF` is collective
4699 
4700   Input Parameter:
4701 . dm - The `DM`
4702 
4703   Output Parameter:
4704 . sf - The `PetscSF`
4705 
4706   Level: intermediate
4707 
4708   Note:
4709   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4710 
4711 .seealso: `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4712 @*/
4713 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4714 {
4715   PetscFunctionBegin;
4716   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4717   PetscValidPointer(sf, 2);
4718   *sf = dm->sf;
4719   PetscFunctionReturn(0);
4720 }
4721 
4722 /*@
4723   DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.
4724 
4725   Collective on dm
4726 
4727   Input Parameters:
4728 + dm - The `DM`
4729 - sf - The` PetscSF`
4730 
4731   Level: intermediate
4732 
4733 .seealso: `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4734 @*/
4735 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4736 {
4737   PetscFunctionBegin;
4738   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4739   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4740   PetscCall(PetscObjectReference((PetscObject)sf));
4741   PetscCall(PetscSFDestroy(&dm->sf));
4742   dm->sf = sf;
4743   PetscFunctionReturn(0);
4744 }
4745 
4746 /*@
4747   DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering
4748 
4749   Input Parameter:
4750 . dm - The `DM`
4751 
4752   Output Parameter:
4753 . sf - The `PetscSF`
4754 
4755   Level: intermediate
4756 
4757   Note:
4758   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4759 
4760 .seealso: `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4761 @*/
4762 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4763 {
4764   PetscFunctionBegin;
4765   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4766   PetscValidPointer(sf, 2);
4767   *sf = dm->sfNatural;
4768   PetscFunctionReturn(0);
4769 }
4770 
4771 /*@
4772   DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4773 
4774   Input Parameters:
4775 + dm - The DM
4776 - sf - The PetscSF
4777 
4778   Level: intermediate
4779 
4780 .seealso: `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4781 @*/
4782 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4783 {
4784   PetscFunctionBegin;
4785   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4786   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4787   PetscCall(PetscObjectReference((PetscObject)sf));
4788   PetscCall(PetscSFDestroy(&dm->sfNatural));
4789   dm->sfNatural = sf;
4790   PetscFunctionReturn(0);
4791 }
4792 
4793 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4794 {
4795   PetscClassId id;
4796 
4797   PetscFunctionBegin;
4798   PetscCall(PetscObjectGetClassId(disc, &id));
4799   if (id == PETSCFE_CLASSID) {
4800     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4801   } else if (id == PETSCFV_CLASSID) {
4802     PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE));
4803   } else {
4804     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4805   }
4806   PetscFunctionReturn(0);
4807 }
4808 
4809 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4810 {
4811   RegionField *tmpr;
4812   PetscInt     Nf = dm->Nf, f;
4813 
4814   PetscFunctionBegin;
4815   if (Nf >= NfNew) PetscFunctionReturn(0);
4816   PetscCall(PetscMalloc1(NfNew, &tmpr));
4817   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4818   for (f = Nf; f < NfNew; ++f) {
4819     tmpr[f].disc        = NULL;
4820     tmpr[f].label       = NULL;
4821     tmpr[f].avoidTensor = PETSC_FALSE;
4822   }
4823   PetscCall(PetscFree(dm->fields));
4824   dm->Nf     = NfNew;
4825   dm->fields = tmpr;
4826   PetscFunctionReturn(0);
4827 }
4828 
4829 /*@
4830   DMClearFields - Remove all fields from the DM
4831 
4832   Logically collective on dm
4833 
4834   Input Parameter:
4835 . dm - The DM
4836 
4837   Level: intermediate
4838 
4839 .seealso: `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4840 @*/
4841 PetscErrorCode DMClearFields(DM dm)
4842 {
4843   PetscInt f;
4844 
4845   PetscFunctionBegin;
4846   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4847   for (f = 0; f < dm->Nf; ++f) {
4848     PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4849     PetscCall(DMLabelDestroy(&dm->fields[f].label));
4850   }
4851   PetscCall(PetscFree(dm->fields));
4852   dm->fields = NULL;
4853   dm->Nf     = 0;
4854   PetscFunctionReturn(0);
4855 }
4856 
4857 /*@
4858   DMGetNumFields - Get the number of fields in the DM
4859 
4860   Not collective
4861 
4862   Input Parameter:
4863 . dm - The DM
4864 
4865   Output Parameter:
4866 . Nf - The number of fields
4867 
4868   Level: intermediate
4869 
4870 .seealso: `DMSetNumFields()`, `DMSetField()`
4871 @*/
4872 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4873 {
4874   PetscFunctionBegin;
4875   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4876   PetscValidIntPointer(numFields, 2);
4877   *numFields = dm->Nf;
4878   PetscFunctionReturn(0);
4879 }
4880 
4881 /*@
4882   DMSetNumFields - Set the number of fields in the DM
4883 
4884   Logically collective on dm
4885 
4886   Input Parameters:
4887 + dm - The DM
4888 - Nf - The number of fields
4889 
4890   Level: intermediate
4891 
4892 .seealso: `DMGetNumFields()`, `DMSetField()`
4893 @*/
4894 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4895 {
4896   PetscInt Nf, f;
4897 
4898   PetscFunctionBegin;
4899   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4900   PetscCall(DMGetNumFields(dm, &Nf));
4901   for (f = Nf; f < numFields; ++f) {
4902     PetscContainer obj;
4903 
4904     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj));
4905     PetscCall(DMAddField(dm, NULL, (PetscObject)obj));
4906     PetscCall(PetscContainerDestroy(&obj));
4907   }
4908   PetscFunctionReturn(0);
4909 }
4910 
4911 /*@
4912   DMGetField - Return the `DMLabel` and discretization object for a given `DM` field
4913 
4914   Not collective
4915 
4916   Input Parameters:
4917 + dm - The `DM`
4918 - f  - The field number
4919 
4920   Output Parameters:
4921 + label - The label indicating the support of the field, or NULL for the entire mesh (pass in NULL if not needed)
4922 - disc - The discretization object (pass in NULL if not needed)
4923 
4924   Level: intermediate
4925 
4926 .seealso: `DMAddField()`, `DMSetField()`
4927 @*/
4928 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
4929 {
4930   PetscFunctionBegin;
4931   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4932   PetscValidPointer(disc, 4);
4933   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);
4934   if (label) *label = dm->fields[f].label;
4935   if (disc) *disc = dm->fields[f].disc;
4936   PetscFunctionReturn(0);
4937 }
4938 
4939 /* Does not clear the DS */
4940 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
4941 {
4942   PetscFunctionBegin;
4943   PetscCall(DMFieldEnlarge_Static(dm, f + 1));
4944   PetscCall(DMLabelDestroy(&dm->fields[f].label));
4945   PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4946   dm->fields[f].label = label;
4947   dm->fields[f].disc  = disc;
4948   PetscCall(PetscObjectReference((PetscObject)label));
4949   PetscCall(PetscObjectReference((PetscObject)disc));
4950   PetscFunctionReturn(0);
4951 }
4952 
4953 /*@
4954   DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
4955   the field numbering.
4956 
4957   Logically collective on dm
4958 
4959   Input Parameters:
4960 + dm    - The `DM`
4961 . f     - The field number
4962 . label - The label indicating the support of the field, or NULL for the entire mesh
4963 - disc - The discretization object
4964 
4965   Level: intermediate
4966 
4967 .seealso: `DMAddField()`, `DMGetField()`
4968 @*/
4969 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
4970 {
4971   PetscFunctionBegin;
4972   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4973   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
4974   PetscValidHeader(disc, 4);
4975   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
4976   PetscCall(DMSetField_Internal(dm, f, label, disc));
4977   PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc));
4978   PetscCall(DMClearDS(dm));
4979   PetscFunctionReturn(0);
4980 }
4981 
4982 /*@
4983   DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
4984   and a discretization object that defines the function space associated with those points.
4985 
4986   Logically collective on dm
4987 
4988   Input Parameters:
4989 + dm    - The `DM`
4990 . label - The label indicating the support of the field, or NULL for the entire mesh
4991 - disc - The discretization object
4992 
4993   Level: intermediate
4994 
4995   Notes:
4996   The label already exists or will be added to the `DM` with `DMSetLabel()`.
4997 
4998   For example, a piecewise continous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
4999   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
5000   geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.
5001 
5002 .seealso: `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
5003 @*/
5004 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
5005 {
5006   PetscInt Nf = dm->Nf;
5007 
5008   PetscFunctionBegin;
5009   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5010   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5011   PetscValidHeader(disc, 3);
5012   PetscCall(DMFieldEnlarge_Static(dm, Nf + 1));
5013   dm->fields[Nf].label = label;
5014   dm->fields[Nf].disc  = disc;
5015   PetscCall(PetscObjectReference((PetscObject)label));
5016   PetscCall(PetscObjectReference((PetscObject)disc));
5017   PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc));
5018   PetscCall(DMClearDS(dm));
5019   PetscFunctionReturn(0);
5020 }
5021 
5022 /*@
5023   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
5024 
5025   Logically collective on dm
5026 
5027   Input Parameters:
5028 + dm          - The `DM`
5029 . f           - The field index
5030 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells
5031 
5032   Level: intermediate
5033 
5034 .seealso: `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
5035 @*/
5036 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
5037 {
5038   PetscFunctionBegin;
5039   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);
5040   dm->fields[f].avoidTensor = avoidTensor;
5041   PetscFunctionReturn(0);
5042 }
5043 
5044 /*@
5045   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
5046 
5047   Not collective
5048 
5049   Input Parameters:
5050 + dm          - The `DM`
5051 - f           - The field index
5052 
5053   Output Parameter:
5054 . avoidTensor - The flag to avoid defining the field on tensor cells
5055 
5056   Level: intermediate
5057 
5058  .seealso: `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
5059 @*/
5060 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
5061 {
5062   PetscFunctionBegin;
5063   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);
5064   *avoidTensor = dm->fields[f].avoidTensor;
5065   PetscFunctionReturn(0);
5066 }
5067 
5068 /*@
5069   DMCopyFields - Copy the discretizations for the `DM` into another `DM`
5070 
5071   Collective on dm
5072 
5073   Input Parameter:
5074 . dm - The `DM`
5075 
5076   Output Parameter:
5077 . newdm - The `DM`
5078 
5079   Level: advanced
5080 
5081 .seealso: `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
5082 @*/
5083 PetscErrorCode DMCopyFields(DM dm, DM newdm)
5084 {
5085   PetscInt Nf, f;
5086 
5087   PetscFunctionBegin;
5088   if (dm == newdm) PetscFunctionReturn(0);
5089   PetscCall(DMGetNumFields(dm, &Nf));
5090   PetscCall(DMClearFields(newdm));
5091   for (f = 0; f < Nf; ++f) {
5092     DMLabel     label;
5093     PetscObject field;
5094     PetscBool   useCone, useClosure;
5095 
5096     PetscCall(DMGetField(dm, f, &label, &field));
5097     PetscCall(DMSetField(newdm, f, label, field));
5098     PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
5099     PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure));
5100   }
5101   PetscFunctionReturn(0);
5102 }
5103 
5104 /*@
5105   DMGetAdjacency - Returns the flags for determining variable influence
5106 
5107   Not collective
5108 
5109   Input Parameters:
5110 + dm - The DM object
5111 - f  - The field number, or PETSC_DEFAULT for the default adjacency
5112 
5113   Output Parameters:
5114 + useCone    - Flag for variable influence starting with the cone operation
5115 - useClosure - Flag for variable influence using transitive closure
5116 
5117   Notes:
5118 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5119 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5120 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5121   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5122 
5123   Level: developer
5124 
5125 .seealso: `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
5126 @*/
5127 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
5128 {
5129   PetscFunctionBegin;
5130   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5131   if (useCone) PetscValidBoolPointer(useCone, 3);
5132   if (useClosure) PetscValidBoolPointer(useClosure, 4);
5133   if (f < 0) {
5134     if (useCone) *useCone = dm->adjacency[0];
5135     if (useClosure) *useClosure = dm->adjacency[1];
5136   } else {
5137     PetscInt Nf;
5138 
5139     PetscCall(DMGetNumFields(dm, &Nf));
5140     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5141     if (useCone) *useCone = dm->fields[f].adjacency[0];
5142     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5143   }
5144   PetscFunctionReturn(0);
5145 }
5146 
5147 /*@
5148   DMSetAdjacency - Set the flags for determining variable influence
5149 
5150   Not collective
5151 
5152   Input Parameters:
5153 + dm         - The DM object
5154 . f          - The field number
5155 . useCone    - Flag for variable influence starting with the cone operation
5156 - useClosure - Flag for variable influence using transitive closure
5157 
5158   Notes:
5159 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5160 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5161 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5162   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5163 
5164   Level: developer
5165 
5166 .seealso: `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
5167 @*/
5168 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5169 {
5170   PetscFunctionBegin;
5171   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5172   if (f < 0) {
5173     dm->adjacency[0] = useCone;
5174     dm->adjacency[1] = useClosure;
5175   } else {
5176     PetscInt Nf;
5177 
5178     PetscCall(DMGetNumFields(dm, &Nf));
5179     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5180     dm->fields[f].adjacency[0] = useCone;
5181     dm->fields[f].adjacency[1] = useClosure;
5182   }
5183   PetscFunctionReturn(0);
5184 }
5185 
5186 /*@
5187   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5188 
5189   Not collective
5190 
5191   Input Parameter:
5192 . dm - The DM object
5193 
5194   Output Parameters:
5195 + useCone    - Flag for variable influence starting with the cone operation
5196 - useClosure - Flag for variable influence using transitive closure
5197 
5198   Notes:
5199 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5200 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5201 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5202 
5203   Level: developer
5204 
5205 .seealso: `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5206 @*/
5207 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5208 {
5209   PetscInt Nf;
5210 
5211   PetscFunctionBegin;
5212   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5213   if (useCone) PetscValidBoolPointer(useCone, 2);
5214   if (useClosure) PetscValidBoolPointer(useClosure, 3);
5215   PetscCall(DMGetNumFields(dm, &Nf));
5216   if (!Nf) {
5217     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5218   } else {
5219     PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure));
5220   }
5221   PetscFunctionReturn(0);
5222 }
5223 
5224 /*@
5225   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5226 
5227   Not collective
5228 
5229   Input Parameters:
5230 + dm         - The DM object
5231 . useCone    - Flag for variable influence starting with the cone operation
5232 - useClosure - Flag for variable influence using transitive closure
5233 
5234   Notes:
5235 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5236 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5237 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5238 
5239   Level: developer
5240 
5241 .seealso: `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5242 @*/
5243 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5244 {
5245   PetscInt Nf;
5246 
5247   PetscFunctionBegin;
5248   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5249   PetscCall(DMGetNumFields(dm, &Nf));
5250   if (!Nf) {
5251     PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5252   } else {
5253     PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure));
5254   }
5255   PetscFunctionReturn(0);
5256 }
5257 
5258 PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5259 {
5260   DM           plex;
5261   DMLabel     *labels, *glabels;
5262   const char **names;
5263   char        *sendNames, *recvNames;
5264   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5265   size_t       len;
5266   MPI_Comm     comm;
5267   PetscMPIInt  rank, size, p, *counts, *displs;
5268 
5269   PetscFunctionBegin;
5270   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5271   PetscCallMPI(MPI_Comm_size(comm, &size));
5272   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5273   PetscCall(DMGetNumDS(dm, &Nds));
5274   for (s = 0; s < Nds; ++s) {
5275     PetscDS  dsBC;
5276     PetscInt numBd;
5277 
5278     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC));
5279     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5280     maxLabels += numBd;
5281   }
5282   PetscCall(PetscCalloc1(maxLabels, &labels));
5283   /* Get list of labels to be completed */
5284   for (s = 0; s < Nds; ++s) {
5285     PetscDS  dsBC;
5286     PetscInt numBd, bd;
5287 
5288     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC));
5289     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5290     for (bd = 0; bd < numBd; ++bd) {
5291       DMLabel      label;
5292       PetscInt     field;
5293       PetscObject  obj;
5294       PetscClassId id;
5295 
5296       PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
5297       PetscCall(DMGetField(dm, field, NULL, &obj));
5298       PetscCall(PetscObjectGetClassId(obj, &id));
5299       if (!(id == PETSCFE_CLASSID) || !label) continue;
5300       for (l = 0; l < Nl; ++l)
5301         if (labels[l] == label) break;
5302       if (l == Nl) labels[Nl++] = label;
5303     }
5304   }
5305   /* Get label names */
5306   PetscCall(PetscMalloc1(Nl, &names));
5307   for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l]));
5308   for (l = 0; l < Nl; ++l) {
5309     PetscCall(PetscStrlen(names[l], &len));
5310     maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5311   }
5312   PetscCall(PetscFree(labels));
5313   PetscCallMPI(MPI_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm));
5314   PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames));
5315   for (l = 0; l < Nl; ++l) PetscCall(PetscStrcpy(&sendNames[gmaxLen * l], names[l]));
5316   PetscCall(PetscFree(names));
5317   /* Put all names on all processes */
5318   PetscCall(PetscCalloc2(size, &counts, size + 1, &displs));
5319   PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm));
5320   for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5321   gNl = displs[size];
5322   for (p = 0; p < size; ++p) {
5323     counts[p] *= gmaxLen;
5324     displs[p] *= gmaxLen;
5325   }
5326   PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels));
5327   PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm));
5328   PetscCall(PetscFree2(counts, displs));
5329   PetscCall(PetscFree(sendNames));
5330   for (l = 0, gl = 0; l < gNl; ++l) {
5331     PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]));
5332     PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank);
5333     for (m = 0; m < gl; ++m)
5334       if (glabels[m] == glabels[gl]) continue;
5335     PetscCall(DMConvert(dm, DMPLEX, &plex));
5336     PetscCall(DMPlexLabelComplete(plex, glabels[gl]));
5337     PetscCall(DMDestroy(&plex));
5338     ++gl;
5339   }
5340   PetscCall(PetscFree2(recvNames, glabels));
5341   PetscFunctionReturn(0);
5342 }
5343 
5344 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5345 {
5346   DMSpace *tmpd;
5347   PetscInt Nds = dm->Nds, s;
5348 
5349   PetscFunctionBegin;
5350   if (Nds >= NdsNew) PetscFunctionReturn(0);
5351   PetscCall(PetscMalloc1(NdsNew, &tmpd));
5352   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5353   for (s = Nds; s < NdsNew; ++s) {
5354     tmpd[s].ds     = NULL;
5355     tmpd[s].label  = NULL;
5356     tmpd[s].fields = NULL;
5357   }
5358   PetscCall(PetscFree(dm->probs));
5359   dm->Nds   = NdsNew;
5360   dm->probs = tmpd;
5361   PetscFunctionReturn(0);
5362 }
5363 
5364 /*@
5365   DMGetNumDS - Get the number of discrete systems in the DM
5366 
5367   Not collective
5368 
5369   Input Parameter:
5370 . dm - The DM
5371 
5372   Output Parameter:
5373 . Nds - The number of PetscDS objects
5374 
5375   Level: intermediate
5376 
5377 .seealso: `DMGetDS()`, `DMGetCellDS()`
5378 @*/
5379 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5380 {
5381   PetscFunctionBegin;
5382   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5383   PetscValidIntPointer(Nds, 2);
5384   *Nds = dm->Nds;
5385   PetscFunctionReturn(0);
5386 }
5387 
5388 /*@
5389   DMClearDS - Remove all discrete systems from the DM
5390 
5391   Logically collective on dm
5392 
5393   Input Parameter:
5394 . dm - The DM
5395 
5396   Level: intermediate
5397 
5398 .seealso: `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5399 @*/
5400 PetscErrorCode DMClearDS(DM dm)
5401 {
5402   PetscInt s;
5403 
5404   PetscFunctionBegin;
5405   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5406   for (s = 0; s < dm->Nds; ++s) {
5407     PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5408     PetscCall(DMLabelDestroy(&dm->probs[s].label));
5409     PetscCall(ISDestroy(&dm->probs[s].fields));
5410   }
5411   PetscCall(PetscFree(dm->probs));
5412   dm->probs = NULL;
5413   dm->Nds   = 0;
5414   PetscFunctionReturn(0);
5415 }
5416 
5417 /*@
5418   DMGetDS - Get the default PetscDS
5419 
5420   Not collective
5421 
5422   Input Parameter:
5423 . dm    - The DM
5424 
5425   Output Parameter:
5426 . prob - The default PetscDS
5427 
5428   Level: intermediate
5429 
5430 .seealso: `DMGetCellDS()`, `DMGetRegionDS()`
5431 @*/
5432 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5433 {
5434   PetscFunctionBeginHot;
5435   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5436   PetscValidPointer(prob, 2);
5437   if (dm->Nds <= 0) {
5438     PetscDS ds;
5439 
5440     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
5441     PetscCall(DMSetRegionDS(dm, NULL, NULL, ds));
5442     PetscCall(PetscDSDestroy(&ds));
5443   }
5444   *prob = dm->probs[0].ds;
5445   PetscFunctionReturn(0);
5446 }
5447 
5448 /*@
5449   DMGetCellDS - Get the PetscDS defined on a given cell
5450 
5451   Not collective
5452 
5453   Input Parameters:
5454 + dm    - The DM
5455 - point - Cell for the DS
5456 
5457   Output Parameter:
5458 . prob - The PetscDS defined on the given cell
5459 
5460   Level: developer
5461 
5462 .seealso: `DMGetDS()`, `DMSetRegionDS()`
5463 @*/
5464 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5465 {
5466   PetscDS  probDef = NULL;
5467   PetscInt s;
5468 
5469   PetscFunctionBeginHot;
5470   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5471   PetscValidPointer(prob, 3);
5472   PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5473   *prob = NULL;
5474   for (s = 0; s < dm->Nds; ++s) {
5475     PetscInt val;
5476 
5477     if (!dm->probs[s].label) {
5478       probDef = dm->probs[s].ds;
5479     } else {
5480       PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5481       if (val >= 0) {
5482         *prob = dm->probs[s].ds;
5483         break;
5484       }
5485     }
5486   }
5487   if (!*prob) *prob = probDef;
5488   PetscFunctionReturn(0);
5489 }
5490 
5491 /*@
5492   DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
5493 
5494   Not collective
5495 
5496   Input Parameters:
5497 + dm    - The DM
5498 - label - The DMLabel defining the mesh region, or NULL for the entire mesh
5499 
5500   Output Parameters:
5501 + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5502 - prob - The PetscDS defined on the given region, or NULL
5503 
5504   Note:
5505   If a non-NULL label is given, but there is no PetscDS on that specific label,
5506   the PetscDS for the full domain (if present) is returned. Returns with
5507   fields=NULL and prob=NULL if there is no PetscDS for the full domain.
5508 
5509   Level: advanced
5510 
5511 .seealso: `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5512 @*/
5513 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5514 {
5515   PetscInt Nds = dm->Nds, s;
5516 
5517   PetscFunctionBegin;
5518   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5519   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5520   if (fields) {
5521     PetscValidPointer(fields, 3);
5522     *fields = NULL;
5523   }
5524   if (ds) {
5525     PetscValidPointer(ds, 4);
5526     *ds = NULL;
5527   }
5528   for (s = 0; s < Nds; ++s) {
5529     if (dm->probs[s].label == label || !dm->probs[s].label) {
5530       if (fields) *fields = dm->probs[s].fields;
5531       if (ds) *ds = dm->probs[s].ds;
5532       if (dm->probs[s].label) PetscFunctionReturn(0);
5533     }
5534   }
5535   PetscFunctionReturn(0);
5536 }
5537 
5538 /*@
5539   DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5540 
5541   Collective on dm
5542 
5543   Input Parameters:
5544 + dm     - The `DM`
5545 . label  - The `DMLabel` defining the mesh region, or NULL for the entire mesh
5546 . fields - The IS containing the `DM` field numbers for the fields in this `PetscDS`, or NULL for all fields
5547 - prob   - The `PetscDS` defined on the given region
5548 
5549   Note:
5550   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5551   the fields argument is ignored.
5552 
5553   Level: advanced
5554 
5555 .seealso: `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5556 @*/
5557 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5558 {
5559   PetscInt Nds = dm->Nds, s;
5560 
5561   PetscFunctionBegin;
5562   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5563   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5564   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5565   for (s = 0; s < Nds; ++s) {
5566     if (dm->probs[s].label == label) {
5567       PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5568       dm->probs[s].ds = ds;
5569       PetscFunctionReturn(0);
5570     }
5571   }
5572   PetscCall(DMDSEnlarge_Static(dm, Nds + 1));
5573   PetscCall(PetscObjectReference((PetscObject)label));
5574   PetscCall(PetscObjectReference((PetscObject)fields));
5575   PetscCall(PetscObjectReference((PetscObject)ds));
5576   if (!label) {
5577     /* Put the NULL label at the front, so it is returned as the default */
5578     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5579     Nds = 0;
5580   }
5581   dm->probs[Nds].label  = label;
5582   dm->probs[Nds].fields = fields;
5583   dm->probs[Nds].ds     = ds;
5584   PetscFunctionReturn(0);
5585 }
5586 
5587 /*@
5588   DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
5589 
5590   Not collective
5591 
5592   Input Parameters:
5593 + dm  - The DM
5594 - num - The region number, in [0, Nds)
5595 
5596   Output Parameters:
5597 + label  - The region label, or NULL
5598 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5599 - ds     - The PetscDS defined on the given region, or NULL
5600 
5601   Level: advanced
5602 
5603 .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5604 @*/
5605 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5606 {
5607   PetscInt Nds;
5608 
5609   PetscFunctionBegin;
5610   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5611   PetscCall(DMGetNumDS(dm, &Nds));
5612   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5613   if (label) {
5614     PetscValidPointer(label, 3);
5615     *label = dm->probs[num].label;
5616   }
5617   if (fields) {
5618     PetscValidPointer(fields, 4);
5619     *fields = dm->probs[num].fields;
5620   }
5621   if (ds) {
5622     PetscValidPointer(ds, 5);
5623     *ds = dm->probs[num].ds;
5624   }
5625   PetscFunctionReturn(0);
5626 }
5627 
5628 /*@
5629   DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number
5630 
5631   Not collective
5632 
5633   Input Parameters:
5634 + dm     - The DM
5635 . num    - The region number, in [0, Nds)
5636 . label  - The region label, or NULL
5637 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5638 - ds     - The PetscDS defined on the given region, or NULL to prevent setting
5639 
5640   Level: advanced
5641 
5642 .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5643 @*/
5644 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5645 {
5646   PetscInt Nds;
5647 
5648   PetscFunctionBegin;
5649   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5650   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5651   PetscCall(DMGetNumDS(dm, &Nds));
5652   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5653   PetscCall(PetscObjectReference((PetscObject)label));
5654   PetscCall(DMLabelDestroy(&dm->probs[num].label));
5655   dm->probs[num].label = label;
5656   if (fields) {
5657     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5658     PetscCall(PetscObjectReference((PetscObject)fields));
5659     PetscCall(ISDestroy(&dm->probs[num].fields));
5660     dm->probs[num].fields = fields;
5661   }
5662   if (ds) {
5663     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5664     PetscCall(PetscObjectReference((PetscObject)ds));
5665     PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5666     dm->probs[num].ds = ds;
5667   }
5668   PetscFunctionReturn(0);
5669 }
5670 
5671 /*@
5672   DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found.
5673 
5674   Not collective
5675 
5676   Input Parameters:
5677 + dm  - The DM
5678 - ds  - The PetscDS defined on the given region
5679 
5680   Output Parameter:
5681 . num - The region number, in [0, Nds), or -1 if not found
5682 
5683   Level: advanced
5684 
5685 .seealso: `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5686 @*/
5687 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5688 {
5689   PetscInt Nds, n;
5690 
5691   PetscFunctionBegin;
5692   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5693   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5694   PetscValidIntPointer(num, 3);
5695   PetscCall(DMGetNumDS(dm, &Nds));
5696   for (n = 0; n < Nds; ++n)
5697     if (ds == dm->probs[n].ds) break;
5698   if (n >= Nds) *num = -1;
5699   else *num = n;
5700   PetscFunctionReturn(0);
5701 }
5702 
5703 /*@C
5704   DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5705 
5706   Not collective
5707 
5708   Input Parameters:
5709 + dm     - The `DM`
5710 . Nc     - The number of components for the field
5711 . prefix - The options prefix for the output `PetscFE`, or NULL
5712 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5713 
5714   Output Parameter:
5715 . fem - The `PetscFE`
5716 
5717   Note:
5718   This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5719 
5720   Level: intermediate
5721 
5722 .seealso: `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5723 @*/
5724 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5725 {
5726   DMPolytopeType ct;
5727   PetscInt       dim, cStart;
5728 
5729   PetscFunctionBegin;
5730   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5731   PetscValidLogicalCollectiveInt(dm, Nc, 2);
5732   if (prefix) PetscValidCharPointer(prefix, 3);
5733   PetscValidLogicalCollectiveInt(dm, qorder, 4);
5734   PetscValidPointer(fem, 5);
5735   PetscCall(DMGetDimension(dm, &dim));
5736   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5737   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5738   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5739   PetscFunctionReturn(0);
5740 }
5741 
5742 /*@
5743   DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5744 
5745   Collective on dm
5746 
5747   Input Parameter:
5748 . dm - The `DM`
5749 
5750   Options Database Keys:
5751 . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5752 
5753   Note:
5754   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`.
5755 
5756   Level: intermediate
5757 
5758 .seealso: `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5759 @*/
5760 PetscErrorCode DMCreateDS(DM dm)
5761 {
5762   MPI_Comm  comm;
5763   PetscDS   dsDef;
5764   DMLabel  *labelSet;
5765   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5766   PetscBool doSetup = PETSC_TRUE, flg;
5767 
5768   PetscFunctionBegin;
5769   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5770   if (!dm->fields) PetscFunctionReturn(0);
5771   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5772   PetscCall(DMGetCoordinateDim(dm, &dE));
5773   /* Determine how many regions we have */
5774   PetscCall(PetscMalloc1(Nf, &labelSet));
5775   Nl   = 0;
5776   Ndef = 0;
5777   for (f = 0; f < Nf; ++f) {
5778     DMLabel  label = dm->fields[f].label;
5779     PetscInt l;
5780 
5781 #ifdef PETSC_HAVE_LIBCEED
5782     /* Move CEED context to discretizations */
5783     {
5784       PetscClassId id;
5785 
5786       PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5787       if (id == PETSCFE_CLASSID) {
5788         Ceed ceed;
5789 
5790         PetscCall(DMGetCeed(dm, &ceed));
5791         PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed));
5792       }
5793     }
5794 #endif
5795     if (!label) {
5796       ++Ndef;
5797       continue;
5798     }
5799     for (l = 0; l < Nl; ++l)
5800       if (label == labelSet[l]) break;
5801     if (l < Nl) continue;
5802     labelSet[Nl++] = label;
5803   }
5804   /* Create default DS if there are no labels to intersect with */
5805   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef));
5806   if (!dsDef && Ndef && !Nl) {
5807     IS        fields;
5808     PetscInt *fld, nf;
5809 
5810     for (f = 0, nf = 0; f < Nf; ++f)
5811       if (!dm->fields[f].label) ++nf;
5812     PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5813     PetscCall(PetscMalloc1(nf, &fld));
5814     for (f = 0, nf = 0; f < Nf; ++f)
5815       if (!dm->fields[f].label) fld[nf++] = f;
5816     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5817     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5818     PetscCall(ISSetType(fields, ISGENERAL));
5819     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5820 
5821     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5822     PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef));
5823     PetscCall(PetscDSDestroy(&dsDef));
5824     PetscCall(ISDestroy(&fields));
5825   }
5826   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef));
5827   if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5828   /* Intersect labels with default fields */
5829   if (Ndef && Nl) {
5830     DM              plex;
5831     DMLabel         cellLabel;
5832     IS              fieldIS, allcellIS, defcellIS = NULL;
5833     PetscInt       *fields;
5834     const PetscInt *cells;
5835     PetscInt        depth, nf = 0, n, c;
5836 
5837     PetscCall(DMConvert(dm, DMPLEX, &plex));
5838     PetscCall(DMPlexGetDepth(plex, &depth));
5839     PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
5840     if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
5841     /* TODO This looks like it only works for one label */
5842     for (l = 0; l < Nl; ++l) {
5843       DMLabel label = labelSet[l];
5844       IS      pointIS;
5845 
5846       PetscCall(ISDestroy(&defcellIS));
5847       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
5848       PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
5849       PetscCall(ISDestroy(&pointIS));
5850     }
5851     PetscCall(ISDestroy(&allcellIS));
5852 
5853     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
5854     PetscCall(ISGetLocalSize(defcellIS, &n));
5855     PetscCall(ISGetIndices(defcellIS, &cells));
5856     for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
5857     PetscCall(ISRestoreIndices(defcellIS, &cells));
5858     PetscCall(ISDestroy(&defcellIS));
5859     PetscCall(DMPlexLabelComplete(plex, cellLabel));
5860 
5861     PetscCall(PetscMalloc1(Ndef, &fields));
5862     for (f = 0; f < Nf; ++f)
5863       if (!dm->fields[f].label) fields[nf++] = f;
5864     PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
5865     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_"));
5866     PetscCall(ISSetType(fieldIS, ISGENERAL));
5867     PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
5868 
5869     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5870     PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef));
5871     PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5872     PetscCall(DMLabelDestroy(&cellLabel));
5873     PetscCall(PetscDSDestroy(&dsDef));
5874     PetscCall(ISDestroy(&fieldIS));
5875     PetscCall(DMDestroy(&plex));
5876   }
5877   /* Create label DSes
5878      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5879   */
5880   /* TODO Should check that labels are disjoint */
5881   for (l = 0; l < Nl; ++l) {
5882     DMLabel   label = labelSet[l];
5883     PetscDS   ds;
5884     IS        fields;
5885     PetscInt *fld, nf;
5886 
5887     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
5888     for (f = 0, nf = 0; f < Nf; ++f)
5889       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5890     PetscCall(PetscMalloc1(nf, &fld));
5891     for (f = 0, nf = 0; f < Nf; ++f)
5892       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5893     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5894     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5895     PetscCall(ISSetType(fields, ISGENERAL));
5896     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5897     PetscCall(DMSetRegionDS(dm, label, fields, ds));
5898     PetscCall(ISDestroy(&fields));
5899     PetscCall(PetscDSSetCoordinateDimension(ds, dE));
5900     {
5901       DMPolytopeType ct;
5902       PetscInt       lStart, lEnd;
5903       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;
5904 
5905       PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
5906       if (lStart >= 0) {
5907         PetscCall(DMPlexGetCellType(dm, lStart, &ct));
5908         switch (ct) {
5909         case DM_POLYTOPE_POINT_PRISM_TENSOR:
5910         case DM_POLYTOPE_SEG_PRISM_TENSOR:
5911         case DM_POLYTOPE_TRI_PRISM_TENSOR:
5912         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5913           isCohesiveLocal = PETSC_TRUE;
5914           break;
5915         default:
5916           break;
5917         }
5918       }
5919       PetscCallMPI(MPI_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm));
5920       for (f = 0, nf = 0; f < Nf; ++f) {
5921         if (label == dm->fields[f].label || !dm->fields[f].label) {
5922           if (label == dm->fields[f].label) {
5923             PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
5924             PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
5925           }
5926           ++nf;
5927         }
5928       }
5929     }
5930     PetscCall(PetscDSDestroy(&ds));
5931   }
5932   PetscCall(PetscFree(labelSet));
5933   /* Set fields in DSes */
5934   for (s = 0; s < dm->Nds; ++s) {
5935     PetscDS         ds     = dm->probs[s].ds;
5936     IS              fields = dm->probs[s].fields;
5937     const PetscInt *fld;
5938     PetscInt        nf, dsnf;
5939     PetscBool       isCohesive;
5940 
5941     PetscCall(PetscDSGetNumFields(ds, &dsnf));
5942     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
5943     PetscCall(ISGetLocalSize(fields, &nf));
5944     PetscCall(ISGetIndices(fields, &fld));
5945     for (f = 0; f < nf; ++f) {
5946       PetscObject  disc = dm->fields[fld[f]].disc;
5947       PetscBool    isCohesiveField;
5948       PetscClassId id;
5949 
5950       /* Handle DS with no fields */
5951       if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
5952       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
5953       if (isCohesive && !isCohesiveField) PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&disc));
5954       PetscCall(PetscDSSetDiscretization(ds, f, disc));
5955       /* We allow people to have placeholder fields and construct the Section by hand */
5956       PetscCall(PetscObjectGetClassId(disc, &id));
5957       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5958     }
5959     PetscCall(ISRestoreIndices(fields, &fld));
5960   }
5961   /* Allow k-jet tabulation */
5962   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
5963   if (flg) {
5964     for (s = 0; s < dm->Nds; ++s) {
5965       PetscDS  ds = dm->probs[s].ds;
5966       PetscInt Nf, f;
5967 
5968       PetscCall(PetscDSGetNumFields(ds, &Nf));
5969       for (f = 0; f < Nf; ++f) PetscCall(PetscDSSetJetDegree(ds, f, k));
5970     }
5971   }
5972   /* Setup DSes */
5973   if (doSetup) {
5974     for (s = 0; s < dm->Nds; ++s) PetscCall(PetscDSSetUp(dm->probs[s].ds));
5975   }
5976   PetscFunctionReturn(0);
5977 }
5978 
5979 /*@
5980   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
5981 
5982   Collective on `DM`
5983 
5984   Input Parameters:
5985 + dm   - The `DM`
5986 - time - The time
5987 
5988   Output Parameters:
5989 + u    - The vector will be filled with exact solution values, or NULL
5990 - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL
5991 
5992   Note:
5993   The user must call `PetscDSSetExactSolution()` before using this routine
5994 
5995   Level: developer
5996 
5997 .seealso: `PetscDSSetExactSolution()`
5998 @*/
5999 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
6000 {
6001   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
6002   void   **ectxs;
6003   PetscInt Nf, Nds, s;
6004 
6005   PetscFunctionBegin;
6006   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6007   if (u) PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
6008   if (u_t) PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
6009   PetscCall(DMGetNumFields(dm, &Nf));
6010   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
6011   PetscCall(DMGetNumDS(dm, &Nds));
6012   for (s = 0; s < Nds; ++s) {
6013     PetscDS         ds;
6014     DMLabel         label;
6015     IS              fieldIS;
6016     const PetscInt *fields, id = 1;
6017     PetscInt        dsNf, f;
6018 
6019     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
6020     PetscCall(PetscDSGetNumFields(ds, &dsNf));
6021     PetscCall(ISGetIndices(fieldIS, &fields));
6022     PetscCall(PetscArrayzero(exacts, Nf));
6023     PetscCall(PetscArrayzero(ectxs, Nf));
6024     if (u) {
6025       for (f = 0; f < dsNf; ++f) {
6026         const PetscInt field = fields[f];
6027         PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]));
6028       }
6029       PetscCall(ISRestoreIndices(fieldIS, &fields));
6030       if (label) {
6031         PetscCall(DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u));
6032       } else {
6033         PetscCall(DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u));
6034       }
6035     }
6036     if (u_t) {
6037       PetscCall(PetscArrayzero(exacts, Nf));
6038       PetscCall(PetscArrayzero(ectxs, Nf));
6039       for (f = 0; f < dsNf; ++f) {
6040         const PetscInt field = fields[f];
6041         PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]));
6042       }
6043       PetscCall(ISRestoreIndices(fieldIS, &fields));
6044       if (label) {
6045         PetscCall(DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t));
6046       } else {
6047         PetscCall(DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t));
6048       }
6049     }
6050   }
6051   if (u) {
6052     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6053     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6054   }
6055   if (u_t) {
6056     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6057     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6058   }
6059   PetscCall(PetscFree2(exacts, ectxs));
6060   PetscFunctionReturn(0);
6061 }
6062 
6063 PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
6064 {
6065   PetscDS    dsNew;
6066   DSBoundary b;
6067   PetscInt   cdim, Nf, f, d;
6068   PetscBool  isCohesive;
6069   void      *ctx;
6070 
6071   PetscFunctionBegin;
6072   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6073   PetscCall(PetscDSCopyConstants(ds, dsNew));
6074   PetscCall(PetscDSCopyExactSolutions(ds, dsNew));
6075   PetscCall(PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew));
6076   PetscCall(PetscDSCopyEquations(ds, dsNew));
6077   PetscCall(PetscDSGetNumFields(ds, &Nf));
6078   for (f = 0; f < Nf; ++f) {
6079     PetscCall(PetscDSGetContext(ds, f, &ctx));
6080     PetscCall(PetscDSSetContext(dsNew, f, ctx));
6081     PetscCall(PetscDSGetCohesive(ds, f, &isCohesive));
6082     PetscCall(PetscDSSetCohesive(dsNew, f, isCohesive));
6083     PetscCall(PetscDSGetJetDegree(ds, f, &d));
6084     PetscCall(PetscDSSetJetDegree(dsNew, f, d));
6085   }
6086   if (Nf) {
6087     PetscCall(PetscDSGetCoordinateDimension(ds, &cdim));
6088     PetscCall(PetscDSSetCoordinateDimension(dsNew, cdim));
6089   }
6090   PetscCall(PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew));
6091   for (b = dsNew->boundary; b; b = b->next) {
6092     PetscCall(DMGetLabel(dm, b->lname, &b->label));
6093     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
6094     //PetscCheck(b->label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name);
6095   }
6096 
6097   PetscCall(DMSetRegionDS(dm, label, fields, dsNew));
6098   PetscCall(PetscDSDestroy(&dsNew));
6099   PetscFunctionReturn(0);
6100 }
6101 
6102 /*@
6103   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6104 
6105   Collective on dm
6106 
6107   Input Parameter:
6108 . dm - The `DM`
6109 
6110   Output Parameter:
6111 . newdm - The `DM`
6112 
6113   Level: advanced
6114 
6115 .seealso: `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6116 @*/
6117 PetscErrorCode DMCopyDS(DM dm, DM newdm)
6118 {
6119   PetscInt Nds, s;
6120 
6121   PetscFunctionBegin;
6122   if (dm == newdm) PetscFunctionReturn(0);
6123   PetscCall(DMGetNumDS(dm, &Nds));
6124   PetscCall(DMClearDS(newdm));
6125   for (s = 0; s < Nds; ++s) {
6126     DMLabel  label;
6127     IS       fields;
6128     PetscDS  ds, newds;
6129     PetscInt Nbd, bd;
6130 
6131     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds));
6132     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6133     PetscCall(DMTransferDS_Internal(newdm, label, fields, ds));
6134     /* Commplete new labels in the new DS */
6135     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds));
6136     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6137     for (bd = 0; bd < Nbd; ++bd) {
6138       PetscWeakForm wf;
6139       DMLabel       label;
6140       PetscInt      field;
6141 
6142       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6143       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6144     }
6145   }
6146   PetscCall(DMCompleteBCLabels_Internal(newdm));
6147   PetscFunctionReturn(0);
6148 }
6149 
6150 /*@
6151   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6152 
6153   Collective on dm
6154 
6155   Input Parameter:
6156 . dm - The `DM`
6157 
6158   Output Parameter:
6159 . newdm - The `DM`
6160 
6161   Level: advanced
6162 
6163   Developer Note:
6164   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6165 
6166 .seealso: `DMCopyFields()`, `DMCopyDS()`
6167 @*/
6168 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6169 {
6170   PetscFunctionBegin;
6171   PetscCall(DMCopyFields(dm, newdm));
6172   PetscCall(DMCopyDS(dm, newdm));
6173   PetscFunctionReturn(0);
6174 }
6175 
6176 /*@
6177   DMGetDimension - Return the topological dimension of the `DM`
6178 
6179   Not collective
6180 
6181   Input Parameter:
6182 . dm - The `DM`
6183 
6184   Output Parameter:
6185 . dim - The topological dimension
6186 
6187   Level: beginner
6188 
6189 .seealso: `DMSetDimension()`, `DMCreate()`
6190 @*/
6191 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6192 {
6193   PetscFunctionBegin;
6194   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6195   PetscValidIntPointer(dim, 2);
6196   *dim = dm->dim;
6197   PetscFunctionReturn(0);
6198 }
6199 
6200 /*@
6201   DMSetDimension - Set the topological dimension of the `DM`
6202 
6203   Collective on dm
6204 
6205   Input Parameters:
6206 + dm - The `DM`
6207 - dim - The topological dimension
6208 
6209   Level: beginner
6210 
6211 .seealso: `DMGetDimension()`, `DMCreate()`
6212 @*/
6213 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6214 {
6215   PetscDS  ds;
6216   PetscInt Nds, n;
6217 
6218   PetscFunctionBegin;
6219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6220   PetscValidLogicalCollectiveInt(dm, dim, 2);
6221   dm->dim = dim;
6222   if (dm->dim >= 0) {
6223     PetscCall(DMGetNumDS(dm, &Nds));
6224     for (n = 0; n < Nds; ++n) {
6225       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds));
6226       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6227     }
6228   }
6229   PetscFunctionReturn(0);
6230 }
6231 
6232 /*@
6233   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6234 
6235   Collective on dm
6236 
6237   Input Parameters:
6238 + dm - the `DM`
6239 - dim - the dimension
6240 
6241   Output Parameters:
6242 + pStart - The first point of the given dimension
6243 - pEnd - The first point following points of the given dimension
6244 
6245   Note:
6246   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6247   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6248   then the interval is empty.
6249 
6250   Level: intermediate
6251 
6252 .seealso: `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6253 @*/
6254 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6255 {
6256   PetscInt d;
6257 
6258   PetscFunctionBegin;
6259   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6260   PetscCall(DMGetDimension(dm, &d));
6261   PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6262   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6263   PetscFunctionReturn(0);
6264 }
6265 
6266 /*@
6267   DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6268 
6269   Collective on dm
6270 
6271   Input Parameter:
6272 . dm - The original `DM`
6273 
6274   Output Parameter:
6275 . odm - The `DM` which provides the layout for output
6276 
6277   Level: intermediate
6278 
6279   Note:
6280   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6281   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6282   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6283 
6284 .seealso: `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6285 @*/
6286 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6287 {
6288   PetscSection section;
6289   PetscBool    hasConstraints, ghasConstraints;
6290 
6291   PetscFunctionBegin;
6292   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6293   PetscValidPointer(odm, 2);
6294   PetscCall(DMGetLocalSection(dm, &section));
6295   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6296   PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6297   if (!ghasConstraints) {
6298     *odm = dm;
6299     PetscFunctionReturn(0);
6300   }
6301   if (!dm->dmBC) {
6302     PetscSection newSection, gsection;
6303     PetscSF      sf;
6304 
6305     PetscCall(DMClone(dm, &dm->dmBC));
6306     PetscCall(DMCopyDisc(dm, dm->dmBC));
6307     PetscCall(PetscSectionClone(section, &newSection));
6308     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6309     PetscCall(PetscSectionDestroy(&newSection));
6310     PetscCall(DMGetPointSF(dm->dmBC, &sf));
6311     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
6312     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6313     PetscCall(PetscSectionDestroy(&gsection));
6314   }
6315   *odm = dm->dmBC;
6316   PetscFunctionReturn(0);
6317 }
6318 
6319 /*@
6320   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6321 
6322   Input Parameter:
6323 . dm - The original `DM`
6324 
6325   Output Parameters:
6326 + num - The output sequence number
6327 - val - The output sequence value
6328 
6329   Level: intermediate
6330 
6331   Note:
6332   This is intended for output that should appear in sequence, for instance
6333   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6334 
6335   Developer Note:
6336   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6337   not directly related to the `DM`.
6338 
6339 .seealso: `VecView()`
6340 @*/
6341 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6342 {
6343   PetscFunctionBegin;
6344   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6345   if (num) {
6346     PetscValidIntPointer(num, 2);
6347     *num = dm->outputSequenceNum;
6348   }
6349   if (val) {
6350     PetscValidRealPointer(val, 3);
6351     *val = dm->outputSequenceVal;
6352   }
6353   PetscFunctionReturn(0);
6354 }
6355 
6356 /*@
6357   DMSetOutputSequenceNumber - Set the sequence number/value for output
6358 
6359   Input Parameters:
6360 + dm - The original `DM`
6361 . num - The output sequence number
6362 - val - The output sequence value
6363 
6364   Level: intermediate
6365 
6366   Note:
6367   This is intended for output that should appear in sequence, for instance
6368   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6369 
6370 .seealso: `VecView()`
6371 @*/
6372 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6373 {
6374   PetscFunctionBegin;
6375   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6376   dm->outputSequenceNum = num;
6377   dm->outputSequenceVal = val;
6378   PetscFunctionReturn(0);
6379 }
6380 
6381 /*@C
6382  DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6383 
6384   Input Parameters:
6385 + dm   - The original `DM`
6386 . name - The sequence name
6387 - num  - The output sequence number
6388 
6389   Output Parameter:
6390 . val  - The output sequence value
6391 
6392   Level: intermediate
6393 
6394   Note:
6395   This is intended for output that should appear in sequence, for instance
6396   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6397 
6398   Developer Note:
6399   It is unclear at the user API level why a `DM` is needed as input
6400 
6401 .seealso: `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6402 @*/
6403 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6404 {
6405   PetscBool ishdf5;
6406 
6407   PetscFunctionBegin;
6408   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6409   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6410   PetscValidRealPointer(val, 5);
6411   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6412   if (ishdf5) {
6413 #if defined(PETSC_HAVE_HDF5)
6414     PetscScalar value;
6415 
6416     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6417     *val = PetscRealPart(value);
6418 #endif
6419   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6420   PetscFunctionReturn(0);
6421 }
6422 
6423 /*@
6424   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6425 
6426   Not collective
6427 
6428   Input Parameter:
6429 . dm - The `DM`
6430 
6431   Output Parameter:
6432 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6433 
6434   Level: beginner
6435 
6436 .seealso: `DMSetUseNatural()`, `DMCreate()`
6437 @*/
6438 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6439 {
6440   PetscFunctionBegin;
6441   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6442   PetscValidBoolPointer(useNatural, 2);
6443   *useNatural = dm->useNatural;
6444   PetscFunctionReturn(0);
6445 }
6446 
6447 /*@
6448   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6449 
6450   Collective on dm
6451 
6452   Input Parameters:
6453  + dm - The `DM`
6454 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6455 
6456   Note:
6457   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6458 
6459   Level: beginner
6460 
6461 .seealso: `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6462 @*/
6463 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6464 {
6465   PetscFunctionBegin;
6466   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6467   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6468   dm->useNatural = useNatural;
6469   PetscFunctionReturn(0);
6470 }
6471 
6472 /*@C
6473   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6474 
6475   Not Collective
6476 
6477   Input Parameters:
6478 + dm   - The `DM` object
6479 - name - The label name
6480 
6481   Level: intermediate
6482 
6483 .seealso: `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6484 @*/
6485 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6486 {
6487   PetscBool flg;
6488   DMLabel   label;
6489 
6490   PetscFunctionBegin;
6491   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6492   PetscValidCharPointer(name, 2);
6493   PetscCall(DMHasLabel(dm, name, &flg));
6494   if (!flg) {
6495     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6496     PetscCall(DMAddLabel(dm, label));
6497     PetscCall(DMLabelDestroy(&label));
6498   }
6499   PetscFunctionReturn(0);
6500 }
6501 
6502 /*@C
6503   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6504 
6505   Not Collective
6506 
6507   Input Parameters:
6508 + dm   - The `DM` object
6509 . l    - The index for the label
6510 - name - The label name
6511 
6512   Level: intermediate
6513 
6514 .seealso: `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6515 @*/
6516 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6517 {
6518   DMLabelLink orig, prev = NULL;
6519   DMLabel     label;
6520   PetscInt    Nl, m;
6521   PetscBool   flg, match;
6522   const char *lname;
6523 
6524   PetscFunctionBegin;
6525   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6526   PetscValidCharPointer(name, 3);
6527   PetscCall(DMHasLabel(dm, name, &flg));
6528   if (!flg) {
6529     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6530     PetscCall(DMAddLabel(dm, label));
6531     PetscCall(DMLabelDestroy(&label));
6532   }
6533   PetscCall(DMGetNumLabels(dm, &Nl));
6534   PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6535   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6536     PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6537     PetscCall(PetscStrcmp(name, lname, &match));
6538     if (match) break;
6539   }
6540   if (m == l) PetscFunctionReturn(0);
6541   if (!m) dm->labels = orig->next;
6542   else prev->next = orig->next;
6543   if (!l) {
6544     orig->next = dm->labels;
6545     dm->labels = orig;
6546   } else {
6547     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next)
6548       ;
6549     orig->next = prev->next;
6550     prev->next = orig;
6551   }
6552   PetscFunctionReturn(0);
6553 }
6554 
6555 /*@C
6556   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6557 
6558   Not Collective
6559 
6560   Input Parameters:
6561 + dm   - The `DM` object
6562 . name - The label name
6563 - point - The mesh point
6564 
6565   Output Parameter:
6566 . value - The label value for this point, or -1 if the point is not in the label
6567 
6568   Level: beginner
6569 
6570 .seealso: `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6571 @*/
6572 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6573 {
6574   DMLabel label;
6575 
6576   PetscFunctionBegin;
6577   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6578   PetscValidCharPointer(name, 2);
6579   PetscCall(DMGetLabel(dm, name, &label));
6580   PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6581   PetscCall(DMLabelGetValue(label, point, value));
6582   PetscFunctionReturn(0);
6583 }
6584 
6585 /*@C
6586   DMSetLabelValue - Add a point to a `DMLabel` with given value
6587 
6588   Not Collective
6589 
6590   Input Parameters:
6591 + dm   - The `DM` object
6592 . name - The label name
6593 . point - The mesh point
6594 - value - The label value for this point
6595 
6596   Output Parameter:
6597 
6598   Level: beginner
6599 
6600 .seealso: `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6601 @*/
6602 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6603 {
6604   DMLabel label;
6605 
6606   PetscFunctionBegin;
6607   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6608   PetscValidCharPointer(name, 2);
6609   PetscCall(DMGetLabel(dm, name, &label));
6610   if (!label) {
6611     PetscCall(DMCreateLabel(dm, name));
6612     PetscCall(DMGetLabel(dm, name, &label));
6613   }
6614   PetscCall(DMLabelSetValue(label, point, value));
6615   PetscFunctionReturn(0);
6616 }
6617 
6618 /*@C
6619   DMClearLabelValue - Remove a point from a `DMLabel` with given value
6620 
6621   Not Collective
6622 
6623   Input Parameters:
6624 + dm   - The `DM` object
6625 . name - The label name
6626 . point - The mesh point
6627 - value - The label value for this point
6628 
6629   Level: beginner
6630 
6631 .seealso: `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6632 @*/
6633 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6634 {
6635   DMLabel label;
6636 
6637   PetscFunctionBegin;
6638   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6639   PetscValidCharPointer(name, 2);
6640   PetscCall(DMGetLabel(dm, name, &label));
6641   if (!label) PetscFunctionReturn(0);
6642   PetscCall(DMLabelClearValue(label, point, value));
6643   PetscFunctionReturn(0);
6644 }
6645 
6646 /*@C
6647   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6648 
6649   Not Collective
6650 
6651   Input Parameters:
6652 + dm   - The `DM` object
6653 - name - The label name
6654 
6655   Output Parameter:
6656 . size - The number of different integer ids, or 0 if the label does not exist
6657 
6658   Level: beginner
6659 
6660   Developer Note:
6661   This should be renamed to something like `DMGetLabelNumValues()` or removed.
6662 
6663 .seealso: `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6664 @*/
6665 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6666 {
6667   DMLabel label;
6668 
6669   PetscFunctionBegin;
6670   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6671   PetscValidCharPointer(name, 2);
6672   PetscValidIntPointer(size, 3);
6673   PetscCall(DMGetLabel(dm, name, &label));
6674   *size = 0;
6675   if (!label) PetscFunctionReturn(0);
6676   PetscCall(DMLabelGetNumValues(label, size));
6677   PetscFunctionReturn(0);
6678 }
6679 
6680 /*@C
6681   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6682 
6683   Not Collective
6684 
6685   Input Parameters:
6686 + mesh - The `DM` object
6687 - name - The label name
6688 
6689   Output Parameter:
6690 . ids - The integer ids, or NULL if the label does not exist
6691 
6692   Level: beginner
6693 
6694 .seealso: `DMLabelGetValueIS()`, `DMGetLabelSize()`
6695 @*/
6696 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6697 {
6698   DMLabel label;
6699 
6700   PetscFunctionBegin;
6701   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6702   PetscValidCharPointer(name, 2);
6703   PetscValidPointer(ids, 3);
6704   PetscCall(DMGetLabel(dm, name, &label));
6705   *ids = NULL;
6706   if (label) {
6707     PetscCall(DMLabelGetValueIS(label, ids));
6708   } else {
6709     /* returning an empty IS */
6710     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
6711   }
6712   PetscFunctionReturn(0);
6713 }
6714 
6715 /*@C
6716   DMGetStratumSize - Get the number of points in a label stratum
6717 
6718   Not Collective
6719 
6720   Input Parameters:
6721 + dm - The `DM` object
6722 . name - The label name
6723 - value - The stratum value
6724 
6725   Output Parameter:
6726 . size - The number of points, also called the stratum size
6727 
6728   Level: beginner
6729 
6730 .seealso: `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6731 @*/
6732 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6733 {
6734   DMLabel label;
6735 
6736   PetscFunctionBegin;
6737   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6738   PetscValidCharPointer(name, 2);
6739   PetscValidIntPointer(size, 4);
6740   PetscCall(DMGetLabel(dm, name, &label));
6741   *size = 0;
6742   if (!label) PetscFunctionReturn(0);
6743   PetscCall(DMLabelGetStratumSize(label, value, size));
6744   PetscFunctionReturn(0);
6745 }
6746 
6747 /*@C
6748   DMGetStratumIS - Get the points in a label stratum
6749 
6750   Not Collective
6751 
6752   Input Parameters:
6753 + dm - The `DM` object
6754 . name - The label name
6755 - value - The stratum value
6756 
6757   Output Parameter:
6758 . points - The stratum points, or NULL if the label does not exist or does not have that value
6759 
6760   Level: beginner
6761 
6762 .seealso: `DMLabelGetStratumIS()`, `DMGetStratumSize()`
6763 @*/
6764 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6765 {
6766   DMLabel label;
6767 
6768   PetscFunctionBegin;
6769   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6770   PetscValidCharPointer(name, 2);
6771   PetscValidPointer(points, 4);
6772   PetscCall(DMGetLabel(dm, name, &label));
6773   *points = NULL;
6774   if (!label) PetscFunctionReturn(0);
6775   PetscCall(DMLabelGetStratumIS(label, value, points));
6776   PetscFunctionReturn(0);
6777 }
6778 
6779 /*@C
6780   DMSetStratumIS - Set the points in a label stratum
6781 
6782   Not Collective
6783 
6784   Input Parameters:
6785 + dm - The `DM` object
6786 . name - The label name
6787 . value - The stratum value
6788 - points - The stratum points
6789 
6790   Level: beginner
6791 
6792 .seealso: `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
6793 @*/
6794 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6795 {
6796   DMLabel label;
6797 
6798   PetscFunctionBegin;
6799   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6800   PetscValidCharPointer(name, 2);
6801   PetscValidPointer(points, 4);
6802   PetscCall(DMGetLabel(dm, name, &label));
6803   if (!label) PetscFunctionReturn(0);
6804   PetscCall(DMLabelSetStratumIS(label, value, points));
6805   PetscFunctionReturn(0);
6806 }
6807 
6808 /*@C
6809   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
6810 
6811   Not Collective
6812 
6813   Input Parameters:
6814 + dm   - The `DM` object
6815 . name - The label name
6816 - value - The label value for this point
6817 
6818   Output Parameter:
6819 
6820   Level: beginner
6821 
6822 .seealso: `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6823 @*/
6824 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6825 {
6826   DMLabel label;
6827 
6828   PetscFunctionBegin;
6829   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6830   PetscValidCharPointer(name, 2);
6831   PetscCall(DMGetLabel(dm, name, &label));
6832   if (!label) PetscFunctionReturn(0);
6833   PetscCall(DMLabelClearStratum(label, value));
6834   PetscFunctionReturn(0);
6835 }
6836 
6837 /*@
6838   DMGetNumLabels - Return the number of labels defined by on the `DM`
6839 
6840   Not Collective
6841 
6842   Input Parameter:
6843 . dm   - The `DM` object
6844 
6845   Output Parameter:
6846 . numLabels - the number of Labels
6847 
6848   Level: intermediate
6849 
6850 .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6851 @*/
6852 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6853 {
6854   DMLabelLink next = dm->labels;
6855   PetscInt    n    = 0;
6856 
6857   PetscFunctionBegin;
6858   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6859   PetscValidIntPointer(numLabels, 2);
6860   while (next) {
6861     ++n;
6862     next = next->next;
6863   }
6864   *numLabels = n;
6865   PetscFunctionReturn(0);
6866 }
6867 
6868 /*@C
6869   DMGetLabelName - Return the name of nth label
6870 
6871   Not Collective
6872 
6873   Input Parameters:
6874 + dm - The `DM` object
6875 - n  - the label number
6876 
6877   Output Parameter:
6878 . name - the label name
6879 
6880   Level: intermediate
6881 
6882   Developer Note:
6883   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
6884 
6885 .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6886 @*/
6887 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
6888 {
6889   DMLabelLink next = dm->labels;
6890   PetscInt    l    = 0;
6891 
6892   PetscFunctionBegin;
6893   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6894   PetscValidPointer(name, 3);
6895   while (next) {
6896     if (l == n) {
6897       PetscCall(PetscObjectGetName((PetscObject)next->label, name));
6898       PetscFunctionReturn(0);
6899     }
6900     ++l;
6901     next = next->next;
6902   }
6903   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
6904 }
6905 
6906 /*@C
6907   DMHasLabel - Determine whether the `DM` has a label of a given name
6908 
6909   Not Collective
6910 
6911   Input Parameters:
6912 + dm   - The `DM` object
6913 - name - The label name
6914 
6915   Output Parameter:
6916 . hasLabel - `PETSC_TRUE` if the label is present
6917 
6918   Level: intermediate
6919 
6920 .seealso: `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6921 @*/
6922 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
6923 {
6924   DMLabelLink next = dm->labels;
6925   const char *lname;
6926 
6927   PetscFunctionBegin;
6928   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6929   PetscValidCharPointer(name, 2);
6930   PetscValidBoolPointer(hasLabel, 3);
6931   *hasLabel = PETSC_FALSE;
6932   while (next) {
6933     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
6934     PetscCall(PetscStrcmp(name, lname, hasLabel));
6935     if (*hasLabel) break;
6936     next = next->next;
6937   }
6938   PetscFunctionReturn(0);
6939 }
6940 
6941 /*@C
6942   DMGetLabel - Return the label of a given name, or NULL, from a `DM`
6943 
6944   Not Collective
6945 
6946   Input Parameters:
6947 + dm   - The `DM` object
6948 - name - The label name
6949 
6950   Output Parameter:
6951 . label - The `DMLabel`, or NULL if the label is absent
6952 
6953   Default labels in a `DMPLEX`:
6954 +   "depth"       - Holds the depth (co-dimension) of each mesh point
6955 .   "celltype"    - Holds the topological type of each cell
6956 .   "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
6957 .   "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
6958 .   "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
6959 -  "Vertex Sets" - Mirrors the vertex sets defined by GMsh
6960 
6961   Level: intermediate
6962 
6963 .seealso: `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
6964 @*/
6965 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
6966 {
6967   DMLabelLink next = dm->labels;
6968   PetscBool   hasLabel;
6969   const char *lname;
6970 
6971   PetscFunctionBegin;
6972   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6973   PetscValidCharPointer(name, 2);
6974   PetscValidPointer(label, 3);
6975   *label = NULL;
6976   while (next) {
6977     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
6978     PetscCall(PetscStrcmp(name, lname, &hasLabel));
6979     if (hasLabel) {
6980       *label = next->label;
6981       break;
6982     }
6983     next = next->next;
6984   }
6985   PetscFunctionReturn(0);
6986 }
6987 
6988 /*@C
6989   DMGetLabelByNum - Return the nth label on a `DM`
6990 
6991   Not Collective
6992 
6993   Input Parameters:
6994 + dm - The `DM` object
6995 - n  - the label number
6996 
6997   Output Parameter:
6998 . label - the label
6999 
7000   Level: intermediate
7001 
7002 .seealso: `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7003 @*/
7004 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7005 {
7006   DMLabelLink next = dm->labels;
7007   PetscInt    l    = 0;
7008 
7009   PetscFunctionBegin;
7010   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7011   PetscValidPointer(label, 3);
7012   while (next) {
7013     if (l == n) {
7014       *label = next->label;
7015       PetscFunctionReturn(0);
7016     }
7017     ++l;
7018     next = next->next;
7019   }
7020   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7021 }
7022 
7023 /*@C
7024   DMAddLabel - Add the label to this `DM`
7025 
7026   Not Collective
7027 
7028   Input Parameters:
7029 + dm   - The `DM` object
7030 - label - The `DMLabel`
7031 
7032   Level: developer
7033 
7034 .seealso: `DMLabel`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7035 @*/
7036 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7037 {
7038   DMLabelLink l, *p, tmpLabel;
7039   PetscBool   hasLabel;
7040   const char *lname;
7041   PetscBool   flg;
7042 
7043   PetscFunctionBegin;
7044   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7045   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7046   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7047   PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7048   PetscCall(PetscCalloc1(1, &tmpLabel));
7049   tmpLabel->label  = label;
7050   tmpLabel->output = PETSC_TRUE;
7051   for (p = &dm->labels; (l = *p); p = &l->next) { }
7052   *p = tmpLabel;
7053   PetscCall(PetscObjectReference((PetscObject)label));
7054   PetscCall(PetscStrcmp(lname, "depth", &flg));
7055   if (flg) dm->depthLabel = label;
7056   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7057   if (flg) dm->celltypeLabel = label;
7058   PetscFunctionReturn(0);
7059 }
7060 
7061 /*@C
7062   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7063 
7064   Not Collective
7065 
7066   Input Parameters:
7067 + dm    - The `DM` object
7068 - label - The `DMLabel`, having the same name, to substitute
7069 
7070   Default labels in a `DMPLEX`:
7071 +  "depth"       - Holds the depth (co-dimension) of each mesh point
7072 .  "celltype"    - Holds the topological type of each cell
7073 .  "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7074 .  "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7075 .  "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7076 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7077 
7078   Level: intermediate
7079 
7080 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7081 @*/
7082 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7083 {
7084   DMLabelLink next = dm->labels;
7085   PetscBool   hasLabel, flg;
7086   const char *name, *lname;
7087 
7088   PetscFunctionBegin;
7089   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7090   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7091   PetscCall(PetscObjectGetName((PetscObject)label, &name));
7092   while (next) {
7093     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7094     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7095     if (hasLabel) {
7096       PetscCall(PetscObjectReference((PetscObject)label));
7097       PetscCall(PetscStrcmp(lname, "depth", &flg));
7098       if (flg) dm->depthLabel = label;
7099       PetscCall(PetscStrcmp(lname, "celltype", &flg));
7100       if (flg) dm->celltypeLabel = label;
7101       PetscCall(DMLabelDestroy(&next->label));
7102       next->label = label;
7103       break;
7104     }
7105     next = next->next;
7106   }
7107   PetscFunctionReturn(0);
7108 }
7109 
7110 /*@C
7111   DMRemoveLabel - Remove the label given by name from this `DM`
7112 
7113   Not Collective
7114 
7115   Input Parameters:
7116 + dm   - The `DM` object
7117 - name - The label name
7118 
7119   Output Parameter:
7120 . label - The `DMLabel`, or NULL if the label is absent. Pass in NULL to call `DMLabelDestroy()` on the label, otherwise the
7121           caller is responsible for calling `DMLabelDestroy()`.
7122 
7123   Level: developer
7124 
7125 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7126 @*/
7127 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7128 {
7129   DMLabelLink link, *pnext;
7130   PetscBool   hasLabel;
7131   const char *lname;
7132 
7133   PetscFunctionBegin;
7134   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7135   PetscValidCharPointer(name, 2);
7136   if (label) {
7137     PetscValidPointer(label, 3);
7138     *label = NULL;
7139   }
7140   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7141     PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7142     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7143     if (hasLabel) {
7144       *pnext = link->next; /* Remove from list */
7145       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7146       if (hasLabel) dm->depthLabel = NULL;
7147       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7148       if (hasLabel) dm->celltypeLabel = NULL;
7149       if (label) *label = link->label;
7150       else PetscCall(DMLabelDestroy(&link->label));
7151       PetscCall(PetscFree(link));
7152       break;
7153     }
7154   }
7155   PetscFunctionReturn(0);
7156 }
7157 
7158 /*@
7159   DMRemoveLabelBySelf - Remove the label from this `DM`
7160 
7161   Not Collective
7162 
7163   Input Parameters:
7164 + dm   - The `DM` object
7165 . label - The `DMLabel` to be removed from the `DM`
7166 - failNotFound - Should it fail if the label is not found in the DM?
7167 
7168   Level: developer
7169 
7170   Note:
7171   Only exactly the same instance is removed if found, name match is ignored.
7172   If the `DM` has an exclusive reference to the label, the label gets destroyed and
7173   *label nullified.
7174 
7175 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7176 @*/
7177 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7178 {
7179   DMLabelLink link, *pnext;
7180   PetscBool   hasLabel = PETSC_FALSE;
7181 
7182   PetscFunctionBegin;
7183   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7184   PetscValidPointer(label, 2);
7185   if (!*label && !failNotFound) PetscFunctionReturn(0);
7186   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7187   PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7188   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7189     if (*label == link->label) {
7190       hasLabel = PETSC_TRUE;
7191       *pnext   = link->next; /* Remove from list */
7192       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7193       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7194       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7195       PetscCall(DMLabelDestroy(&link->label));
7196       PetscCall(PetscFree(link));
7197       break;
7198     }
7199   }
7200   PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7201   PetscFunctionReturn(0);
7202 }
7203 
7204 /*@C
7205   DMGetLabelOutput - Get the output flag for a given label
7206 
7207   Not Collective
7208 
7209   Input Parameters:
7210 + dm   - The `DM` object
7211 - name - The label name
7212 
7213   Output Parameter:
7214 . output - The flag for output
7215 
7216   Level: developer
7217 
7218 .seealso: `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7219 @*/
7220 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7221 {
7222   DMLabelLink next = dm->labels;
7223   const char *lname;
7224 
7225   PetscFunctionBegin;
7226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7227   PetscValidCharPointer(name, 2);
7228   PetscValidBoolPointer(output, 3);
7229   while (next) {
7230     PetscBool flg;
7231 
7232     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7233     PetscCall(PetscStrcmp(name, lname, &flg));
7234     if (flg) {
7235       *output = next->output;
7236       PetscFunctionReturn(0);
7237     }
7238     next = next->next;
7239   }
7240   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7241 }
7242 
7243 /*@C
7244   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7245 
7246   Not Collective
7247 
7248   Input Parameters:
7249 + dm     - The `DM` object
7250 . name   - The label name
7251 - output - `PETSC_TRUE` to save the label to the viewer
7252 
7253   Level: developer
7254 
7255 .seealso: `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7256 @*/
7257 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7258 {
7259   DMLabelLink next = dm->labels;
7260   const char *lname;
7261 
7262   PetscFunctionBegin;
7263   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7264   PetscValidCharPointer(name, 2);
7265   while (next) {
7266     PetscBool flg;
7267 
7268     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7269     PetscCall(PetscStrcmp(name, lname, &flg));
7270     if (flg) {
7271       next->output = output;
7272       PetscFunctionReturn(0);
7273     }
7274     next = next->next;
7275   }
7276   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7277 }
7278 
7279 /*@
7280   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7281 
7282   Collective on dmA
7283 
7284   Input Parameters:
7285 + dmA - The `DM` object with initial labels
7286 . dmB - The `DM` object to which labels are copied
7287 . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7288 . all  - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7289 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7290 
7291   Level: intermediate
7292 
7293   Note:
7294   This is typically used when interpolating or otherwise adding to a mesh, or testing.
7295 
7296 .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7297 @*/
7298 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7299 {
7300   DMLabel     label, labelNew, labelOld;
7301   const char *name;
7302   PetscBool   flg;
7303   DMLabelLink link;
7304 
7305   PetscFunctionBegin;
7306   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7307   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7308   PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7309   PetscValidLogicalCollectiveBool(dmA, all, 4);
7310   PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7311   if (dmA == dmB) PetscFunctionReturn(0);
7312   for (link = dmA->labels; link; link = link->next) {
7313     label = link->label;
7314     PetscCall(PetscObjectGetName((PetscObject)label, &name));
7315     if (!all) {
7316       PetscCall(PetscStrcmp(name, "depth", &flg));
7317       if (flg) continue;
7318       PetscCall(PetscStrcmp(name, "dim", &flg));
7319       if (flg) continue;
7320       PetscCall(PetscStrcmp(name, "celltype", &flg));
7321       if (flg) continue;
7322     }
7323     PetscCall(DMGetLabel(dmB, name, &labelOld));
7324     if (labelOld) {
7325       switch (emode) {
7326       case DM_COPY_LABELS_KEEP:
7327         continue;
7328       case DM_COPY_LABELS_REPLACE:
7329         PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7330         break;
7331       case DM_COPY_LABELS_FAIL:
7332         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7333       default:
7334         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7335       }
7336     }
7337     if (mode == PETSC_COPY_VALUES) {
7338       PetscCall(DMLabelDuplicate(label, &labelNew));
7339     } else {
7340       labelNew = label;
7341     }
7342     PetscCall(DMAddLabel(dmB, labelNew));
7343     if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7344   }
7345   PetscFunctionReturn(0);
7346 }
7347 
7348 /*@C
7349   DMCompareLabels - Compare labels of two `DMPLEX` meshes
7350 
7351   Collective
7352 
7353   Input Parameters:
7354 + dm0 - First `DM` object
7355 - dm1 - Second `DM` object
7356 
7357   Output Parameters
7358 + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
7359 - message - (Optional) Message describing the difference, or NULL if there is no difference
7360 
7361   Level: intermediate
7362 
7363   Notes:
7364   The output flag equal will be the same on all processes.
7365 
7366   If equal is passed as NULL and difference is found, an error is thrown on all processes.
7367 
7368   Make sure to pass equal is NULL on all processes or none of them.
7369 
7370   The output message is set independently on each rank.
7371 
7372   message must be freed with `PetscFree()`
7373 
7374   If message is passed as NULL and a difference is found, the difference description is printed to stderr in synchronized manner.
7375 
7376   Make sure to pass message as NULL on all processes or no processes.
7377 
7378   Labels are matched by name. If the number of labels and their names are equal,
7379   `DMLabelCompare()` is used to compare each pair of labels with the same name.
7380 
7381   Fortran Note:
7382   This function is not available from Fortran.
7383 
7384 .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7385 @*/
7386 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7387 {
7388   PetscInt    n, i;
7389   char        msg[PETSC_MAX_PATH_LEN] = "";
7390   PetscBool   eq;
7391   MPI_Comm    comm;
7392   PetscMPIInt rank;
7393 
7394   PetscFunctionBegin;
7395   PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7396   PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7397   PetscCheckSameComm(dm0, 1, dm1, 2);
7398   if (equal) PetscValidBoolPointer(equal, 3);
7399   if (message) PetscValidPointer(message, 4);
7400   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7401   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7402   {
7403     PetscInt n1;
7404 
7405     PetscCall(DMGetNumLabels(dm0, &n));
7406     PetscCall(DMGetNumLabels(dm1, &n1));
7407     eq = (PetscBool)(n == n1);
7408     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7409     PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7410     if (!eq) goto finish;
7411   }
7412   for (i = 0; i < n; i++) {
7413     DMLabel     l0, l1;
7414     const char *name;
7415     char       *msgInner;
7416 
7417     /* Ignore label order */
7418     PetscCall(DMGetLabelByNum(dm0, i, &l0));
7419     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7420     PetscCall(DMGetLabel(dm1, name, &l1));
7421     if (!l1) {
7422       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7423       eq = PETSC_FALSE;
7424       break;
7425     }
7426     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7427     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7428     PetscCall(PetscFree(msgInner));
7429     if (!eq) break;
7430   }
7431   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7432 finish:
7433   /* If message output arg not set, print to stderr */
7434   if (message) {
7435     *message = NULL;
7436     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7437   } else {
7438     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7439     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7440   }
7441   /* If same output arg not ser and labels are not equal, throw error */
7442   if (equal) *equal = eq;
7443   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7444   PetscFunctionReturn(0);
7445 }
7446 
7447 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7448 {
7449   PetscFunctionBegin;
7450   PetscValidPointer(label, 2);
7451   if (!*label) {
7452     PetscCall(DMCreateLabel(dm, name));
7453     PetscCall(DMGetLabel(dm, name, label));
7454   }
7455   PetscCall(DMLabelSetValue(*label, point, value));
7456   PetscFunctionReturn(0);
7457 }
7458 
7459 /*
7460   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7461   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7462   (label, id) pair in the DM.
7463 
7464   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7465   each label.
7466 */
7467 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7468 {
7469   DMUniversalLabel ul;
7470   PetscBool       *active;
7471   PetscInt         pStart, pEnd, p, Nl, l, m;
7472 
7473   PetscFunctionBegin;
7474   PetscCall(PetscMalloc1(1, &ul));
7475   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7476   PetscCall(DMGetNumLabels(dm, &Nl));
7477   PetscCall(PetscCalloc1(Nl, &active));
7478   ul->Nl = 0;
7479   for (l = 0; l < Nl; ++l) {
7480     PetscBool   isdepth, iscelltype;
7481     const char *name;
7482 
7483     PetscCall(DMGetLabelName(dm, l, &name));
7484     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7485     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7486     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7487     if (active[l]) ++ul->Nl;
7488   }
7489   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7490   ul->Nv = 0;
7491   for (l = 0, m = 0; l < Nl; ++l) {
7492     DMLabel     label;
7493     PetscInt    nv;
7494     const char *name;
7495 
7496     if (!active[l]) continue;
7497     PetscCall(DMGetLabelName(dm, l, &name));
7498     PetscCall(DMGetLabelByNum(dm, l, &label));
7499     PetscCall(DMLabelGetNumValues(label, &nv));
7500     PetscCall(PetscStrallocpy(name, &ul->names[m]));
7501     ul->indices[m] = l;
7502     ul->Nv += nv;
7503     ul->offsets[m + 1] = nv;
7504     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7505     ++m;
7506   }
7507   for (l = 1; l <= ul->Nl; ++l) {
7508     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7509     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7510   }
7511   for (l = 0; l < ul->Nl; ++l) {
7512     PetscInt b;
7513 
7514     ul->masks[l] = 0;
7515     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7516   }
7517   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7518   for (l = 0, m = 0; l < Nl; ++l) {
7519     DMLabel         label;
7520     IS              valueIS;
7521     const PetscInt *varr;
7522     PetscInt        nv, v;
7523 
7524     if (!active[l]) continue;
7525     PetscCall(DMGetLabelByNum(dm, l, &label));
7526     PetscCall(DMLabelGetNumValues(label, &nv));
7527     PetscCall(DMLabelGetValueIS(label, &valueIS));
7528     PetscCall(ISGetIndices(valueIS, &varr));
7529     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7530     PetscCall(ISRestoreIndices(valueIS, &varr));
7531     PetscCall(ISDestroy(&valueIS));
7532     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7533     ++m;
7534   }
7535   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7536   for (p = pStart; p < pEnd; ++p) {
7537     PetscInt  uval   = 0;
7538     PetscBool marked = PETSC_FALSE;
7539 
7540     for (l = 0, m = 0; l < Nl; ++l) {
7541       DMLabel  label;
7542       PetscInt val, defval, loc, nv;
7543 
7544       if (!active[l]) continue;
7545       PetscCall(DMGetLabelByNum(dm, l, &label));
7546       PetscCall(DMLabelGetValue(label, p, &val));
7547       PetscCall(DMLabelGetDefaultValue(label, &defval));
7548       if (val == defval) {
7549         ++m;
7550         continue;
7551       }
7552       nv     = ul->offsets[m + 1] - ul->offsets[m];
7553       marked = PETSC_TRUE;
7554       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7555       PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7556       uval += (loc + 1) << ul->bits[m];
7557       ++m;
7558     }
7559     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7560   }
7561   PetscCall(PetscFree(active));
7562   *universal = ul;
7563   PetscFunctionReturn(0);
7564 }
7565 
7566 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7567 {
7568   PetscInt l;
7569 
7570   PetscFunctionBegin;
7571   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7572   PetscCall(DMLabelDestroy(&(*universal)->label));
7573   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7574   PetscCall(PetscFree((*universal)->values));
7575   PetscCall(PetscFree(*universal));
7576   *universal = NULL;
7577   PetscFunctionReturn(0);
7578 }
7579 
7580 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7581 {
7582   PetscFunctionBegin;
7583   PetscValidPointer(ulabel, 2);
7584   *ulabel = ul->label;
7585   PetscFunctionReturn(0);
7586 }
7587 
7588 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7589 {
7590   PetscInt Nl = ul->Nl, l;
7591 
7592   PetscFunctionBegin;
7593   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7594   for (l = 0; l < Nl; ++l) {
7595     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7596     else PetscCall(DMCreateLabel(dm, ul->names[l]));
7597   }
7598   if (preserveOrder) {
7599     for (l = 0; l < ul->Nl; ++l) {
7600       const char *name;
7601       PetscBool   match;
7602 
7603       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7604       PetscCall(PetscStrcmp(name, ul->names[l], &match));
7605       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]);
7606     }
7607   }
7608   PetscFunctionReturn(0);
7609 }
7610 
7611 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7612 {
7613   PetscInt l;
7614 
7615   PetscFunctionBegin;
7616   for (l = 0; l < ul->Nl; ++l) {
7617     DMLabel  label;
7618     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7619 
7620     if (lval) {
7621       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7622       else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7623       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7624     }
7625   }
7626   PetscFunctionReturn(0);
7627 }
7628 
7629 /*@
7630   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7631 
7632   Not collective
7633 
7634   Input Parameter:
7635 . dm - The `DM` object
7636 
7637   Output Parameter:
7638 . cdm - The coarse `DM`
7639 
7640   Level: intermediate
7641 
7642 .seealso: `DMSetCoarseDM()`, `DMCoarsen()`
7643 @*/
7644 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7645 {
7646   PetscFunctionBegin;
7647   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7648   PetscValidPointer(cdm, 2);
7649   *cdm = dm->coarseMesh;
7650   PetscFunctionReturn(0);
7651 }
7652 
7653 /*@
7654   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7655 
7656   Input Parameters:
7657 + dm - The `DM` object
7658 - cdm - The coarse `DM`
7659 
7660   Level: intermediate
7661 
7662   Note:
7663   Normally this is set automatically by `DMRefine()`
7664 
7665 .seealso: `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7666 @*/
7667 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7668 {
7669   PetscFunctionBegin;
7670   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7671   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7672   if (dm == cdm) cdm = NULL;
7673   PetscCall(PetscObjectReference((PetscObject)cdm));
7674   PetscCall(DMDestroy(&dm->coarseMesh));
7675   dm->coarseMesh = cdm;
7676   PetscFunctionReturn(0);
7677 }
7678 
7679 /*@
7680   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7681 
7682   Input Parameter:
7683 . dm - The `DM` object
7684 
7685   Output Parameter:
7686 . fdm - The fine `DM`
7687 
7688   Level: intermediate
7689 
7690 .seealso: `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7691 @*/
7692 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7693 {
7694   PetscFunctionBegin;
7695   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7696   PetscValidPointer(fdm, 2);
7697   *fdm = dm->fineMesh;
7698   PetscFunctionReturn(0);
7699 }
7700 
7701 /*@
7702   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7703 
7704   Input Parameters:
7705 + dm - The `DM` object
7706 - fdm - The fine `DM`
7707 
7708   Level: developer
7709 
7710   Note:
7711   Normally this is set automatically by `DMCoarsen()`
7712 
7713 .seealso: `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7714 @*/
7715 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7716 {
7717   PetscFunctionBegin;
7718   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7719   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7720   if (dm == fdm) fdm = NULL;
7721   PetscCall(PetscObjectReference((PetscObject)fdm));
7722   PetscCall(DMDestroy(&dm->fineMesh));
7723   dm->fineMesh = fdm;
7724   PetscFunctionReturn(0);
7725 }
7726 
7727 /*@C
7728   DMAddBoundary - Add a boundary condition to a model represented by a `DM`
7729 
7730   Collective on dm
7731 
7732   Input Parameters:
7733 + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
7734 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7735 . name     - The BC name
7736 . label    - The label defining constrained points
7737 . Nv       - The number of `DMLabel` values for constrained points
7738 . values   - An array of values for constrained points
7739 . field    - The field to constrain
7740 . Nc       - The number of constrained field components (0 will constrain all fields)
7741 . comps    - An array of constrained component numbers
7742 . bcFunc   - A pointwise function giving boundary values
7743 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7744 - ctx      - An optional user context for bcFunc
7745 
7746   Output Parameter:
7747 . bd          - (Optional) Boundary number
7748 
7749   Options Database Keys:
7750 + -bc_<boundary name> <num> - Overrides the boundary ids
7751 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7752 
7753   Notes:
7754   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is:
7755 
7756 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
7757 
7758   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is:
7759 
7760 $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7761 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7762 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7763 $        PetscReal time, const PetscReal x[], PetscScalar bcval[])
7764 
7765 + dim - the spatial dimension
7766 . Nf - the number of fields
7767 . uOff - the offset into u[] and u_t[] for each field
7768 . uOff_x - the offset into u_x[] for each field
7769 . u - each field evaluated at the current point
7770 . u_t - the time derivative of each field evaluated at the current point
7771 . u_x - the gradient of each field evaluated at the current point
7772 . aOff - the offset into a[] and a_t[] for each auxiliary field
7773 . aOff_x - the offset into a_x[] for each auxiliary field
7774 . a - each auxiliary field evaluated at the current point
7775 . a_t - the time derivative of each auxiliary field evaluated at the current point
7776 . a_x - the gradient of auxiliary each field evaluated at the current point
7777 . t - current time
7778 . x - coordinates of the current point
7779 . numConstants - number of constant parameters
7780 . constants - constant parameters
7781 - bcval - output values at the current point
7782 
7783   Level: intermediate
7784 
7785 .seealso: `DSGetBoundary()`, `PetscDSAddBoundary()`
7786 @*/
7787 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)
7788 {
7789   PetscDS ds;
7790 
7791   PetscFunctionBegin;
7792   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7793   PetscValidLogicalCollectiveEnum(dm, type, 2);
7794   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
7795   PetscValidLogicalCollectiveInt(dm, Nv, 5);
7796   PetscValidLogicalCollectiveInt(dm, field, 7);
7797   PetscValidLogicalCollectiveInt(dm, Nc, 8);
7798   PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
7799   PetscCall(DMGetDS(dm, &ds));
7800   /* Complete label */
7801   if (label) {
7802     PetscObject  obj;
7803     PetscClassId id;
7804 
7805     PetscCall(DMGetField(dm, field, NULL, &obj));
7806     PetscCall(PetscObjectGetClassId(obj, &id));
7807     if (id == PETSCFE_CLASSID) {
7808       DM plex;
7809 
7810       PetscCall(DMConvert(dm, DMPLEX, &plex));
7811       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
7812       PetscCall(DMDestroy(&plex));
7813     }
7814   }
7815   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
7816   PetscFunctionReturn(0);
7817 }
7818 
7819 /* TODO Remove this since now the structures are the same */
7820 static PetscErrorCode DMPopulateBoundary(DM dm)
7821 {
7822   PetscDS     ds;
7823   DMBoundary *lastnext;
7824   DSBoundary  dsbound;
7825 
7826   PetscFunctionBegin;
7827   PetscCall(DMGetDS(dm, &ds));
7828   dsbound = ds->boundary;
7829   if (dm->boundary) {
7830     DMBoundary next = dm->boundary;
7831 
7832     /* quick check to see if the PetscDS has changed */
7833     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
7834     /* the PetscDS has changed: tear down and rebuild */
7835     while (next) {
7836       DMBoundary b = next;
7837 
7838       next = b->next;
7839       PetscCall(PetscFree(b));
7840     }
7841     dm->boundary = NULL;
7842   }
7843 
7844   lastnext = &(dm->boundary);
7845   while (dsbound) {
7846     DMBoundary dmbound;
7847 
7848     PetscCall(PetscNew(&dmbound));
7849     dmbound->dsboundary = dsbound;
7850     dmbound->label      = dsbound->label;
7851     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7852     *lastnext = dmbound;
7853     lastnext  = &(dmbound->next);
7854     dsbound   = dsbound->next;
7855   }
7856   PetscFunctionReturn(0);
7857 }
7858 
7859 /* TODO: missing manual page */
7860 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7861 {
7862   DMBoundary b;
7863 
7864   PetscFunctionBegin;
7865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7866   PetscValidBoolPointer(isBd, 3);
7867   *isBd = PETSC_FALSE;
7868   PetscCall(DMPopulateBoundary(dm));
7869   b = dm->boundary;
7870   while (b && !(*isBd)) {
7871     DMLabel    label = b->label;
7872     DSBoundary dsb   = b->dsboundary;
7873     PetscInt   i;
7874 
7875     if (label) {
7876       for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
7877     }
7878     b = b->next;
7879   }
7880   PetscFunctionReturn(0);
7881 }
7882 
7883 /*@C
7884   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
7885 
7886   Collective on dm
7887 
7888   Input Parameters:
7889 + dm      - The `DM`
7890 . time    - The time
7891 . funcs   - The coordinate functions to evaluate, one per field
7892 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7893 - mode    - The insertion mode for values
7894 
7895   Output Parameter:
7896 . X - vector
7897 
7898    Calling sequence of func:
7899 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7900 
7901 +  dim - The spatial dimension
7902 .  time - The time at which to sample
7903 .  x   - The coordinates
7904 .  Nc  - The number of components
7905 .  u   - The output field values
7906 -  ctx - optional user-defined function context
7907 
7908   Level: developer
7909 
7910   Developer Notes:
7911   This API is specific to only particular usage of `DM`
7912 
7913   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7914 
7915 .seealso: `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7916 @*/
7917 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7918 {
7919   Vec localX;
7920 
7921   PetscFunctionBegin;
7922   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7923   PetscCall(DMGetLocalVector(dm, &localX));
7924   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
7925   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
7926   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
7927   PetscCall(DMRestoreLocalVector(dm, &localX));
7928   PetscFunctionReturn(0);
7929 }
7930 
7931 /*@C
7932   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
7933 
7934   Not collective
7935 
7936   Input Parameters:
7937 + dm      - The `DM`
7938 . time    - The time
7939 . funcs   - The coordinate functions to evaluate, one per field
7940 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7941 - mode    - The insertion mode for values
7942 
7943   Output Parameter:
7944 . localX - vector
7945 
7946    Calling sequence of func:
7947 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7948 
7949 +  dim - The spatial dimension
7950 .  x   - The coordinates
7951 .  Nc  - The number of components
7952 .  u   - The output field values
7953 -  ctx - optional user-defined function context
7954 
7955   Level: developer
7956 
7957   Developer Notes:
7958   This API is specific to only particular usage of `DM`
7959 
7960   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7961 
7962 .seealso: `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7963 @*/
7964 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7965 {
7966   PetscFunctionBegin;
7967   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7968   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
7969   PetscCall((dm->ops->projectfunctionlocal)(dm, time, funcs, ctxs, mode, localX));
7970   PetscFunctionReturn(0);
7971 }
7972 
7973 /*@C
7974   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.
7975 
7976   Collective on dm
7977 
7978   Input Parameters:
7979 + dm      - The `DM`
7980 . time    - The time
7981 . label   - The `DMLabel` selecting the portion of the mesh for projection
7982 . funcs   - The coordinate functions to evaluate, one per field
7983 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
7984 - mode    - The insertion mode for values
7985 
7986   Output Parameter:
7987 . X - vector
7988 
7989    Calling sequence of func:
7990 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7991 
7992 +  dim - The spatial dimension
7993 .  x   - The coordinates
7994 .  Nc  - The number of components
7995 .  u   - The output field values
7996 -  ctx - optional user-defined function context
7997 
7998   Level: developer
7999 
8000   Developer Notes:
8001   This API is specific to only particular usage of `DM`
8002 
8003   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8004 
8005 .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8006 @*/
8007 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)
8008 {
8009   Vec localX;
8010 
8011   PetscFunctionBegin;
8012   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8013   PetscCall(DMGetLocalVector(dm, &localX));
8014   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8015   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8016   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8017   PetscCall(DMRestoreLocalVector(dm, &localX));
8018   PetscFunctionReturn(0);
8019 }
8020 
8021 /*@C
8022   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.
8023 
8024   Not collective
8025 
8026   Input Parameters:
8027 + dm      - The `DM`
8028 . time    - The time
8029 . label   - The `DMLabel` selecting the portion of the mesh for projection
8030 . funcs   - The coordinate functions to evaluate, one per field
8031 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8032 - mode    - The insertion mode for values
8033 
8034   Output Parameter:
8035 . localX - vector
8036 
8037    Calling sequence of func:
8038 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8039 
8040 +  dim - The spatial dimension
8041 .  x   - The coordinates
8042 .  Nc  - The number of components
8043 .  u   - The output field values
8044 -  ctx - optional user-defined function context
8045 
8046   Level: developer
8047 
8048   Developer Notes:
8049   This API is specific to only particular usage of `DM`
8050 
8051   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8052 
8053 .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8054 @*/
8055 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)
8056 {
8057   PetscFunctionBegin;
8058   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8059   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8060   PetscCall((dm->ops->projectfunctionlabellocal)(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8061   PetscFunctionReturn(0);
8062 }
8063 
8064 /*@C
8065   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.
8066 
8067   Not collective
8068 
8069   Input Parameters:
8070 + dm      - The `DM`
8071 . time    - The time
8072 . localU  - The input field vector
8073 . funcs   - The functions to evaluate, one per field
8074 - mode    - The insertion mode for values
8075 
8076   Output Parameter:
8077 . localX  - The output vector
8078 
8079    Calling sequence of func:
8080 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8081 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8082 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8083 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8084 
8085 +  dim          - The spatial dimension
8086 .  Nf           - The number of input fields
8087 .  NfAux        - The number of input auxiliary fields
8088 .  uOff         - The offset of each field in u[]
8089 .  uOff_x       - The offset of each field in u_x[]
8090 .  u            - The field values at this point in space
8091 .  u_t          - The field time derivative at this point in space (or NULL)
8092 .  u_x          - The field derivatives at this point in space
8093 .  aOff         - The offset of each auxiliary field in u[]
8094 .  aOff_x       - The offset of each auxiliary field in u_x[]
8095 .  a            - The auxiliary field values at this point in space
8096 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8097 .  a_x          - The auxiliary field derivatives at this point in space
8098 .  t            - The current time
8099 .  x            - The coordinates of this point
8100 .  numConstants - The number of constants
8101 .  constants    - The value of each constant
8102 -  f            - The value of the function at this point in space
8103 
8104   Note:
8105   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.
8106   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
8107   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8108   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8109 
8110   Level: intermediate
8111 
8112   Developer Notes:
8113   This API is specific to only particular usage of `DM`
8114 
8115   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8116 
8117 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8118 @*/
8119 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)
8120 {
8121   PetscFunctionBegin;
8122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8123   PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8124   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8125   PetscCall((dm->ops->projectfieldlocal)(dm, time, localU, funcs, mode, localX));
8126   PetscFunctionReturn(0);
8127 }
8128 
8129 /*@C
8130   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.
8131 
8132   Not collective
8133 
8134   Input Parameters:
8135 + dm      - The `DM`
8136 . time    - The time
8137 . label   - The `DMLabel` marking the portion of the domain to output
8138 . numIds  - The number of label ids to use
8139 . ids     - The label ids to use for marking
8140 . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8141 . comps   - The components to set in the output, or NULL for all components
8142 . localU  - The input field vector
8143 . funcs   - The functions to evaluate, one per field
8144 - mode    - The insertion mode for values
8145 
8146   Output Parameter:
8147 . localX  - The output vector
8148 
8149    Calling sequence of func:
8150 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8151 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8152 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8153 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8154 
8155 +  dim          - The spatial dimension
8156 .  Nf           - The number of input fields
8157 .  NfAux        - The number of input auxiliary fields
8158 .  uOff         - The offset of each field in u[]
8159 .  uOff_x       - The offset of each field in u_x[]
8160 .  u            - The field values at this point in space
8161 .  u_t          - The field time derivative at this point in space (or NULL)
8162 .  u_x          - The field derivatives at this point in space
8163 .  aOff         - The offset of each auxiliary field in u[]
8164 .  aOff_x       - The offset of each auxiliary field in u_x[]
8165 .  a            - The auxiliary field values at this point in space
8166 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8167 .  a_x          - The auxiliary field derivatives at this point in space
8168 .  t            - The current time
8169 .  x            - The coordinates of this point
8170 .  numConstants - The number of constants
8171 .  constants    - The value of each constant
8172 -  f            - The value of the function at this point in space
8173 
8174   Note:
8175   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.
8176   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
8177   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8178   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8179 
8180   Level: intermediate
8181 
8182   Developer Notes:
8183   This API is specific to only particular usage of `DM`
8184 
8185   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8186 
8187 .seealso: `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8188 @*/
8189 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)
8190 {
8191   PetscFunctionBegin;
8192   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8193   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8194   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8195   PetscCall((dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8196   PetscFunctionReturn(0);
8197 }
8198 
8199 /*@C
8200   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.
8201 
8202   Not collective
8203 
8204   Input Parameters:
8205 + dm      - The `DM`
8206 . time    - The time
8207 . label   - The `DMLabel` marking the portion of the domain to output
8208 . numIds  - The number of label ids to use
8209 . ids     - The label ids to use for marking
8210 . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8211 . comps   - The components to set in the output, or NULL for all components
8212 . U       - The input field vector
8213 . funcs   - The functions to evaluate, one per field
8214 - mode    - The insertion mode for values
8215 
8216   Output Parameter:
8217 . X       - The output vector
8218 
8219    Calling sequence of func:
8220 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8221 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8222 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8223 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8224 
8225 +  dim          - The spatial dimension
8226 .  Nf           - The number of input fields
8227 .  NfAux        - The number of input auxiliary fields
8228 .  uOff         - The offset of each field in u[]
8229 .  uOff_x       - The offset of each field in u_x[]
8230 .  u            - The field values at this point in space
8231 .  u_t          - The field time derivative at this point in space (or NULL)
8232 .  u_x          - The field derivatives at this point in space
8233 .  aOff         - The offset of each auxiliary field in u[]
8234 .  aOff_x       - The offset of each auxiliary field in u_x[]
8235 .  a            - The auxiliary field values at this point in space
8236 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8237 .  a_x          - The auxiliary field derivatives at this point in space
8238 .  t            - The current time
8239 .  x            - The coordinates of this point
8240 .  numConstants - The number of constants
8241 .  constants    - The value of each constant
8242 -  f            - The value of the function at this point in space
8243 
8244   Note:
8245   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.
8246   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
8247   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8248   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8249 
8250   Level: intermediate
8251 
8252   Developer Notes:
8253   This API is specific to only particular usage of `DM`
8254 
8255   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8256 
8257 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8258 @*/
8259 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)
8260 {
8261   DM  dmIn;
8262   Vec localU, localX;
8263 
8264   PetscFunctionBegin;
8265   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8266   PetscCall(VecGetDM(U, &dmIn));
8267   PetscCall(DMGetLocalVector(dmIn, &localU));
8268   PetscCall(DMGetLocalVector(dm, &localX));
8269   PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8270   PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8271   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8272   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8273   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8274   PetscCall(DMRestoreLocalVector(dm, &localX));
8275   PetscCall(DMRestoreLocalVector(dmIn, &localU));
8276   PetscFunctionReturn(0);
8277 }
8278 
8279 /*@C
8280   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.
8281 
8282   Not collective
8283 
8284   Input Parameters:
8285 + dm      - The `DM`
8286 . time    - The time
8287 . label   - The `DMLabel` marking the portion of the domain boundary to output
8288 . numIds  - The number of label ids to use
8289 . ids     - The label ids to use for marking
8290 . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8291 . comps   - The components to set in the output, or NULL for all components
8292 . localU  - The input field vector
8293 . funcs   - The functions to evaluate, one per field
8294 - mode    - The insertion mode for values
8295 
8296   Output Parameter:
8297 . localX  - The output vector
8298 
8299    Calling sequence of func:
8300 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8301 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8302 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8303 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8304 
8305 +  dim          - The spatial dimension
8306 .  Nf           - The number of input fields
8307 .  NfAux        - The number of input auxiliary fields
8308 .  uOff         - The offset of each field in u[]
8309 .  uOff_x       - The offset of each field in u_x[]
8310 .  u            - The field values at this point in space
8311 .  u_t          - The field time derivative at this point in space (or NULL)
8312 .  u_x          - The field derivatives at this point in space
8313 .  aOff         - The offset of each auxiliary field in u[]
8314 .  aOff_x       - The offset of each auxiliary field in u_x[]
8315 .  a            - The auxiliary field values at this point in space
8316 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8317 .  a_x          - The auxiliary field derivatives at this point in space
8318 .  t            - The current time
8319 .  x            - The coordinates of this point
8320 .  n            - The face normal
8321 .  numConstants - The number of constants
8322 .  constants    - The value of each constant
8323 -  f            - The value of the function at this point in space
8324 
8325   Note:
8326   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.
8327   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
8328   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8329   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8330 
8331   Level: intermediate
8332 
8333   Developer Notes:
8334   This API is specific to only particular usage of `DM`
8335 
8336   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8337 
8338 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8339 @*/
8340 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)
8341 {
8342   PetscFunctionBegin;
8343   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8344   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8345   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8346   PetscCall((dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8347   PetscFunctionReturn(0);
8348 }
8349 
8350 /*@C
8351   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8352 
8353   Collective on dm
8354 
8355   Input Parameters:
8356 + dm    - The `DM`
8357 . time  - The time
8358 . funcs - The functions to evaluate for each field component
8359 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8360 - X     - The coefficient vector u_h, a global vector
8361 
8362   Output Parameter:
8363 . diff - The diff ||u - u_h||_2
8364 
8365   Level: developer
8366 
8367   Developer Notes:
8368   This API is specific to only particular usage of `DM`
8369 
8370   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8371 
8372 .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8373 @*/
8374 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8375 {
8376   PetscFunctionBegin;
8377   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8378   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8379   PetscCall((dm->ops->computel2diff)(dm, time, funcs, ctxs, X, diff));
8380   PetscFunctionReturn(0);
8381 }
8382 
8383 /*@C
8384   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8385 
8386   Collective on dm
8387 
8388   Input Parameters:
8389 + dm    - The `DM`
8390 , time  - The time
8391 . funcs - The gradient functions to evaluate for each field component
8392 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8393 . X     - The coefficient vector u_h, a global vector
8394 - n     - The vector to project along
8395 
8396   Output Parameter:
8397 . diff - The diff ||(grad u - grad u_h) . n||_2
8398 
8399   Level: developer
8400 
8401   Developer Notes:
8402   This API is specific to only particular usage of `DM`
8403 
8404   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8405 
8406 .seealso: `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8407 @*/
8408 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)
8409 {
8410   PetscFunctionBegin;
8411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8412   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8413   PetscCall((dm->ops->computel2gradientdiff)(dm, time, funcs, ctxs, X, n, diff));
8414   PetscFunctionReturn(0);
8415 }
8416 
8417 /*@C
8418   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8419 
8420   Collective on dm
8421 
8422   Input Parameters:
8423 + dm    - The `DM`
8424 . time  - The time
8425 . funcs - The functions to evaluate for each field component
8426 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8427 - X     - The coefficient vector u_h, a global vector
8428 
8429   Output Parameter:
8430 . diff - The array of differences, ||u^f - u^f_h||_2
8431 
8432   Level: developer
8433 
8434   Developer Notes:
8435   This API is specific to only particular usage of `DM`
8436 
8437   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8438 
8439 .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8440 @*/
8441 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8442 {
8443   PetscFunctionBegin;
8444   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8445   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8446   PetscCall((dm->ops->computel2fielddiff)(dm, time, funcs, ctxs, X, diff));
8447   PetscFunctionReturn(0);
8448 }
8449 
8450 /*@C
8451  DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8452 
8453  Not Collective
8454 
8455  Input Parameter:
8456 .  dm    - The `DM`
8457 
8458  Output Parameters:
8459 +  nranks - the number of neighbours
8460 -  ranks - the neighbors ranks
8461 
8462  Note:
8463  Do not free the array, it is freed when the `DM` is destroyed.
8464 
8465  Level: beginner
8466 
8467  .seealso: `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8468 @*/
8469 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8470 {
8471   PetscFunctionBegin;
8472   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8473   PetscCall((dm->ops->getneighbors)(dm, nranks, ranks));
8474   PetscFunctionReturn(0);
8475 }
8476 
8477 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8478 
8479 /*
8480     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8481     This has be a different function because it requires DM which is not defined in the Mat library
8482 */
8483 PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8484 {
8485   PetscFunctionBegin;
8486   if (coloring->ctype == IS_COLORING_LOCAL) {
8487     Vec x1local;
8488     DM  dm;
8489     PetscCall(MatGetDM(J, &dm));
8490     PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8491     PetscCall(DMGetLocalVector(dm, &x1local));
8492     PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8493     PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8494     x1 = x1local;
8495   }
8496   PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8497   if (coloring->ctype == IS_COLORING_LOCAL) {
8498     DM dm;
8499     PetscCall(MatGetDM(J, &dm));
8500     PetscCall(DMRestoreLocalVector(dm, &x1));
8501   }
8502   PetscFunctionReturn(0);
8503 }
8504 
8505 /*@
8506     MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8507 
8508     Input Parameter:
8509 .    coloring - the `MatFDColoring` object
8510 
8511     Developer Note:
8512     this routine exists because the PETSc `Mat` library does not know about the `DM` objects
8513 
8514     Level: advanced
8515 
8516 .seealso: `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8517 @*/
8518 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8519 {
8520   PetscFunctionBegin;
8521   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8522   PetscFunctionReturn(0);
8523 }
8524 
8525 /*@
8526     DMGetCompatibility - determine if two `DM`s are compatible
8527 
8528     Collective
8529 
8530     Input Parameters:
8531 +    dm1 - the first `DM`
8532 -    dm2 - the second `DM`
8533 
8534     Output Parameters:
8535 +    compatible - whether or not the two `DM`s are compatible
8536 -    set - whether or not the compatible value was actually determined and set
8537 
8538     Notes:
8539     Two `DM`s are deemed compatible if they represent the same parallel decomposition
8540     of the same topology. This implies that the section (field data) on one
8541     "makes sense" with respect to the topology and parallel decomposition of the other.
8542     Loosely speaking, compatible `DM`s represent the same domain and parallel
8543     decomposition, but hold different data.
8544 
8545     Typically, one would confirm compatibility if intending to simultaneously iterate
8546     over a pair of vectors obtained from different `DM`s.
8547 
8548     For example, two `DMDA` objects are compatible if they have the same local
8549     and global sizes and the same stencil width. They can have different numbers
8550     of degrees of freedom per node. Thus, one could use the node numbering from
8551     either `DM` in bounds for a loop over vectors derived from either `DM`.
8552 
8553     Consider the operation of summing data living on a 2-dof `DMDA` to data living
8554     on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8555 .vb
8556   ...
8557   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8558   if (set && compatible)  {
8559     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8560     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8561     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8562     for (j=y; j<y+n; ++j) {
8563       for (i=x; i<x+m, ++i) {
8564         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8565       }
8566     }
8567     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8568     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8569   } else {
8570     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8571   }
8572   ...
8573 .ve
8574 
8575     Checking compatibility might be expensive for a given implementation of `DM`,
8576     or might be impossible to unambiguously confirm or deny. For this reason,
8577     this function may decline to determine compatibility, and hence users should
8578     always check the "set" output parameter.
8579 
8580     A `DM` is always compatible with itself.
8581 
8582     In the current implementation, `DM`s which live on "unequal" communicators
8583     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8584     incompatible.
8585 
8586     This function is labeled "Collective," as information about all subdomains
8587     is required on each rank. However, in `DM` implementations which store all this
8588     information locally, this function may be merely "Logically Collective".
8589 
8590     Developer Note:
8591     Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8592     iff B is compatible with A. Thus, this function checks the implementations
8593     of both dm and dmc (if they are of different types), attempting to determine
8594     compatibility. It is left to `DM` implementers to ensure that symmetry is
8595     preserved. The simplest way to do this is, when implementing type-specific
8596     logic for this function, is to check for existing logic in the implementation
8597     of other `DM` types and let *set = PETSC_FALSE if found.
8598 
8599     Level: advanced
8600 
8601 .seealso: `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8602 @*/
8603 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8604 {
8605   PetscMPIInt compareResult;
8606   DMType      type, type2;
8607   PetscBool   sameType;
8608 
8609   PetscFunctionBegin;
8610   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8611   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8612 
8613   /* Declare a DM compatible with itself */
8614   if (dm1 == dm2) {
8615     *set        = PETSC_TRUE;
8616     *compatible = PETSC_TRUE;
8617     PetscFunctionReturn(0);
8618   }
8619 
8620   /* Declare a DM incompatible with a DM that lives on an "unequal"
8621      communicator. Note that this does not preclude compatibility with
8622      DMs living on "congruent" or "similar" communicators, but this must be
8623      determined by the implementation-specific logic */
8624   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8625   if (compareResult == MPI_UNEQUAL) {
8626     *set        = PETSC_TRUE;
8627     *compatible = PETSC_FALSE;
8628     PetscFunctionReturn(0);
8629   }
8630 
8631   /* Pass to the implementation-specific routine, if one exists. */
8632   if (dm1->ops->getcompatibility) {
8633     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8634     if (*set) PetscFunctionReturn(0);
8635   }
8636 
8637   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8638      with an implementation of this function from dm2 */
8639   PetscCall(DMGetType(dm1, &type));
8640   PetscCall(DMGetType(dm2, &type2));
8641   PetscCall(PetscStrcmp(type, type2, &sameType));
8642   if (!sameType && dm2->ops->getcompatibility) {
8643     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8644   } else {
8645     *set = PETSC_FALSE;
8646   }
8647   PetscFunctionReturn(0);
8648 }
8649 
8650 /*@C
8651   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8652 
8653   Logically Collective on dm
8654 
8655   Input Parameters:
8656 + DM - the `DM`
8657 . f - the monitor function
8658 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8659 - monitordestroy - [optional] routine that frees monitor context (may be NULL)
8660 
8661   Options Database Keys:
8662 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8663                             does not cancel those set via the options database.
8664 
8665   Note:
8666   Several different monitoring routines may be set by calling
8667   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8668   order in which they were set.
8669 
8670   Fortran Note:
8671   Only a single monitor function can be set for each `DM` object
8672 
8673   Developer Note:
8674   This API has a generic name but seems specific to a very particular aspect of the use of `DM`
8675 
8676   Level: intermediate
8677 
8678 .seealso: `DMMonitorCancel()`,`DMMonitorSetFromOptions()`, `DMMonitor()`
8679 @*/
8680 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **))
8681 {
8682   PetscInt m;
8683 
8684   PetscFunctionBegin;
8685   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8686   for (m = 0; m < dm->numbermonitors; ++m) {
8687     PetscBool identical;
8688 
8689     PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
8690     if (identical) PetscFunctionReturn(0);
8691   }
8692   PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8693   dm->monitor[dm->numbermonitors]          = f;
8694   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8695   dm->monitorcontext[dm->numbermonitors++] = (void *)mctx;
8696   PetscFunctionReturn(0);
8697 }
8698 
8699 /*@
8700   DMMonitorCancel - Clears all the monitor functions for a `DM` object.
8701 
8702   Logically Collective on dm
8703 
8704   Input Parameter:
8705 . dm - the DM
8706 
8707   Options Database Key:
8708 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8709   into a code by calls to `DMonitorSet()`, but does not cancel those
8710   set via the options database
8711 
8712   Note:
8713   There is no way to clear one specific monitor from a `DM` object.
8714 
8715   Level: intermediate
8716 
8717 .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`,  `DMMonitor()`
8718 @*/
8719 PetscErrorCode DMMonitorCancel(DM dm)
8720 {
8721   PetscInt m;
8722 
8723   PetscFunctionBegin;
8724   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8725   for (m = 0; m < dm->numbermonitors; ++m) {
8726     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
8727   }
8728   dm->numbermonitors = 0;
8729   PetscFunctionReturn(0);
8730 }
8731 
8732 /*@C
8733   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8734 
8735   Collective on dm
8736 
8737   Input Parameters:
8738 + dm   - `DM` object you wish to monitor
8739 . name - the monitor type one is seeking
8740 . help - message indicating what monitoring is done
8741 . manual - manual page for the monitor
8742 . monitor - the monitor function
8743 - 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
8744 
8745   Output Parameter:
8746 . flg - Flag set if the monitor was created
8747 
8748   Level: developer
8749 
8750 .seealso: `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8751           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8752           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
8753           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8754           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8755           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8756           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8757 @*/
8758 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8759 {
8760   PetscViewer       viewer;
8761   PetscViewerFormat format;
8762 
8763   PetscFunctionBegin;
8764   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8765   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
8766   if (*flg) {
8767     PetscViewerAndFormat *vf;
8768 
8769     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
8770     PetscCall(PetscObjectDereference((PetscObject)viewer));
8771     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
8772     PetscCall(DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy));
8773   }
8774   PetscFunctionReturn(0);
8775 }
8776 
8777 /*@
8778    DMMonitor - runs the user provided monitor routines, if they exist
8779 
8780    Collective on dm
8781 
8782    Input Parameters:
8783 .  dm - The `DM`
8784 
8785    Level: developer
8786 
8787    Question:
8788    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
8789    since some `DM` have no concept of discretization
8790 
8791 .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`
8792 @*/
8793 PetscErrorCode DMMonitor(DM dm)
8794 {
8795   PetscInt m;
8796 
8797   PetscFunctionBegin;
8798   if (!dm) PetscFunctionReturn(0);
8799   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8800   for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
8801   PetscFunctionReturn(0);
8802 }
8803 
8804 /*@
8805   DMComputeError - Computes the error assuming the user has provided the exact solution functions
8806 
8807   Collective on dm
8808 
8809   Input Parameters:
8810 + dm     - The `DM`
8811 - sol    - The solution vector
8812 
8813   Input/Output Parameter:
8814 . errors - An array of length Nf, the number of fields, or NULL for no output; on output
8815            contains the error in each field
8816 
8817   Output Parameter:
8818 . errorVec - A vector to hold the cellwise error (may be NULL)
8819 
8820   Note:
8821   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
8822 
8823   Level: developer
8824 
8825 .seealso: `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
8826 @*/
8827 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
8828 {
8829   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
8830   void    **ctxs;
8831   PetscReal time;
8832   PetscInt  Nf, f, Nds, s;
8833 
8834   PetscFunctionBegin;
8835   PetscCall(DMGetNumFields(dm, &Nf));
8836   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
8837   PetscCall(DMGetNumDS(dm, &Nds));
8838   for (s = 0; s < Nds; ++s) {
8839     PetscDS         ds;
8840     DMLabel         label;
8841     IS              fieldIS;
8842     const PetscInt *fields;
8843     PetscInt        dsNf;
8844 
8845     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
8846     PetscCall(PetscDSGetNumFields(ds, &dsNf));
8847     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
8848     for (f = 0; f < dsNf; ++f) {
8849       const PetscInt field = fields[f];
8850       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
8851     }
8852     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
8853   }
8854   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);
8855   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
8856   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
8857   if (errorVec) {
8858     DM             edm;
8859     DMPolytopeType ct;
8860     PetscBool      simplex;
8861     PetscInt       dim, cStart, Nf;
8862 
8863     PetscCall(DMClone(dm, &edm));
8864     PetscCall(DMGetDimension(edm, &dim));
8865     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
8866     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
8867     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
8868     PetscCall(DMGetNumFields(dm, &Nf));
8869     for (f = 0; f < Nf; ++f) {
8870       PetscFE         fe, efe;
8871       PetscQuadrature q;
8872       const char     *name;
8873 
8874       PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
8875       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
8876       PetscCall(PetscObjectGetName((PetscObject)fe, &name));
8877       PetscCall(PetscObjectSetName((PetscObject)efe, name));
8878       PetscCall(PetscFEGetQuadrature(fe, &q));
8879       PetscCall(PetscFESetQuadrature(efe, q));
8880       PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
8881       PetscCall(PetscFEDestroy(&efe));
8882     }
8883     PetscCall(DMCreateDS(edm));
8884 
8885     PetscCall(DMCreateGlobalVector(edm, errorVec));
8886     PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
8887     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
8888     PetscCall(DMDestroy(&edm));
8889   }
8890   PetscCall(PetscFree2(exactSol, ctxs));
8891   PetscFunctionReturn(0);
8892 }
8893 
8894 /*@
8895   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
8896 
8897   Not collective
8898 
8899   Input Parameter:
8900 . dm     - The `DM`
8901 
8902   Output Parameter:
8903 . numAux - The number of auxiliary data vectors
8904 
8905   Level: advanced
8906 
8907 .seealso: `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
8908 @*/
8909 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
8910 {
8911   PetscFunctionBegin;
8912   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8913   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
8914   PetscFunctionReturn(0);
8915 }
8916 
8917 /*@
8918   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
8919 
8920   Not collective
8921 
8922   Input Parameters:
8923 + dm     - The `DM`
8924 . label  - The `DMLabel`
8925 . value  - The label value indicating the region
8926 - part   - The equation part, or 0 if unused
8927 
8928   Output Parameter:
8929 . aux    - The `Vec` holding auxiliary field data
8930 
8931   Note:
8932   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
8933 
8934   Level: advanced
8935 
8936 .seealso: `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
8937 @*/
8938 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
8939 {
8940   PetscHashAuxKey key, wild = {NULL, 0, 0};
8941   PetscBool       has;
8942 
8943   PetscFunctionBegin;
8944   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8945   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
8946   key.label = label;
8947   key.value = value;
8948   key.part  = part;
8949   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
8950   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
8951   else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
8952   PetscFunctionReturn(0);
8953 }
8954 
8955 /*@
8956   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
8957 
8958   Not collective because auxilary vectors are not parallel
8959 
8960   Input Parameters:
8961 + dm     - The `DM`
8962 . label  - The `DMLabel`
8963 . value  - The label value indicating the region
8964 . part   - The equation part, or 0 if unused
8965 - aux    - The `Vec` holding auxiliary field data
8966 
8967   Level: advanced
8968 
8969 .seealso: `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
8970 @*/
8971 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
8972 {
8973   Vec             old;
8974   PetscHashAuxKey key;
8975 
8976   PetscFunctionBegin;
8977   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8978   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
8979   key.label = label;
8980   key.value = value;
8981   key.part  = part;
8982   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
8983   PetscCall(PetscObjectReference((PetscObject)aux));
8984   PetscCall(PetscObjectDereference((PetscObject)old));
8985   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
8986   else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
8987   PetscFunctionReturn(0);
8988 }
8989 
8990 /*@C
8991   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
8992 
8993   Not collective
8994 
8995   Input Parameter:
8996 . dm      - The `DM`
8997 
8998   Output Parameters:
8999 + labels  - The `DMLabel`s for each `Vec`
9000 . values  - The label values for each `Vec`
9001 - parts   - The equation parts for each `Vec`
9002 
9003   Note:
9004   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
9005 
9006   Level: advanced
9007 
9008 .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMSetAuxiliaryVec()`, DMCopyAuxiliaryVec()`
9009 @*/
9010 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9011 {
9012   PetscHashAuxKey *keys;
9013   PetscInt         n, i, off = 0;
9014 
9015   PetscFunctionBegin;
9016   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9017   PetscValidPointer(labels, 2);
9018   PetscValidIntPointer(values, 3);
9019   PetscValidIntPointer(parts, 4);
9020   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9021   PetscCall(PetscMalloc1(n, &keys));
9022   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9023   for (i = 0; i < n; ++i) {
9024     labels[i] = keys[i].label;
9025     values[i] = keys[i].value;
9026     parts[i]  = keys[i].part;
9027   }
9028   PetscCall(PetscFree(keys));
9029   PetscFunctionReturn(0);
9030 }
9031 
9032 /*@
9033   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
9034 
9035   Not collective
9036 
9037   Input Parameter:
9038 . dm    - The `DM`
9039 
9040   Output Parameter:
9041 . dmNew - The new `DM`, now with the same auxiliary data
9042 
9043   Level: advanced
9044 
9045   Note:
9046   This is a shallow copy of the auxiliary vectors
9047 
9048 .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9049 @*/
9050 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9051 {
9052   PetscFunctionBegin;
9053   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9054   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9055   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9056   PetscFunctionReturn(0);
9057 }
9058 
9059 /*@C
9060   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9061 
9062   Not collective
9063 
9064   Input Parameters:
9065 + ct         - The `DMPolytopeType`
9066 . sourceCone - The source arrangement of faces
9067 - targetCone - The target arrangement of faces
9068 
9069   Output Parameters:
9070 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9071 - found - Flag indicating that a suitable orientation was found
9072 
9073   Level: advanced
9074 
9075   Note:
9076   An arrangement is a face order combined with an orientation for each face
9077 
9078   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
9079   that labels each arrangement (face ordering plus orientation for each face).
9080 
9081   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9082 
9083 .seealso: `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9084 @*/
9085 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9086 {
9087   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9088   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
9089   PetscInt       o, c;
9090 
9091   PetscFunctionBegin;
9092   if (!nO) {
9093     *ornt  = 0;
9094     *found = PETSC_TRUE;
9095     PetscFunctionReturn(0);
9096   }
9097   for (o = -nO; o < nO; ++o) {
9098     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
9099 
9100     for (c = 0; c < cS; ++c)
9101       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9102     if (c == cS) {
9103       *ornt = o;
9104       break;
9105     }
9106   }
9107   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9108   PetscFunctionReturn(0);
9109 }
9110 
9111 /*@C
9112   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9113 
9114   Not collective
9115 
9116   Input Parameters:
9117 + ct         - The `DMPolytopeType`
9118 . sourceCone - The source arrangement of faces
9119 - targetCone - The target arrangement of faces
9120 
9121   Output Parameters:
9122 . ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9123 
9124   Level: advanced
9125 
9126   Note:
9127   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9128 
9129   Developer Note:
9130   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9131 
9132 .seealso: `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9133 @*/
9134 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9135 {
9136   PetscBool found;
9137 
9138   PetscFunctionBegin;
9139   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9140   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9141   PetscFunctionReturn(0);
9142 }
9143 
9144 /*@C
9145   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9146 
9147   Not collective
9148 
9149   Input Parameters:
9150 + ct         - The `DMPolytopeType`
9151 . sourceVert - The source arrangement of vertices
9152 - targetVert - The target arrangement of vertices
9153 
9154   Output Parameters:
9155 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9156 - found - Flag indicating that a suitable orientation was found
9157 
9158   Level: advanced
9159 
9160   Note:
9161   An arrangement is a vertex order
9162 
9163   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
9164   that labels each arrangement (vertex ordering).
9165 
9166   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9167 
9168 .seealso: `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangment()`
9169 @*/
9170 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9171 {
9172   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9173   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
9174   PetscInt       o, c;
9175 
9176   PetscFunctionBegin;
9177   if (!nO) {
9178     *ornt  = 0;
9179     *found = PETSC_TRUE;
9180     PetscFunctionReturn(0);
9181   }
9182   for (o = -nO; o < nO; ++o) {
9183     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);
9184 
9185     for (c = 0; c < cS; ++c)
9186       if (sourceVert[arr[c]] != targetVert[c]) break;
9187     if (c == cS) {
9188       *ornt = o;
9189       break;
9190     }
9191   }
9192   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9193   PetscFunctionReturn(0);
9194 }
9195 
9196 /*@C
9197   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9198 
9199   Not collective
9200 
9201   Input Parameters:
9202 + ct         - The `DMPolytopeType`
9203 . sourceCone - The source arrangement of vertices
9204 - targetCone - The target arrangement of vertices
9205 
9206   Output Parameters:
9207 . ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9208 
9209   Level: advanced
9210 
9211   Note:
9212   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9213 
9214   Developer Note:
9215   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9216 
9217 .seealso: `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9218 @*/
9219 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9220 {
9221   PetscBool found;
9222 
9223   PetscFunctionBegin;
9224   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9225   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9226   PetscFunctionReturn(0);
9227 }
9228 
9229 /*@C
9230   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9231 
9232   Not collective
9233 
9234   Input Parameters:
9235 + ct    - The `DMPolytopeType`
9236 - point - Coordinates of the point
9237 
9238   Output Parameters:
9239 . inside  - Flag indicating whether the point is inside the reference cell of given type
9240 
9241   Level: advanced
9242 
9243 .seealso: `DM`, `DMPolytopeType`, `DMLocatePoints()`
9244 @*/
9245 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9246 {
9247   PetscReal sum = 0.0;
9248   PetscInt  d;
9249 
9250   PetscFunctionBegin;
9251   *inside = PETSC_TRUE;
9252   switch (ct) {
9253   case DM_POLYTOPE_TRIANGLE:
9254   case DM_POLYTOPE_TETRAHEDRON:
9255     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9256       if (point[d] < -1.0) {
9257         *inside = PETSC_FALSE;
9258         break;
9259       }
9260       sum += point[d];
9261     }
9262     if (sum > PETSC_SMALL) {
9263       *inside = PETSC_FALSE;
9264       break;
9265     }
9266     break;
9267   case DM_POLYTOPE_QUADRILATERAL:
9268   case DM_POLYTOPE_HEXAHEDRON:
9269     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9270       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9271         *inside = PETSC_FALSE;
9272         break;
9273       }
9274     break;
9275   default:
9276     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9277   }
9278   PetscFunctionReturn(0);
9279 }
9280