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