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