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