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