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