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