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