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