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