xref: /petsc/src/dm/interface/dm.c (revision 390d3996fed1e5c2d89175ebb68cf53cdee176f4)
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) {
4140       conv = dm->ops->convert;
4141     }
4142     if (conv) goto foundconv;
4143 #endif
4144 
4145     /* 5) Use a really basic converter. */
4146     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject)dm)->type_name, newtype);
4147 
4148   foundconv:
4149     PetscCall(PetscLogEventBegin(DM_Convert, dm, 0, 0, 0));
4150     PetscCall((*conv)(dm, newtype, M));
4151     /* Things that are independent of DM type: We should consult DMClone() here */
4152     {
4153       const PetscReal *maxCell, *Lstart, *L;
4154 
4155       PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
4156       PetscCall(DMSetPeriodicity(*M, maxCell, Lstart, L));
4157       (*M)->prealloc_only = dm->prealloc_only;
4158       PetscCall(PetscFree((*M)->vectype));
4159       PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype));
4160       PetscCall(PetscFree((*M)->mattype));
4161       PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype));
4162     }
4163     PetscCall(PetscLogEventEnd(DM_Convert, dm, 0, 0, 0));
4164   }
4165   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4166   PetscFunctionReturn(PETSC_SUCCESS);
4167 }
4168 
4169 /*@C
4170   DMRegister -  Adds a new `DM` type implementation
4171 
4172   Not Collective, No Fortran Support
4173 
4174   Input Parameters:
4175 + sname    - The name of a new user-defined creation routine
4176 - function - The creation routine itself
4177 
4178   Level: advanced
4179 
4180   Note:
4181   `DMRegister()` may be called multiple times to add several user-defined `DM`s
4182 
4183   Example Usage:
4184 .vb
4185     DMRegister("my_da", MyDMCreate);
4186 .ve
4187 
4188   Then, your `DM` type can be chosen with the procedural interface via
4189 .vb
4190     DMCreate(MPI_Comm, DM *);
4191     DMSetType(DM,"my_da");
4192 .ve
4193   or at runtime via the option
4194 .vb
4195     -da_type my_da
4196 .ve
4197 
4198 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()`
4199 @*/
4200 PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM))
4201 {
4202   PetscFunctionBegin;
4203   PetscCall(DMInitializePackage());
4204   PetscCall(PetscFunctionListAdd(&DMList, sname, function));
4205   PetscFunctionReturn(PETSC_SUCCESS);
4206 }
4207 
4208 /*@
4209   DMLoad - Loads a DM that has been stored in binary  with `DMView()`.
4210 
4211   Collective
4212 
4213   Input Parameters:
4214 + newdm  - the newly loaded `DM`, this needs to have been created with `DMCreate()` or
4215            some related function before a call to `DMLoad()`.
4216 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
4217            `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()`
4218 
4219   Level: intermediate
4220 
4221   Notes:
4222   The type is determined by the data in the file, any type set into the DM before this call is ignored.
4223 
4224   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
4225   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
4226   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
4227 
4228 .seealso: [](ch_dmbase), `DM`, `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()`
4229 @*/
4230 PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
4231 {
4232   PetscBool isbinary, ishdf5;
4233 
4234   PetscFunctionBegin;
4235   PetscValidHeaderSpecific(newdm, DM_CLASSID, 1);
4236   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
4237   PetscCall(PetscViewerCheckReadable(viewer));
4238   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
4239   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
4240   PetscCall(PetscLogEventBegin(DM_Load, viewer, 0, 0, 0));
4241   if (isbinary) {
4242     PetscInt classid;
4243     char     type[256];
4244 
4245     PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT));
4246     PetscCheck(classid == DM_FILE_CLASSID, PetscObjectComm((PetscObject)newdm), PETSC_ERR_ARG_WRONG, "Not DM next in file, classid found %" PetscInt_FMT, classid);
4247     PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
4248     PetscCall(DMSetType(newdm, type));
4249     PetscTryTypeMethod(newdm, load, viewer);
4250   } else if (ishdf5) {
4251     PetscTryTypeMethod(newdm, load, viewer);
4252   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4253   PetscCall(PetscLogEventEnd(DM_Load, viewer, 0, 0, 0));
4254   PetscFunctionReturn(PETSC_SUCCESS);
4255 }
4256 
4257 /* FEM Support */
4258 
4259 PetscErrorCode DMPrintCellIndices(PetscInt c, const char name[], PetscInt len, const PetscInt x[])
4260 {
4261   PetscInt f;
4262 
4263   PetscFunctionBegin;
4264   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4265   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %" PetscInt_FMT " |\n", x[f]));
4266   PetscFunctionReturn(PETSC_SUCCESS);
4267 }
4268 
4269 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4270 {
4271   PetscInt f;
4272 
4273   PetscFunctionBegin;
4274   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4275   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f])));
4276   PetscFunctionReturn(PETSC_SUCCESS);
4277 }
4278 
4279 PetscErrorCode DMPrintCellVectorReal(PetscInt c, const char name[], PetscInt len, const PetscReal x[])
4280 {
4281   PetscInt f;
4282 
4283   PetscFunctionBegin;
4284   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4285   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)x[f]));
4286   PetscFunctionReturn(PETSC_SUCCESS);
4287 }
4288 
4289 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4290 {
4291   PetscInt f, g;
4292 
4293   PetscFunctionBegin;
4294   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4295   for (f = 0; f < rows; ++f) {
4296     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  |"));
4297     for (g = 0; g < cols; ++g) PetscCall(PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g])));
4298     PetscCall(PetscPrintf(PETSC_COMM_SELF, " |\n"));
4299   }
4300   PetscFunctionReturn(PETSC_SUCCESS);
4301 }
4302 
4303 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4304 {
4305   PetscInt           localSize, bs;
4306   PetscMPIInt        size;
4307   Vec                x, xglob;
4308   const PetscScalar *xarray;
4309 
4310   PetscFunctionBegin;
4311   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
4312   PetscCall(VecDuplicate(X, &x));
4313   PetscCall(VecCopy(X, x));
4314   PetscCall(VecFilter(x, tol));
4315   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name));
4316   if (size > 1) {
4317     PetscCall(VecGetLocalSize(x, &localSize));
4318     PetscCall(VecGetArrayRead(x, &xarray));
4319     PetscCall(VecGetBlockSize(x, &bs));
4320     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob));
4321   } else {
4322     xglob = x;
4323   }
4324   PetscCall(VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm))));
4325   if (size > 1) {
4326     PetscCall(VecDestroy(&xglob));
4327     PetscCall(VecRestoreArrayRead(x, &xarray));
4328   }
4329   PetscCall(VecDestroy(&x));
4330   PetscFunctionReturn(PETSC_SUCCESS);
4331 }
4332 
4333 /*@
4334   DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`.
4335 
4336   Input Parameter:
4337 . dm - The `DM`
4338 
4339   Output Parameter:
4340 . section - The `PetscSection`
4341 
4342   Options Database Key:
4343 . -dm_petscsection_view - View the section created by the `DM`
4344 
4345   Level: intermediate
4346 
4347   Note:
4348   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4349 
4350 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4351 @*/
4352 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4353 {
4354   PetscFunctionBegin;
4355   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4356   PetscAssertPointer(section, 2);
4357   if (!dm->localSection && dm->ops->createlocalsection) {
4358     PetscInt d;
4359 
4360     if (dm->setfromoptionscalled) {
4361       PetscObject       obj = (PetscObject)dm;
4362       PetscViewer       viewer;
4363       PetscViewerFormat format;
4364       PetscBool         flg;
4365 
4366       PetscCall(PetscOptionsCreateViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg));
4367       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
4368       for (d = 0; d < dm->Nds; ++d) {
4369         PetscCall(PetscDSSetFromOptions(dm->probs[d].ds));
4370         if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer));
4371       }
4372       if (flg) {
4373         PetscCall(PetscViewerFlush(viewer));
4374         PetscCall(PetscViewerPopFormat(viewer));
4375         PetscCall(PetscViewerDestroy(&viewer));
4376       }
4377     }
4378     PetscUseTypeMethod(dm, createlocalsection);
4379     if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view"));
4380   }
4381   *section = dm->localSection;
4382   PetscFunctionReturn(PETSC_SUCCESS);
4383 }
4384 
4385 /*@
4386   DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.
4387 
4388   Input Parameters:
4389 + dm      - The `DM`
4390 - section - The `PetscSection`
4391 
4392   Level: intermediate
4393 
4394   Note:
4395   Any existing Section will be destroyed
4396 
4397 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4398 @*/
4399 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4400 {
4401   PetscInt numFields = 0;
4402   PetscInt f;
4403 
4404   PetscFunctionBegin;
4405   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4406   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4407   PetscCall(PetscObjectReference((PetscObject)section));
4408   PetscCall(PetscSectionDestroy(&dm->localSection));
4409   dm->localSection = section;
4410   if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields));
4411   if (numFields) {
4412     PetscCall(DMSetNumFields(dm, numFields));
4413     for (f = 0; f < numFields; ++f) {
4414       PetscObject disc;
4415       const char *name;
4416 
4417       PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name));
4418       PetscCall(DMGetField(dm, f, NULL, &disc));
4419       PetscCall(PetscObjectSetName(disc, name));
4420     }
4421   }
4422   /* The global section and the SectionSF will be rebuilt
4423      in the next call to DMGetGlobalSection() and DMGetSectionSF(). */
4424   PetscCall(PetscSectionDestroy(&dm->globalSection));
4425   PetscCall(PetscSFDestroy(&dm->sectionSF));
4426   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4427 
4428   /* Clear scratch vectors */
4429   PetscCall(DMClearGlobalVectors(dm));
4430   PetscCall(DMClearLocalVectors(dm));
4431   PetscCall(DMClearNamedGlobalVectors(dm));
4432   PetscCall(DMClearNamedLocalVectors(dm));
4433   PetscFunctionReturn(PETSC_SUCCESS);
4434 }
4435 
4436 /*@C
4437   DMCreateSectionPermutation - Create a permutation of the `PetscSection` chart and optionally a block structure.
4438 
4439   Input Parameter:
4440 . dm - The `DM`
4441 
4442   Output Parameters:
4443 + perm        - A permutation of the mesh points in the chart
4444 - blockStarts - A high bit is set for the point that begins every block, or `NULL` for default blocking
4445 
4446   Level: developer
4447 
4448 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4449 @*/
4450 PetscErrorCode DMCreateSectionPermutation(DM dm, IS *perm, PetscBT *blockStarts)
4451 {
4452   PetscFunctionBegin;
4453   *perm        = NULL;
4454   *blockStarts = NULL;
4455   PetscTryTypeMethod(dm, createsectionpermutation, perm, blockStarts);
4456   PetscFunctionReturn(PETSC_SUCCESS);
4457 }
4458 
4459 /*@
4460   DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation.
4461 
4462   not Collective
4463 
4464   Input Parameter:
4465 . dm - The `DM`
4466 
4467   Output Parameters:
4468 + 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.
4469 . 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.
4470 - bias    - Vector containing bias to be added to constrained dofs
4471 
4472   Level: advanced
4473 
4474   Note:
4475   This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`.
4476 
4477 .seealso: [](ch_dmbase), `DM`, `DMSetDefaultConstraints()`
4478 @*/
4479 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4480 {
4481   PetscFunctionBegin;
4482   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4483   if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4484   if (section) *section = dm->defaultConstraint.section;
4485   if (mat) *mat = dm->defaultConstraint.mat;
4486   if (bias) *bias = dm->defaultConstraint.bias;
4487   PetscFunctionReturn(PETSC_SUCCESS);
4488 }
4489 
4490 /*@
4491   DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.
4492 
4493   Collective
4494 
4495   Input Parameters:
4496 + dm      - The `DM`
4497 . 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).
4498 . 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).
4499 - 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).
4500 
4501   Level: advanced
4502 
4503   Notes:
4504   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()`.
4505 
4506   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.
4507 
4508   This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them.
4509 
4510 .seealso: [](ch_dmbase), `DM`, `DMGetDefaultConstraints()`
4511 @*/
4512 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4513 {
4514   PetscMPIInt result;
4515 
4516   PetscFunctionBegin;
4517   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4518   if (section) {
4519     PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4520     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result));
4521     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator");
4522   }
4523   if (mat) {
4524     PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
4525     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result));
4526     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator");
4527   }
4528   if (bias) {
4529     PetscValidHeaderSpecific(bias, VEC_CLASSID, 4);
4530     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result));
4531     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator");
4532   }
4533   PetscCall(PetscObjectReference((PetscObject)section));
4534   PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section));
4535   dm->defaultConstraint.section = section;
4536   PetscCall(PetscObjectReference((PetscObject)mat));
4537   PetscCall(MatDestroy(&dm->defaultConstraint.mat));
4538   dm->defaultConstraint.mat = mat;
4539   PetscCall(PetscObjectReference((PetscObject)bias));
4540   PetscCall(VecDestroy(&dm->defaultConstraint.bias));
4541   dm->defaultConstraint.bias = bias;
4542   PetscFunctionReturn(PETSC_SUCCESS);
4543 }
4544 
4545 #if defined(PETSC_USE_DEBUG)
4546 /*
4547   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.
4548 
4549   Input Parameters:
4550 + dm - The `DM`
4551 . localSection - `PetscSection` describing the local data layout
4552 - globalSection - `PetscSection` describing the global data layout
4553 
4554   Level: intermediate
4555 
4556 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`
4557 */
4558 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4559 {
4560   MPI_Comm        comm;
4561   PetscLayout     layout;
4562   const PetscInt *ranges;
4563   PetscInt        pStart, pEnd, p, nroots;
4564   PetscMPIInt     size, rank;
4565   PetscBool       valid = PETSC_TRUE, gvalid;
4566 
4567   PetscFunctionBegin;
4568   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4569   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4570   PetscCallMPI(MPI_Comm_size(comm, &size));
4571   PetscCallMPI(MPI_Comm_rank(comm, &rank));
4572   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
4573   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
4574   PetscCall(PetscLayoutCreate(comm, &layout));
4575   PetscCall(PetscLayoutSetBlockSize(layout, 1));
4576   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
4577   PetscCall(PetscLayoutSetUp(layout));
4578   PetscCall(PetscLayoutGetRanges(layout, &ranges));
4579   for (p = pStart; p < pEnd; ++p) {
4580     PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4581 
4582     PetscCall(PetscSectionGetDof(localSection, p, &dof));
4583     PetscCall(PetscSectionGetOffset(localSection, p, &off));
4584     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
4585     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
4586     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
4587     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
4588     if (!gdof) continue; /* Censored point */
4589     if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4590       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof));
4591       valid = PETSC_FALSE;
4592     }
4593     if (gcdof && (gcdof != cdof)) {
4594       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof));
4595       valid = PETSC_FALSE;
4596     }
4597     if (gdof < 0) {
4598       gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4599       for (d = 0; d < gsize; ++d) {
4600         PetscInt offset = -(goff + 1) + d, r;
4601 
4602         PetscCall(PetscFindInt(offset, size + 1, ranges, &r));
4603         if (r < 0) r = -(r + 2);
4604         if ((r < 0) || (r >= size)) {
4605           PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff));
4606           valid = PETSC_FALSE;
4607           break;
4608         }
4609       }
4610     }
4611   }
4612   PetscCall(PetscLayoutDestroy(&layout));
4613   PetscCall(PetscSynchronizedFlush(comm, NULL));
4614   PetscCallMPI(MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm));
4615   if (!gvalid) {
4616     PetscCall(DMView(dm, NULL));
4617     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4618   }
4619   PetscFunctionReturn(PETSC_SUCCESS);
4620 }
4621 #endif
4622 
4623 PetscErrorCode DMGetIsoperiodicPointSF_Internal(DM dm, PetscSF *sf)
4624 {
4625   PetscErrorCode (*f)(DM, PetscSF *);
4626 
4627   PetscFunctionBegin;
4628   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4629   PetscAssertPointer(sf, 2);
4630   PetscCall(PetscObjectQueryFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", &f));
4631   if (f) PetscCall(f(dm, sf));
4632   else *sf = dm->sf;
4633   PetscFunctionReturn(PETSC_SUCCESS);
4634 }
4635 
4636 /*@
4637   DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.
4638 
4639   Collective
4640 
4641   Input Parameter:
4642 . dm - The `DM`
4643 
4644   Output Parameter:
4645 . section - The `PetscSection`
4646 
4647   Level: intermediate
4648 
4649   Note:
4650   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4651 
4652 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`
4653 @*/
4654 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4655 {
4656   PetscFunctionBegin;
4657   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4658   PetscAssertPointer(section, 2);
4659   if (!dm->globalSection) {
4660     PetscSection s;
4661     PetscSF      sf;
4662 
4663     PetscCall(DMGetLocalSection(dm, &s));
4664     PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4665     PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4666     PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &sf));
4667     PetscCall(PetscSectionCreateGlobalSection(s, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &dm->globalSection));
4668     PetscCall(PetscLayoutDestroy(&dm->map));
4669     PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map));
4670     PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view"));
4671   }
4672   *section = dm->globalSection;
4673   PetscFunctionReturn(PETSC_SUCCESS);
4674 }
4675 
4676 /*@
4677   DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.
4678 
4679   Input Parameters:
4680 + dm      - The `DM`
4681 - section - The PetscSection, or `NULL`
4682 
4683   Level: intermediate
4684 
4685   Note:
4686   Any existing `PetscSection` will be destroyed
4687 
4688 .seealso: [](ch_dmbase), `DM`, `DMGetGlobalSection()`, `DMSetLocalSection()`
4689 @*/
4690 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4691 {
4692   PetscFunctionBegin;
4693   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4694   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4695   PetscCall(PetscObjectReference((PetscObject)section));
4696   PetscCall(PetscSectionDestroy(&dm->globalSection));
4697   dm->globalSection = section;
4698 #if defined(PETSC_USE_DEBUG)
4699   if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section));
4700 #endif
4701   /* Clear global scratch vectors and sectionSF */
4702   PetscCall(PetscSFDestroy(&dm->sectionSF));
4703   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4704   PetscCall(DMClearGlobalVectors(dm));
4705   PetscCall(DMClearNamedGlobalVectors(dm));
4706   PetscFunctionReturn(PETSC_SUCCESS);
4707 }
4708 
4709 /*@
4710   DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set,
4711   it is created from the default `PetscSection` layouts in the `DM`.
4712 
4713   Input Parameter:
4714 . dm - The `DM`
4715 
4716   Output Parameter:
4717 . sf - The `PetscSF`
4718 
4719   Level: intermediate
4720 
4721   Note:
4722   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4723 
4724 .seealso: [](ch_dmbase), `DM`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4725 @*/
4726 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4727 {
4728   PetscInt nroots;
4729 
4730   PetscFunctionBegin;
4731   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4732   PetscAssertPointer(sf, 2);
4733   if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4734   PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL));
4735   if (nroots < 0) {
4736     PetscSection section, gSection;
4737 
4738     PetscCall(DMGetLocalSection(dm, &section));
4739     if (section) {
4740       PetscCall(DMGetGlobalSection(dm, &gSection));
4741       PetscCall(DMCreateSectionSF(dm, section, gSection));
4742     } else {
4743       *sf = NULL;
4744       PetscFunctionReturn(PETSC_SUCCESS);
4745     }
4746   }
4747   *sf = dm->sectionSF;
4748   PetscFunctionReturn(PETSC_SUCCESS);
4749 }
4750 
4751 /*@
4752   DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`
4753 
4754   Input Parameters:
4755 + dm - The `DM`
4756 - sf - The `PetscSF`
4757 
4758   Level: intermediate
4759 
4760   Note:
4761   Any previous `PetscSF` is destroyed
4762 
4763 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMCreateSectionSF()`
4764 @*/
4765 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4766 {
4767   PetscFunctionBegin;
4768   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4769   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4770   PetscCall(PetscObjectReference((PetscObject)sf));
4771   PetscCall(PetscSFDestroy(&dm->sectionSF));
4772   dm->sectionSF = sf;
4773   PetscFunctionReturn(PETSC_SUCCESS);
4774 }
4775 
4776 /*@
4777   DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4778   describing the data layout.
4779 
4780   Input Parameters:
4781 + dm            - The `DM`
4782 . localSection  - `PetscSection` describing the local data layout
4783 - globalSection - `PetscSection` describing the global data layout
4784 
4785   Level: developer
4786 
4787   Note:
4788   One usually uses `DMGetSectionSF()` to obtain the `PetscSF`
4789 
4790   Developer Note:
4791   Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF`
4792   directly into the `DM`, perhaps this function should not take the local and global sections as
4793   input and should just obtain them from the `DM`? Plus PETSc creation functions return the thing
4794   they create, this returns nothing
4795 
4796 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4797 @*/
4798 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4799 {
4800   PetscFunctionBegin;
4801   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4802   PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection));
4803   PetscFunctionReturn(PETSC_SUCCESS);
4804 }
4805 
4806 /*@
4807   DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.
4808 
4809   Not collective but the resulting `PetscSF` is collective
4810 
4811   Input Parameter:
4812 . dm - The `DM`
4813 
4814   Output Parameter:
4815 . sf - The `PetscSF`
4816 
4817   Level: intermediate
4818 
4819   Note:
4820   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4821 
4822 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4823 @*/
4824 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4825 {
4826   PetscFunctionBegin;
4827   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4828   PetscAssertPointer(sf, 2);
4829   *sf = dm->sf;
4830   PetscFunctionReturn(PETSC_SUCCESS);
4831 }
4832 
4833 /*@
4834   DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.
4835 
4836   Collective
4837 
4838   Input Parameters:
4839 + dm - The `DM`
4840 - sf - The `PetscSF`
4841 
4842   Level: intermediate
4843 
4844 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4845 @*/
4846 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4847 {
4848   PetscFunctionBegin;
4849   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4850   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4851   PetscCall(PetscObjectReference((PetscObject)sf));
4852   PetscCall(PetscSFDestroy(&dm->sf));
4853   dm->sf = sf;
4854   PetscFunctionReturn(PETSC_SUCCESS);
4855 }
4856 
4857 /*@
4858   DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering
4859 
4860   Input Parameter:
4861 . dm - The `DM`
4862 
4863   Output Parameter:
4864 . sf - The `PetscSF`
4865 
4866   Level: intermediate
4867 
4868   Note:
4869   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4870 
4871 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4872 @*/
4873 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4874 {
4875   PetscFunctionBegin;
4876   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4877   PetscAssertPointer(sf, 2);
4878   *sf = dm->sfNatural;
4879   PetscFunctionReturn(PETSC_SUCCESS);
4880 }
4881 
4882 /*@
4883   DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4884 
4885   Input Parameters:
4886 + dm - The DM
4887 - sf - The PetscSF
4888 
4889   Level: intermediate
4890 
4891 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4892 @*/
4893 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4894 {
4895   PetscFunctionBegin;
4896   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4897   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4898   PetscCall(PetscObjectReference((PetscObject)sf));
4899   PetscCall(PetscSFDestroy(&dm->sfNatural));
4900   dm->sfNatural = sf;
4901   PetscFunctionReturn(PETSC_SUCCESS);
4902 }
4903 
4904 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4905 {
4906   PetscClassId id;
4907 
4908   PetscFunctionBegin;
4909   PetscCall(PetscObjectGetClassId(disc, &id));
4910   if (id == PETSCFE_CLASSID) {
4911     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4912   } else if (id == PETSCFV_CLASSID) {
4913     PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE));
4914   } else {
4915     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4916   }
4917   PetscFunctionReturn(PETSC_SUCCESS);
4918 }
4919 
4920 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4921 {
4922   RegionField *tmpr;
4923   PetscInt     Nf = dm->Nf, f;
4924 
4925   PetscFunctionBegin;
4926   if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS);
4927   PetscCall(PetscMalloc1(NfNew, &tmpr));
4928   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4929   for (f = Nf; f < NfNew; ++f) {
4930     tmpr[f].disc        = NULL;
4931     tmpr[f].label       = NULL;
4932     tmpr[f].avoidTensor = PETSC_FALSE;
4933   }
4934   PetscCall(PetscFree(dm->fields));
4935   dm->Nf     = NfNew;
4936   dm->fields = tmpr;
4937   PetscFunctionReturn(PETSC_SUCCESS);
4938 }
4939 
4940 /*@
4941   DMClearFields - Remove all fields from the `DM`
4942 
4943   Logically Collective
4944 
4945   Input Parameter:
4946 . dm - The `DM`
4947 
4948   Level: intermediate
4949 
4950 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4951 @*/
4952 PetscErrorCode DMClearFields(DM dm)
4953 {
4954   PetscInt f;
4955 
4956   PetscFunctionBegin;
4957   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4958   if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS); // DMDA does not use fields field in DM
4959   for (f = 0; f < dm->Nf; ++f) {
4960     PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4961     PetscCall(DMLabelDestroy(&dm->fields[f].label));
4962   }
4963   PetscCall(PetscFree(dm->fields));
4964   dm->fields = NULL;
4965   dm->Nf     = 0;
4966   PetscFunctionReturn(PETSC_SUCCESS);
4967 }
4968 
4969 /*@
4970   DMGetNumFields - Get the number of fields in the `DM`
4971 
4972   Not Collective
4973 
4974   Input Parameter:
4975 . dm - The `DM`
4976 
4977   Output Parameter:
4978 . numFields - The number of fields
4979 
4980   Level: intermediate
4981 
4982 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()`
4983 @*/
4984 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4985 {
4986   PetscFunctionBegin;
4987   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4988   PetscAssertPointer(numFields, 2);
4989   *numFields = dm->Nf;
4990   PetscFunctionReturn(PETSC_SUCCESS);
4991 }
4992 
4993 /*@
4994   DMSetNumFields - Set the number of fields in the `DM`
4995 
4996   Logically Collective
4997 
4998   Input Parameters:
4999 + dm        - The `DM`
5000 - numFields - The number of fields
5001 
5002   Level: intermediate
5003 
5004 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()`
5005 @*/
5006 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
5007 {
5008   PetscInt Nf, f;
5009 
5010   PetscFunctionBegin;
5011   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5012   PetscCall(DMGetNumFields(dm, &Nf));
5013   for (f = Nf; f < numFields; ++f) {
5014     PetscContainer obj;
5015 
5016     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj));
5017     PetscCall(DMAddField(dm, NULL, (PetscObject)obj));
5018     PetscCall(PetscContainerDestroy(&obj));
5019   }
5020   PetscFunctionReturn(PETSC_SUCCESS);
5021 }
5022 
5023 /*@
5024   DMGetField - Return the `DMLabel` and discretization object for a given `DM` field
5025 
5026   Not Collective
5027 
5028   Input Parameters:
5029 + dm - The `DM`
5030 - f  - The field number
5031 
5032   Output Parameters:
5033 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed)
5034 - disc  - The discretization object (pass in `NULL` if not needed)
5035 
5036   Level: intermediate
5037 
5038 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`
5039 @*/
5040 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
5041 {
5042   PetscFunctionBegin;
5043   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5044   PetscAssertPointer(disc, 4);
5045   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);
5046   if (!dm->fields) {
5047     if (label) *label = NULL;
5048     if (disc) *disc = NULL;
5049   } else { // some DM such as DMDA do not have dm->fields
5050     if (label) *label = dm->fields[f].label;
5051     if (disc) *disc = dm->fields[f].disc;
5052   }
5053   PetscFunctionReturn(PETSC_SUCCESS);
5054 }
5055 
5056 /* Does not clear the DS */
5057 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5058 {
5059   PetscFunctionBegin;
5060   PetscCall(DMFieldEnlarge_Static(dm, f + 1));
5061   PetscCall(DMLabelDestroy(&dm->fields[f].label));
5062   PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
5063   dm->fields[f].label = label;
5064   dm->fields[f].disc  = disc;
5065   PetscCall(PetscObjectReference((PetscObject)label));
5066   PetscCall(PetscObjectReference(disc));
5067   PetscFunctionReturn(PETSC_SUCCESS);
5068 }
5069 
5070 /*@
5071   DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
5072   the field numbering.
5073 
5074   Logically Collective
5075 
5076   Input Parameters:
5077 + dm    - The `DM`
5078 . f     - The field number
5079 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5080 - disc  - The discretization object
5081 
5082   Level: intermediate
5083 
5084 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`
5085 @*/
5086 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5087 {
5088   PetscFunctionBegin;
5089   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5090   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5091   PetscValidHeader(disc, 4);
5092   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
5093   PetscCall(DMSetField_Internal(dm, f, label, disc));
5094   PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc));
5095   PetscCall(DMClearDS(dm));
5096   PetscFunctionReturn(PETSC_SUCCESS);
5097 }
5098 
5099 /*@
5100   DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
5101   and a discretization object that defines the function space associated with those points.
5102 
5103   Logically Collective
5104 
5105   Input Parameters:
5106 + dm    - The `DM`
5107 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5108 - disc  - The discretization object
5109 
5110   Level: intermediate
5111 
5112   Notes:
5113   The label already exists or will be added to the `DM` with `DMSetLabel()`.
5114 
5115   For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
5116   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
5117   geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.
5118 
5119   Fortran Note:
5120   Use the argument `PetscObjectCast(disc)` as the second argument
5121 
5122 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
5123 @*/
5124 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
5125 {
5126   PetscInt Nf = dm->Nf;
5127 
5128   PetscFunctionBegin;
5129   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5130   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5131   PetscValidHeader(disc, 3);
5132   PetscCall(DMFieldEnlarge_Static(dm, Nf + 1));
5133   dm->fields[Nf].label = label;
5134   dm->fields[Nf].disc  = disc;
5135   PetscCall(PetscObjectReference((PetscObject)label));
5136   PetscCall(PetscObjectReference(disc));
5137   PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc));
5138   PetscCall(DMClearDS(dm));
5139   PetscFunctionReturn(PETSC_SUCCESS);
5140 }
5141 
5142 /*@
5143   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
5144 
5145   Logically Collective
5146 
5147   Input Parameters:
5148 + dm          - The `DM`
5149 . f           - The field index
5150 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells
5151 
5152   Level: intermediate
5153 
5154 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
5155 @*/
5156 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
5157 {
5158   PetscFunctionBegin;
5159   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);
5160   dm->fields[f].avoidTensor = avoidTensor;
5161   PetscFunctionReturn(PETSC_SUCCESS);
5162 }
5163 
5164 /*@
5165   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
5166 
5167   Not Collective
5168 
5169   Input Parameters:
5170 + dm - The `DM`
5171 - f  - The field index
5172 
5173   Output Parameter:
5174 . avoidTensor - The flag to avoid defining the field on tensor cells
5175 
5176   Level: intermediate
5177 
5178 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`
5179 @*/
5180 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
5181 {
5182   PetscFunctionBegin;
5183   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);
5184   *avoidTensor = dm->fields[f].avoidTensor;
5185   PetscFunctionReturn(PETSC_SUCCESS);
5186 }
5187 
5188 /*@
5189   DMCopyFields - Copy the discretizations for the `DM` into another `DM`
5190 
5191   Collective
5192 
5193   Input Parameters:
5194 + dm        - The `DM`
5195 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
5196 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
5197 
5198   Output Parameter:
5199 . newdm - The `DM`
5200 
5201   Level: advanced
5202 
5203 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
5204 @*/
5205 PetscErrorCode DMCopyFields(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
5206 {
5207   PetscInt Nf, f;
5208 
5209   PetscFunctionBegin;
5210   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
5211   PetscCall(DMGetNumFields(dm, &Nf));
5212   PetscCall(DMClearFields(newdm));
5213   for (f = 0; f < Nf; ++f) {
5214     DMLabel      label;
5215     PetscObject  field;
5216     PetscClassId id;
5217     PetscBool    useCone, useClosure;
5218 
5219     PetscCall(DMGetField(dm, f, &label, &field));
5220     PetscCall(PetscObjectGetClassId(field, &id));
5221     if (id == PETSCFE_CLASSID) {
5222       PetscFE newfe;
5223 
5224       PetscCall(PetscFELimitDegree((PetscFE)field, minDegree, maxDegree, &newfe));
5225       PetscCall(DMSetField(newdm, f, label, (PetscObject)newfe));
5226       PetscCall(PetscFEDestroy(&newfe));
5227     } else {
5228       PetscCall(DMSetField(newdm, f, label, field));
5229     }
5230     PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
5231     PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure));
5232   }
5233   // Create nullspace constructor slots
5234   if (dm->nullspaceConstructors) {
5235     PetscCall(PetscFree2(newdm->nullspaceConstructors, newdm->nearnullspaceConstructors));
5236     PetscCall(PetscCalloc2(Nf, &newdm->nullspaceConstructors, Nf, &newdm->nearnullspaceConstructors));
5237   }
5238   PetscFunctionReturn(PETSC_SUCCESS);
5239 }
5240 
5241 /*@
5242   DMGetAdjacency - Returns the flags for determining variable influence
5243 
5244   Not Collective
5245 
5246   Input Parameters:
5247 + dm - The `DM` object
5248 - f  - The field number, or `PETSC_DEFAULT` for the default adjacency
5249 
5250   Output Parameters:
5251 + useCone    - Flag for variable influence starting with the cone operation
5252 - useClosure - Flag for variable influence using transitive closure
5253 
5254   Level: developer
5255 
5256   Notes:
5257 .vb
5258      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5259      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5260      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5261 .ve
5262   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5263 
5264 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
5265 @*/
5266 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
5267 {
5268   PetscFunctionBegin;
5269   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5270   if (useCone) PetscAssertPointer(useCone, 3);
5271   if (useClosure) PetscAssertPointer(useClosure, 4);
5272   if (f < 0) {
5273     if (useCone) *useCone = dm->adjacency[0];
5274     if (useClosure) *useClosure = dm->adjacency[1];
5275   } else {
5276     PetscInt Nf;
5277 
5278     PetscCall(DMGetNumFields(dm, &Nf));
5279     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5280     if (useCone) *useCone = dm->fields[f].adjacency[0];
5281     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5282   }
5283   PetscFunctionReturn(PETSC_SUCCESS);
5284 }
5285 
5286 /*@
5287   DMSetAdjacency - Set the flags for determining variable influence
5288 
5289   Not Collective
5290 
5291   Input Parameters:
5292 + dm         - The `DM` object
5293 . f          - The field number
5294 . useCone    - Flag for variable influence starting with the cone operation
5295 - useClosure - Flag for variable influence using transitive closure
5296 
5297   Level: developer
5298 
5299   Notes:
5300 .vb
5301      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5302      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5303      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5304 .ve
5305   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5306 
5307 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
5308 @*/
5309 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5310 {
5311   PetscFunctionBegin;
5312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5313   if (f < 0) {
5314     dm->adjacency[0] = useCone;
5315     dm->adjacency[1] = useClosure;
5316   } else {
5317     PetscInt Nf;
5318 
5319     PetscCall(DMGetNumFields(dm, &Nf));
5320     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5321     dm->fields[f].adjacency[0] = useCone;
5322     dm->fields[f].adjacency[1] = useClosure;
5323   }
5324   PetscFunctionReturn(PETSC_SUCCESS);
5325 }
5326 
5327 /*@
5328   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5329 
5330   Not collective
5331 
5332   Input Parameter:
5333 . dm - The `DM` object
5334 
5335   Output Parameters:
5336 + useCone    - Flag for variable influence starting with the cone operation
5337 - useClosure - Flag for variable influence using transitive closure
5338 
5339   Level: developer
5340 
5341   Notes:
5342 .vb
5343      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5344      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5345      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5346 .ve
5347 
5348 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5349 @*/
5350 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5351 {
5352   PetscInt Nf;
5353 
5354   PetscFunctionBegin;
5355   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5356   if (useCone) PetscAssertPointer(useCone, 2);
5357   if (useClosure) PetscAssertPointer(useClosure, 3);
5358   PetscCall(DMGetNumFields(dm, &Nf));
5359   if (!Nf) {
5360     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5361   } else {
5362     PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure));
5363   }
5364   PetscFunctionReturn(PETSC_SUCCESS);
5365 }
5366 
5367 /*@
5368   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5369 
5370   Not Collective
5371 
5372   Input Parameters:
5373 + dm         - The `DM` object
5374 . useCone    - Flag for variable influence starting with the cone operation
5375 - useClosure - Flag for variable influence using transitive closure
5376 
5377   Level: developer
5378 
5379   Notes:
5380 .vb
5381      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5382      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5383      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5384 .ve
5385 
5386 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5387 @*/
5388 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5389 {
5390   PetscInt Nf;
5391 
5392   PetscFunctionBegin;
5393   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5394   PetscCall(DMGetNumFields(dm, &Nf));
5395   if (!Nf) {
5396     PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5397   } else {
5398     PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure));
5399   }
5400   PetscFunctionReturn(PETSC_SUCCESS);
5401 }
5402 
5403 PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5404 {
5405   DM           plex;
5406   DMLabel     *labels, *glabels;
5407   const char **names;
5408   char        *sendNames, *recvNames;
5409   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5410   size_t       len;
5411   MPI_Comm     comm;
5412   PetscMPIInt  rank, size, p, *counts, *displs;
5413 
5414   PetscFunctionBegin;
5415   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5416   PetscCallMPI(MPI_Comm_size(comm, &size));
5417   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5418   PetscCall(DMGetNumDS(dm, &Nds));
5419   for (s = 0; s < Nds; ++s) {
5420     PetscDS  dsBC;
5421     PetscInt numBd;
5422 
5423     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5424     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5425     maxLabels += numBd;
5426   }
5427   PetscCall(PetscCalloc1(maxLabels, &labels));
5428   /* Get list of labels to be completed */
5429   for (s = 0; s < Nds; ++s) {
5430     PetscDS  dsBC;
5431     PetscInt numBd, bd;
5432 
5433     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5434     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5435     for (bd = 0; bd < numBd; ++bd) {
5436       DMLabel      label;
5437       PetscInt     field;
5438       PetscObject  obj;
5439       PetscClassId id;
5440 
5441       PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
5442       PetscCall(DMGetField(dm, field, NULL, &obj));
5443       PetscCall(PetscObjectGetClassId(obj, &id));
5444       if (id != PETSCFE_CLASSID || !label) continue;
5445       for (l = 0; l < Nl; ++l)
5446         if (labels[l] == label) break;
5447       if (l == Nl) labels[Nl++] = label;
5448     }
5449   }
5450   /* Get label names */
5451   PetscCall(PetscMalloc1(Nl, &names));
5452   for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l]));
5453   for (l = 0; l < Nl; ++l) {
5454     PetscCall(PetscStrlen(names[l], &len));
5455     maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5456   }
5457   PetscCall(PetscFree(labels));
5458   PetscCallMPI(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm));
5459   PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames));
5460   for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen));
5461   PetscCall(PetscFree(names));
5462   /* Put all names on all processes */
5463   PetscCall(PetscCalloc2(size, &counts, size + 1, &displs));
5464   PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm));
5465   for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5466   gNl = displs[size];
5467   for (p = 0; p < size; ++p) {
5468     counts[p] *= gmaxLen;
5469     displs[p] *= gmaxLen;
5470   }
5471   PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels));
5472   PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm));
5473   PetscCall(PetscFree2(counts, displs));
5474   PetscCall(PetscFree(sendNames));
5475   for (l = 0, gl = 0; l < gNl; ++l) {
5476     PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]));
5477     PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank);
5478     for (m = 0; m < gl; ++m)
5479       if (glabels[m] == glabels[gl]) goto next_label;
5480     PetscCall(DMConvert(dm, DMPLEX, &plex));
5481     PetscCall(DMPlexLabelComplete(plex, glabels[gl]));
5482     PetscCall(DMDestroy(&plex));
5483     ++gl;
5484   next_label:
5485     continue;
5486   }
5487   PetscCall(PetscFree2(recvNames, glabels));
5488   PetscFunctionReturn(PETSC_SUCCESS);
5489 }
5490 
5491 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5492 {
5493   DMSpace *tmpd;
5494   PetscInt Nds = dm->Nds, s;
5495 
5496   PetscFunctionBegin;
5497   if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS);
5498   PetscCall(PetscMalloc1(NdsNew, &tmpd));
5499   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5500   for (s = Nds; s < NdsNew; ++s) {
5501     tmpd[s].ds     = NULL;
5502     tmpd[s].label  = NULL;
5503     tmpd[s].fields = NULL;
5504   }
5505   PetscCall(PetscFree(dm->probs));
5506   dm->Nds   = NdsNew;
5507   dm->probs = tmpd;
5508   PetscFunctionReturn(PETSC_SUCCESS);
5509 }
5510 
5511 /*@
5512   DMGetNumDS - Get the number of discrete systems in the `DM`
5513 
5514   Not Collective
5515 
5516   Input Parameter:
5517 . dm - The `DM`
5518 
5519   Output Parameter:
5520 . Nds - The number of `PetscDS` objects
5521 
5522   Level: intermediate
5523 
5524 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()`
5525 @*/
5526 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5527 {
5528   PetscFunctionBegin;
5529   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5530   PetscAssertPointer(Nds, 2);
5531   *Nds = dm->Nds;
5532   PetscFunctionReturn(PETSC_SUCCESS);
5533 }
5534 
5535 /*@
5536   DMClearDS - Remove all discrete systems from the `DM`
5537 
5538   Logically Collective
5539 
5540   Input Parameter:
5541 . dm - The `DM`
5542 
5543   Level: intermediate
5544 
5545 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5546 @*/
5547 PetscErrorCode DMClearDS(DM dm)
5548 {
5549   PetscInt s;
5550 
5551   PetscFunctionBegin;
5552   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5553   for (s = 0; s < dm->Nds; ++s) {
5554     PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5555     PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5556     PetscCall(DMLabelDestroy(&dm->probs[s].label));
5557     PetscCall(ISDestroy(&dm->probs[s].fields));
5558   }
5559   PetscCall(PetscFree(dm->probs));
5560   dm->probs = NULL;
5561   dm->Nds   = 0;
5562   PetscFunctionReturn(PETSC_SUCCESS);
5563 }
5564 
5565 /*@
5566   DMGetDS - Get the default `PetscDS`
5567 
5568   Not Collective
5569 
5570   Input Parameter:
5571 . dm - The `DM`
5572 
5573   Output Parameter:
5574 . ds - The default `PetscDS`
5575 
5576   Level: intermediate
5577 
5578   Note:
5579   The `ds` is owned by the `dm` and should not be destroyed directly.
5580 
5581 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()`
5582 @*/
5583 PetscErrorCode DMGetDS(DM dm, PetscDS *ds)
5584 {
5585   PetscFunctionBeginHot;
5586   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5587   PetscAssertPointer(ds, 2);
5588   PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()");
5589   *ds = dm->probs[0].ds;
5590   PetscFunctionReturn(PETSC_SUCCESS);
5591 }
5592 
5593 /*@
5594   DMGetCellDS - Get the `PetscDS` defined on a given cell
5595 
5596   Not Collective
5597 
5598   Input Parameters:
5599 + dm    - The `DM`
5600 - point - Cell for the `PetscDS`
5601 
5602   Output Parameters:
5603 + ds   - The `PetscDS` defined on the given cell
5604 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds
5605 
5606   Level: developer
5607 
5608 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()`
5609 @*/
5610 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn)
5611 {
5612   PetscDS  dsDef = NULL;
5613   PetscInt s;
5614 
5615   PetscFunctionBeginHot;
5616   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5617   if (ds) PetscAssertPointer(ds, 3);
5618   if (dsIn) PetscAssertPointer(dsIn, 4);
5619   PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5620   if (ds) *ds = NULL;
5621   if (dsIn) *dsIn = NULL;
5622   for (s = 0; s < dm->Nds; ++s) {
5623     PetscInt val;
5624 
5625     if (!dm->probs[s].label) {
5626       dsDef = dm->probs[s].ds;
5627     } else {
5628       PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5629       if (val >= 0) {
5630         if (ds) *ds = dm->probs[s].ds;
5631         if (dsIn) *dsIn = dm->probs[s].dsIn;
5632         break;
5633       }
5634     }
5635   }
5636   if (ds && !*ds) *ds = dsDef;
5637   PetscFunctionReturn(PETSC_SUCCESS);
5638 }
5639 
5640 /*@
5641   DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel`
5642 
5643   Not Collective
5644 
5645   Input Parameters:
5646 + dm    - The `DM`
5647 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5648 
5649   Output Parameters:
5650 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5651 . ds     - The `PetscDS` defined on the given region, or `NULL`
5652 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5653 
5654   Level: advanced
5655 
5656   Note:
5657   If a non-`NULL` label is given, but there is no `PetscDS` on that specific label,
5658   the `PetscDS` for the full domain (if present) is returned. Returns with
5659   fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain.
5660 
5661 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5662 @*/
5663 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5664 {
5665   PetscInt Nds = dm->Nds, s;
5666 
5667   PetscFunctionBegin;
5668   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5669   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5670   if (fields) {
5671     PetscAssertPointer(fields, 3);
5672     *fields = NULL;
5673   }
5674   if (ds) {
5675     PetscAssertPointer(ds, 4);
5676     *ds = NULL;
5677   }
5678   if (dsIn) {
5679     PetscAssertPointer(dsIn, 5);
5680     *dsIn = NULL;
5681   }
5682   for (s = 0; s < Nds; ++s) {
5683     if (dm->probs[s].label == label || !dm->probs[s].label) {
5684       if (fields) *fields = dm->probs[s].fields;
5685       if (ds) *ds = dm->probs[s].ds;
5686       if (dsIn) *dsIn = dm->probs[s].dsIn;
5687       if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS);
5688     }
5689   }
5690   PetscFunctionReturn(PETSC_SUCCESS);
5691 }
5692 
5693 /*@
5694   DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5695 
5696   Collective
5697 
5698   Input Parameters:
5699 + dm     - The `DM`
5700 . label  - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5701 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields
5702 . ds     - The `PetscDS` defined on the given region
5703 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5704 
5705   Level: advanced
5706 
5707   Note:
5708   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5709   the fields argument is ignored.
5710 
5711 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5712 @*/
5713 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5714 {
5715   PetscInt Nds = dm->Nds, s;
5716 
5717   PetscFunctionBegin;
5718   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5719   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5720   if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3);
5721   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5722   if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5);
5723   for (s = 0; s < Nds; ++s) {
5724     if (dm->probs[s].label == label) {
5725       PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5726       PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5727       dm->probs[s].ds   = ds;
5728       dm->probs[s].dsIn = dsIn;
5729       PetscFunctionReturn(PETSC_SUCCESS);
5730     }
5731   }
5732   PetscCall(DMDSEnlarge_Static(dm, Nds + 1));
5733   PetscCall(PetscObjectReference((PetscObject)label));
5734   PetscCall(PetscObjectReference((PetscObject)fields));
5735   PetscCall(PetscObjectReference((PetscObject)ds));
5736   PetscCall(PetscObjectReference((PetscObject)dsIn));
5737   if (!label) {
5738     /* Put the NULL label at the front, so it is returned as the default */
5739     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5740     Nds = 0;
5741   }
5742   dm->probs[Nds].label  = label;
5743   dm->probs[Nds].fields = fields;
5744   dm->probs[Nds].ds     = ds;
5745   dm->probs[Nds].dsIn   = dsIn;
5746   PetscFunctionReturn(PETSC_SUCCESS);
5747 }
5748 
5749 /*@
5750   DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number
5751 
5752   Not Collective
5753 
5754   Input Parameters:
5755 + dm  - The `DM`
5756 - num - The region number, in [0, Nds)
5757 
5758   Output Parameters:
5759 + label  - The region label, or `NULL`
5760 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5761 . ds     - The `PetscDS` defined on the given region, or `NULL`
5762 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5763 
5764   Level: advanced
5765 
5766 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5767 @*/
5768 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5769 {
5770   PetscInt Nds;
5771 
5772   PetscFunctionBegin;
5773   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5774   PetscCall(DMGetNumDS(dm, &Nds));
5775   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5776   if (label) {
5777     PetscAssertPointer(label, 3);
5778     *label = dm->probs[num].label;
5779   }
5780   if (fields) {
5781     PetscAssertPointer(fields, 4);
5782     *fields = dm->probs[num].fields;
5783   }
5784   if (ds) {
5785     PetscAssertPointer(ds, 5);
5786     *ds = dm->probs[num].ds;
5787   }
5788   if (dsIn) {
5789     PetscAssertPointer(dsIn, 6);
5790     *dsIn = dm->probs[num].dsIn;
5791   }
5792   PetscFunctionReturn(PETSC_SUCCESS);
5793 }
5794 
5795 /*@
5796   DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number
5797 
5798   Not Collective
5799 
5800   Input Parameters:
5801 + dm     - The `DM`
5802 . num    - The region number, in [0, Nds)
5803 . label  - The region label, or `NULL`
5804 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting
5805 . ds     - The `PetscDS` defined on the given region, or `NULL` to prevent setting
5806 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5807 
5808   Level: advanced
5809 
5810 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5811 @*/
5812 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5813 {
5814   PetscInt Nds;
5815 
5816   PetscFunctionBegin;
5817   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5818   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5819   PetscCall(DMGetNumDS(dm, &Nds));
5820   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5821   PetscCall(PetscObjectReference((PetscObject)label));
5822   PetscCall(DMLabelDestroy(&dm->probs[num].label));
5823   dm->probs[num].label = label;
5824   if (fields) {
5825     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5826     PetscCall(PetscObjectReference((PetscObject)fields));
5827     PetscCall(ISDestroy(&dm->probs[num].fields));
5828     dm->probs[num].fields = fields;
5829   }
5830   if (ds) {
5831     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5832     PetscCall(PetscObjectReference((PetscObject)ds));
5833     PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5834     dm->probs[num].ds = ds;
5835   }
5836   if (dsIn) {
5837     PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6);
5838     PetscCall(PetscObjectReference((PetscObject)dsIn));
5839     PetscCall(PetscDSDestroy(&dm->probs[num].dsIn));
5840     dm->probs[num].dsIn = dsIn;
5841   }
5842   PetscFunctionReturn(PETSC_SUCCESS);
5843 }
5844 
5845 /*@
5846   DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found.
5847 
5848   Not Collective
5849 
5850   Input Parameters:
5851 + dm - The `DM`
5852 - ds - The `PetscDS` defined on the given region
5853 
5854   Output Parameter:
5855 . num - The region number, in [0, Nds), or -1 if not found
5856 
5857   Level: advanced
5858 
5859 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5860 @*/
5861 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5862 {
5863   PetscInt Nds, n;
5864 
5865   PetscFunctionBegin;
5866   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5867   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5868   PetscAssertPointer(num, 3);
5869   PetscCall(DMGetNumDS(dm, &Nds));
5870   for (n = 0; n < Nds; ++n)
5871     if (ds == dm->probs[n].ds) break;
5872   if (n >= Nds) *num = -1;
5873   else *num = n;
5874   PetscFunctionReturn(PETSC_SUCCESS);
5875 }
5876 
5877 /*@
5878   DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5879 
5880   Not Collective
5881 
5882   Input Parameters:
5883 + dm     - The `DM`
5884 . Nc     - The number of components for the field
5885 . prefix - The options prefix for the output `PetscFE`, or `NULL`
5886 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5887 
5888   Output Parameter:
5889 . fem - The `PetscFE`
5890 
5891   Level: intermediate
5892 
5893   Note:
5894   This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5895 
5896 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5897 @*/
5898 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5899 {
5900   DMPolytopeType ct;
5901   PetscInt       dim, cStart;
5902 
5903   PetscFunctionBegin;
5904   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5905   PetscValidLogicalCollectiveInt(dm, Nc, 2);
5906   if (prefix) PetscAssertPointer(prefix, 3);
5907   PetscValidLogicalCollectiveInt(dm, qorder, 4);
5908   PetscAssertPointer(fem, 5);
5909   PetscCall(DMGetDimension(dm, &dim));
5910   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5911   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5912   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5913   PetscFunctionReturn(PETSC_SUCCESS);
5914 }
5915 
5916 /*@
5917   DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5918 
5919   Collective
5920 
5921   Input Parameter:
5922 . dm - The `DM`
5923 
5924   Options Database Key:
5925 . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5926 
5927   Level: intermediate
5928 
5929   Developer Note:
5930   The name of this function is wrong. Create functions always return the created object as one of the arguments.
5931 
5932 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5933 @*/
5934 PetscErrorCode DMCreateDS(DM dm)
5935 {
5936   MPI_Comm  comm;
5937   PetscDS   dsDef;
5938   DMLabel  *labelSet;
5939   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5940   PetscBool doSetup = PETSC_TRUE, flg;
5941 
5942   PetscFunctionBegin;
5943   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5944   if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS);
5945   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5946   PetscCall(DMGetCoordinateDim(dm, &dE));
5947   // Create nullspace constructor slots
5948   PetscCall(PetscFree2(dm->nullspaceConstructors, dm->nearnullspaceConstructors));
5949   PetscCall(PetscCalloc2(Nf, &dm->nullspaceConstructors, Nf, &dm->nearnullspaceConstructors));
5950   /* Determine how many regions we have */
5951   PetscCall(PetscMalloc1(Nf, &labelSet));
5952   Nl   = 0;
5953   Ndef = 0;
5954   for (f = 0; f < Nf; ++f) {
5955     DMLabel  label = dm->fields[f].label;
5956     PetscInt l;
5957 
5958 #ifdef PETSC_HAVE_LIBCEED
5959     /* Move CEED context to discretizations */
5960     {
5961       PetscClassId id;
5962 
5963       PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5964       if (id == PETSCFE_CLASSID) {
5965         Ceed ceed;
5966 
5967         PetscCall(DMGetCeed(dm, &ceed));
5968         PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed));
5969       }
5970     }
5971 #endif
5972     if (!label) {
5973       ++Ndef;
5974       continue;
5975     }
5976     for (l = 0; l < Nl; ++l)
5977       if (label == labelSet[l]) break;
5978     if (l < Nl) continue;
5979     labelSet[Nl++] = label;
5980   }
5981   /* Create default DS if there are no labels to intersect with */
5982   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5983   if (!dsDef && Ndef && !Nl) {
5984     IS        fields;
5985     PetscInt *fld, nf;
5986 
5987     for (f = 0, nf = 0; f < Nf; ++f)
5988       if (!dm->fields[f].label) ++nf;
5989     PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5990     PetscCall(PetscMalloc1(nf, &fld));
5991     for (f = 0, nf = 0; f < Nf; ++f)
5992       if (!dm->fields[f].label) fld[nf++] = f;
5993     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5994     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5995     PetscCall(ISSetType(fields, ISGENERAL));
5996     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5997 
5998     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5999     PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL));
6000     PetscCall(PetscDSDestroy(&dsDef));
6001     PetscCall(ISDestroy(&fields));
6002   }
6003   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
6004   if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
6005   /* Intersect labels with default fields */
6006   if (Ndef && Nl) {
6007     DM              plex;
6008     DMLabel         cellLabel;
6009     IS              fieldIS, allcellIS, defcellIS = NULL;
6010     PetscInt       *fields;
6011     const PetscInt *cells;
6012     PetscInt        depth, nf = 0, n, c;
6013 
6014     PetscCall(DMConvert(dm, DMPLEX, &plex));
6015     PetscCall(DMPlexGetDepth(plex, &depth));
6016     PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
6017     if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
6018     /* TODO This looks like it only works for one label */
6019     for (l = 0; l < Nl; ++l) {
6020       DMLabel label = labelSet[l];
6021       IS      pointIS;
6022 
6023       PetscCall(ISDestroy(&defcellIS));
6024       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
6025       PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
6026       PetscCall(ISDestroy(&pointIS));
6027     }
6028     PetscCall(ISDestroy(&allcellIS));
6029 
6030     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
6031     PetscCall(ISGetLocalSize(defcellIS, &n));
6032     PetscCall(ISGetIndices(defcellIS, &cells));
6033     for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
6034     PetscCall(ISRestoreIndices(defcellIS, &cells));
6035     PetscCall(ISDestroy(&defcellIS));
6036     PetscCall(DMPlexLabelComplete(plex, cellLabel));
6037 
6038     PetscCall(PetscMalloc1(Ndef, &fields));
6039     for (f = 0; f < Nf; ++f)
6040       if (!dm->fields[f].label) fields[nf++] = f;
6041     PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
6042     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_"));
6043     PetscCall(ISSetType(fieldIS, ISGENERAL));
6044     PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
6045 
6046     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
6047     PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL));
6048     PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
6049     PetscCall(DMLabelDestroy(&cellLabel));
6050     PetscCall(PetscDSDestroy(&dsDef));
6051     PetscCall(ISDestroy(&fieldIS));
6052     PetscCall(DMDestroy(&plex));
6053   }
6054   /* Create label DSes
6055      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
6056   */
6057   /* TODO Should check that labels are disjoint */
6058   for (l = 0; l < Nl; ++l) {
6059     DMLabel   label = labelSet[l];
6060     PetscDS   ds, dsIn = NULL;
6061     IS        fields;
6062     PetscInt *fld, nf;
6063 
6064     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
6065     for (f = 0, nf = 0; f < Nf; ++f)
6066       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
6067     PetscCall(PetscMalloc1(nf, &fld));
6068     for (f = 0, nf = 0; f < Nf; ++f)
6069       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
6070     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
6071     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
6072     PetscCall(ISSetType(fields, ISGENERAL));
6073     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
6074     PetscCall(PetscDSSetCoordinateDimension(ds, dE));
6075     {
6076       DMPolytopeType ct;
6077       PetscInt       lStart, lEnd;
6078       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;
6079 
6080       PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
6081       if (lStart >= 0) {
6082         PetscCall(DMPlexGetCellType(dm, lStart, &ct));
6083         switch (ct) {
6084         case DM_POLYTOPE_POINT_PRISM_TENSOR:
6085         case DM_POLYTOPE_SEG_PRISM_TENSOR:
6086         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6087         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
6088           isCohesiveLocal = PETSC_TRUE;
6089           break;
6090         default:
6091           break;
6092         }
6093       }
6094       PetscCallMPI(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm));
6095       if (isCohesive) {
6096         PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn));
6097         PetscCall(PetscDSSetCoordinateDimension(dsIn, dE));
6098       }
6099       for (f = 0, nf = 0; f < Nf; ++f) {
6100         if (label == dm->fields[f].label || !dm->fields[f].label) {
6101           if (label == dm->fields[f].label) {
6102             PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
6103             PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
6104             if (dsIn) {
6105               PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL));
6106               PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive));
6107             }
6108           }
6109           ++nf;
6110         }
6111       }
6112     }
6113     PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn));
6114     PetscCall(ISDestroy(&fields));
6115     PetscCall(PetscDSDestroy(&ds));
6116     PetscCall(PetscDSDestroy(&dsIn));
6117   }
6118   PetscCall(PetscFree(labelSet));
6119   /* Set fields in DSes */
6120   for (s = 0; s < dm->Nds; ++s) {
6121     PetscDS         ds     = dm->probs[s].ds;
6122     PetscDS         dsIn   = dm->probs[s].dsIn;
6123     IS              fields = dm->probs[s].fields;
6124     const PetscInt *fld;
6125     PetscInt        nf, dsnf;
6126     PetscBool       isCohesive;
6127 
6128     PetscCall(PetscDSGetNumFields(ds, &dsnf));
6129     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
6130     PetscCall(ISGetLocalSize(fields, &nf));
6131     PetscCall(ISGetIndices(fields, &fld));
6132     for (f = 0; f < nf; ++f) {
6133       PetscObject  disc = dm->fields[fld[f]].disc;
6134       PetscBool    isCohesiveField;
6135       PetscClassId id;
6136 
6137       /* Handle DS with no fields */
6138       if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
6139       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
6140       if (isCohesive) {
6141         if (!isCohesiveField) {
6142           PetscObject bdDisc;
6143 
6144           PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc));
6145           PetscCall(PetscDSSetDiscretization(ds, f, bdDisc));
6146           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6147         } else {
6148           PetscCall(PetscDSSetDiscretization(ds, f, disc));
6149           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6150         }
6151       } else {
6152         PetscCall(PetscDSSetDiscretization(ds, f, disc));
6153       }
6154       /* We allow people to have placeholder fields and construct the Section by hand */
6155       PetscCall(PetscObjectGetClassId(disc, &id));
6156       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
6157     }
6158     PetscCall(ISRestoreIndices(fields, &fld));
6159   }
6160   /* Allow k-jet tabulation */
6161   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
6162   if (flg) {
6163     for (s = 0; s < dm->Nds; ++s) {
6164       PetscDS  ds   = dm->probs[s].ds;
6165       PetscDS  dsIn = dm->probs[s].dsIn;
6166       PetscInt Nf, f;
6167 
6168       PetscCall(PetscDSGetNumFields(ds, &Nf));
6169       for (f = 0; f < Nf; ++f) {
6170         PetscCall(PetscDSSetJetDegree(ds, f, k));
6171         if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k));
6172       }
6173     }
6174   }
6175   /* Setup DSes */
6176   if (doSetup) {
6177     for (s = 0; s < dm->Nds; ++s) {
6178       if (dm->setfromoptionscalled) {
6179         PetscCall(PetscDSSetFromOptions(dm->probs[s].ds));
6180         if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn));
6181       }
6182       PetscCall(PetscDSSetUp(dm->probs[s].ds));
6183       if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn));
6184     }
6185   }
6186   PetscFunctionReturn(PETSC_SUCCESS);
6187 }
6188 
6189 /*@
6190   DMUseTensorOrder - Use a tensor product closure ordering for the default section
6191 
6192   Input Parameters:
6193 + dm     - The DM
6194 - tensor - Flag for tensor order
6195 
6196   Level: developer
6197 
6198 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()`
6199 @*/
6200 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor)
6201 {
6202   PetscInt  Nf;
6203   PetscBool reorder = PETSC_TRUE, isPlex;
6204 
6205   PetscFunctionBegin;
6206   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
6207   PetscCall(DMGetNumFields(dm, &Nf));
6208   for (PetscInt f = 0; f < Nf; ++f) {
6209     PetscObject  obj;
6210     PetscClassId id;
6211 
6212     PetscCall(DMGetField(dm, f, NULL, &obj));
6213     PetscCall(PetscObjectGetClassId(obj, &id));
6214     if (id == PETSCFE_CLASSID) {
6215       PetscSpace sp;
6216       PetscBool  tensor;
6217 
6218       PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp));
6219       PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor));
6220       reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE;
6221     } else reorder = PETSC_FALSE;
6222   }
6223   if (tensor) {
6224     if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL));
6225   } else {
6226     PetscSection s;
6227 
6228     PetscCall(DMGetLocalSection(dm, &s));
6229     if (s) PetscCall(PetscSectionResetClosurePermutation(s));
6230   }
6231   PetscFunctionReturn(PETSC_SUCCESS);
6232 }
6233 
6234 /*@
6235   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
6236 
6237   Collective
6238 
6239   Input Parameters:
6240 + dm   - The `DM`
6241 - time - The time
6242 
6243   Output Parameters:
6244 + u   - The vector will be filled with exact solution values, or `NULL`
6245 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL`
6246 
6247   Level: developer
6248 
6249   Note:
6250   The user must call `PetscDSSetExactSolution()` before using this routine
6251 
6252 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()`
6253 @*/
6254 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
6255 {
6256   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
6257   void   **ectxs;
6258   Vec      locu, locu_t;
6259   PetscInt Nf, Nds, s;
6260 
6261   PetscFunctionBegin;
6262   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6263   if (u) {
6264     PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
6265     PetscCall(DMGetLocalVector(dm, &locu));
6266     PetscCall(VecSet(locu, 0.));
6267   }
6268   if (u_t) {
6269     PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
6270     PetscCall(DMGetLocalVector(dm, &locu_t));
6271     PetscCall(VecSet(locu_t, 0.));
6272   }
6273   PetscCall(DMGetNumFields(dm, &Nf));
6274   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
6275   PetscCall(DMGetNumDS(dm, &Nds));
6276   for (s = 0; s < Nds; ++s) {
6277     PetscDS         ds;
6278     DMLabel         label;
6279     IS              fieldIS;
6280     const PetscInt *fields, id = 1;
6281     PetscInt        dsNf, f;
6282 
6283     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
6284     PetscCall(PetscDSGetNumFields(ds, &dsNf));
6285     PetscCall(ISGetIndices(fieldIS, &fields));
6286     PetscCall(PetscArrayzero(exacts, Nf));
6287     PetscCall(PetscArrayzero(ectxs, Nf));
6288     if (u) {
6289       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6290       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu));
6291       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu));
6292     }
6293     if (u_t) {
6294       PetscCall(PetscArrayzero(exacts, Nf));
6295       PetscCall(PetscArrayzero(ectxs, Nf));
6296       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6297       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6298       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6299     }
6300     PetscCall(ISRestoreIndices(fieldIS, &fields));
6301   }
6302   if (u) {
6303     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6304     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6305   }
6306   if (u_t) {
6307     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6308     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6309   }
6310   PetscCall(PetscFree2(exacts, ectxs));
6311   if (u) {
6312     PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u));
6313     PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u));
6314     PetscCall(DMRestoreLocalVector(dm, &locu));
6315   }
6316   if (u_t) {
6317     PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t));
6318     PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t));
6319     PetscCall(DMRestoreLocalVector(dm, &locu_t));
6320   }
6321   PetscFunctionReturn(PETSC_SUCCESS);
6322 }
6323 
6324 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscInt minDegree, PetscInt maxDegree, PetscDS ds, PetscDS dsIn)
6325 {
6326   PetscDS dsNew, dsInNew = NULL;
6327 
6328   PetscFunctionBegin;
6329   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6330   PetscCall(PetscDSCopy(ds, minDegree, maxDegree, dm, dsNew));
6331   if (dsIn) {
6332     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew));
6333     PetscCall(PetscDSCopy(dsIn, minDegree, maxDegree, dm, dsInNew));
6334   }
6335   PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew));
6336   PetscCall(PetscDSDestroy(&dsNew));
6337   PetscCall(PetscDSDestroy(&dsInNew));
6338   PetscFunctionReturn(PETSC_SUCCESS);
6339 }
6340 
6341 /*@
6342   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6343 
6344   Collective
6345 
6346   Input Parameters:
6347 + dm        - The `DM`
6348 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
6349 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
6350 
6351   Output Parameter:
6352 . newdm - The `DM`
6353 
6354   Level: advanced
6355 
6356 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6357 @*/
6358 PetscErrorCode DMCopyDS(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
6359 {
6360   PetscInt Nds, s;
6361 
6362   PetscFunctionBegin;
6363   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
6364   PetscCall(DMGetNumDS(dm, &Nds));
6365   PetscCall(DMClearDS(newdm));
6366   for (s = 0; s < Nds; ++s) {
6367     DMLabel  label;
6368     IS       fields;
6369     PetscDS  ds, dsIn, newds;
6370     PetscInt Nbd, bd;
6371 
6372     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn));
6373     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6374     PetscCall(DMTransferDS_Internal(newdm, label, fields, minDegree, maxDegree, ds, dsIn));
6375     /* Complete new labels in the new DS */
6376     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL));
6377     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6378     for (bd = 0; bd < Nbd; ++bd) {
6379       PetscWeakForm wf;
6380       DMLabel       label;
6381       PetscInt      field;
6382 
6383       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6384       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6385     }
6386   }
6387   PetscCall(DMCompleteBCLabels_Internal(newdm));
6388   PetscFunctionReturn(PETSC_SUCCESS);
6389 }
6390 
6391 /*@
6392   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6393 
6394   Collective
6395 
6396   Input Parameter:
6397 . dm - The `DM`
6398 
6399   Output Parameter:
6400 . newdm - The `DM`
6401 
6402   Level: advanced
6403 
6404   Developer Note:
6405   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6406 
6407 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()`
6408 @*/
6409 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6410 {
6411   PetscFunctionBegin;
6412   PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6413   PetscCall(DMCopyDS(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6414   PetscFunctionReturn(PETSC_SUCCESS);
6415 }
6416 
6417 /*@
6418   DMGetDimension - Return the topological dimension of the `DM`
6419 
6420   Not Collective
6421 
6422   Input Parameter:
6423 . dm - The `DM`
6424 
6425   Output Parameter:
6426 . dim - The topological dimension
6427 
6428   Level: beginner
6429 
6430 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()`
6431 @*/
6432 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6433 {
6434   PetscFunctionBegin;
6435   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6436   PetscAssertPointer(dim, 2);
6437   *dim = dm->dim;
6438   PetscFunctionReturn(PETSC_SUCCESS);
6439 }
6440 
6441 /*@
6442   DMSetDimension - Set the topological dimension of the `DM`
6443 
6444   Collective
6445 
6446   Input Parameters:
6447 + dm  - The `DM`
6448 - dim - The topological dimension
6449 
6450   Level: beginner
6451 
6452 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()`
6453 @*/
6454 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6455 {
6456   PetscDS  ds;
6457   PetscInt Nds, n;
6458 
6459   PetscFunctionBegin;
6460   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6461   PetscValidLogicalCollectiveInt(dm, dim, 2);
6462   dm->dim = dim;
6463   if (dm->dim >= 0) {
6464     PetscCall(DMGetNumDS(dm, &Nds));
6465     for (n = 0; n < Nds; ++n) {
6466       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL));
6467       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6468     }
6469   }
6470   PetscFunctionReturn(PETSC_SUCCESS);
6471 }
6472 
6473 /*@
6474   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6475 
6476   Collective
6477 
6478   Input Parameters:
6479 + dm  - the `DM`
6480 - dim - the dimension
6481 
6482   Output Parameters:
6483 + pStart - The first point of the given dimension
6484 - pEnd   - The first point following points of the given dimension
6485 
6486   Level: intermediate
6487 
6488   Note:
6489   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6490   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6491   then the interval is empty.
6492 
6493 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6494 @*/
6495 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6496 {
6497   PetscInt d;
6498 
6499   PetscFunctionBegin;
6500   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6501   PetscCall(DMGetDimension(dm, &d));
6502   PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6503   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6504   PetscFunctionReturn(PETSC_SUCCESS);
6505 }
6506 
6507 /*@
6508   DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6509 
6510   Collective
6511 
6512   Input Parameter:
6513 . dm - The original `DM`
6514 
6515   Output Parameter:
6516 . odm - The `DM` which provides the layout for output
6517 
6518   Level: intermediate
6519 
6520   Note:
6521   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6522   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6523   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6524 
6525 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6526 @*/
6527 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6528 {
6529   PetscSection section;
6530   IS           perm;
6531   PetscBool    hasConstraints, newDM, gnewDM;
6532   PetscInt     num_face_sfs = 0;
6533 
6534   PetscFunctionBegin;
6535   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6536   PetscAssertPointer(odm, 2);
6537   PetscCall(DMGetLocalSection(dm, &section));
6538   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6539   PetscCall(PetscSectionGetPermutation(section, &perm));
6540   PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, NULL));
6541   newDM = hasConstraints || perm || (num_face_sfs > 0) ? PETSC_TRUE : PETSC_FALSE;
6542   PetscCallMPI(MPIU_Allreduce(&newDM, &gnewDM, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6543   if (!gnewDM) {
6544     *odm = dm;
6545     PetscFunctionReturn(PETSC_SUCCESS);
6546   }
6547   if (!dm->dmBC) {
6548     PetscSection newSection, gsection;
6549     PetscSF      sf, sfNatural;
6550     PetscBool    usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE;
6551 
6552     PetscCall(DMClone(dm, &dm->dmBC));
6553     PetscCall(DMCopyDisc(dm, dm->dmBC));
6554     PetscCall(PetscSectionClone(section, &newSection));
6555     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6556     PetscCall(PetscSectionDestroy(&newSection));
6557     PetscCall(DMGetNaturalSF(dm, &sfNatural));
6558     PetscCall(DMSetNaturalSF(dm->dmBC, sfNatural));
6559     PetscCall(DMGetPointSF(dm->dmBC, &sf));
6560     PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection));
6561     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6562     PetscCall(PetscSectionDestroy(&gsection));
6563   }
6564   *odm = dm->dmBC;
6565   PetscFunctionReturn(PETSC_SUCCESS);
6566 }
6567 
6568 /*@
6569   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6570 
6571   Input Parameter:
6572 . dm - The original `DM`
6573 
6574   Output Parameters:
6575 + num - The output sequence number
6576 - val - The output sequence value
6577 
6578   Level: intermediate
6579 
6580   Note:
6581   This is intended for output that should appear in sequence, for instance
6582   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6583 
6584   Developer Note:
6585   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6586   not directly related to the `DM`.
6587 
6588 .seealso: [](ch_dmbase), `DM`, `VecView()`
6589 @*/
6590 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6591 {
6592   PetscFunctionBegin;
6593   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6594   if (num) {
6595     PetscAssertPointer(num, 2);
6596     *num = dm->outputSequenceNum;
6597   }
6598   if (val) {
6599     PetscAssertPointer(val, 3);
6600     *val = dm->outputSequenceVal;
6601   }
6602   PetscFunctionReturn(PETSC_SUCCESS);
6603 }
6604 
6605 /*@
6606   DMSetOutputSequenceNumber - Set the sequence number/value for output
6607 
6608   Input Parameters:
6609 + dm  - The original `DM`
6610 . num - The output sequence number
6611 - val - The output sequence value
6612 
6613   Level: intermediate
6614 
6615   Note:
6616   This is intended for output that should appear in sequence, for instance
6617   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6618 
6619 .seealso: [](ch_dmbase), `DM`, `VecView()`
6620 @*/
6621 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6622 {
6623   PetscFunctionBegin;
6624   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6625   dm->outputSequenceNum = num;
6626   dm->outputSequenceVal = val;
6627   PetscFunctionReturn(PETSC_SUCCESS);
6628 }
6629 
6630 /*@
6631   DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6632 
6633   Input Parameters:
6634 + dm     - The original `DM`
6635 . viewer - The `PetscViewer` to get it from
6636 . name   - The sequence name
6637 - num    - The output sequence number
6638 
6639   Output Parameter:
6640 . val - The output sequence value
6641 
6642   Level: intermediate
6643 
6644   Note:
6645   This is intended for output that should appear in sequence, for instance
6646   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6647 
6648   Developer Note:
6649   It is unclear at the user API level why a `DM` is needed as input
6650 
6651 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6652 @*/
6653 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char name[], PetscInt num, PetscReal *val)
6654 {
6655   PetscBool ishdf5;
6656 
6657   PetscFunctionBegin;
6658   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6659   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6660   PetscAssertPointer(name, 3);
6661   PetscAssertPointer(val, 5);
6662   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6663   if (ishdf5) {
6664 #if defined(PETSC_HAVE_HDF5)
6665     PetscScalar value;
6666 
6667     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6668     *val = PetscRealPart(value);
6669 #endif
6670   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6671   PetscFunctionReturn(PETSC_SUCCESS);
6672 }
6673 
6674 /*@
6675   DMGetOutputSequenceLength - Retrieve the number of sequence values from a `PetscViewer`
6676 
6677   Input Parameters:
6678 + dm     - The original `DM`
6679 . viewer - The `PetscViewer` to get it from
6680 - name   - The sequence name
6681 
6682   Output Parameter:
6683 . len - The length of the output sequence
6684 
6685   Level: intermediate
6686 
6687   Note:
6688   This is intended for output that should appear in sequence, for instance
6689   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6690 
6691   Developer Note:
6692   It is unclear at the user API level why a `DM` is needed as input
6693 
6694 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6695 @*/
6696 PetscErrorCode DMGetOutputSequenceLength(DM dm, PetscViewer viewer, const char name[], PetscInt *len)
6697 {
6698   PetscBool ishdf5;
6699 
6700   PetscFunctionBegin;
6701   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6702   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6703   PetscAssertPointer(name, 3);
6704   PetscAssertPointer(len, 4);
6705   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6706   if (ishdf5) {
6707 #if defined(PETSC_HAVE_HDF5)
6708     PetscCall(DMSequenceGetLength_HDF5_Internal(dm, name, len, viewer));
6709 #endif
6710   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6711   PetscFunctionReturn(PETSC_SUCCESS);
6712 }
6713 
6714 /*@
6715   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6716 
6717   Not Collective
6718 
6719   Input Parameter:
6720 . dm - The `DM`
6721 
6722   Output Parameter:
6723 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6724 
6725   Level: beginner
6726 
6727 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()`
6728 @*/
6729 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6730 {
6731   PetscFunctionBegin;
6732   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6733   PetscAssertPointer(useNatural, 2);
6734   *useNatural = dm->useNatural;
6735   PetscFunctionReturn(PETSC_SUCCESS);
6736 }
6737 
6738 /*@
6739   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6740 
6741   Collective
6742 
6743   Input Parameters:
6744 + dm         - The `DM`
6745 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6746 
6747   Level: beginner
6748 
6749   Note:
6750   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6751 
6752 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6753 @*/
6754 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6755 {
6756   PetscFunctionBegin;
6757   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6758   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6759   dm->useNatural = useNatural;
6760   PetscFunctionReturn(PETSC_SUCCESS);
6761 }
6762 
6763 /*@
6764   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6765 
6766   Not Collective
6767 
6768   Input Parameters:
6769 + dm   - The `DM` object
6770 - name - The label name
6771 
6772   Level: intermediate
6773 
6774 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6775 @*/
6776 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6777 {
6778   PetscBool flg;
6779   DMLabel   label;
6780 
6781   PetscFunctionBegin;
6782   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6783   PetscAssertPointer(name, 2);
6784   PetscCall(DMHasLabel(dm, name, &flg));
6785   if (!flg) {
6786     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6787     PetscCall(DMAddLabel(dm, label));
6788     PetscCall(DMLabelDestroy(&label));
6789   }
6790   PetscFunctionReturn(PETSC_SUCCESS);
6791 }
6792 
6793 /*@
6794   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6795 
6796   Not Collective
6797 
6798   Input Parameters:
6799 + dm   - The `DM` object
6800 . l    - The index for the label
6801 - name - The label name
6802 
6803   Level: intermediate
6804 
6805 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6806 @*/
6807 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6808 {
6809   DMLabelLink orig, prev = NULL;
6810   DMLabel     label;
6811   PetscInt    Nl, m;
6812   PetscBool   flg, match;
6813   const char *lname;
6814 
6815   PetscFunctionBegin;
6816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6817   PetscAssertPointer(name, 3);
6818   PetscCall(DMHasLabel(dm, name, &flg));
6819   if (!flg) {
6820     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6821     PetscCall(DMAddLabel(dm, label));
6822     PetscCall(DMLabelDestroy(&label));
6823   }
6824   PetscCall(DMGetNumLabels(dm, &Nl));
6825   PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6826   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6827     PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6828     PetscCall(PetscStrcmp(name, lname, &match));
6829     if (match) break;
6830   }
6831   if (m == l) PetscFunctionReturn(PETSC_SUCCESS);
6832   if (!m) dm->labels = orig->next;
6833   else prev->next = orig->next;
6834   if (!l) {
6835     orig->next = dm->labels;
6836     dm->labels = orig;
6837   } else {
6838     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next);
6839     orig->next = prev->next;
6840     prev->next = orig;
6841   }
6842   PetscFunctionReturn(PETSC_SUCCESS);
6843 }
6844 
6845 /*@
6846   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6847 
6848   Not Collective
6849 
6850   Input Parameters:
6851 + dm    - The `DM` object
6852 . name  - The label name
6853 - point - The mesh point
6854 
6855   Output Parameter:
6856 . value - The label value for this point, or -1 if the point is not in the label
6857 
6858   Level: beginner
6859 
6860 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6861 @*/
6862 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6863 {
6864   DMLabel label;
6865 
6866   PetscFunctionBegin;
6867   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6868   PetscAssertPointer(name, 2);
6869   PetscCall(DMGetLabel(dm, name, &label));
6870   PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6871   PetscCall(DMLabelGetValue(label, point, value));
6872   PetscFunctionReturn(PETSC_SUCCESS);
6873 }
6874 
6875 /*@
6876   DMSetLabelValue - Add a point to a `DMLabel` with given value
6877 
6878   Not Collective
6879 
6880   Input Parameters:
6881 + dm    - The `DM` object
6882 . name  - The label name
6883 . point - The mesh point
6884 - value - The label value for this point
6885 
6886   Output Parameter:
6887 
6888   Level: beginner
6889 
6890 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6891 @*/
6892 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6893 {
6894   DMLabel label;
6895 
6896   PetscFunctionBegin;
6897   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6898   PetscAssertPointer(name, 2);
6899   PetscCall(DMGetLabel(dm, name, &label));
6900   if (!label) {
6901     PetscCall(DMCreateLabel(dm, name));
6902     PetscCall(DMGetLabel(dm, name, &label));
6903   }
6904   PetscCall(DMLabelSetValue(label, point, value));
6905   PetscFunctionReturn(PETSC_SUCCESS);
6906 }
6907 
6908 /*@
6909   DMClearLabelValue - Remove a point from a `DMLabel` with given value
6910 
6911   Not Collective
6912 
6913   Input Parameters:
6914 + dm    - The `DM` object
6915 . name  - The label name
6916 . point - The mesh point
6917 - value - The label value for this point
6918 
6919   Level: beginner
6920 
6921 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6922 @*/
6923 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6924 {
6925   DMLabel label;
6926 
6927   PetscFunctionBegin;
6928   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6929   PetscAssertPointer(name, 2);
6930   PetscCall(DMGetLabel(dm, name, &label));
6931   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6932   PetscCall(DMLabelClearValue(label, point, value));
6933   PetscFunctionReturn(PETSC_SUCCESS);
6934 }
6935 
6936 /*@
6937   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6938 
6939   Not Collective
6940 
6941   Input Parameters:
6942 + dm   - The `DM` object
6943 - name - The label name
6944 
6945   Output Parameter:
6946 . size - The number of different integer ids, or 0 if the label does not exist
6947 
6948   Level: beginner
6949 
6950   Developer Note:
6951   This should be renamed to something like `DMGetLabelNumValues()` or removed.
6952 
6953 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6954 @*/
6955 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6956 {
6957   DMLabel label;
6958 
6959   PetscFunctionBegin;
6960   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6961   PetscAssertPointer(name, 2);
6962   PetscAssertPointer(size, 3);
6963   PetscCall(DMGetLabel(dm, name, &label));
6964   *size = 0;
6965   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6966   PetscCall(DMLabelGetNumValues(label, size));
6967   PetscFunctionReturn(PETSC_SUCCESS);
6968 }
6969 
6970 /*@
6971   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6972 
6973   Not Collective
6974 
6975   Input Parameters:
6976 + dm   - The `DM` object
6977 - name - The label name
6978 
6979   Output Parameter:
6980 . ids - The integer ids, or `NULL` if the label does not exist
6981 
6982   Level: beginner
6983 
6984 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()`
6985 @*/
6986 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6987 {
6988   DMLabel label;
6989 
6990   PetscFunctionBegin;
6991   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6992   PetscAssertPointer(name, 2);
6993   PetscAssertPointer(ids, 3);
6994   PetscCall(DMGetLabel(dm, name, &label));
6995   *ids = NULL;
6996   if (label) {
6997     PetscCall(DMLabelGetValueIS(label, ids));
6998   } else {
6999     /* returning an empty IS */
7000     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
7001   }
7002   PetscFunctionReturn(PETSC_SUCCESS);
7003 }
7004 
7005 /*@
7006   DMGetStratumSize - Get the number of points in a label stratum
7007 
7008   Not Collective
7009 
7010   Input Parameters:
7011 + dm    - The `DM` object
7012 . name  - The label name of the stratum
7013 - value - The stratum value
7014 
7015   Output Parameter:
7016 . size - The number of points, also called the stratum size
7017 
7018   Level: beginner
7019 
7020 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
7021 @*/
7022 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7023 {
7024   DMLabel label;
7025 
7026   PetscFunctionBegin;
7027   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7028   PetscAssertPointer(name, 2);
7029   PetscAssertPointer(size, 4);
7030   PetscCall(DMGetLabel(dm, name, &label));
7031   *size = 0;
7032   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7033   PetscCall(DMLabelGetStratumSize(label, value, size));
7034   PetscFunctionReturn(PETSC_SUCCESS);
7035 }
7036 
7037 /*@
7038   DMGetStratumIS - Get the points in a label stratum
7039 
7040   Not Collective
7041 
7042   Input Parameters:
7043 + dm    - The `DM` object
7044 . name  - The label name
7045 - value - The stratum value
7046 
7047   Output Parameter:
7048 . points - The stratum points, or `NULL` if the label does not exist or does not have that value
7049 
7050   Level: beginner
7051 
7052 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()`
7053 @*/
7054 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7055 {
7056   DMLabel label;
7057 
7058   PetscFunctionBegin;
7059   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7060   PetscAssertPointer(name, 2);
7061   PetscAssertPointer(points, 4);
7062   PetscCall(DMGetLabel(dm, name, &label));
7063   *points = NULL;
7064   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7065   PetscCall(DMLabelGetStratumIS(label, value, points));
7066   PetscFunctionReturn(PETSC_SUCCESS);
7067 }
7068 
7069 /*@
7070   DMSetStratumIS - Set the points in a label stratum
7071 
7072   Not Collective
7073 
7074   Input Parameters:
7075 + dm     - The `DM` object
7076 . name   - The label name
7077 . value  - The stratum value
7078 - points - The stratum points
7079 
7080   Level: beginner
7081 
7082 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
7083 @*/
7084 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7085 {
7086   DMLabel label;
7087 
7088   PetscFunctionBegin;
7089   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7090   PetscAssertPointer(name, 2);
7091   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
7092   PetscCall(DMGetLabel(dm, name, &label));
7093   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7094   PetscCall(DMLabelSetStratumIS(label, value, points));
7095   PetscFunctionReturn(PETSC_SUCCESS);
7096 }
7097 
7098 /*@
7099   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
7100 
7101   Not Collective
7102 
7103   Input Parameters:
7104 + dm    - The `DM` object
7105 . name  - The label name
7106 - value - The label value for this point
7107 
7108   Output Parameter:
7109 
7110   Level: beginner
7111 
7112 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
7113 @*/
7114 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7115 {
7116   DMLabel label;
7117 
7118   PetscFunctionBegin;
7119   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7120   PetscAssertPointer(name, 2);
7121   PetscCall(DMGetLabel(dm, name, &label));
7122   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7123   PetscCall(DMLabelClearStratum(label, value));
7124   PetscFunctionReturn(PETSC_SUCCESS);
7125 }
7126 
7127 /*@
7128   DMGetNumLabels - Return the number of labels defined by on the `DM`
7129 
7130   Not Collective
7131 
7132   Input Parameter:
7133 . dm - The `DM` object
7134 
7135   Output Parameter:
7136 . numLabels - the number of Labels
7137 
7138   Level: intermediate
7139 
7140 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7141 @*/
7142 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7143 {
7144   DMLabelLink next = dm->labels;
7145   PetscInt    n    = 0;
7146 
7147   PetscFunctionBegin;
7148   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7149   PetscAssertPointer(numLabels, 2);
7150   while (next) {
7151     ++n;
7152     next = next->next;
7153   }
7154   *numLabels = n;
7155   PetscFunctionReturn(PETSC_SUCCESS);
7156 }
7157 
7158 /*@
7159   DMGetLabelName - Return the name of nth label
7160 
7161   Not Collective
7162 
7163   Input Parameters:
7164 + dm - The `DM` object
7165 - n  - the label number
7166 
7167   Output Parameter:
7168 . name - the label name
7169 
7170   Level: intermediate
7171 
7172   Developer Note:
7173   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
7174 
7175 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7176 @*/
7177 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char *name[])
7178 {
7179   DMLabelLink next = dm->labels;
7180   PetscInt    l    = 0;
7181 
7182   PetscFunctionBegin;
7183   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7184   PetscAssertPointer(name, 3);
7185   while (next) {
7186     if (l == n) {
7187       PetscCall(PetscObjectGetName((PetscObject)next->label, name));
7188       PetscFunctionReturn(PETSC_SUCCESS);
7189     }
7190     ++l;
7191     next = next->next;
7192   }
7193   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7194 }
7195 
7196 /*@
7197   DMHasLabel - Determine whether the `DM` has a label of a given name
7198 
7199   Not Collective
7200 
7201   Input Parameters:
7202 + dm   - The `DM` object
7203 - name - The label name
7204 
7205   Output Parameter:
7206 . hasLabel - `PETSC_TRUE` if the label is present
7207 
7208   Level: intermediate
7209 
7210 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7211 @*/
7212 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7213 {
7214   DMLabelLink next = dm->labels;
7215   const char *lname;
7216 
7217   PetscFunctionBegin;
7218   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7219   PetscAssertPointer(name, 2);
7220   PetscAssertPointer(hasLabel, 3);
7221   *hasLabel = PETSC_FALSE;
7222   while (next) {
7223     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7224     PetscCall(PetscStrcmp(name, lname, hasLabel));
7225     if (*hasLabel) break;
7226     next = next->next;
7227   }
7228   PetscFunctionReturn(PETSC_SUCCESS);
7229 }
7230 
7231 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7232 /*@
7233   DMGetLabel - Return the label of a given name, or `NULL`, from a `DM`
7234 
7235   Not Collective
7236 
7237   Input Parameters:
7238 + dm   - The `DM` object
7239 - name - The label name
7240 
7241   Output Parameter:
7242 . label - The `DMLabel`, or `NULL` if the label is absent
7243 
7244   Default labels in a `DMPLEX`:
7245 + "depth"       - Holds the depth (co-dimension) of each mesh point
7246 . "celltype"    - Holds the topological type of each cell
7247 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7248 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7249 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7250 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7251 
7252   Level: intermediate
7253 
7254 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7255 @*/
7256 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7257 {
7258   DMLabelLink next = dm->labels;
7259   PetscBool   hasLabel;
7260   const char *lname;
7261 
7262   PetscFunctionBegin;
7263   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7264   PetscAssertPointer(name, 2);
7265   PetscAssertPointer(label, 3);
7266   *label = NULL;
7267   while (next) {
7268     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7269     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7270     if (hasLabel) {
7271       *label = next->label;
7272       break;
7273     }
7274     next = next->next;
7275   }
7276   PetscFunctionReturn(PETSC_SUCCESS);
7277 }
7278 
7279 /*@
7280   DMGetLabelByNum - Return the nth label on a `DM`
7281 
7282   Not Collective
7283 
7284   Input Parameters:
7285 + dm - The `DM` object
7286 - n  - the label number
7287 
7288   Output Parameter:
7289 . label - the label
7290 
7291   Level: intermediate
7292 
7293 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7294 @*/
7295 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7296 {
7297   DMLabelLink next = dm->labels;
7298   PetscInt    l    = 0;
7299 
7300   PetscFunctionBegin;
7301   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7302   PetscAssertPointer(label, 3);
7303   while (next) {
7304     if (l == n) {
7305       *label = next->label;
7306       PetscFunctionReturn(PETSC_SUCCESS);
7307     }
7308     ++l;
7309     next = next->next;
7310   }
7311   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7312 }
7313 
7314 /*@
7315   DMAddLabel - Add the label to this `DM`
7316 
7317   Not Collective
7318 
7319   Input Parameters:
7320 + dm    - The `DM` object
7321 - label - The `DMLabel`
7322 
7323   Level: developer
7324 
7325 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7326 @*/
7327 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7328 {
7329   DMLabelLink l, *p, tmpLabel;
7330   PetscBool   hasLabel;
7331   const char *lname;
7332   PetscBool   flg;
7333 
7334   PetscFunctionBegin;
7335   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7336   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7337   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7338   PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7339   PetscCall(PetscCalloc1(1, &tmpLabel));
7340   tmpLabel->label  = label;
7341   tmpLabel->output = PETSC_TRUE;
7342   for (p = &dm->labels; (l = *p); p = &l->next) { }
7343   *p = tmpLabel;
7344   PetscCall(PetscObjectReference((PetscObject)label));
7345   PetscCall(PetscStrcmp(lname, "depth", &flg));
7346   if (flg) dm->depthLabel = label;
7347   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7348   if (flg) dm->celltypeLabel = label;
7349   PetscFunctionReturn(PETSC_SUCCESS);
7350 }
7351 
7352 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7353 /*@
7354   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7355 
7356   Not Collective
7357 
7358   Input Parameters:
7359 + dm    - The `DM` object
7360 - label - The `DMLabel`, having the same name, to substitute
7361 
7362   Default labels in a `DMPLEX`:
7363 + "depth"       - Holds the depth (co-dimension) of each mesh point
7364 . "celltype"    - Holds the topological type of each cell
7365 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7366 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7367 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7368 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7369 
7370   Level: intermediate
7371 
7372 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7373 @*/
7374 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7375 {
7376   DMLabelLink next = dm->labels;
7377   PetscBool   hasLabel, flg;
7378   const char *name, *lname;
7379 
7380   PetscFunctionBegin;
7381   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7382   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7383   PetscCall(PetscObjectGetName((PetscObject)label, &name));
7384   while (next) {
7385     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7386     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7387     if (hasLabel) {
7388       PetscCall(PetscObjectReference((PetscObject)label));
7389       PetscCall(PetscStrcmp(lname, "depth", &flg));
7390       if (flg) dm->depthLabel = label;
7391       PetscCall(PetscStrcmp(lname, "celltype", &flg));
7392       if (flg) dm->celltypeLabel = label;
7393       PetscCall(DMLabelDestroy(&next->label));
7394       next->label = label;
7395       break;
7396     }
7397     next = next->next;
7398   }
7399   PetscFunctionReturn(PETSC_SUCCESS);
7400 }
7401 
7402 /*@
7403   DMRemoveLabel - Remove the label given by name from this `DM`
7404 
7405   Not Collective
7406 
7407   Input Parameters:
7408 + dm   - The `DM` object
7409 - name - The label name
7410 
7411   Output Parameter:
7412 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the
7413           caller is responsible for calling `DMLabelDestroy()`.
7414 
7415   Level: developer
7416 
7417 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7418 @*/
7419 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7420 {
7421   DMLabelLink link, *pnext;
7422   PetscBool   hasLabel;
7423   const char *lname;
7424 
7425   PetscFunctionBegin;
7426   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7427   PetscAssertPointer(name, 2);
7428   if (label) {
7429     PetscAssertPointer(label, 3);
7430     *label = NULL;
7431   }
7432   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7433     PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7434     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7435     if (hasLabel) {
7436       *pnext = link->next; /* Remove from list */
7437       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7438       if (hasLabel) dm->depthLabel = NULL;
7439       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7440       if (hasLabel) dm->celltypeLabel = NULL;
7441       if (label) *label = link->label;
7442       else PetscCall(DMLabelDestroy(&link->label));
7443       PetscCall(PetscFree(link));
7444       break;
7445     }
7446   }
7447   PetscFunctionReturn(PETSC_SUCCESS);
7448 }
7449 
7450 /*@
7451   DMRemoveLabelBySelf - Remove the label from this `DM`
7452 
7453   Not Collective
7454 
7455   Input Parameters:
7456 + dm           - The `DM` object
7457 . label        - The `DMLabel` to be removed from the `DM`
7458 - failNotFound - Should it fail if the label is not found in the `DM`?
7459 
7460   Level: developer
7461 
7462   Note:
7463   Only exactly the same instance is removed if found, name match is ignored.
7464   If the `DM` has an exclusive reference to the label, the label gets destroyed and
7465   *label nullified.
7466 
7467 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7468 @*/
7469 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7470 {
7471   DMLabelLink link, *pnext;
7472   PetscBool   hasLabel = PETSC_FALSE;
7473 
7474   PetscFunctionBegin;
7475   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7476   PetscAssertPointer(label, 2);
7477   if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS);
7478   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7479   PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7480   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7481     if (*label == link->label) {
7482       hasLabel = PETSC_TRUE;
7483       *pnext   = link->next; /* Remove from list */
7484       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7485       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7486       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7487       PetscCall(DMLabelDestroy(&link->label));
7488       PetscCall(PetscFree(link));
7489       break;
7490     }
7491   }
7492   PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7493   PetscFunctionReturn(PETSC_SUCCESS);
7494 }
7495 
7496 /*@
7497   DMGetLabelOutput - Get the output flag for a given label
7498 
7499   Not Collective
7500 
7501   Input Parameters:
7502 + dm   - The `DM` object
7503 - name - The label name
7504 
7505   Output Parameter:
7506 . output - The flag for output
7507 
7508   Level: developer
7509 
7510 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7511 @*/
7512 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7513 {
7514   DMLabelLink next = dm->labels;
7515   const char *lname;
7516 
7517   PetscFunctionBegin;
7518   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7519   PetscAssertPointer(name, 2);
7520   PetscAssertPointer(output, 3);
7521   while (next) {
7522     PetscBool flg;
7523 
7524     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7525     PetscCall(PetscStrcmp(name, lname, &flg));
7526     if (flg) {
7527       *output = next->output;
7528       PetscFunctionReturn(PETSC_SUCCESS);
7529     }
7530     next = next->next;
7531   }
7532   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7533 }
7534 
7535 /*@
7536   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7537 
7538   Not Collective
7539 
7540   Input Parameters:
7541 + dm     - The `DM` object
7542 . name   - The label name
7543 - output - `PETSC_TRUE` to save the label to the viewer
7544 
7545   Level: developer
7546 
7547 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7548 @*/
7549 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7550 {
7551   DMLabelLink next = dm->labels;
7552   const char *lname;
7553 
7554   PetscFunctionBegin;
7555   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7556   PetscAssertPointer(name, 2);
7557   while (next) {
7558     PetscBool flg;
7559 
7560     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7561     PetscCall(PetscStrcmp(name, lname, &flg));
7562     if (flg) {
7563       next->output = output;
7564       PetscFunctionReturn(PETSC_SUCCESS);
7565     }
7566     next = next->next;
7567   }
7568   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7569 }
7570 
7571 /*@
7572   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7573 
7574   Collective
7575 
7576   Input Parameters:
7577 + dmA   - The `DM` object with initial labels
7578 . dmB   - The `DM` object to which labels are copied
7579 . mode  - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7580 . all   - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7581 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7582 
7583   Level: intermediate
7584 
7585   Note:
7586   This is typically used when interpolating or otherwise adding to a mesh, or testing.
7587 
7588 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7589 @*/
7590 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7591 {
7592   DMLabel     label, labelNew, labelOld;
7593   const char *name;
7594   PetscBool   flg;
7595   DMLabelLink link;
7596 
7597   PetscFunctionBegin;
7598   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7599   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7600   PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7601   PetscValidLogicalCollectiveBool(dmA, all, 4);
7602   PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7603   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
7604   for (link = dmA->labels; link; link = link->next) {
7605     label = link->label;
7606     PetscCall(PetscObjectGetName((PetscObject)label, &name));
7607     if (!all) {
7608       PetscCall(PetscStrcmp(name, "depth", &flg));
7609       if (flg) continue;
7610       PetscCall(PetscStrcmp(name, "dim", &flg));
7611       if (flg) continue;
7612       PetscCall(PetscStrcmp(name, "celltype", &flg));
7613       if (flg) continue;
7614     }
7615     PetscCall(DMGetLabel(dmB, name, &labelOld));
7616     if (labelOld) {
7617       switch (emode) {
7618       case DM_COPY_LABELS_KEEP:
7619         continue;
7620       case DM_COPY_LABELS_REPLACE:
7621         PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7622         break;
7623       case DM_COPY_LABELS_FAIL:
7624         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7625       default:
7626         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7627       }
7628     }
7629     if (mode == PETSC_COPY_VALUES) {
7630       PetscCall(DMLabelDuplicate(label, &labelNew));
7631     } else {
7632       labelNew = label;
7633     }
7634     PetscCall(DMAddLabel(dmB, labelNew));
7635     if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7636   }
7637   PetscFunctionReturn(PETSC_SUCCESS);
7638 }
7639 
7640 /*@C
7641   DMCompareLabels - Compare labels between two `DM` objects
7642 
7643   Collective; No Fortran Support
7644 
7645   Input Parameters:
7646 + dm0 - First `DM` object
7647 - dm1 - Second `DM` object
7648 
7649   Output Parameters:
7650 + equal   - (Optional) Flag whether labels of `dm0` and `dm1` are the same
7651 - message - (Optional) Message describing the difference, or `NULL` if there is no difference
7652 
7653   Level: intermediate
7654 
7655   Notes:
7656   The output flag equal will be the same on all processes.
7657 
7658   If equal is passed as `NULL` and difference is found, an error is thrown on all processes.
7659 
7660   Make sure to pass equal is `NULL` on all processes or none of them.
7661 
7662   The output message is set independently on each rank.
7663 
7664   message must be freed with `PetscFree()`
7665 
7666   If message is passed as `NULL` and a difference is found, the difference description is printed to `stderr` in synchronized manner.
7667 
7668   Make sure to pass message as `NULL` on all processes or no processes.
7669 
7670   Labels are matched by name. If the number of labels and their names are equal,
7671   `DMLabelCompare()` is used to compare each pair of labels with the same name.
7672 
7673   Developer Note:
7674   Cannot automatically generate the Fortran stub because `message` must be freed with `PetscFree()`
7675 
7676 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7677 @*/
7678 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char *message[]) PeNS
7679 {
7680   PetscInt    n, i;
7681   char        msg[PETSC_MAX_PATH_LEN] = "";
7682   PetscBool   eq;
7683   MPI_Comm    comm;
7684   PetscMPIInt rank;
7685 
7686   PetscFunctionBegin;
7687   PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7688   PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7689   PetscCheckSameComm(dm0, 1, dm1, 2);
7690   if (equal) PetscAssertPointer(equal, 3);
7691   if (message) PetscAssertPointer(message, 4);
7692   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7693   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7694   {
7695     PetscInt n1;
7696 
7697     PetscCall(DMGetNumLabels(dm0, &n));
7698     PetscCall(DMGetNumLabels(dm1, &n1));
7699     eq = (PetscBool)(n == n1);
7700     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7701     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7702     if (!eq) goto finish;
7703   }
7704   for (i = 0; i < n; i++) {
7705     DMLabel     l0, l1;
7706     const char *name;
7707     char       *msgInner;
7708 
7709     /* Ignore label order */
7710     PetscCall(DMGetLabelByNum(dm0, i, &l0));
7711     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7712     PetscCall(DMGetLabel(dm1, name, &l1));
7713     if (!l1) {
7714       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7715       eq = PETSC_FALSE;
7716       break;
7717     }
7718     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7719     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7720     PetscCall(PetscFree(msgInner));
7721     if (!eq) break;
7722   }
7723   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7724 finish:
7725   /* If message output arg not set, print to stderr */
7726   if (message) {
7727     *message = NULL;
7728     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7729   } else {
7730     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7731     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7732   }
7733   /* If same output arg not ser and labels are not equal, throw error */
7734   if (equal) *equal = eq;
7735   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7736   PetscFunctionReturn(PETSC_SUCCESS);
7737 }
7738 
7739 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7740 {
7741   PetscFunctionBegin;
7742   PetscAssertPointer(label, 2);
7743   if (!*label) {
7744     PetscCall(DMCreateLabel(dm, name));
7745     PetscCall(DMGetLabel(dm, name, label));
7746   }
7747   PetscCall(DMLabelSetValue(*label, point, value));
7748   PetscFunctionReturn(PETSC_SUCCESS);
7749 }
7750 
7751 /*
7752   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7753   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7754   (label, id) pair in the DM.
7755 
7756   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7757   each label.
7758 */
7759 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7760 {
7761   DMUniversalLabel ul;
7762   PetscBool       *active;
7763   PetscInt         pStart, pEnd, p, Nl, l, m;
7764 
7765   PetscFunctionBegin;
7766   PetscCall(PetscMalloc1(1, &ul));
7767   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7768   PetscCall(DMGetNumLabels(dm, &Nl));
7769   PetscCall(PetscCalloc1(Nl, &active));
7770   ul->Nl = 0;
7771   for (l = 0; l < Nl; ++l) {
7772     PetscBool   isdepth, iscelltype;
7773     const char *name;
7774 
7775     PetscCall(DMGetLabelName(dm, l, &name));
7776     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7777     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7778     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7779     if (active[l]) ++ul->Nl;
7780   }
7781   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7782   ul->Nv = 0;
7783   for (l = 0, m = 0; l < Nl; ++l) {
7784     DMLabel     label;
7785     PetscInt    nv;
7786     const char *name;
7787 
7788     if (!active[l]) continue;
7789     PetscCall(DMGetLabelName(dm, l, &name));
7790     PetscCall(DMGetLabelByNum(dm, l, &label));
7791     PetscCall(DMLabelGetNumValues(label, &nv));
7792     PetscCall(PetscStrallocpy(name, &ul->names[m]));
7793     ul->indices[m] = l;
7794     ul->Nv += nv;
7795     ul->offsets[m + 1] = nv;
7796     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7797     ++m;
7798   }
7799   for (l = 1; l <= ul->Nl; ++l) {
7800     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7801     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7802   }
7803   for (l = 0; l < ul->Nl; ++l) {
7804     PetscInt b;
7805 
7806     ul->masks[l] = 0;
7807     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7808   }
7809   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7810   for (l = 0, m = 0; l < Nl; ++l) {
7811     DMLabel         label;
7812     IS              valueIS;
7813     const PetscInt *varr;
7814     PetscInt        nv, v;
7815 
7816     if (!active[l]) continue;
7817     PetscCall(DMGetLabelByNum(dm, l, &label));
7818     PetscCall(DMLabelGetNumValues(label, &nv));
7819     PetscCall(DMLabelGetValueIS(label, &valueIS));
7820     PetscCall(ISGetIndices(valueIS, &varr));
7821     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7822     PetscCall(ISRestoreIndices(valueIS, &varr));
7823     PetscCall(ISDestroy(&valueIS));
7824     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7825     ++m;
7826   }
7827   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7828   for (p = pStart; p < pEnd; ++p) {
7829     PetscInt  uval   = 0;
7830     PetscBool marked = PETSC_FALSE;
7831 
7832     for (l = 0, m = 0; l < Nl; ++l) {
7833       DMLabel  label;
7834       PetscInt val, defval, loc, nv;
7835 
7836       if (!active[l]) continue;
7837       PetscCall(DMGetLabelByNum(dm, l, &label));
7838       PetscCall(DMLabelGetValue(label, p, &val));
7839       PetscCall(DMLabelGetDefaultValue(label, &defval));
7840       if (val == defval) {
7841         ++m;
7842         continue;
7843       }
7844       nv     = ul->offsets[m + 1] - ul->offsets[m];
7845       marked = PETSC_TRUE;
7846       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7847       PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7848       uval += (loc + 1) << ul->bits[m];
7849       ++m;
7850     }
7851     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7852   }
7853   PetscCall(PetscFree(active));
7854   *universal = ul;
7855   PetscFunctionReturn(PETSC_SUCCESS);
7856 }
7857 
7858 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7859 {
7860   PetscInt l;
7861 
7862   PetscFunctionBegin;
7863   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7864   PetscCall(DMLabelDestroy(&(*universal)->label));
7865   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7866   PetscCall(PetscFree((*universal)->values));
7867   PetscCall(PetscFree(*universal));
7868   *universal = NULL;
7869   PetscFunctionReturn(PETSC_SUCCESS);
7870 }
7871 
7872 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7873 {
7874   PetscFunctionBegin;
7875   PetscAssertPointer(ulabel, 2);
7876   *ulabel = ul->label;
7877   PetscFunctionReturn(PETSC_SUCCESS);
7878 }
7879 
7880 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7881 {
7882   PetscInt Nl = ul->Nl, l;
7883 
7884   PetscFunctionBegin;
7885   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7886   for (l = 0; l < Nl; ++l) {
7887     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7888     else PetscCall(DMCreateLabel(dm, ul->names[l]));
7889   }
7890   if (preserveOrder) {
7891     for (l = 0; l < ul->Nl; ++l) {
7892       const char *name;
7893       PetscBool   match;
7894 
7895       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7896       PetscCall(PetscStrcmp(name, ul->names[l], &match));
7897       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]);
7898     }
7899   }
7900   PetscFunctionReturn(PETSC_SUCCESS);
7901 }
7902 
7903 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7904 {
7905   PetscInt l;
7906 
7907   PetscFunctionBegin;
7908   for (l = 0; l < ul->Nl; ++l) {
7909     DMLabel  label;
7910     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7911 
7912     if (lval) {
7913       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7914       else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7915       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7916     }
7917   }
7918   PetscFunctionReturn(PETSC_SUCCESS);
7919 }
7920 
7921 /*@
7922   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7923 
7924   Not Collective
7925 
7926   Input Parameter:
7927 . dm - The `DM` object
7928 
7929   Output Parameter:
7930 . cdm - The coarse `DM`
7931 
7932   Level: intermediate
7933 
7934 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()`
7935 @*/
7936 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7937 {
7938   PetscFunctionBegin;
7939   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7940   PetscAssertPointer(cdm, 2);
7941   *cdm = dm->coarseMesh;
7942   PetscFunctionReturn(PETSC_SUCCESS);
7943 }
7944 
7945 /*@
7946   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7947 
7948   Input Parameters:
7949 + dm  - The `DM` object
7950 - cdm - The coarse `DM`
7951 
7952   Level: intermediate
7953 
7954   Note:
7955   Normally this is set automatically by `DMRefine()`
7956 
7957 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7958 @*/
7959 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7960 {
7961   PetscFunctionBegin;
7962   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7963   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7964   if (dm == cdm) cdm = NULL;
7965   PetscCall(PetscObjectReference((PetscObject)cdm));
7966   PetscCall(DMDestroy(&dm->coarseMesh));
7967   dm->coarseMesh = cdm;
7968   PetscFunctionReturn(PETSC_SUCCESS);
7969 }
7970 
7971 /*@
7972   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7973 
7974   Input Parameter:
7975 . dm - The `DM` object
7976 
7977   Output Parameter:
7978 . fdm - The fine `DM`
7979 
7980   Level: intermediate
7981 
7982 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7983 @*/
7984 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7985 {
7986   PetscFunctionBegin;
7987   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7988   PetscAssertPointer(fdm, 2);
7989   *fdm = dm->fineMesh;
7990   PetscFunctionReturn(PETSC_SUCCESS);
7991 }
7992 
7993 /*@
7994   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7995 
7996   Input Parameters:
7997 + dm  - The `DM` object
7998 - fdm - The fine `DM`
7999 
8000   Level: developer
8001 
8002   Note:
8003   Normally this is set automatically by `DMCoarsen()`
8004 
8005 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
8006 @*/
8007 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8008 {
8009   PetscFunctionBegin;
8010   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8011   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
8012   if (dm == fdm) fdm = NULL;
8013   PetscCall(PetscObjectReference((PetscObject)fdm));
8014   PetscCall(DMDestroy(&dm->fineMesh));
8015   dm->fineMesh = fdm;
8016   PetscFunctionReturn(PETSC_SUCCESS);
8017 }
8018 
8019 /*@C
8020   DMAddBoundary - Add a boundary condition, for a single field, to a model represented by a `DM`
8021 
8022   Collective
8023 
8024   Input Parameters:
8025 + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
8026 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
8027 . name     - The BC name
8028 . label    - The label defining constrained points
8029 . Nv       - The number of `DMLabel` values for constrained points
8030 . values   - An array of values for constrained points
8031 . field    - The field to constrain
8032 . Nc       - The number of constrained field components (0 will constrain all components)
8033 . comps    - An array of constrained component numbers
8034 . bcFunc   - A pointwise function giving boundary values
8035 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8036 - ctx      - An optional user context for bcFunc
8037 
8038   Output Parameter:
8039 . bd - (Optional) Boundary number
8040 
8041   Options Database Keys:
8042 + -bc_<boundary name> <num>      - Overrides the boundary ids
8043 - -bc_<boundary name>_comp <num> - Overrides the boundary components
8044 
8045   Level: intermediate
8046 
8047   Notes:
8048   If the `DM` is of type `DMPLEX` and the field is of type `PetscFE`, then this function completes the label using `DMPlexLabelComplete()`.
8049 
8050   Both bcFunc and bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:
8051 .vb
8052  void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8053 .ve
8054 
8055   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
8056 
8057 .vb
8058   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8059               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8060               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8061               PetscReal time, const PetscReal x[], PetscScalar bcval[])
8062 .ve
8063 + dim - the spatial dimension
8064 . Nf - the number of fields
8065 . uOff - the offset into u[] and u_t[] for each field
8066 . uOff_x - the offset into u_x[] for each field
8067 . u - each field evaluated at the current point
8068 . u_t - the time derivative of each field evaluated at the current point
8069 . u_x - the gradient of each field evaluated at the current point
8070 . aOff - the offset into a[] and a_t[] for each auxiliary field
8071 . aOff_x - the offset into a_x[] for each auxiliary field
8072 . a - each auxiliary field evaluated at the current point
8073 . a_t - the time derivative of each auxiliary field evaluated at the current point
8074 . a_x - the gradient of auxiliary each field evaluated at the current point
8075 . t - current time
8076 . x - coordinates of the current point
8077 . numConstants - number of constant parameters
8078 . constants - constant parameters
8079 - bcval - output values at the current point
8080 
8081 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()`
8082 @*/
8083 PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd)
8084 {
8085   PetscDS ds;
8086 
8087   PetscFunctionBegin;
8088   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8089   PetscValidLogicalCollectiveEnum(dm, type, 2);
8090   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
8091   PetscValidLogicalCollectiveInt(dm, Nv, 5);
8092   PetscValidLogicalCollectiveInt(dm, field, 7);
8093   PetscValidLogicalCollectiveInt(dm, Nc, 8);
8094   PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
8095   PetscCall(DMGetDS(dm, &ds));
8096   /* Complete label */
8097   if (label) {
8098     PetscObject  obj;
8099     PetscClassId id;
8100 
8101     PetscCall(DMGetField(dm, field, NULL, &obj));
8102     PetscCall(PetscObjectGetClassId(obj, &id));
8103     if (id == PETSCFE_CLASSID) {
8104       DM plex;
8105 
8106       PetscCall(DMConvert(dm, DMPLEX, &plex));
8107       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
8108       PetscCall(DMDestroy(&plex));
8109     }
8110   }
8111   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
8112   PetscFunctionReturn(PETSC_SUCCESS);
8113 }
8114 
8115 /* TODO Remove this since now the structures are the same */
8116 static PetscErrorCode DMPopulateBoundary(DM dm)
8117 {
8118   PetscDS     ds;
8119   DMBoundary *lastnext;
8120   DSBoundary  dsbound;
8121 
8122   PetscFunctionBegin;
8123   PetscCall(DMGetDS(dm, &ds));
8124   dsbound = ds->boundary;
8125   if (dm->boundary) {
8126     DMBoundary next = dm->boundary;
8127 
8128     /* quick check to see if the PetscDS has changed */
8129     if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS);
8130     /* the PetscDS has changed: tear down and rebuild */
8131     while (next) {
8132       DMBoundary b = next;
8133 
8134       next = b->next;
8135       PetscCall(PetscFree(b));
8136     }
8137     dm->boundary = NULL;
8138   }
8139 
8140   lastnext = &dm->boundary;
8141   while (dsbound) {
8142     DMBoundary dmbound;
8143 
8144     PetscCall(PetscNew(&dmbound));
8145     dmbound->dsboundary = dsbound;
8146     dmbound->label      = dsbound->label;
8147     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8148     *lastnext = dmbound;
8149     lastnext  = &dmbound->next;
8150     dsbound   = dsbound->next;
8151   }
8152   PetscFunctionReturn(PETSC_SUCCESS);
8153 }
8154 
8155 /* TODO: missing manual page */
8156 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8157 {
8158   DMBoundary b;
8159 
8160   PetscFunctionBegin;
8161   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8162   PetscAssertPointer(isBd, 3);
8163   *isBd = PETSC_FALSE;
8164   PetscCall(DMPopulateBoundary(dm));
8165   b = dm->boundary;
8166   while (b && !*isBd) {
8167     DMLabel    label = b->label;
8168     DSBoundary dsb   = b->dsboundary;
8169     PetscInt   i;
8170 
8171     if (label) {
8172       for (i = 0; i < dsb->Nv && !*isBd; ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
8173     }
8174     b = b->next;
8175   }
8176   PetscFunctionReturn(PETSC_SUCCESS);
8177 }
8178 
8179 /*@
8180   DMHasBound - Determine whether a bound condition was specified
8181 
8182   Logically collective
8183 
8184   Input Parameter:
8185 . dm - The `DM`, with a `PetscDS` that matches the problem being constrained
8186 
8187   Output Parameter:
8188 . hasBound - Flag indicating if a bound condition was specified
8189 
8190   Level: intermediate
8191 
8192 .seealso: [](ch_dmbase), `DM`, `DSAddBoundary()`, `PetscDSAddBoundary()`
8193 @*/
8194 PetscErrorCode DMHasBound(DM dm, PetscBool *hasBound)
8195 {
8196   PetscDS  ds;
8197   PetscInt Nf, numBd;
8198 
8199   PetscFunctionBegin;
8200   *hasBound = PETSC_FALSE;
8201   PetscCall(DMGetDS(dm, &ds));
8202   PetscCall(PetscDSGetNumFields(ds, &Nf));
8203   for (PetscInt f = 0; f < Nf; ++f) {
8204     PetscSimplePointFn *lfunc, *ufunc;
8205 
8206     PetscCall(PetscDSGetLowerBound(ds, f, &lfunc, NULL));
8207     PetscCall(PetscDSGetUpperBound(ds, f, &ufunc, NULL));
8208     if (lfunc || ufunc) *hasBound = PETSC_TRUE;
8209   }
8210 
8211   PetscCall(PetscDSGetNumBoundary(ds, &numBd));
8212   PetscCall(PetscDSUpdateBoundaryLabels(ds, dm));
8213   for (PetscInt b = 0; b < numBd; ++b) {
8214     PetscWeakForm           wf;
8215     DMBoundaryConditionType type;
8216     const char             *name;
8217     DMLabel                 label;
8218     PetscInt                numids;
8219     const PetscInt         *ids;
8220     PetscInt                field, Nc;
8221     const PetscInt         *comps;
8222     void (*bvfunc)(void);
8223     void *ctx;
8224 
8225     PetscCall(PetscDSGetBoundary(ds, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx));
8226     if (type == DM_BC_LOWER_BOUND || type == DM_BC_UPPER_BOUND) *hasBound = PETSC_TRUE;
8227   }
8228   PetscFunctionReturn(PETSC_SUCCESS);
8229 }
8230 
8231 /*@C
8232   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
8233 
8234   Collective
8235 
8236   Input Parameters:
8237 + dm    - The `DM`
8238 . time  - The time
8239 . funcs - The coordinate functions to evaluate, one per field
8240 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8241 - mode  - The insertion mode for values
8242 
8243   Output Parameter:
8244 . X - vector
8245 
8246   Calling sequence of `funcs`:
8247 + dim  - The spatial dimension
8248 . time - The time at which to sample
8249 . x    - The coordinates
8250 . Nc   - The number of components
8251 . u    - The output field values
8252 - ctx  - optional user-defined function context
8253 
8254   Level: developer
8255 
8256   Developer Notes:
8257   This API is specific to only particular usage of `DM`
8258 
8259   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8260 
8261 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8262 @*/
8263 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)
8264 {
8265   Vec localX;
8266 
8267   PetscFunctionBegin;
8268   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8269   PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0));
8270   PetscCall(DMGetLocalVector(dm, &localX));
8271   PetscCall(VecSet(localX, 0.));
8272   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
8273   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8274   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8275   PetscCall(DMRestoreLocalVector(dm, &localX));
8276   PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0));
8277   PetscFunctionReturn(PETSC_SUCCESS);
8278 }
8279 
8280 /*@C
8281   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
8282 
8283   Not Collective
8284 
8285   Input Parameters:
8286 + dm    - The `DM`
8287 . time  - The time
8288 . funcs - The coordinate functions to evaluate, one per field
8289 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8290 - mode  - The insertion mode for values
8291 
8292   Output Parameter:
8293 . localX - vector
8294 
8295   Calling sequence of `funcs`:
8296 + dim  - The spatial dimension
8297 . time - The current timestep
8298 . x    - The coordinates
8299 . Nc   - The number of components
8300 . u    - The output field values
8301 - ctx  - optional user-defined function context
8302 
8303   Level: developer
8304 
8305   Developer Notes:
8306   This API is specific to only particular usage of `DM`
8307 
8308   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8309 
8310 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8311 @*/
8312 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)
8313 {
8314   PetscFunctionBegin;
8315   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8316   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8317   PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX);
8318   PetscFunctionReturn(PETSC_SUCCESS);
8319 }
8320 
8321 /*@C
8322   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.
8323 
8324   Collective
8325 
8326   Input Parameters:
8327 + dm     - The `DM`
8328 . time   - The time
8329 . numIds - The number of ids
8330 . ids    - The ids
8331 . Nc     - The number of components
8332 . comps  - The components
8333 . label  - The `DMLabel` selecting the portion of the mesh for projection
8334 . funcs  - The coordinate functions to evaluate, one per field
8335 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
8336 - mode   - The insertion mode for values
8337 
8338   Output Parameter:
8339 . X - vector
8340 
8341   Calling sequence of `funcs`:
8342 + dim  - The spatial dimension
8343 . time - The current timestep
8344 . x    - The coordinates
8345 . Nc   - The number of components
8346 . u    - The output field values
8347 - ctx  - optional user-defined function context
8348 
8349   Level: developer
8350 
8351   Developer Notes:
8352   This API is specific to only particular usage of `DM`
8353 
8354   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8355 
8356 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8357 @*/
8358 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)
8359 {
8360   Vec localX;
8361 
8362   PetscFunctionBegin;
8363   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8364   PetscCall(DMGetLocalVector(dm, &localX));
8365   PetscCall(VecSet(localX, 0.));
8366   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8367   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8368   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8369   PetscCall(DMRestoreLocalVector(dm, &localX));
8370   PetscFunctionReturn(PETSC_SUCCESS);
8371 }
8372 
8373 /*@C
8374   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.
8375 
8376   Not Collective
8377 
8378   Input Parameters:
8379 + dm     - The `DM`
8380 . time   - The time
8381 . label  - The `DMLabel` selecting the portion of the mesh for projection
8382 . numIds - The number of ids
8383 . ids    - The ids
8384 . Nc     - The number of components
8385 . comps  - The components
8386 . funcs  - The coordinate functions to evaluate, one per field
8387 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8388 - mode   - The insertion mode for values
8389 
8390   Output Parameter:
8391 . localX - vector
8392 
8393   Calling sequence of `funcs`:
8394 + dim  - The spatial dimension
8395 . time - The current time
8396 . x    - The coordinates
8397 . Nc   - The number of components
8398 . u    - The output field values
8399 - ctx  - optional user-defined function context
8400 
8401   Level: developer
8402 
8403   Developer Notes:
8404   This API is specific to only particular usage of `DM`
8405 
8406   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8407 
8408 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8409 @*/
8410 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)
8411 {
8412   PetscFunctionBegin;
8413   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8414   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8415   PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8416   PetscFunctionReturn(PETSC_SUCCESS);
8417 }
8418 
8419 /*@C
8420   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.
8421 
8422   Not Collective
8423 
8424   Input Parameters:
8425 + dm     - The `DM`
8426 . time   - The time
8427 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates
8428 . funcs  - The functions to evaluate, one per field
8429 - mode   - The insertion mode for values
8430 
8431   Output Parameter:
8432 . localX - The output vector
8433 
8434   Calling sequence of `funcs`:
8435 + dim          - The spatial dimension
8436 . Nf           - The number of input fields
8437 . NfAux        - The number of input auxiliary fields
8438 . uOff         - The offset of each field in u[]
8439 . uOff_x       - The offset of each field in u_x[]
8440 . u            - The field values at this point in space
8441 . u_t          - The field time derivative at this point in space (or NULL)
8442 . u_x          - The field derivatives at this point in space
8443 . aOff         - The offset of each auxiliary field in u[]
8444 . aOff_x       - The offset of each auxiliary field in u_x[]
8445 . a            - The auxiliary field values at this point in space
8446 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8447 . a_x          - The auxiliary field derivatives at this point in space
8448 . t            - The current time
8449 . x            - The coordinates of this point
8450 . numConstants - The number of constants
8451 . constants    - The value of each constant
8452 - f            - The value of the function at this point in space
8453 
8454   Level: intermediate
8455 
8456   Note:
8457   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.
8458   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
8459   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8460   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8461 
8462   Developer Notes:
8463   This API is specific to only particular usage of `DM`
8464 
8465   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8466 
8467 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`,
8468 `DMProjectFunction()`, `DMComputeL2Diff()`
8469 @*/
8470 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)
8471 {
8472   PetscFunctionBegin;
8473   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8474   if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8475   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8476   PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX);
8477   PetscFunctionReturn(PETSC_SUCCESS);
8478 }
8479 
8480 /*@C
8481   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.
8482 
8483   Not Collective
8484 
8485   Input Parameters:
8486 + dm     - The `DM`
8487 . time   - The time
8488 . label  - The `DMLabel` marking the portion of the domain to output
8489 . numIds - The number of label ids to use
8490 . ids    - The label ids to use for marking
8491 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8492 . comps  - The components to set in the output, or `NULL` for all components
8493 . localU - The input field vector
8494 . funcs  - The functions to evaluate, one per field
8495 - mode   - The insertion mode for values
8496 
8497   Output Parameter:
8498 . localX - The output vector
8499 
8500   Calling sequence of `funcs`:
8501 + dim          - The spatial dimension
8502 . Nf           - The number of input fields
8503 . NfAux        - The number of input auxiliary fields
8504 . uOff         - The offset of each field in u[]
8505 . uOff_x       - The offset of each field in u_x[]
8506 . u            - The field values at this point in space
8507 . u_t          - The field time derivative at this point in space (or NULL)
8508 . u_x          - The field derivatives at this point in space
8509 . aOff         - The offset of each auxiliary field in u[]
8510 . aOff_x       - The offset of each auxiliary field in u_x[]
8511 . a            - The auxiliary field values at this point in space
8512 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8513 . a_x          - The auxiliary field derivatives at this point in space
8514 . t            - The current time
8515 . x            - The coordinates of this point
8516 . numConstants - The number of constants
8517 . constants    - The value of each constant
8518 - f            - The value of the function at this point in space
8519 
8520   Level: intermediate
8521 
8522   Note:
8523   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.
8524   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
8525   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8526   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8527 
8528   Developer Notes:
8529   This API is specific to only particular usage of `DM`
8530 
8531   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8532 
8533 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8534 @*/
8535 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)
8536 {
8537   PetscFunctionBegin;
8538   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8539   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8540   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8541   PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8542   PetscFunctionReturn(PETSC_SUCCESS);
8543 }
8544 
8545 /*@C
8546   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.
8547 
8548   Not Collective
8549 
8550   Input Parameters:
8551 + dm     - The `DM`
8552 . time   - The time
8553 . label  - The `DMLabel` marking the portion of the domain to output
8554 . numIds - The number of label ids to use
8555 . ids    - The label ids to use for marking
8556 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8557 . comps  - The components to set in the output, or `NULL` for all components
8558 . U      - The input field vector
8559 . funcs  - The functions to evaluate, one per field
8560 - mode   - The insertion mode for values
8561 
8562   Output Parameter:
8563 . X - The output vector
8564 
8565   Calling sequence of `funcs`:
8566 + dim          - The spatial dimension
8567 . Nf           - The number of input fields
8568 . NfAux        - The number of input auxiliary fields
8569 . uOff         - The offset of each field in u[]
8570 . uOff_x       - The offset of each field in u_x[]
8571 . u            - The field values at this point in space
8572 . u_t          - The field time derivative at this point in space (or NULL)
8573 . u_x          - The field derivatives at this point in space
8574 . aOff         - The offset of each auxiliary field in u[]
8575 . aOff_x       - The offset of each auxiliary field in u_x[]
8576 . a            - The auxiliary field values at this point in space
8577 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8578 . a_x          - The auxiliary field derivatives at this point in space
8579 . t            - The current time
8580 . x            - The coordinates of this point
8581 . numConstants - The number of constants
8582 . constants    - The value of each constant
8583 - f            - The value of the function at this point in space
8584 
8585   Level: intermediate
8586 
8587   Note:
8588   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.
8589   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
8590   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8591   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8592 
8593   Developer Notes:
8594   This API is specific to only particular usage of `DM`
8595 
8596   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8597 
8598 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8599 @*/
8600 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)
8601 {
8602   DM  dmIn;
8603   Vec localU, localX;
8604 
8605   PetscFunctionBegin;
8606   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8607   PetscCall(VecGetDM(U, &dmIn));
8608   PetscCall(DMGetLocalVector(dmIn, &localU));
8609   PetscCall(DMGetLocalVector(dm, &localX));
8610   PetscCall(VecSet(localX, 0.));
8611   PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8612   PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8613   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8614   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8615   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8616   PetscCall(DMRestoreLocalVector(dm, &localX));
8617   PetscCall(DMRestoreLocalVector(dmIn, &localU));
8618   PetscFunctionReturn(PETSC_SUCCESS);
8619 }
8620 
8621 /*@C
8622   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.
8623 
8624   Not Collective
8625 
8626   Input Parameters:
8627 + dm     - The `DM`
8628 . time   - The time
8629 . label  - The `DMLabel` marking the portion of the domain boundary to output
8630 . numIds - The number of label ids to use
8631 . ids    - The label ids to use for marking
8632 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8633 . comps  - The components to set in the output, or `NULL` for all components
8634 . localU - The input field vector
8635 . funcs  - The functions to evaluate, one per field
8636 - mode   - The insertion mode for values
8637 
8638   Output Parameter:
8639 . localX - The output vector
8640 
8641   Calling sequence of `funcs`:
8642 + dim          - The spatial dimension
8643 . Nf           - The number of input fields
8644 . NfAux        - The number of input auxiliary fields
8645 . uOff         - The offset of each field in u[]
8646 . uOff_x       - The offset of each field in u_x[]
8647 . u            - The field values at this point in space
8648 . u_t          - The field time derivative at this point in space (or NULL)
8649 . u_x          - The field derivatives at this point in space
8650 . aOff         - The offset of each auxiliary field in u[]
8651 . aOff_x       - The offset of each auxiliary field in u_x[]
8652 . a            - The auxiliary field values at this point in space
8653 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8654 . a_x          - The auxiliary field derivatives at this point in space
8655 . t            - The current time
8656 . x            - The coordinates of this point
8657 . n            - The face normal
8658 . numConstants - The number of constants
8659 . constants    - The value of each constant
8660 - f            - The value of the function at this point in space
8661 
8662   Level: intermediate
8663 
8664   Note:
8665   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.
8666   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
8667   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8668   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8669 
8670   Developer Notes:
8671   This API is specific to only particular usage of `DM`
8672 
8673   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8674 
8675 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8676 @*/
8677 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)
8678 {
8679   PetscFunctionBegin;
8680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8681   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8682   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8683   PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8684   PetscFunctionReturn(PETSC_SUCCESS);
8685 }
8686 
8687 /*@C
8688   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8689 
8690   Collective
8691 
8692   Input Parameters:
8693 + dm    - The `DM`
8694 . time  - The time
8695 . funcs - The functions to evaluate for each field component
8696 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8697 - X     - The coefficient vector u_h, a global vector
8698 
8699   Output Parameter:
8700 . diff - The diff ||u - u_h||_2
8701 
8702   Level: developer
8703 
8704   Developer Notes:
8705   This API is specific to only particular usage of `DM`
8706 
8707   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8708 
8709 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8710 @*/
8711 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8712 {
8713   PetscFunctionBegin;
8714   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8715   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8716   PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff);
8717   PetscFunctionReturn(PETSC_SUCCESS);
8718 }
8719 
8720 /*@C
8721   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8722 
8723   Collective
8724 
8725   Input Parameters:
8726 + dm    - The `DM`
8727 . time  - The time
8728 . funcs - The gradient functions to evaluate for each field component
8729 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8730 . X     - The coefficient vector u_h, a global vector
8731 - n     - The vector to project along
8732 
8733   Output Parameter:
8734 . diff - The diff ||(grad u - grad u_h) . n||_2
8735 
8736   Level: developer
8737 
8738   Developer Notes:
8739   This API is specific to only particular usage of `DM`
8740 
8741   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8742 
8743 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8744 @*/
8745 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)
8746 {
8747   PetscFunctionBegin;
8748   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8749   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8750   PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff);
8751   PetscFunctionReturn(PETSC_SUCCESS);
8752 }
8753 
8754 /*@C
8755   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8756 
8757   Collective
8758 
8759   Input Parameters:
8760 + dm    - The `DM`
8761 . time  - The time
8762 . funcs - The functions to evaluate for each field component
8763 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8764 - X     - The coefficient vector u_h, a global vector
8765 
8766   Output Parameter:
8767 . diff - The array of differences, ||u^f - u^f_h||_2
8768 
8769   Level: developer
8770 
8771   Developer Notes:
8772   This API is specific to only particular usage of `DM`
8773 
8774   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8775 
8776 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()`
8777 @*/
8778 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8779 {
8780   PetscFunctionBegin;
8781   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8782   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8783   PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff);
8784   PetscFunctionReturn(PETSC_SUCCESS);
8785 }
8786 
8787 /*@C
8788   DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8789 
8790   Not Collective
8791 
8792   Input Parameter:
8793 . dm - The `DM`
8794 
8795   Output Parameters:
8796 + nranks - the number of neighbours
8797 - ranks  - the neighbors ranks
8798 
8799   Level: beginner
8800 
8801   Note:
8802   Do not free the array, it is freed when the `DM` is destroyed.
8803 
8804 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8805 @*/
8806 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8807 {
8808   PetscFunctionBegin;
8809   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8810   PetscUseTypeMethod(dm, getneighbors, nranks, ranks);
8811   PetscFunctionReturn(PETSC_SUCCESS);
8812 }
8813 
8814 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8815 
8816 /*
8817     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8818     This must be a different function because it requires DM which is not defined in the Mat library
8819 */
8820 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8821 {
8822   PetscFunctionBegin;
8823   if (coloring->ctype == IS_COLORING_LOCAL) {
8824     Vec x1local;
8825     DM  dm;
8826     PetscCall(MatGetDM(J, &dm));
8827     PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8828     PetscCall(DMGetLocalVector(dm, &x1local));
8829     PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8830     PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8831     x1 = x1local;
8832   }
8833   PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8834   if (coloring->ctype == IS_COLORING_LOCAL) {
8835     DM dm;
8836     PetscCall(MatGetDM(J, &dm));
8837     PetscCall(DMRestoreLocalVector(dm, &x1));
8838   }
8839   PetscFunctionReturn(PETSC_SUCCESS);
8840 }
8841 
8842 /*@
8843   MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8844 
8845   Input Parameters:
8846 + coloring   - The matrix to get the `DM` from
8847 - fdcoloring - the `MatFDColoring` object
8848 
8849   Level: advanced
8850 
8851   Developer Note:
8852   This routine exists because the PETSc `Mat` library does not know about the `DM` objects
8853 
8854 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8855 @*/
8856 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8857 {
8858   PetscFunctionBegin;
8859   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8860   PetscFunctionReturn(PETSC_SUCCESS);
8861 }
8862 
8863 /*@
8864   DMGetCompatibility - determine if two `DM`s are compatible
8865 
8866   Collective
8867 
8868   Input Parameters:
8869 + dm1 - the first `DM`
8870 - dm2 - the second `DM`
8871 
8872   Output Parameters:
8873 + compatible - whether or not the two `DM`s are compatible
8874 - set        - whether or not the compatible value was actually determined and set
8875 
8876   Level: advanced
8877 
8878   Notes:
8879   Two `DM`s are deemed compatible if they represent the same parallel decomposition
8880   of the same topology. This implies that the section (field data) on one
8881   "makes sense" with respect to the topology and parallel decomposition of the other.
8882   Loosely speaking, compatible `DM`s represent the same domain and parallel
8883   decomposition, but hold different data.
8884 
8885   Typically, one would confirm compatibility if intending to simultaneously iterate
8886   over a pair of vectors obtained from different `DM`s.
8887 
8888   For example, two `DMDA` objects are compatible if they have the same local
8889   and global sizes and the same stencil width. They can have different numbers
8890   of degrees of freedom per node. Thus, one could use the node numbering from
8891   either `DM` in bounds for a loop over vectors derived from either `DM`.
8892 
8893   Consider the operation of summing data living on a 2-dof `DMDA` to data living
8894   on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8895 .vb
8896   ...
8897   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8898   if (set && compatible)  {
8899     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8900     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8901     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8902     for (j=y; j<y+n; ++j) {
8903       for (i=x; i<x+m, ++i) {
8904         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8905       }
8906     }
8907     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8908     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8909   } else {
8910     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8911   }
8912   ...
8913 .ve
8914 
8915   Checking compatibility might be expensive for a given implementation of `DM`,
8916   or might be impossible to unambiguously confirm or deny. For this reason,
8917   this function may decline to determine compatibility, and hence users should
8918   always check the "set" output parameter.
8919 
8920   A `DM` is always compatible with itself.
8921 
8922   In the current implementation, `DM`s which live on "unequal" communicators
8923   (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8924   incompatible.
8925 
8926   This function is labeled "Collective," as information about all subdomains
8927   is required on each rank. However, in `DM` implementations which store all this
8928   information locally, this function may be merely "Logically Collective".
8929 
8930   Developer Note:
8931   Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8932   iff B is compatible with A. Thus, this function checks the implementations
8933   of both dm and dmc (if they are of different types), attempting to determine
8934   compatibility. It is left to `DM` implementers to ensure that symmetry is
8935   preserved. The simplest way to do this is, when implementing type-specific
8936   logic for this function, is to check for existing logic in the implementation
8937   of other `DM` types and let *set = PETSC_FALSE if found.
8938 
8939 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8940 @*/
8941 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8942 {
8943   PetscMPIInt compareResult;
8944   DMType      type, type2;
8945   PetscBool   sameType;
8946 
8947   PetscFunctionBegin;
8948   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8949   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8950 
8951   /* Declare a DM compatible with itself */
8952   if (dm1 == dm2) {
8953     *set        = PETSC_TRUE;
8954     *compatible = PETSC_TRUE;
8955     PetscFunctionReturn(PETSC_SUCCESS);
8956   }
8957 
8958   /* Declare a DM incompatible with a DM that lives on an "unequal"
8959      communicator. Note that this does not preclude compatibility with
8960      DMs living on "congruent" or "similar" communicators, but this must be
8961      determined by the implementation-specific logic */
8962   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8963   if (compareResult == MPI_UNEQUAL) {
8964     *set        = PETSC_TRUE;
8965     *compatible = PETSC_FALSE;
8966     PetscFunctionReturn(PETSC_SUCCESS);
8967   }
8968 
8969   /* Pass to the implementation-specific routine, if one exists. */
8970   if (dm1->ops->getcompatibility) {
8971     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8972     if (*set) PetscFunctionReturn(PETSC_SUCCESS);
8973   }
8974 
8975   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8976      with an implementation of this function from dm2 */
8977   PetscCall(DMGetType(dm1, &type));
8978   PetscCall(DMGetType(dm2, &type2));
8979   PetscCall(PetscStrcmp(type, type2, &sameType));
8980   if (!sameType && dm2->ops->getcompatibility) {
8981     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8982   } else {
8983     *set = PETSC_FALSE;
8984   }
8985   PetscFunctionReturn(PETSC_SUCCESS);
8986 }
8987 
8988 /*@C
8989   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8990 
8991   Logically Collective
8992 
8993   Input Parameters:
8994 + dm             - the `DM`
8995 . f              - the monitor function
8996 . mctx           - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
8997 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence
8998 
8999   Options Database Key:
9000 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
9001                        does not cancel those set via the options database.
9002 
9003   Level: intermediate
9004 
9005   Note:
9006   Several different monitoring routines may be set by calling
9007   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
9008   order in which they were set.
9009 
9010   Fortran Note:
9011   Only a single monitor function can be set for each `DM` object
9012 
9013   Developer Note:
9014   This API has a generic name but seems specific to a very particular aspect of the use of `DM`
9015 
9016 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`, `PetscCtxDestroyFn`
9017 @*/
9018 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscCtxDestroyFn *monitordestroy)
9019 {
9020   PetscInt m;
9021 
9022   PetscFunctionBegin;
9023   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9024   for (m = 0; m < dm->numbermonitors; ++m) {
9025     PetscBool identical;
9026 
9027     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))f, mctx, monitordestroy, (PetscErrorCode (*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
9028     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
9029   }
9030   PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9031   dm->monitor[dm->numbermonitors]          = f;
9032   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9033   dm->monitorcontext[dm->numbermonitors++] = mctx;
9034   PetscFunctionReturn(PETSC_SUCCESS);
9035 }
9036 
9037 /*@
9038   DMMonitorCancel - Clears all the monitor functions for a `DM` object.
9039 
9040   Logically Collective
9041 
9042   Input Parameter:
9043 . dm - the DM
9044 
9045   Options Database Key:
9046 . -dm_monitor_cancel - cancels all monitors that have been hardwired
9047   into a code by calls to `DMonitorSet()`, but does not cancel those
9048   set via the options database
9049 
9050   Level: intermediate
9051 
9052   Note:
9053   There is no way to clear one specific monitor from a `DM` object.
9054 
9055 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
9056 @*/
9057 PetscErrorCode DMMonitorCancel(DM dm)
9058 {
9059   PetscInt m;
9060 
9061   PetscFunctionBegin;
9062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9063   for (m = 0; m < dm->numbermonitors; ++m) {
9064     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
9065   }
9066   dm->numbermonitors = 0;
9067   PetscFunctionReturn(PETSC_SUCCESS);
9068 }
9069 
9070 /*@C
9071   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9072 
9073   Collective
9074 
9075   Input Parameters:
9076 + dm           - `DM` object you wish to monitor
9077 . name         - the monitor type one is seeking
9078 . help         - message indicating what monitoring is done
9079 . manual       - manual page for the monitor
9080 . monitor      - the monitor function, this must use a `PetscViewerFormat` as its context
9081 - 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
9082 
9083   Output Parameter:
9084 . flg - Flag set if the monitor was created
9085 
9086   Level: developer
9087 
9088 .seealso: [](ch_dmbase), `DM`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
9089           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
9090           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
9091           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
9092           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
9093           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
9094           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
9095 @*/
9096 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9097 {
9098   PetscViewer       viewer;
9099   PetscViewerFormat format;
9100 
9101   PetscFunctionBegin;
9102   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9103   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
9104   if (*flg) {
9105     PetscViewerAndFormat *vf;
9106 
9107     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
9108     PetscCall(PetscViewerDestroy(&viewer));
9109     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
9110     PetscCall(DMMonitorSet(dm, monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
9111   }
9112   PetscFunctionReturn(PETSC_SUCCESS);
9113 }
9114 
9115 /*@
9116   DMMonitor - runs the user provided monitor routines, if they exist
9117 
9118   Collective
9119 
9120   Input Parameter:
9121 . dm - The `DM`
9122 
9123   Level: developer
9124 
9125   Developer Note:
9126   Note should indicate when during the life of the `DM` the monitor is run. It appears to be
9127   related to the discretization process seems rather specialized since some `DM` have no
9128   concept of discretization.
9129 
9130 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`
9131 @*/
9132 PetscErrorCode DMMonitor(DM dm)
9133 {
9134   PetscInt m;
9135 
9136   PetscFunctionBegin;
9137   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
9138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9139   for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
9140   PetscFunctionReturn(PETSC_SUCCESS);
9141 }
9142 
9143 /*@
9144   DMComputeError - Computes the error assuming the user has provided the exact solution functions
9145 
9146   Collective
9147 
9148   Input Parameters:
9149 + dm  - The `DM`
9150 - sol - The solution vector
9151 
9152   Input/Output Parameter:
9153 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output
9154            contains the error in each field
9155 
9156   Output Parameter:
9157 . errorVec - A vector to hold the cellwise error (may be `NULL`)
9158 
9159   Level: developer
9160 
9161   Note:
9162   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
9163 
9164 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
9165 @*/
9166 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9167 {
9168   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9169   void    **ctxs;
9170   PetscReal time;
9171   PetscInt  Nf, f, Nds, s;
9172 
9173   PetscFunctionBegin;
9174   PetscCall(DMGetNumFields(dm, &Nf));
9175   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
9176   PetscCall(DMGetNumDS(dm, &Nds));
9177   for (s = 0; s < Nds; ++s) {
9178     PetscDS         ds;
9179     DMLabel         label;
9180     IS              fieldIS;
9181     const PetscInt *fields;
9182     PetscInt        dsNf;
9183 
9184     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
9185     PetscCall(PetscDSGetNumFields(ds, &dsNf));
9186     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
9187     for (f = 0; f < dsNf; ++f) {
9188       const PetscInt field = fields[f];
9189       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
9190     }
9191     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
9192   }
9193   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);
9194   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
9195   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
9196   if (errorVec) {
9197     DM             edm;
9198     DMPolytopeType ct;
9199     PetscBool      simplex;
9200     PetscInt       dim, cStart, Nf;
9201 
9202     PetscCall(DMClone(dm, &edm));
9203     PetscCall(DMGetDimension(edm, &dim));
9204     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
9205     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9206     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
9207     PetscCall(DMGetNumFields(dm, &Nf));
9208     for (f = 0; f < Nf; ++f) {
9209       PetscFE         fe, efe;
9210       PetscQuadrature q;
9211       const char     *name;
9212 
9213       PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
9214       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
9215       PetscCall(PetscObjectGetName((PetscObject)fe, &name));
9216       PetscCall(PetscObjectSetName((PetscObject)efe, name));
9217       PetscCall(PetscFEGetQuadrature(fe, &q));
9218       PetscCall(PetscFESetQuadrature(efe, q));
9219       PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
9220       PetscCall(PetscFEDestroy(&efe));
9221     }
9222     PetscCall(DMCreateDS(edm));
9223 
9224     PetscCall(DMCreateGlobalVector(edm, errorVec));
9225     PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
9226     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
9227     PetscCall(DMDestroy(&edm));
9228   }
9229   PetscCall(PetscFree2(exactSol, ctxs));
9230   PetscFunctionReturn(PETSC_SUCCESS);
9231 }
9232 
9233 /*@
9234   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
9235 
9236   Not Collective
9237 
9238   Input Parameter:
9239 . dm - The `DM`
9240 
9241   Output Parameter:
9242 . numAux - The number of auxiliary data vectors
9243 
9244   Level: advanced
9245 
9246 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`
9247 @*/
9248 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9249 {
9250   PetscFunctionBegin;
9251   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9252   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
9253   PetscFunctionReturn(PETSC_SUCCESS);
9254 }
9255 
9256 /*@
9257   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
9258 
9259   Not Collective
9260 
9261   Input Parameters:
9262 + dm    - The `DM`
9263 . label - The `DMLabel`
9264 . value - The label value indicating the region
9265 - part  - The equation part, or 0 if unused
9266 
9267   Output Parameter:
9268 . aux - The `Vec` holding auxiliary field data
9269 
9270   Level: advanced
9271 
9272   Note:
9273   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
9274 
9275 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
9276 @*/
9277 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
9278 {
9279   PetscHashAuxKey key, wild = {NULL, 0, 0};
9280   PetscBool       has;
9281 
9282   PetscFunctionBegin;
9283   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9284   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9285   key.label = label;
9286   key.value = value;
9287   key.part  = part;
9288   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
9289   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
9290   else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
9291   PetscFunctionReturn(PETSC_SUCCESS);
9292 }
9293 
9294 /*@
9295   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
9296 
9297   Not Collective because auxiliary vectors are not parallel
9298 
9299   Input Parameters:
9300 + dm    - The `DM`
9301 . label - The `DMLabel`
9302 . value - The label value indicating the region
9303 . part  - The equation part, or 0 if unused
9304 - aux   - The `Vec` holding auxiliary field data
9305 
9306   Level: advanced
9307 
9308 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
9309 @*/
9310 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
9311 {
9312   Vec             old;
9313   PetscHashAuxKey key;
9314 
9315   PetscFunctionBegin;
9316   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9317   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9318   key.label = label;
9319   key.value = value;
9320   key.part  = part;
9321   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9322   PetscCall(PetscObjectReference((PetscObject)aux));
9323   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9324   else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9325   PetscCall(VecDestroy(&old));
9326   PetscFunctionReturn(PETSC_SUCCESS);
9327 }
9328 
9329 /*@
9330   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
9331 
9332   Not Collective
9333 
9334   Input Parameter:
9335 . dm - The `DM`
9336 
9337   Output Parameters:
9338 + labels - The `DMLabel`s for each `Vec`
9339 . values - The label values for each `Vec`
9340 - parts  - The equation parts for each `Vec`
9341 
9342   Level: advanced
9343 
9344   Note:
9345   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
9346 
9347 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()`
9348 @*/
9349 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9350 {
9351   PetscHashAuxKey *keys;
9352   PetscInt         n, i, off = 0;
9353 
9354   PetscFunctionBegin;
9355   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9356   PetscAssertPointer(labels, 2);
9357   PetscAssertPointer(values, 3);
9358   PetscAssertPointer(parts, 4);
9359   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9360   PetscCall(PetscMalloc1(n, &keys));
9361   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9362   for (i = 0; i < n; ++i) {
9363     labels[i] = keys[i].label;
9364     values[i] = keys[i].value;
9365     parts[i]  = keys[i].part;
9366   }
9367   PetscCall(PetscFree(keys));
9368   PetscFunctionReturn(PETSC_SUCCESS);
9369 }
9370 
9371 /*@
9372   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
9373 
9374   Not Collective
9375 
9376   Input Parameter:
9377 . dm - The `DM`
9378 
9379   Output Parameter:
9380 . dmNew - The new `DM`, now with the same auxiliary data
9381 
9382   Level: advanced
9383 
9384   Note:
9385   This is a shallow copy of the auxiliary vectors
9386 
9387 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9388 @*/
9389 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9390 {
9391   PetscFunctionBegin;
9392   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9393   PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2);
9394   if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS);
9395   PetscCall(DMClearAuxiliaryVec(dmNew));
9396 
9397   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9398   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9399   {
9400     Vec     *auxData;
9401     PetscInt n, i, off = 0;
9402 
9403     PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n));
9404     PetscCall(PetscMalloc1(n, &auxData));
9405     PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData));
9406     for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i]));
9407     PetscCall(PetscFree(auxData));
9408   }
9409   PetscFunctionReturn(PETSC_SUCCESS);
9410 }
9411 
9412 /*@
9413   DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one
9414 
9415   Not Collective
9416 
9417   Input Parameter:
9418 . dm - The `DM`
9419 
9420   Level: advanced
9421 
9422 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9423 @*/
9424 PetscErrorCode DMClearAuxiliaryVec(DM dm)
9425 {
9426   Vec     *auxData;
9427   PetscInt n, i, off = 0;
9428 
9429   PetscFunctionBegin;
9430   PetscCall(PetscHMapAuxGetSize(dm->auxData, &n));
9431   PetscCall(PetscMalloc1(n, &auxData));
9432   PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData));
9433   for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i]));
9434   PetscCall(PetscFree(auxData));
9435   PetscCall(PetscHMapAuxDestroy(&dm->auxData));
9436   PetscCall(PetscHMapAuxCreate(&dm->auxData));
9437   PetscFunctionReturn(PETSC_SUCCESS);
9438 }
9439 
9440 /*@
9441   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9442 
9443   Not Collective
9444 
9445   Input Parameters:
9446 + ct         - The `DMPolytopeType`
9447 . sourceCone - The source arrangement of faces
9448 - targetCone - The target arrangement of faces
9449 
9450   Output Parameters:
9451 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9452 - found - Flag indicating that a suitable orientation was found
9453 
9454   Level: advanced
9455 
9456   Note:
9457   An arrangement is a face order combined with an orientation for each face
9458 
9459   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9460   that labels each arrangement (face ordering plus orientation for each face).
9461 
9462   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9463 
9464 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9465 @*/
9466 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9467 {
9468   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9469   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9470   PetscInt       o, c;
9471 
9472   PetscFunctionBegin;
9473   if (!nO) {
9474     *ornt  = 0;
9475     *found = PETSC_TRUE;
9476     PetscFunctionReturn(PETSC_SUCCESS);
9477   }
9478   for (o = -nO; o < nO; ++o) {
9479     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
9480 
9481     for (c = 0; c < cS; ++c)
9482       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9483     if (c == cS) {
9484       *ornt = o;
9485       break;
9486     }
9487   }
9488   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9489   PetscFunctionReturn(PETSC_SUCCESS);
9490 }
9491 
9492 /*@
9493   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9494 
9495   Not Collective
9496 
9497   Input Parameters:
9498 + ct         - The `DMPolytopeType`
9499 . sourceCone - The source arrangement of faces
9500 - targetCone - The target arrangement of faces
9501 
9502   Output Parameter:
9503 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9504 
9505   Level: advanced
9506 
9507   Note:
9508   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9509 
9510   Developer Note:
9511   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9512 
9513 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9514 @*/
9515 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9516 {
9517   PetscBool found;
9518 
9519   PetscFunctionBegin;
9520   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9521   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9522   PetscFunctionReturn(PETSC_SUCCESS);
9523 }
9524 
9525 /*@
9526   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9527 
9528   Not Collective
9529 
9530   Input Parameters:
9531 + ct         - The `DMPolytopeType`
9532 . sourceVert - The source arrangement of vertices
9533 - targetVert - The target arrangement of vertices
9534 
9535   Output Parameters:
9536 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9537 - found - Flag indicating that a suitable orientation was found
9538 
9539   Level: advanced
9540 
9541   Notes:
9542   An arrangement is a vertex order
9543 
9544   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9545   that labels each arrangement (vertex ordering).
9546 
9547   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9548 
9549 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()`
9550 @*/
9551 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9552 {
9553   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9554   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9555   PetscInt       o, c;
9556 
9557   PetscFunctionBegin;
9558   if (!nO) {
9559     *ornt  = 0;
9560     *found = PETSC_TRUE;
9561     PetscFunctionReturn(PETSC_SUCCESS);
9562   }
9563   for (o = -nO; o < nO; ++o) {
9564     const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o);
9565 
9566     for (c = 0; c < cS; ++c)
9567       if (sourceVert[arr[c]] != targetVert[c]) break;
9568     if (c == cS) {
9569       *ornt = o;
9570       break;
9571     }
9572   }
9573   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9574   PetscFunctionReturn(PETSC_SUCCESS);
9575 }
9576 
9577 /*@
9578   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9579 
9580   Not Collective
9581 
9582   Input Parameters:
9583 + ct         - The `DMPolytopeType`
9584 . sourceCone - The source arrangement of vertices
9585 - targetCone - The target arrangement of vertices
9586 
9587   Output Parameter:
9588 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9589 
9590   Level: advanced
9591 
9592   Note:
9593   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9594 
9595   Developer Note:
9596   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9597 
9598 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9599 @*/
9600 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9601 {
9602   PetscBool found;
9603 
9604   PetscFunctionBegin;
9605   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9606   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9607   PetscFunctionReturn(PETSC_SUCCESS);
9608 }
9609 
9610 /*@
9611   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9612 
9613   Not Collective
9614 
9615   Input Parameters:
9616 + ct    - The `DMPolytopeType`
9617 - point - Coordinates of the point
9618 
9619   Output Parameter:
9620 . inside - Flag indicating whether the point is inside the reference cell of given type
9621 
9622   Level: advanced
9623 
9624 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()`
9625 @*/
9626 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9627 {
9628   PetscReal sum = 0.0;
9629   PetscInt  d;
9630 
9631   PetscFunctionBegin;
9632   *inside = PETSC_TRUE;
9633   switch (ct) {
9634   case DM_POLYTOPE_TRIANGLE:
9635   case DM_POLYTOPE_TETRAHEDRON:
9636     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9637       if (point[d] < -1.0) {
9638         *inside = PETSC_FALSE;
9639         break;
9640       }
9641       sum += point[d];
9642     }
9643     if (sum > PETSC_SMALL) {
9644       *inside = PETSC_FALSE;
9645       break;
9646     }
9647     break;
9648   case DM_POLYTOPE_QUADRILATERAL:
9649   case DM_POLYTOPE_HEXAHEDRON:
9650     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9651       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9652         *inside = PETSC_FALSE;
9653         break;
9654       }
9655     break;
9656   default:
9657     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9658   }
9659   PetscFunctionReturn(PETSC_SUCCESS);
9660 }
9661 
9662 /*@
9663   DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default
9664 
9665   Logically collective
9666 
9667   Input Parameters:
9668 + dm      - The DM
9669 - reorder - Flag for reordering
9670 
9671   Level: intermediate
9672 
9673 .seealso: `DMReorderSectionGetDefault()`
9674 @*/
9675 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder)
9676 {
9677   PetscFunctionBegin;
9678   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9679   PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder));
9680   PetscFunctionReturn(PETSC_SUCCESS);
9681 }
9682 
9683 /*@
9684   DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default
9685 
9686   Not collective
9687 
9688   Input Parameter:
9689 . dm - The DM
9690 
9691   Output Parameter:
9692 . reorder - Flag for reordering
9693 
9694   Level: intermediate
9695 
9696 .seealso: `DMReorderSetDefault()`
9697 @*/
9698 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder)
9699 {
9700   PetscFunctionBegin;
9701   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9702   PetscAssertPointer(reorder, 2);
9703   *reorder = DM_REORDER_DEFAULT_NOTSET;
9704   PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder));
9705   PetscFunctionReturn(PETSC_SUCCESS);
9706 }
9707 
9708 /*@
9709   DMReorderSectionSetType - Set the type of local section reordering
9710 
9711   Logically collective
9712 
9713   Input Parameters:
9714 + dm      - The DM
9715 - reorder - The reordering method
9716 
9717   Level: intermediate
9718 
9719 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()`
9720 @*/
9721 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder)
9722 {
9723   PetscFunctionBegin;
9724   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9725   PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder));
9726   PetscFunctionReturn(PETSC_SUCCESS);
9727 }
9728 
9729 /*@
9730   DMReorderSectionGetType - Get the reordering type for the local section
9731 
9732   Not collective
9733 
9734   Input Parameter:
9735 . dm - The DM
9736 
9737   Output Parameter:
9738 . reorder - The reordering method
9739 
9740   Level: intermediate
9741 
9742 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()`
9743 @*/
9744 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder)
9745 {
9746   PetscFunctionBegin;
9747   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9748   PetscAssertPointer(reorder, 2);
9749   *reorder = NULL;
9750   PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder));
9751   PetscFunctionReturn(PETSC_SUCCESS);
9752 }
9753