xref: /petsc/src/dm/interface/dm.c (revision 40750d414264c8a755a615ff0e2cc923e44b4f14)
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         PetscCallMPI(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) PetscCallMPI(MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm)));
4121   if (gmax) PetscCallMPI(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   PetscCallMPI(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   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;
6672       PetscBool      simplex;
6673 
6674       /* Assume linear vertex coordinates */
6675       PetscCall(DMGetDimension(dm, &dim));
6676       PetscCall(DMGetCoordinateDim(dm, &dE));
6677       PetscCall(DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL));
6678       PetscCall(DMPlexGetCellType(dm, cStart, &ct));
6679       switch (ct) {
6680         case DM_POLYTOPE_TRI_PRISM:
6681         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6682           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6683         default: break;
6684       }
6685       simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
6686       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear));
6687       PetscCall(DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear));
6688       PetscCall(PetscFEDestroy(&feLinear));
6689       PetscCall(DMCreateDS(cdmOld));
6690       PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld));
6691     } else {
6692       const char *discname;
6693 
6694       PetscCall(PetscObjectGetType((PetscObject)discOld, &discname));
6695       SETERRQ(PetscObjectComm((PetscObject)discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6696     }
6697   }
6698   if (!disc) PetscFunctionReturn(0);
6699   { // Check if the new space is the same as the old modulo quadrature
6700     PetscDualSpace dsOld, ds;
6701     PetscCall(PetscFEGetDualSpace(discOld, &dsOld));
6702     PetscCall(PetscFEGetDualSpace(disc, &ds));
6703     PetscCall(PetscDualSpaceEqual(dsOld, ds, &same_space));
6704   }
6705   /* Make a fresh clone of the coordinate DM */
6706   PetscCall(DMClone(cdmOld, &cdmNew));
6707   PetscCall(DMSetField(cdmNew, 0, NULL, (PetscObject) disc));
6708   PetscCall(DMCreateDS(cdmNew));
6709   PetscCall(DMGetCoordinates(dm, &coordsOld));
6710   if (same_space) {
6711     PetscCall(PetscObjectReference((PetscObject)coordsOld));
6712     coordsNew = coordsOld;
6713   } else { // Project the coordinate vector from old to new space
6714     PetscCall(DMCreateGlobalVector(cdmNew, &coordsNew));
6715     PetscCall(DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL));
6716     PetscCall(MatInterpolate(matInterp, coordsOld, coordsNew));
6717     PetscCall(MatDestroy(&matInterp));
6718   }
6719   /* Set new coordinate structures */
6720   PetscCall(DMSetCoordinateField(dm, NULL));
6721   PetscCall(DMSetCoordinateDM(dm, cdmNew));
6722   PetscCall(DMSetCoordinates(dm, coordsNew));
6723   PetscCall(VecDestroy(&coordsNew));
6724   PetscCall(DMDestroy(&cdmNew));
6725   PetscFunctionReturn(0);
6726 }
6727 
6728 /*@C
6729   DMGetPeriodicity - Get the description of mesh periodicity
6730 
6731   Input Parameter:
6732 . dm      - The DM object
6733 
6734   Output Parameters:
6735 + per     - Whether the DM is periodic or not
6736 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6737 . L       - If we assume the mesh is a torus, this is the length of each coordinate
6738 - bd      - This describes the type of periodicity in each topological dimension
6739 
6740   Level: developer
6741 
6742 .seealso: DMGetPeriodicity()
6743 @*/
6744 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6745 {
6746   PetscFunctionBegin;
6747   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6748   if (per)     *per     = dm->periodic;
6749   if (L)       *L       = dm->L;
6750   if (maxCell) *maxCell = dm->maxCell;
6751   if (bd)      *bd      = dm->bdtype;
6752   PetscFunctionReturn(0);
6753 }
6754 
6755 /*@C
6756   DMSetPeriodicity - Set the description of mesh periodicity
6757 
6758   Input Parameters:
6759 + dm      - The DM object
6760 . per     - Whether the DM is periodic or not.
6761 . 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.
6762 . L       - If we assume the mesh is a torus, this is the length of each coordinate
6763 - bd      - This describes the type of periodicity in each topological dimension
6764 
6765   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.
6766 
6767   Level: developer
6768 
6769 .seealso: DMGetPeriodicity()
6770 @*/
6771 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6772 {
6773   PetscInt       dim, d;
6774 
6775   PetscFunctionBegin;
6776   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6777   PetscValidLogicalCollectiveBool(dm,per,2);
6778   if (maxCell) {PetscValidRealPointer(maxCell,3);}
6779   if (L)       {PetscValidRealPointer(L,4);}
6780   if (bd)      {PetscValidPointer(bd,5);}
6781   PetscCall(DMGetDimension(dm, &dim));
6782   if (maxCell) {
6783     if (!dm->maxCell) PetscCall(PetscMalloc1(dim, &dm->maxCell));
6784     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6785   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6786     PetscCall(PetscFree(dm->maxCell));
6787   }
6788 
6789   if (L) {
6790     if (!dm->L) PetscCall(PetscMalloc1(dim, &dm->L));
6791     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6792   }
6793   if (bd) {
6794     if (!dm->bdtype) PetscCall(PetscMalloc1(dim, &dm->bdtype));
6795     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6796   }
6797   dm->periodic = per;
6798   PetscFunctionReturn(0);
6799 }
6800 
6801 /*@
6802   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.
6803 
6804   Input Parameters:
6805 + dm     - The DM
6806 . in     - The input coordinate point (dim numbers)
6807 - endpoint - Include the endpoint L_i
6808 
6809   Output Parameter:
6810 . out - The localized coordinate point
6811 
6812   Level: developer
6813 
6814 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6815 @*/
6816 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6817 {
6818   PetscInt       dim, d;
6819 
6820   PetscFunctionBegin;
6821   PetscCall(DMGetCoordinateDim(dm, &dim));
6822   if (!dm->maxCell) {
6823     for (d = 0; d < dim; ++d) out[d] = in[d];
6824   } else {
6825     if (endpoint) {
6826       for (d = 0; d < dim; ++d) {
6827         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)) {
6828           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6829         } else {
6830           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6831         }
6832       }
6833     } else {
6834       for (d = 0; d < dim; ++d) {
6835         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6836       }
6837     }
6838   }
6839   PetscFunctionReturn(0);
6840 }
6841 
6842 /*
6843   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.
6844 
6845   Input Parameters:
6846 + dm     - The DM
6847 . dim    - The spatial dimension
6848 . anchor - The anchor point, the input point can be no more than maxCell away from it
6849 - in     - The input coordinate point (dim numbers)
6850 
6851   Output Parameter:
6852 . out - The localized coordinate point
6853 
6854   Level: developer
6855 
6856   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
6857 
6858 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6859 */
6860 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6861 {
6862   PetscInt d;
6863 
6864   PetscFunctionBegin;
6865   if (!dm->maxCell) {
6866     for (d = 0; d < dim; ++d) out[d] = in[d];
6867   } else {
6868     for (d = 0; d < dim; ++d) {
6869       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6870         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6871       } else {
6872         out[d] = in[d];
6873       }
6874     }
6875   }
6876   PetscFunctionReturn(0);
6877 }
6878 
6879 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6880 {
6881   PetscInt d;
6882 
6883   PetscFunctionBegin;
6884   if (!dm->maxCell) {
6885     for (d = 0; d < dim; ++d) out[d] = in[d];
6886   } else {
6887     for (d = 0; d < dim; ++d) {
6888       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6889         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6890       } else {
6891         out[d] = in[d];
6892       }
6893     }
6894   }
6895   PetscFunctionReturn(0);
6896 }
6897 
6898 /*
6899   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.
6900 
6901   Input Parameters:
6902 + dm     - The DM
6903 . dim    - The spatial dimension
6904 . anchor - The anchor point, the input point can be no more than maxCell away from it
6905 . in     - The input coordinate delta (dim numbers)
6906 - out    - The input coordinate point (dim numbers)
6907 
6908   Output Parameter:
6909 . out    - The localized coordinate in + out
6910 
6911   Level: developer
6912 
6913   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
6914 
6915 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6916 */
6917 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6918 {
6919   PetscInt d;
6920 
6921   PetscFunctionBegin;
6922   if (!dm->maxCell) {
6923     for (d = 0; d < dim; ++d) out[d] += in[d];
6924   } else {
6925     for (d = 0; d < dim; ++d) {
6926       const PetscReal maxC = dm->maxCell[d];
6927 
6928       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6929         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6930 
6931         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6932           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]));
6933         out[d] += newCoord;
6934       } else {
6935         out[d] += in[d];
6936       }
6937     }
6938   }
6939   PetscFunctionReturn(0);
6940 }
6941 
6942 /*@
6943   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6944 
6945   Not collective
6946 
6947   Input Parameter:
6948 . dm - The DM
6949 
6950   Output Parameter:
6951   areLocalized - True if localized
6952 
6953   Level: developer
6954 
6955 .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6956 @*/
6957 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6958 {
6959   DM             cdm;
6960   PetscSection   coordSection;
6961   PetscInt       depth, cStart, cEnd, sStart, sEnd, c, dof;
6962   PetscBool      isPlex, alreadyLocalized;
6963 
6964   PetscFunctionBegin;
6965   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6966   PetscValidBoolPointer(areLocalized, 2);
6967   *areLocalized = PETSC_FALSE;
6968 
6969   /* We need some generic way of refering to cells/vertices */
6970   PetscCall(DMGetCoordinateDM(dm, &cdm));
6971   PetscCall(PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex));
6972   if (!isPlex) PetscFunctionReturn(0);
6973   PetscCall(DMPlexGetDepth(cdm, &depth));
6974   if (!depth) PetscFunctionReturn(0);
6975 
6976   PetscCall(DMGetCoordinateSection(dm, &coordSection));
6977   PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd));
6978   PetscCall(PetscSectionGetChart(coordSection, &sStart, &sEnd));
6979   alreadyLocalized = PETSC_FALSE;
6980   for (c = cStart; c < cEnd; ++c) {
6981     if (c < sStart || c >= sEnd) continue;
6982     PetscCall(PetscSectionGetDof(coordSection, c, &dof));
6983     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6984   }
6985   *areLocalized = alreadyLocalized;
6986   PetscFunctionReturn(0);
6987 }
6988 
6989 /*@
6990   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6991 
6992   Collective on dm
6993 
6994   Input Parameter:
6995 . dm - The DM
6996 
6997   Output Parameter:
6998   areLocalized - True if localized
6999 
7000   Level: developer
7001 
7002 .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
7003 @*/
7004 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
7005 {
7006   PetscBool      localized;
7007 
7008   PetscFunctionBegin;
7009   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7010   PetscValidBoolPointer(areLocalized, 2);
7011   PetscCall(DMGetCoordinatesLocalizedLocal(dm,&localized));
7012   PetscCallMPI(MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm)));
7013   PetscFunctionReturn(0);
7014 }
7015 
7016 /*@
7017   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
7018 
7019   Collective on dm
7020 
7021   Input Parameter:
7022 . dm - The DM
7023 
7024   Level: developer
7025 
7026 .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
7027 @*/
7028 PetscErrorCode DMLocalizeCoordinates(DM dm)
7029 {
7030   DM             cdm;
7031   PetscSection   coordSection, cSection;
7032   Vec            coordinates,  cVec;
7033   PetscScalar   *coords, *coords2, *anchor, *localized;
7034   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
7035   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
7036   PetscInt       maxHeight = 0, h;
7037   PetscInt       *pStart = NULL, *pEnd = NULL;
7038 
7039   PetscFunctionBegin;
7040   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7041   if (!dm->periodic) PetscFunctionReturn(0);
7042   PetscCall(DMGetCoordinatesLocalized(dm, &alreadyLocalized));
7043   if (alreadyLocalized) PetscFunctionReturn(0);
7044 
7045   /* We need some generic way of refering to cells/vertices */
7046   PetscCall(DMGetCoordinateDM(dm, &cdm));
7047   {
7048     PetscBool isplex;
7049 
7050     PetscCall(PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex));
7051     if (isplex) {
7052       PetscCall(DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd));
7053       PetscCall(DMPlexGetMaxProjectionHeight(cdm,&maxHeight));
7054       PetscCall(DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart));
7055       pEnd = &pStart[maxHeight + 1];
7056       newStart = vStart;
7057       newEnd   = vEnd;
7058       for (h = 0; h <= maxHeight; h++) {
7059         PetscCall(DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]));
7060         newStart = PetscMin(newStart,pStart[h]);
7061         newEnd   = PetscMax(newEnd,pEnd[h]);
7062       }
7063     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
7064   }
7065   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
7066   PetscCheck(coordinates,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
7067   PetscCall(DMGetCoordinateSection(dm, &coordSection));
7068   PetscCall(VecGetBlockSize(coordinates, &bs));
7069   PetscCall(PetscSectionGetChart(coordSection,&sStart,&sEnd));
7070 
7071   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection));
7072   PetscCall(PetscSectionSetNumFields(cSection, 1));
7073   PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
7074   PetscCall(PetscSectionSetFieldComponents(cSection, 0, Nc));
7075   PetscCall(PetscSectionSetChart(cSection, newStart, newEnd));
7076 
7077   PetscCall(DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor));
7078   localized = &anchor[bs];
7079   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
7080   for (h = 0; h <= maxHeight; h++) {
7081     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
7082 
7083     for (c = cStart; c < cEnd; ++c) {
7084       PetscScalar *cellCoords = NULL;
7085       PetscInt     b;
7086 
7087       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
7088       PetscCall(DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords));
7089       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7090       for (d = 0; d < dof/bs; ++d) {
7091         PetscCall(DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized));
7092         for (b = 0; b < bs; b++) {
7093           if (cellCoords[d*bs + b] != localized[b]) break;
7094         }
7095         if (b < bs) break;
7096       }
7097       if (d < dof/bs) {
7098         if (c >= sStart && c < sEnd) {
7099           PetscInt cdof;
7100 
7101           PetscCall(PetscSectionGetDof(coordSection, c, &cdof));
7102           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
7103         }
7104         PetscCall(PetscSectionSetDof(cSection, c, dof));
7105         PetscCall(PetscSectionSetFieldDof(cSection, c, 0, dof));
7106       }
7107       PetscCall(DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords));
7108     }
7109   }
7110   PetscCallMPI(MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm)));
7111   if (alreadyLocalizedGlobal) {
7112     PetscCall(DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor));
7113     PetscCall(PetscSectionDestroy(&cSection));
7114     PetscCall(DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart));
7115     PetscFunctionReturn(0);
7116   }
7117   for (v = vStart; v < vEnd; ++v) {
7118     PetscCall(PetscSectionGetDof(coordSection, v, &dof));
7119     PetscCall(PetscSectionSetDof(cSection, v, dof));
7120     PetscCall(PetscSectionSetFieldDof(cSection, v, 0, dof));
7121   }
7122   PetscCall(PetscSectionSetUp(cSection));
7123   PetscCall(PetscSectionGetStorageSize(cSection, &coordSize));
7124   PetscCall(VecCreate(PETSC_COMM_SELF, &cVec));
7125   PetscCall(PetscObjectSetName((PetscObject)cVec,"coordinates"));
7126   PetscCall(VecSetBlockSize(cVec, bs));
7127   PetscCall(VecSetSizes(cVec, coordSize, PETSC_DETERMINE));
7128   PetscCall(VecSetType(cVec, VECSTANDARD));
7129   PetscCall(VecGetArrayRead(coordinates, (const PetscScalar**)&coords));
7130   PetscCall(VecGetArray(cVec, &coords2));
7131   for (v = vStart; v < vEnd; ++v) {
7132     PetscCall(PetscSectionGetDof(coordSection, v, &dof));
7133     PetscCall(PetscSectionGetOffset(coordSection, v, &off));
7134     PetscCall(PetscSectionGetOffset(cSection,     v, &off2));
7135     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
7136   }
7137   for (h = 0; h <= maxHeight; h++) {
7138     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
7139 
7140     for (c = cStart; c < cEnd; ++c) {
7141       PetscScalar *cellCoords = NULL;
7142       PetscInt     b, cdof;
7143 
7144       PetscCall(PetscSectionGetDof(cSection,c,&cdof));
7145       if (!cdof) continue;
7146       PetscCall(DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords));
7147       PetscCall(PetscSectionGetOffset(cSection, c, &off2));
7148       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7149       for (d = 0; d < dof/bs; ++d) PetscCall(DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]));
7150       PetscCall(DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords));
7151     }
7152   }
7153   PetscCall(DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor));
7154   PetscCall(DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart));
7155   PetscCall(VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords));
7156   PetscCall(VecRestoreArray(cVec, &coords2));
7157   PetscCall(DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection));
7158   PetscCall(DMSetCoordinatesLocal(dm, cVec));
7159   PetscCall(VecDestroy(&cVec));
7160   PetscCall(PetscSectionDestroy(&cSection));
7161   PetscFunctionReturn(0);
7162 }
7163 
7164 /*@
7165   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
7166 
7167   Collective on v (see explanation below)
7168 
7169   Input Parameters:
7170 + dm - The DM
7171 - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
7172 
7173   Input/Output Parameters:
7174 + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
7175 - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point;
7176            on output, the PetscSF containing the ranks and local indices of the containing points
7177 
7178   Level: developer
7179 
7180   Notes:
7181   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
7182   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
7183 
7184   If *cellSF is NULL on input, a PetscSF will be created.
7185   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
7186 
7187   An array that maps each point to its containing cell can be obtained with
7188 
7189 $    const PetscSFNode *cells;
7190 $    PetscInt           nFound;
7191 $    const PetscInt    *found;
7192 $
7193 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
7194 
7195   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
7196   the index of the cell in its rank's local numbering.
7197 
7198 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
7199 @*/
7200 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
7201 {
7202   PetscFunctionBegin;
7203   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7204   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
7205   PetscValidPointer(cellSF,4);
7206   if (*cellSF) {
7207     PetscMPIInt result;
7208 
7209     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
7210     PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result));
7211     PetscCheck(result == MPI_IDENT || result == MPI_CONGRUENT,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
7212   } else {
7213     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF));
7214   }
7215   PetscCheck(dm->ops->locatepoints,PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
7216   PetscCall(PetscLogEventBegin(DM_LocatePoints,dm,0,0,0));
7217   PetscCall((*dm->ops->locatepoints)(dm,v,ltype,*cellSF));
7218   PetscCall(PetscLogEventEnd(DM_LocatePoints,dm,0,0,0));
7219   PetscFunctionReturn(0);
7220 }
7221 
7222 /*@
7223   DMGetOutputDM - Retrieve the DM associated with the layout for output
7224 
7225   Collective on dm
7226 
7227   Input Parameter:
7228 . dm - The original DM
7229 
7230   Output Parameter:
7231 . odm - The DM which provides the layout for output
7232 
7233   Level: intermediate
7234 
7235 .seealso: VecView(), DMGetGlobalSection()
7236 @*/
7237 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7238 {
7239   PetscSection   section;
7240   PetscBool      hasConstraints, ghasConstraints;
7241 
7242   PetscFunctionBegin;
7243   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7244   PetscValidPointer(odm,2);
7245   PetscCall(DMGetLocalSection(dm, &section));
7246   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
7247   PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm)));
7248   if (!ghasConstraints) {
7249     *odm = dm;
7250     PetscFunctionReturn(0);
7251   }
7252   if (!dm->dmBC) {
7253     PetscSection newSection, gsection;
7254     PetscSF      sf;
7255 
7256     PetscCall(DMClone(dm, &dm->dmBC));
7257     PetscCall(DMCopyDisc(dm, dm->dmBC));
7258     PetscCall(PetscSectionClone(section, &newSection));
7259     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
7260     PetscCall(PetscSectionDestroy(&newSection));
7261     PetscCall(DMGetPointSF(dm->dmBC, &sf));
7262     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
7263     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
7264     PetscCall(PetscSectionDestroy(&gsection));
7265   }
7266   *odm = dm->dmBC;
7267   PetscFunctionReturn(0);
7268 }
7269 
7270 /*@
7271   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
7272 
7273   Input Parameter:
7274 . dm - The original DM
7275 
7276   Output Parameters:
7277 + num - The output sequence number
7278 - val - The output sequence value
7279 
7280   Level: intermediate
7281 
7282   Note: This is intended for output that should appear in sequence, for instance
7283   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7284 
7285 .seealso: VecView()
7286 @*/
7287 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7288 {
7289   PetscFunctionBegin;
7290   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7291   if (num) {PetscValidIntPointer(num,2); *num = dm->outputSequenceNum;}
7292   if (val) {PetscValidRealPointer(val,3);*val = dm->outputSequenceVal;}
7293   PetscFunctionReturn(0);
7294 }
7295 
7296 /*@
7297   DMSetOutputSequenceNumber - Set the sequence number/value for output
7298 
7299   Input Parameters:
7300 + dm - The original DM
7301 . num - The output sequence number
7302 - val - The output sequence value
7303 
7304   Level: intermediate
7305 
7306   Note: This is intended for output that should appear in sequence, for instance
7307   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7308 
7309 .seealso: VecView()
7310 @*/
7311 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7312 {
7313   PetscFunctionBegin;
7314   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7315   dm->outputSequenceNum = num;
7316   dm->outputSequenceVal = val;
7317   PetscFunctionReturn(0);
7318 }
7319 
7320 /*@C
7321   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
7322 
7323   Input Parameters:
7324 + dm   - The original DM
7325 . name - The sequence name
7326 - num  - The output sequence number
7327 
7328   Output Parameter:
7329 . val  - The output sequence value
7330 
7331   Level: intermediate
7332 
7333   Note: This is intended for output that should appear in sequence, for instance
7334   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7335 
7336 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7337 @*/
7338 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7339 {
7340   PetscBool      ishdf5;
7341 
7342   PetscFunctionBegin;
7343   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7344   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
7345   PetscValidRealPointer(val,5);
7346   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
7347   if (ishdf5) {
7348 #if defined(PETSC_HAVE_HDF5)
7349     PetscScalar value;
7350 
7351     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
7352     *val = PetscRealPart(value);
7353 #endif
7354   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7355   PetscFunctionReturn(0);
7356 }
7357 
7358 /*@
7359   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
7360 
7361   Not collective
7362 
7363   Input Parameter:
7364 . dm - The DM
7365 
7366   Output Parameter:
7367 . useNatural - The flag to build the mapping to a natural order during distribution
7368 
7369   Level: beginner
7370 
7371 .seealso: DMSetUseNatural(), DMCreate()
7372 @*/
7373 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7374 {
7375   PetscFunctionBegin;
7376   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7377   PetscValidBoolPointer(useNatural, 2);
7378   *useNatural = dm->useNatural;
7379   PetscFunctionReturn(0);
7380 }
7381 
7382 /*@
7383   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
7384 
7385   Collective on dm
7386 
7387   Input Parameters:
7388 + dm - The DM
7389 - useNatural - The flag to build the mapping to a natural order during distribution
7390 
7391   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
7392 
7393   Level: beginner
7394 
7395 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7396 @*/
7397 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7398 {
7399   PetscFunctionBegin;
7400   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7401   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
7402   dm->useNatural = useNatural;
7403   PetscFunctionReturn(0);
7404 }
7405 
7406 /*@C
7407   DMCreateLabel - Create a label of the given name if it does not already exist
7408 
7409   Not Collective
7410 
7411   Input Parameters:
7412 + dm   - The DM object
7413 - name - The label name
7414 
7415   Level: intermediate
7416 
7417 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7418 @*/
7419 PetscErrorCode DMCreateLabel(DM dm, const char name[])
7420 {
7421   PetscBool      flg;
7422   DMLabel        label;
7423 
7424   PetscFunctionBegin;
7425   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7426   PetscValidCharPointer(name, 2);
7427   PetscCall(DMHasLabel(dm, name, &flg));
7428   if (!flg) {
7429     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
7430     PetscCall(DMAddLabel(dm, label));
7431     PetscCall(DMLabelDestroy(&label));
7432   }
7433   PetscFunctionReturn(0);
7434 }
7435 
7436 /*@C
7437   DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index.
7438 
7439   Not Collective
7440 
7441   Input Parameters:
7442 + dm   - The DM object
7443 . l    - The index for the label
7444 - name - The label name
7445 
7446   Level: intermediate
7447 
7448 .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7449 @*/
7450 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7451 {
7452   DMLabelLink    orig, prev = NULL;
7453   DMLabel        label;
7454   PetscInt       Nl, m;
7455   PetscBool      flg, match;
7456   const char    *lname;
7457 
7458   PetscFunctionBegin;
7459   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7460   PetscValidCharPointer(name, 3);
7461   PetscCall(DMHasLabel(dm, name, &flg));
7462   if (!flg) {
7463     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
7464     PetscCall(DMAddLabel(dm, label));
7465     PetscCall(DMLabelDestroy(&label));
7466   }
7467   PetscCall(DMGetNumLabels(dm, &Nl));
7468   PetscCheck(l < Nl,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
7469   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7470     PetscCall(PetscObjectGetName((PetscObject) orig->label, &lname));
7471     PetscCall(PetscStrcmp(name, lname, &match));
7472     if (match) break;
7473   }
7474   if (m == l) PetscFunctionReturn(0);
7475   if (!m) dm->labels = orig->next;
7476   else    prev->next = orig->next;
7477   if (!l) {
7478     orig->next = dm->labels;
7479     dm->labels = orig;
7480   } else {
7481     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7482     orig->next = prev->next;
7483     prev->next = orig;
7484   }
7485   PetscFunctionReturn(0);
7486 }
7487 
7488 /*@C
7489   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
7490 
7491   Not Collective
7492 
7493   Input Parameters:
7494 + dm   - The DM object
7495 . name - The label name
7496 - point - The mesh point
7497 
7498   Output Parameter:
7499 . value - The label value for this point, or -1 if the point is not in the label
7500 
7501   Level: beginner
7502 
7503 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7504 @*/
7505 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7506 {
7507   DMLabel        label;
7508 
7509   PetscFunctionBegin;
7510   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7511   PetscValidCharPointer(name, 2);
7512   PetscCall(DMGetLabel(dm, name, &label));
7513   PetscCheck(label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7514   PetscCall(DMLabelGetValue(label, point, value));
7515   PetscFunctionReturn(0);
7516 }
7517 
7518 /*@C
7519   DMSetLabelValue - Add a point to a Sieve Label with given value
7520 
7521   Not Collective
7522 
7523   Input Parameters:
7524 + dm   - The DM object
7525 . name - The label name
7526 . point - The mesh point
7527 - value - The label value for this point
7528 
7529   Output Parameter:
7530 
7531   Level: beginner
7532 
7533 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7534 @*/
7535 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7536 {
7537   DMLabel        label;
7538 
7539   PetscFunctionBegin;
7540   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7541   PetscValidCharPointer(name, 2);
7542   PetscCall(DMGetLabel(dm, name, &label));
7543   if (!label) {
7544     PetscCall(DMCreateLabel(dm, name));
7545     PetscCall(DMGetLabel(dm, name, &label));
7546   }
7547   PetscCall(DMLabelSetValue(label, point, value));
7548   PetscFunctionReturn(0);
7549 }
7550 
7551 /*@C
7552   DMClearLabelValue - Remove a point from a Sieve Label with given value
7553 
7554   Not Collective
7555 
7556   Input Parameters:
7557 + dm   - The DM object
7558 . name - The label name
7559 . point - The mesh point
7560 - value - The label value for this point
7561 
7562   Output Parameter:
7563 
7564   Level: beginner
7565 
7566 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7567 @*/
7568 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7569 {
7570   DMLabel        label;
7571 
7572   PetscFunctionBegin;
7573   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7574   PetscValidCharPointer(name, 2);
7575   PetscCall(DMGetLabel(dm, name, &label));
7576   if (!label) PetscFunctionReturn(0);
7577   PetscCall(DMLabelClearValue(label, point, value));
7578   PetscFunctionReturn(0);
7579 }
7580 
7581 /*@C
7582   DMGetLabelSize - Get the number of different integer ids in a Label
7583 
7584   Not Collective
7585 
7586   Input Parameters:
7587 + dm   - The DM object
7588 - name - The label name
7589 
7590   Output Parameter:
7591 . size - The number of different integer ids, or 0 if the label does not exist
7592 
7593   Level: beginner
7594 
7595 .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7596 @*/
7597 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7598 {
7599   DMLabel        label;
7600 
7601   PetscFunctionBegin;
7602   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7603   PetscValidCharPointer(name, 2);
7604   PetscValidIntPointer(size, 3);
7605   PetscCall(DMGetLabel(dm, name, &label));
7606   *size = 0;
7607   if (!label) PetscFunctionReturn(0);
7608   PetscCall(DMLabelGetNumValues(label, size));
7609   PetscFunctionReturn(0);
7610 }
7611 
7612 /*@C
7613   DMGetLabelIdIS - Get the integer ids in a label
7614 
7615   Not Collective
7616 
7617   Input Parameters:
7618 + mesh - The DM object
7619 - name - The label name
7620 
7621   Output Parameter:
7622 . ids - The integer ids, or NULL if the label does not exist
7623 
7624   Level: beginner
7625 
7626 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7627 @*/
7628 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7629 {
7630   DMLabel        label;
7631 
7632   PetscFunctionBegin;
7633   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7634   PetscValidCharPointer(name, 2);
7635   PetscValidPointer(ids, 3);
7636   PetscCall(DMGetLabel(dm, name, &label));
7637   *ids = NULL;
7638  if (label) {
7639     PetscCall(DMLabelGetValueIS(label, ids));
7640   } else {
7641     /* returning an empty IS */
7642     PetscCall(ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids));
7643   }
7644   PetscFunctionReturn(0);
7645 }
7646 
7647 /*@C
7648   DMGetStratumSize - Get the number of points in a label stratum
7649 
7650   Not Collective
7651 
7652   Input Parameters:
7653 + dm - The DM object
7654 . name - The label name
7655 - value - The stratum value
7656 
7657   Output Parameter:
7658 . size - The stratum size
7659 
7660   Level: beginner
7661 
7662 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7663 @*/
7664 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7665 {
7666   DMLabel        label;
7667 
7668   PetscFunctionBegin;
7669   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7670   PetscValidCharPointer(name, 2);
7671   PetscValidIntPointer(size, 4);
7672   PetscCall(DMGetLabel(dm, name, &label));
7673   *size = 0;
7674   if (!label) PetscFunctionReturn(0);
7675   PetscCall(DMLabelGetStratumSize(label, value, size));
7676   PetscFunctionReturn(0);
7677 }
7678 
7679 /*@C
7680   DMGetStratumIS - Get the points in a label stratum
7681 
7682   Not Collective
7683 
7684   Input Parameters:
7685 + dm - The DM object
7686 . name - The label name
7687 - value - The stratum value
7688 
7689   Output Parameter:
7690 . points - The stratum points, or NULL if the label does not exist or does not have that value
7691 
7692   Level: beginner
7693 
7694 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7695 @*/
7696 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7697 {
7698   DMLabel        label;
7699 
7700   PetscFunctionBegin;
7701   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7702   PetscValidCharPointer(name, 2);
7703   PetscValidPointer(points, 4);
7704   PetscCall(DMGetLabel(dm, name, &label));
7705   *points = NULL;
7706   if (!label) PetscFunctionReturn(0);
7707   PetscCall(DMLabelGetStratumIS(label, value, points));
7708   PetscFunctionReturn(0);
7709 }
7710 
7711 /*@C
7712   DMSetStratumIS - Set the points in a label stratum
7713 
7714   Not Collective
7715 
7716   Input Parameters:
7717 + dm - The DM object
7718 . name - The label name
7719 . value - The stratum value
7720 - points - The stratum points
7721 
7722   Level: beginner
7723 
7724 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7725 @*/
7726 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7727 {
7728   DMLabel        label;
7729 
7730   PetscFunctionBegin;
7731   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7732   PetscValidCharPointer(name, 2);
7733   PetscValidPointer(points, 4);
7734   PetscCall(DMGetLabel(dm, name, &label));
7735   if (!label) PetscFunctionReturn(0);
7736   PetscCall(DMLabelSetStratumIS(label, value, points));
7737   PetscFunctionReturn(0);
7738 }
7739 
7740 /*@C
7741   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
7742 
7743   Not Collective
7744 
7745   Input Parameters:
7746 + dm   - The DM object
7747 . name - The label name
7748 - value - The label value for this point
7749 
7750   Output Parameter:
7751 
7752   Level: beginner
7753 
7754 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7755 @*/
7756 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7757 {
7758   DMLabel        label;
7759 
7760   PetscFunctionBegin;
7761   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7762   PetscValidCharPointer(name, 2);
7763   PetscCall(DMGetLabel(dm, name, &label));
7764   if (!label) PetscFunctionReturn(0);
7765   PetscCall(DMLabelClearStratum(label, value));
7766   PetscFunctionReturn(0);
7767 }
7768 
7769 /*@
7770   DMGetNumLabels - Return the number of labels defined by the mesh
7771 
7772   Not Collective
7773 
7774   Input Parameter:
7775 . dm   - The DM object
7776 
7777   Output Parameter:
7778 . numLabels - the number of Labels
7779 
7780   Level: intermediate
7781 
7782 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7783 @*/
7784 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7785 {
7786   DMLabelLink next = dm->labels;
7787   PetscInt  n    = 0;
7788 
7789   PetscFunctionBegin;
7790   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7791   PetscValidIntPointer(numLabels, 2);
7792   while (next) {++n; next = next->next;}
7793   *numLabels = n;
7794   PetscFunctionReturn(0);
7795 }
7796 
7797 /*@C
7798   DMGetLabelName - Return the name of nth label
7799 
7800   Not Collective
7801 
7802   Input Parameters:
7803 + dm - The DM object
7804 - n  - the label number
7805 
7806   Output Parameter:
7807 . name - the label name
7808 
7809   Level: intermediate
7810 
7811 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7812 @*/
7813 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7814 {
7815   DMLabelLink    next = dm->labels;
7816   PetscInt       l    = 0;
7817 
7818   PetscFunctionBegin;
7819   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7820   PetscValidPointer(name, 3);
7821   while (next) {
7822     if (l == n) {
7823       PetscCall(PetscObjectGetName((PetscObject) next->label, name));
7824       PetscFunctionReturn(0);
7825     }
7826     ++l;
7827     next = next->next;
7828   }
7829   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7830 }
7831 
7832 /*@C
7833   DMHasLabel - Determine whether the mesh has a label of a given name
7834 
7835   Not Collective
7836 
7837   Input Parameters:
7838 + dm   - The DM object
7839 - name - The label name
7840 
7841   Output Parameter:
7842 . hasLabel - PETSC_TRUE if the label is present
7843 
7844   Level: intermediate
7845 
7846 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7847 @*/
7848 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7849 {
7850   DMLabelLink    next = dm->labels;
7851   const char    *lname;
7852 
7853   PetscFunctionBegin;
7854   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7855   PetscValidCharPointer(name, 2);
7856   PetscValidBoolPointer(hasLabel, 3);
7857   *hasLabel = PETSC_FALSE;
7858   while (next) {
7859     PetscCall(PetscObjectGetName((PetscObject) next->label, &lname));
7860     PetscCall(PetscStrcmp(name, lname, hasLabel));
7861     if (*hasLabel) break;
7862     next = next->next;
7863   }
7864   PetscFunctionReturn(0);
7865 }
7866 
7867 /*@C
7868   DMGetLabel - Return the label of a given name, or NULL
7869 
7870   Not Collective
7871 
7872   Input Parameters:
7873 + dm   - The DM object
7874 - name - The label name
7875 
7876   Output Parameter:
7877 . label - The DMLabel, or NULL if the label is absent
7878 
7879   Note: Some of the default labels in a DMPlex will be
7880 $ "depth"       - Holds the depth (co-dimension) of each mesh point
7881 $ "celltype"    - Holds the topological type of each cell
7882 $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7883 $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7884 $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7885 $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7886 
7887   Level: intermediate
7888 
7889 .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7890 @*/
7891 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7892 {
7893   DMLabelLink    next = dm->labels;
7894   PetscBool      hasLabel;
7895   const char    *lname;
7896 
7897   PetscFunctionBegin;
7898   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7899   PetscValidCharPointer(name, 2);
7900   PetscValidPointer(label, 3);
7901   *label = NULL;
7902   while (next) {
7903     PetscCall(PetscObjectGetName((PetscObject) next->label, &lname));
7904     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7905     if (hasLabel) {
7906       *label = next->label;
7907       break;
7908     }
7909     next = next->next;
7910   }
7911   PetscFunctionReturn(0);
7912 }
7913 
7914 /*@C
7915   DMGetLabelByNum - Return the nth label
7916 
7917   Not Collective
7918 
7919   Input Parameters:
7920 + dm - The DM object
7921 - n  - the label number
7922 
7923   Output Parameter:
7924 . label - the label
7925 
7926   Level: intermediate
7927 
7928 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7929 @*/
7930 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7931 {
7932   DMLabelLink next = dm->labels;
7933   PetscInt    l    = 0;
7934 
7935   PetscFunctionBegin;
7936   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7937   PetscValidPointer(label, 3);
7938   while (next) {
7939     if (l == n) {
7940       *label = next->label;
7941       PetscFunctionReturn(0);
7942     }
7943     ++l;
7944     next = next->next;
7945   }
7946   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7947 }
7948 
7949 /*@C
7950   DMAddLabel - Add the label to this mesh
7951 
7952   Not Collective
7953 
7954   Input Parameters:
7955 + dm   - The DM object
7956 - label - The DMLabel
7957 
7958   Level: developer
7959 
7960 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7961 @*/
7962 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7963 {
7964   DMLabelLink    l, *p, tmpLabel;
7965   PetscBool      hasLabel;
7966   const char    *lname;
7967   PetscBool      flg;
7968 
7969   PetscFunctionBegin;
7970   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7971   PetscCall(PetscObjectGetName((PetscObject) label, &lname));
7972   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7973   PetscCheck(!hasLabel,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7974   PetscCall(PetscCalloc1(1, &tmpLabel));
7975   tmpLabel->label  = label;
7976   tmpLabel->output = PETSC_TRUE;
7977   for (p=&dm->labels; (l=*p); p=&l->next) {}
7978   *p = tmpLabel;
7979   PetscCall(PetscObjectReference((PetscObject)label));
7980   PetscCall(PetscStrcmp(lname, "depth", &flg));
7981   if (flg) dm->depthLabel = label;
7982   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7983   if (flg) dm->celltypeLabel = label;
7984   PetscFunctionReturn(0);
7985 }
7986 
7987 /*@C
7988   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7989 
7990   Not Collective
7991 
7992   Input Parameters:
7993 + dm    - The DM object
7994 - label - The DMLabel, having the same name, to substitute
7995 
7996   Note: Some of the default labels in a DMPlex will be
7997 $ "depth"       - Holds the depth (co-dimension) of each mesh point
7998 $ "celltype"    - Holds the topological type of each cell
7999 $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
8000 $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
8001 $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
8002 $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh
8003 
8004   Level: intermediate
8005 
8006 .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
8007 @*/
8008 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
8009 {
8010   DMLabelLink    next = dm->labels;
8011   PetscBool      hasLabel, flg;
8012   const char    *name, *lname;
8013 
8014   PetscFunctionBegin;
8015   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8016   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
8017   PetscCall(PetscObjectGetName((PetscObject) label, &name));
8018   while (next) {
8019     PetscCall(PetscObjectGetName((PetscObject) next->label, &lname));
8020     PetscCall(PetscStrcmp(name, lname, &hasLabel));
8021     if (hasLabel) {
8022       PetscCall(PetscObjectReference((PetscObject) label));
8023       PetscCall(PetscStrcmp(lname, "depth", &flg));
8024       if (flg) dm->depthLabel = label;
8025       PetscCall(PetscStrcmp(lname, "celltype", &flg));
8026       if (flg) dm->celltypeLabel = label;
8027       PetscCall(DMLabelDestroy(&next->label));
8028       next->label = label;
8029       break;
8030     }
8031     next = next->next;
8032   }
8033   PetscFunctionReturn(0);
8034 }
8035 
8036 /*@C
8037   DMRemoveLabel - Remove the label given by name from this mesh
8038 
8039   Not Collective
8040 
8041   Input Parameters:
8042 + dm   - The DM object
8043 - name - The label name
8044 
8045   Output Parameter:
8046 . label - The DMLabel, or NULL if the label is absent
8047 
8048   Level: developer
8049 
8050   Notes:
8051   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
8052   DMLabelDestroy() on the label.
8053 
8054   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
8055   call DMLabelDestroy(). Instead, the label is returned and the user is
8056   responsible of calling DMLabelDestroy() at some point.
8057 
8058 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
8059 @*/
8060 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
8061 {
8062   DMLabelLink    link, *pnext;
8063   PetscBool      hasLabel;
8064   const char    *lname;
8065 
8066   PetscFunctionBegin;
8067   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8068   PetscValidCharPointer(name, 2);
8069   if (label) {
8070     PetscValidPointer(label, 3);
8071     *label = NULL;
8072   }
8073   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8074     PetscCall(PetscObjectGetName((PetscObject) link->label, &lname));
8075     PetscCall(PetscStrcmp(name, lname, &hasLabel));
8076     if (hasLabel) {
8077       *pnext = link->next; /* Remove from list */
8078       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
8079       if (hasLabel) dm->depthLabel = NULL;
8080       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
8081       if (hasLabel) dm->celltypeLabel = NULL;
8082       if (label) *label = link->label;
8083       else       PetscCall(DMLabelDestroy(&link->label));
8084       PetscCall(PetscFree(link));
8085       break;
8086     }
8087   }
8088   PetscFunctionReturn(0);
8089 }
8090 
8091 /*@
8092   DMRemoveLabelBySelf - Remove the label from this mesh
8093 
8094   Not Collective
8095 
8096   Input Parameters:
8097 + dm   - The DM object
8098 . label - The DMLabel to be removed from the DM
8099 - failNotFound - Should it fail if the label is not found in the DM?
8100 
8101   Level: developer
8102 
8103   Notes:
8104   Only exactly the same instance is removed if found, name match is ignored.
8105   If the DM has an exclusive reference to the label, it gets destroyed and
8106   *label nullified.
8107 
8108 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
8109 @*/
8110 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
8111 {
8112   DMLabelLink    link, *pnext;
8113   PetscBool      hasLabel = PETSC_FALSE;
8114 
8115   PetscFunctionBegin;
8116   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8117   PetscValidPointer(label, 2);
8118   if (!*label && !failNotFound) PetscFunctionReturn(0);
8119   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
8120   PetscValidLogicalCollectiveBool(dm,failNotFound,3);
8121   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8122     if (*label == link->label) {
8123       hasLabel = PETSC_TRUE;
8124       *pnext = link->next; /* Remove from list */
8125       if (*label == dm->depthLabel) dm->depthLabel = NULL;
8126       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
8127       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
8128       PetscCall(DMLabelDestroy(&link->label));
8129       PetscCall(PetscFree(link));
8130       break;
8131     }
8132   }
8133   PetscCheck(hasLabel || !failNotFound,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
8134   PetscFunctionReturn(0);
8135 }
8136 
8137 /*@C
8138   DMGetLabelOutput - Get the output flag for a given label
8139 
8140   Not Collective
8141 
8142   Input Parameters:
8143 + dm   - The DM object
8144 - name - The label name
8145 
8146   Output Parameter:
8147 . output - The flag for output
8148 
8149   Level: developer
8150 
8151 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8152 @*/
8153 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
8154 {
8155   DMLabelLink    next = dm->labels;
8156   const char    *lname;
8157 
8158   PetscFunctionBegin;
8159   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8160   PetscValidCharPointer(name, 2);
8161   PetscValidBoolPointer(output, 3);
8162   while (next) {
8163     PetscBool flg;
8164 
8165     PetscCall(PetscObjectGetName((PetscObject) next->label, &lname));
8166     PetscCall(PetscStrcmp(name, lname, &flg));
8167     if (flg) {*output = next->output; PetscFunctionReturn(0);}
8168     next = next->next;
8169   }
8170   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8171 }
8172 
8173 /*@C
8174   DMSetLabelOutput - Set the output flag for a given label
8175 
8176   Not Collective
8177 
8178   Input Parameters:
8179 + dm     - The DM object
8180 . name   - The label name
8181 - output - The flag for output
8182 
8183   Level: developer
8184 
8185 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8186 @*/
8187 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
8188 {
8189   DMLabelLink    next = dm->labels;
8190   const char    *lname;
8191 
8192   PetscFunctionBegin;
8193   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8194   PetscValidCharPointer(name, 2);
8195   while (next) {
8196     PetscBool flg;
8197 
8198     PetscCall(PetscObjectGetName((PetscObject) next->label, &lname));
8199     PetscCall(PetscStrcmp(name, lname, &flg));
8200     if (flg) {next->output = output; PetscFunctionReturn(0);}
8201     next = next->next;
8202   }
8203   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8204 }
8205 
8206 /*@
8207   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
8208 
8209   Collective on dmA
8210 
8211   Input Parameters:
8212 + dmA - The DM object with initial labels
8213 . dmB - The DM object to which labels are copied
8214 . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
8215 . all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
8216 - emode - How to behave when a DMLabel in the source and destination DMs with the same name is encountered (see DMCopyLabelsMode)
8217 
8218   Level: intermediate
8219 
8220   Notes:
8221   This is typically used when interpolating or otherwise adding to a mesh, or testing.
8222 
8223 .seealso: DMAddLabel(), DMCopyLabelsMode
8224 @*/
8225 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
8226 {
8227   DMLabel        label, labelNew, labelOld;
8228   const char    *name;
8229   PetscBool      flg;
8230   DMLabelLink    link;
8231 
8232   PetscFunctionBegin;
8233   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
8234   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
8235   PetscValidLogicalCollectiveEnum(dmA, mode,3);
8236   PetscValidLogicalCollectiveBool(dmA, all, 4);
8237   PetscCheck(mode != PETSC_USE_POINTER,PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
8238   if (dmA == dmB) PetscFunctionReturn(0);
8239   for (link=dmA->labels; link; link=link->next) {
8240     label=link->label;
8241     PetscCall(PetscObjectGetName((PetscObject)label, &name));
8242     if (!all) {
8243       PetscCall(PetscStrcmp(name, "depth", &flg));
8244       if (flg) continue;
8245       PetscCall(PetscStrcmp(name, "dim", &flg));
8246       if (flg) continue;
8247       PetscCall(PetscStrcmp(name, "celltype", &flg));
8248       if (flg) continue;
8249     }
8250     PetscCall(DMGetLabel(dmB, name, &labelOld));
8251     if (labelOld) {
8252       switch (emode) {
8253         case DM_COPY_LABELS_KEEP:
8254           continue;
8255         case DM_COPY_LABELS_REPLACE:
8256           PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
8257           break;
8258         case DM_COPY_LABELS_FAIL:
8259           SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
8260         default:
8261           SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
8262       }
8263     }
8264     if (mode==PETSC_COPY_VALUES) {
8265       PetscCall(DMLabelDuplicate(label, &labelNew));
8266     } else {
8267       labelNew = label;
8268     }
8269     PetscCall(DMAddLabel(dmB, labelNew));
8270     if (mode==PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
8271   }
8272   PetscFunctionReturn(0);
8273 }
8274 
8275 /*@C
8276   DMCompareLabels - Compare labels of two DMPlex meshes
8277 
8278   Collective
8279 
8280   Input Parameters:
8281 + dm0 - First DM object
8282 - dm1 - Second DM object
8283 
8284   Output Parameters
8285 + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
8286 - message - (Optional) Message describing the difference, or NULL if there is no difference
8287 
8288   Level: intermediate
8289 
8290   Notes:
8291   The output flag equal is the same on all processes.
8292   If it is passed as NULL and difference is found, an error is thrown on all processes.
8293   Make sure to pass NULL on all processes.
8294 
8295   The output message is set independently on each rank.
8296   It is set to NULL if no difference was found on the current rank. It must be freed by user.
8297   If message is passed as NULL and difference is found, the difference description is printed to stderr in synchronized manner.
8298   Make sure to pass NULL on all processes.
8299 
8300   Labels are matched by name. If the number of labels and their names are equal,
8301   DMLabelCompare() is used to compare each pair of labels with the same name.
8302 
8303   Fortran Notes:
8304   This function is currently not available from Fortran.
8305 
8306 .seealso: DMAddLabel(), DMCopyLabelsMode, DMLabelCompare()
8307 @*/
8308 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
8309 {
8310   PetscInt        n, i;
8311   char            msg[PETSC_MAX_PATH_LEN] = "";
8312   PetscBool       eq;
8313   MPI_Comm        comm;
8314   PetscMPIInt     rank;
8315 
8316   PetscFunctionBegin;
8317   PetscValidHeaderSpecific(dm0,DM_CLASSID,1);
8318   PetscValidHeaderSpecific(dm1,DM_CLASSID,2);
8319   PetscCheckSameComm(dm0,1,dm1,2);
8320   if (equal) PetscValidBoolPointer(equal,3);
8321   if (message) PetscValidPointer(message, 4);
8322   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
8323   PetscCallMPI(MPI_Comm_rank(comm, &rank));
8324   {
8325     PetscInt n1;
8326 
8327     PetscCall(DMGetNumLabels(dm0, &n));
8328     PetscCall(DMGetNumLabels(dm1, &n1));
8329     eq = (PetscBool) (n == n1);
8330     if (!eq) {
8331       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %D != %D = Number of labels in dm1", n, n1));
8332     }
8333     PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
8334     if (!eq) goto finish;
8335   }
8336   for (i=0; i<n; i++) {
8337     DMLabel     l0, l1;
8338     const char *name;
8339     char       *msgInner;
8340 
8341     /* Ignore label order */
8342     PetscCall(DMGetLabelByNum(dm0, i, &l0));
8343     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
8344     PetscCall(DMGetLabel(dm1, name, &l1));
8345     if (!l1) {
8346       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%D in dm0) not found in dm1", name, i));
8347       eq = PETSC_FALSE;
8348       break;
8349     }
8350     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
8351     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
8352     PetscCall(PetscFree(msgInner));
8353     if (!eq) break;
8354   }
8355   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
8356 finish:
8357   /* If message output arg not set, print to stderr */
8358   if (message) {
8359     *message = NULL;
8360     if (msg[0]) {
8361       PetscCall(PetscStrallocpy(msg, message));
8362     }
8363   } else {
8364     if (msg[0]) {
8365       PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
8366     }
8367     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
8368   }
8369   /* If same output arg not ser and labels are not equal, throw error */
8370   if (equal) *equal = eq;
8371   else PetscCheck(eq,comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
8372   PetscFunctionReturn(0);
8373 }
8374 
8375 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
8376 {
8377   PetscFunctionBegin;
8378   PetscValidPointer(label,2);
8379   if (!*label) {
8380     PetscCall(DMCreateLabel(dm, name));
8381     PetscCall(DMGetLabel(dm, name, label));
8382   }
8383   PetscCall(DMLabelSetValue(*label, point, value));
8384   PetscFunctionReturn(0);
8385 }
8386 
8387 /*
8388   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
8389   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
8390   (label, id) pair in the DM.
8391 
8392   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8393   each label.
8394 */
8395 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8396 {
8397   DMUniversalLabel ul;
8398   PetscBool       *active;
8399   PetscInt         pStart, pEnd, p, Nl, l, m;
8400 
8401   PetscFunctionBegin;
8402   PetscCall(PetscMalloc1(1, &ul));
8403   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
8404   PetscCall(DMGetNumLabels(dm, &Nl));
8405   PetscCall(PetscCalloc1(Nl, &active));
8406   ul->Nl = 0;
8407   for (l = 0; l < Nl; ++l) {
8408     PetscBool   isdepth, iscelltype;
8409     const char *name;
8410 
8411     PetscCall(DMGetLabelName(dm, l, &name));
8412     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
8413     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
8414     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8415     if (active[l]) ++ul->Nl;
8416   }
8417   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks));
8418   ul->Nv = 0;
8419   for (l = 0, m = 0; l < Nl; ++l) {
8420     DMLabel     label;
8421     PetscInt    nv;
8422     const char *name;
8423 
8424     if (!active[l]) continue;
8425     PetscCall(DMGetLabelName(dm, l, &name));
8426     PetscCall(DMGetLabelByNum(dm, l, &label));
8427     PetscCall(DMLabelGetNumValues(label, &nv));
8428     PetscCall(PetscStrallocpy(name, &ul->names[m]));
8429     ul->indices[m]   = l;
8430     ul->Nv          += nv;
8431     ul->offsets[m+1] = nv;
8432     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
8433     ++m;
8434   }
8435   for (l = 1; l <= ul->Nl; ++l) {
8436     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8437     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
8438   }
8439   for (l = 0; l < ul->Nl; ++l) {
8440     PetscInt b;
8441 
8442     ul->masks[l] = 0;
8443     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8444   }
8445   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
8446   for (l = 0, m = 0; l < Nl; ++l) {
8447     DMLabel         label;
8448     IS              valueIS;
8449     const PetscInt *varr;
8450     PetscInt        nv, v;
8451 
8452     if (!active[l]) continue;
8453     PetscCall(DMGetLabelByNum(dm, l, &label));
8454     PetscCall(DMLabelGetNumValues(label, &nv));
8455     PetscCall(DMLabelGetValueIS(label, &valueIS));
8456     PetscCall(ISGetIndices(valueIS, &varr));
8457     for (v = 0; v < nv; ++v) {
8458       ul->values[ul->offsets[m]+v] = varr[v];
8459     }
8460     PetscCall(ISRestoreIndices(valueIS, &varr));
8461     PetscCall(ISDestroy(&valueIS));
8462     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
8463     ++m;
8464   }
8465   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8466   for (p = pStart; p < pEnd; ++p) {
8467     PetscInt  uval = 0;
8468     PetscBool marked = PETSC_FALSE;
8469 
8470     for (l = 0, m = 0; l < Nl; ++l) {
8471       DMLabel  label;
8472       PetscInt val, defval, loc, nv;
8473 
8474       if (!active[l]) continue;
8475       PetscCall(DMGetLabelByNum(dm, l, &label));
8476       PetscCall(DMLabelGetValue(label, p, &val));
8477       PetscCall(DMLabelGetDefaultValue(label, &defval));
8478       if (val == defval) {++m; continue;}
8479       nv = ul->offsets[m+1]-ul->offsets[m];
8480       marked = PETSC_TRUE;
8481       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
8482       PetscCheck(loc >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
8483       uval += (loc+1) << ul->bits[m];
8484       ++m;
8485     }
8486     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
8487   }
8488   PetscCall(PetscFree(active));
8489   *universal = ul;
8490   PetscFunctionReturn(0);
8491 }
8492 
8493 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8494 {
8495   PetscInt       l;
8496 
8497   PetscFunctionBegin;
8498   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
8499   PetscCall(DMLabelDestroy(&(*universal)->label));
8500   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
8501   PetscCall(PetscFree((*universal)->values));
8502   PetscCall(PetscFree(*universal));
8503   *universal = NULL;
8504   PetscFunctionReturn(0);
8505 }
8506 
8507 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8508 {
8509   PetscFunctionBegin;
8510   PetscValidPointer(ulabel, 2);
8511   *ulabel = ul->label;
8512   PetscFunctionReturn(0);
8513 }
8514 
8515 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8516 {
8517   PetscInt       Nl = ul->Nl, l;
8518 
8519   PetscFunctionBegin;
8520   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
8521   for (l = 0; l < Nl; ++l) {
8522     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
8523     else               PetscCall(DMCreateLabel(dm, ul->names[l]));
8524   }
8525   if (preserveOrder) {
8526     for (l = 0; l < ul->Nl; ++l) {
8527       const char *name;
8528       PetscBool   match;
8529 
8530       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
8531       PetscCall(PetscStrcmp(name, ul->names[l], &match));
8532       PetscCheck(match,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %D name %s does not match new name %s", l, name, ul->names[l]);
8533     }
8534   }
8535   PetscFunctionReturn(0);
8536 }
8537 
8538 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8539 {
8540   PetscInt       l;
8541 
8542   PetscFunctionBegin;
8543   for (l = 0; l < ul->Nl; ++l) {
8544     DMLabel  label;
8545     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
8546 
8547     if (lval) {
8548       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
8549       else          PetscCall(DMGetLabel(dm, ul->names[l], &label));
8550       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]));
8551     }
8552   }
8553   PetscFunctionReturn(0);
8554 }
8555 
8556 /*@
8557   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
8558 
8559   Input Parameter:
8560 . dm - The DM object
8561 
8562   Output Parameter:
8563 . cdm - The coarse DM
8564 
8565   Level: intermediate
8566 
8567 .seealso: DMSetCoarseDM()
8568 @*/
8569 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8570 {
8571   PetscFunctionBegin;
8572   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8573   PetscValidPointer(cdm, 2);
8574   *cdm = dm->coarseMesh;
8575   PetscFunctionReturn(0);
8576 }
8577 
8578 /*@
8579   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
8580 
8581   Input Parameters:
8582 + dm - The DM object
8583 - cdm - The coarse DM
8584 
8585   Level: intermediate
8586 
8587 .seealso: DMGetCoarseDM()
8588 @*/
8589 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8590 {
8591   PetscFunctionBegin;
8592   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8593   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
8594   PetscCall(PetscObjectReference((PetscObject)cdm));
8595   PetscCall(DMDestroy(&dm->coarseMesh));
8596   dm->coarseMesh = cdm;
8597   PetscFunctionReturn(0);
8598 }
8599 
8600 /*@
8601   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
8602 
8603   Input Parameter:
8604 . dm - The DM object
8605 
8606   Output Parameter:
8607 . fdm - The fine DM
8608 
8609   Level: intermediate
8610 
8611 .seealso: DMSetFineDM()
8612 @*/
8613 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8614 {
8615   PetscFunctionBegin;
8616   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8617   PetscValidPointer(fdm, 2);
8618   *fdm = dm->fineMesh;
8619   PetscFunctionReturn(0);
8620 }
8621 
8622 /*@
8623   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
8624 
8625   Input Parameters:
8626 + dm - The DM object
8627 - fdm - The fine DM
8628 
8629   Level: intermediate
8630 
8631 .seealso: DMGetFineDM()
8632 @*/
8633 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8634 {
8635   PetscFunctionBegin;
8636   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8637   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
8638   PetscCall(PetscObjectReference((PetscObject)fdm));
8639   PetscCall(DMDestroy(&dm->fineMesh));
8640   dm->fineMesh = fdm;
8641   PetscFunctionReturn(0);
8642 }
8643 
8644 /*=== DMBoundary code ===*/
8645 
8646 /*@C
8647   DMAddBoundary - Add a boundary condition to the model
8648 
8649   Collective on dm
8650 
8651   Input Parameters:
8652 + dm       - The DM, with a PetscDS that matches the problem being constrained
8653 . type     - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8654 . name     - The BC name
8655 . label    - The label defining constrained points
8656 . Nv       - The number of DMLabel values for constrained points
8657 . values   - An array of values for constrained points
8658 . field    - The field to constrain
8659 . Nc       - The number of constrained field components (0 will constrain all fields)
8660 . comps    - An array of constrained component numbers
8661 . bcFunc   - A pointwise function giving boundary values
8662 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8663 - ctx      - An optional user context for bcFunc
8664 
8665   Output Parameter:
8666 . bd          - (Optional) Boundary number
8667 
8668   Options Database Keys:
8669 + -bc_<boundary name> <num> - Overrides the boundary ids
8670 - -bc_<boundary name>_comp <num> - Overrides the boundary components
8671 
8672   Note:
8673   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:
8674 
8675 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8676 
8677   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:
8678 
8679 $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8680 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8681 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8682 $        PetscReal time, const PetscReal x[], PetscScalar bcval[])
8683 
8684 + dim - the spatial dimension
8685 . Nf - the number of fields
8686 . uOff - the offset into u[] and u_t[] for each field
8687 . uOff_x - the offset into u_x[] for each field
8688 . u - each field evaluated at the current point
8689 . u_t - the time derivative of each field evaluated at the current point
8690 . u_x - the gradient of each field evaluated at the current point
8691 . aOff - the offset into a[] and a_t[] for each auxiliary field
8692 . aOff_x - the offset into a_x[] for each auxiliary field
8693 . a - each auxiliary field evaluated at the current point
8694 . a_t - the time derivative of each auxiliary field evaluated at the current point
8695 . a_x - the gradient of auxiliary each field evaluated at the current point
8696 . t - current time
8697 . x - coordinates of the current point
8698 . numConstants - number of constant parameters
8699 . constants - constant parameters
8700 - bcval - output values at the current point
8701 
8702   Level: intermediate
8703 
8704 .seealso: DSGetBoundary(), PetscDSAddBoundary()
8705 @*/
8706 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)
8707 {
8708   PetscDS        ds;
8709 
8710   PetscFunctionBegin;
8711   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8712   PetscValidLogicalCollectiveEnum(dm, type, 2);
8713   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
8714   PetscValidLogicalCollectiveInt(dm, Nv, 5);
8715   PetscValidLogicalCollectiveInt(dm, field, 7);
8716   PetscValidLogicalCollectiveInt(dm, Nc, 8);
8717   PetscCall(DMGetDS(dm, &ds));
8718   PetscCall(DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label));
8719   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
8720   PetscFunctionReturn(0);
8721 }
8722 
8723 /* TODO Remove this since now the structures are the same */
8724 static PetscErrorCode DMPopulateBoundary(DM dm)
8725 {
8726   PetscDS        ds;
8727   DMBoundary    *lastnext;
8728   DSBoundary     dsbound;
8729 
8730   PetscFunctionBegin;
8731   PetscCall(DMGetDS(dm, &ds));
8732   dsbound = ds->boundary;
8733   if (dm->boundary) {
8734     DMBoundary next = dm->boundary;
8735 
8736     /* quick check to see if the PetscDS has changed */
8737     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
8738     /* the PetscDS has changed: tear down and rebuild */
8739     while (next) {
8740       DMBoundary b = next;
8741 
8742       next = b->next;
8743       PetscCall(PetscFree(b));
8744     }
8745     dm->boundary = NULL;
8746   }
8747 
8748   lastnext = &(dm->boundary);
8749   while (dsbound) {
8750     DMBoundary dmbound;
8751 
8752     PetscCall(PetscNew(&dmbound));
8753     dmbound->dsboundary = dsbound;
8754     dmbound->label      = dsbound->label;
8755     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8756     *lastnext = dmbound;
8757     lastnext = &(dmbound->next);
8758     dsbound = dsbound->next;
8759   }
8760   PetscFunctionReturn(0);
8761 }
8762 
8763 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8764 {
8765   DMBoundary     b;
8766 
8767   PetscFunctionBegin;
8768   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8769   PetscValidBoolPointer(isBd, 3);
8770   *isBd = PETSC_FALSE;
8771   PetscCall(DMPopulateBoundary(dm));
8772   b = dm->boundary;
8773   while (b && !(*isBd)) {
8774     DMLabel    label = b->label;
8775     DSBoundary dsb   = b->dsboundary;
8776     PetscInt   i;
8777 
8778     if (label) {
8779       for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
8780     }
8781     b = b->next;
8782   }
8783   PetscFunctionReturn(0);
8784 }
8785 
8786 /*@C
8787   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
8788 
8789   Collective on DM
8790 
8791   Input Parameters:
8792 + dm      - The DM
8793 . time    - The time
8794 . funcs   - The coordinate functions to evaluate, one per field
8795 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8796 - mode    - The insertion mode for values
8797 
8798   Output Parameter:
8799 . X - vector
8800 
8801    Calling sequence of func:
8802 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8803 
8804 +  dim - The spatial dimension
8805 .  time - The time at which to sample
8806 .  x   - The coordinates
8807 .  Nc  - The number of components
8808 .  u   - The output field values
8809 -  ctx - optional user-defined function context
8810 
8811   Level: developer
8812 
8813 .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8814 @*/
8815 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8816 {
8817   Vec            localX;
8818 
8819   PetscFunctionBegin;
8820   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8821   PetscCall(DMGetLocalVector(dm, &localX));
8822   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
8823   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8824   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8825   PetscCall(DMRestoreLocalVector(dm, &localX));
8826   PetscFunctionReturn(0);
8827 }
8828 
8829 /*@C
8830   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
8831 
8832   Not collective
8833 
8834   Input Parameters:
8835 + dm      - The DM
8836 . time    - The time
8837 . funcs   - The coordinate functions to evaluate, one per field
8838 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8839 - mode    - The insertion mode for values
8840 
8841   Output Parameter:
8842 . localX - vector
8843 
8844    Calling sequence of func:
8845 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8846 
8847 +  dim - The spatial dimension
8848 .  x   - The coordinates
8849 .  Nc  - The number of components
8850 .  u   - The output field values
8851 -  ctx - optional user-defined function context
8852 
8853   Level: developer
8854 
8855 .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8856 @*/
8857 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8858 {
8859   PetscFunctionBegin;
8860   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8861   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
8862   PetscCheck(dm->ops->projectfunctionlocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8863   PetscCall((dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX));
8864   PetscFunctionReturn(0);
8865 }
8866 
8867 /*@C
8868   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.
8869 
8870   Collective on DM
8871 
8872   Input Parameters:
8873 + dm      - The DM
8874 . time    - The time
8875 . label   - The DMLabel selecting the portion of the mesh for projection
8876 . funcs   - The coordinate functions to evaluate, one per field
8877 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8878 - mode    - The insertion mode for values
8879 
8880   Output Parameter:
8881 . X - vector
8882 
8883    Calling sequence of func:
8884 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8885 
8886 +  dim - The spatial dimension
8887 .  x   - The coordinates
8888 .  Nc  - The number of components
8889 .  u   - The output field values
8890 -  ctx - optional user-defined function context
8891 
8892   Level: developer
8893 
8894 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8895 @*/
8896 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)
8897 {
8898   Vec            localX;
8899 
8900   PetscFunctionBegin;
8901   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8902   PetscCall(DMGetLocalVector(dm, &localX));
8903   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8904   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8905   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8906   PetscCall(DMRestoreLocalVector(dm, &localX));
8907   PetscFunctionReturn(0);
8908 }
8909 
8910 /*@C
8911   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.
8912 
8913   Not collective
8914 
8915   Input Parameters:
8916 + dm      - The DM
8917 . time    - The time
8918 . label   - The DMLabel selecting the portion of the mesh for projection
8919 . funcs   - The coordinate functions to evaluate, one per field
8920 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8921 - mode    - The insertion mode for values
8922 
8923   Output Parameter:
8924 . localX - vector
8925 
8926    Calling sequence of func:
8927 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8928 
8929 +  dim - The spatial dimension
8930 .  x   - The coordinates
8931 .  Nc  - The number of components
8932 .  u   - The output field values
8933 -  ctx - optional user-defined function context
8934 
8935   Level: developer
8936 
8937 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8938 @*/
8939 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)
8940 {
8941   PetscFunctionBegin;
8942   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8943   PetscValidHeaderSpecific(localX,VEC_CLASSID,11);
8944   PetscCheck(dm->ops->projectfunctionlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8945   PetscCall((dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8946   PetscFunctionReturn(0);
8947 }
8948 
8949 /*@C
8950   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
8951 
8952   Not collective
8953 
8954   Input Parameters:
8955 + dm      - The DM
8956 . time    - The time
8957 . localU  - The input field vector
8958 . funcs   - The functions to evaluate, one per field
8959 - mode    - The insertion mode for values
8960 
8961   Output Parameter:
8962 . localX  - The output vector
8963 
8964    Calling sequence of func:
8965 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8966 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8967 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8968 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8969 
8970 +  dim          - The spatial dimension
8971 .  Nf           - The number of input fields
8972 .  NfAux        - The number of input auxiliary fields
8973 .  uOff         - The offset of each field in u[]
8974 .  uOff_x       - The offset of each field in u_x[]
8975 .  u            - The field values at this point in space
8976 .  u_t          - The field time derivative at this point in space (or NULL)
8977 .  u_x          - The field derivatives at this point in space
8978 .  aOff         - The offset of each auxiliary field in u[]
8979 .  aOff_x       - The offset of each auxiliary field in u_x[]
8980 .  a            - The auxiliary field values at this point in space
8981 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8982 .  a_x          - The auxiliary field derivatives at this point in space
8983 .  t            - The current time
8984 .  x            - The coordinates of this point
8985 .  numConstants - The number of constants
8986 .  constants    - The value of each constant
8987 -  f            - The value of the function at this point in space
8988 
8989   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.
8990   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
8991   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8992   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8993 
8994   Level: intermediate
8995 
8996 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8997 @*/
8998 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8999                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
9000                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9001                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9002                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
9003                                    InsertMode mode, Vec localX)
9004 {
9005   PetscFunctionBegin;
9006   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9007   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
9008   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
9009   PetscCheck(dm->ops->projectfieldlocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
9010   PetscCall((dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX));
9011   PetscFunctionReturn(0);
9012 }
9013 
9014 /*@C
9015   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.
9016 
9017   Not collective
9018 
9019   Input Parameters:
9020 + dm      - The DM
9021 . time    - The time
9022 . label   - The DMLabel marking the portion of the domain to output
9023 . numIds  - The number of label ids to use
9024 . ids     - The label ids to use for marking
9025 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
9026 . comps   - The components to set in the output, or NULL for all components
9027 . localU  - The input field vector
9028 . funcs   - The functions to evaluate, one per field
9029 - mode    - The insertion mode for values
9030 
9031   Output Parameter:
9032 . localX  - The output vector
9033 
9034    Calling sequence of func:
9035 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
9036 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9037 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
9038 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
9039 
9040 +  dim          - The spatial dimension
9041 .  Nf           - The number of input fields
9042 .  NfAux        - The number of input auxiliary fields
9043 .  uOff         - The offset of each field in u[]
9044 .  uOff_x       - The offset of each field in u_x[]
9045 .  u            - The field values at this point in space
9046 .  u_t          - The field time derivative at this point in space (or NULL)
9047 .  u_x          - The field derivatives at this point in space
9048 .  aOff         - The offset of each auxiliary field in u[]
9049 .  aOff_x       - The offset of each auxiliary field in u_x[]
9050 .  a            - The auxiliary field values at this point in space
9051 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
9052 .  a_x          - The auxiliary field derivatives at this point in space
9053 .  t            - The current time
9054 .  x            - The coordinates of this point
9055 .  numConstants - The number of constants
9056 .  constants    - The value of each constant
9057 -  f            - The value of the function at this point in space
9058 
9059   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.
9060   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
9061   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
9062   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
9063 
9064   Level: intermediate
9065 
9066 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
9067 @*/
9068 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
9069                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
9070                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9071                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9072                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
9073                                         InsertMode mode, Vec localX)
9074 {
9075   PetscFunctionBegin;
9076   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9077   PetscValidHeaderSpecific(localU,VEC_CLASSID,8);
9078   PetscValidHeaderSpecific(localX,VEC_CLASSID,11);
9079   PetscCheck(dm->ops->projectfieldlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
9080   PetscCall((dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
9081   PetscFunctionReturn(0);
9082 }
9083 
9084 /*@C
9085   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.
9086 
9087   Not collective
9088 
9089   Input Parameters:
9090 + dm      - The DM
9091 . time    - The time
9092 . label   - The DMLabel marking the portion of the domain boundary to output
9093 . numIds  - The number of label ids to use
9094 . ids     - The label ids to use for marking
9095 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
9096 . comps   - The components to set in the output, or NULL for all components
9097 . localU  - The input field vector
9098 . funcs   - The functions to evaluate, one per field
9099 - mode    - The insertion mode for values
9100 
9101   Output Parameter:
9102 . localX  - The output vector
9103 
9104    Calling sequence of func:
9105 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
9106 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9107 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
9108 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
9109 
9110 +  dim          - The spatial dimension
9111 .  Nf           - The number of input fields
9112 .  NfAux        - The number of input auxiliary fields
9113 .  uOff         - The offset of each field in u[]
9114 .  uOff_x       - The offset of each field in u_x[]
9115 .  u            - The field values at this point in space
9116 .  u_t          - The field time derivative at this point in space (or NULL)
9117 .  u_x          - The field derivatives at this point in space
9118 .  aOff         - The offset of each auxiliary field in u[]
9119 .  aOff_x       - The offset of each auxiliary field in u_x[]
9120 .  a            - The auxiliary field values at this point in space
9121 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
9122 .  a_x          - The auxiliary field derivatives at this point in space
9123 .  t            - The current time
9124 .  x            - The coordinates of this point
9125 .  n            - The face normal
9126 .  numConstants - The number of constants
9127 .  constants    - The value of each constant
9128 -  f            - The value of the function at this point in space
9129 
9130   Note:
9131   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
9132   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
9133   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
9134   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
9135 
9136   Level: intermediate
9137 
9138 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
9139 @*/
9140 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
9141                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
9142                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9143                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9144                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
9145                                           InsertMode mode, Vec localX)
9146 {
9147   PetscFunctionBegin;
9148   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9149   PetscValidHeaderSpecific(localU,VEC_CLASSID,8);
9150   PetscValidHeaderSpecific(localX,VEC_CLASSID,11);
9151   PetscCheck(dm->ops->projectbdfieldlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
9152   PetscCall((dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
9153   PetscFunctionReturn(0);
9154 }
9155 
9156 /*@C
9157   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9158 
9159   Input Parameters:
9160 + dm    - The DM
9161 . time  - The time
9162 . funcs - The functions to evaluate for each field component
9163 . ctxs  - Optional array of contexts to pass to each function, or NULL.
9164 - X     - The coefficient vector u_h, a global vector
9165 
9166   Output Parameter:
9167 . diff - The diff ||u - u_h||_2
9168 
9169   Level: developer
9170 
9171 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9172 @*/
9173 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
9174 {
9175   PetscFunctionBegin;
9176   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9177   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
9178   PetscCheck(dm->ops->computel2diff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
9179   PetscCall((dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff));
9180   PetscFunctionReturn(0);
9181 }
9182 
9183 /*@C
9184   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
9185 
9186   Collective on dm
9187 
9188   Input Parameters:
9189 + dm    - The DM
9190 , time  - The time
9191 . funcs - The gradient functions to evaluate for each field component
9192 . ctxs  - Optional array of contexts to pass to each function, or NULL.
9193 . X     - The coefficient vector u_h, a global vector
9194 - n     - The vector to project along
9195 
9196   Output Parameter:
9197 . diff - The diff ||(grad u - grad u_h) . n||_2
9198 
9199   Level: developer
9200 
9201 .seealso: DMProjectFunction(), DMComputeL2Diff()
9202 @*/
9203 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)
9204 {
9205   PetscFunctionBegin;
9206   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9207   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
9208   PetscCheck(dm->ops->computel2gradientdiff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
9209   PetscCall((dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff));
9210   PetscFunctionReturn(0);
9211 }
9212 
9213 /*@C
9214   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
9215 
9216   Collective on dm
9217 
9218   Input Parameters:
9219 + dm    - The DM
9220 . time  - The time
9221 . funcs - The functions to evaluate for each field component
9222 . ctxs  - Optional array of contexts to pass to each function, or NULL.
9223 - X     - The coefficient vector u_h, a global vector
9224 
9225   Output Parameter:
9226 . diff - The array of differences, ||u^f - u^f_h||_2
9227 
9228   Level: developer
9229 
9230 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9231 @*/
9232 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
9233 {
9234   PetscFunctionBegin;
9235   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9236   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
9237   PetscCheck(dm->ops->computel2fielddiff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
9238   PetscCall((dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff));
9239   PetscFunctionReturn(0);
9240 }
9241 
9242 /*@C
9243  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
9244 
9245  Not Collective
9246 
9247  Input Parameter:
9248 .  dm    - The DM
9249 
9250  Output Parameters:
9251 +  nranks - the number of neighbours
9252 -  ranks - the neighbors ranks
9253 
9254  Notes:
9255  Do not free the array, it is freed when the DM is destroyed.
9256 
9257  Level: beginner
9258 
9259  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9260 @*/
9261 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9262 {
9263   PetscFunctionBegin;
9264   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9265   PetscCheck(dm->ops->getneighbors,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9266   PetscCall((dm->ops->getneighbors)(dm,nranks,ranks));
9267   PetscFunctionReturn(0);
9268 }
9269 
9270 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
9271 
9272 /*
9273     Converts the input vector to a ghosted vector and then calls the standard coloring code.
9274     This has be a different function because it requires DM which is not defined in the Mat library
9275 */
9276 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9277 {
9278   PetscFunctionBegin;
9279   if (coloring->ctype == IS_COLORING_LOCAL) {
9280     Vec x1local;
9281     DM  dm;
9282     PetscCall(MatGetDM(J,&dm));
9283     PetscCheck(dm,PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9284     PetscCall(DMGetLocalVector(dm,&x1local));
9285     PetscCall(DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local));
9286     PetscCall(DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local));
9287     x1   = x1local;
9288   }
9289   PetscCall(MatFDColoringApply_AIJ(J,coloring,x1,sctx));
9290   if (coloring->ctype == IS_COLORING_LOCAL) {
9291     DM  dm;
9292     PetscCall(MatGetDM(J,&dm));
9293     PetscCall(DMRestoreLocalVector(dm,&x1));
9294   }
9295   PetscFunctionReturn(0);
9296 }
9297 
9298 /*@
9299     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
9300 
9301     Input Parameter:
9302 .    coloring - the MatFDColoring object
9303 
9304     Developer Notes:
9305     this routine exists because the PETSc Mat library does not know about the DM objects
9306 
9307     Level: advanced
9308 
9309 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9310 @*/
9311 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9312 {
9313   PetscFunctionBegin;
9314   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9315   PetscFunctionReturn(0);
9316 }
9317 
9318 /*@
9319     DMGetCompatibility - determine if two DMs are compatible
9320 
9321     Collective
9322 
9323     Input Parameters:
9324 +    dm1 - the first DM
9325 -    dm2 - the second DM
9326 
9327     Output Parameters:
9328 +    compatible - whether or not the two DMs are compatible
9329 -    set - whether or not the compatible value was set
9330 
9331     Notes:
9332     Two DMs are deemed compatible if they represent the same parallel decomposition
9333     of the same topology. This implies that the section (field data) on one
9334     "makes sense" with respect to the topology and parallel decomposition of the other.
9335     Loosely speaking, compatible DMs represent the same domain and parallel
9336     decomposition, but hold different data.
9337 
9338     Typically, one would confirm compatibility if intending to simultaneously iterate
9339     over a pair of vectors obtained from different DMs.
9340 
9341     For example, two DMDA objects are compatible if they have the same local
9342     and global sizes and the same stencil width. They can have different numbers
9343     of degrees of freedom per node. Thus, one could use the node numbering from
9344     either DM in bounds for a loop over vectors derived from either DM.
9345 
9346     Consider the operation of summing data living on a 2-dof DMDA to data living
9347     on a 1-dof DMDA, which should be compatible, as in the following snippet.
9348 .vb
9349   ...
9350   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
9351   if (set && compatible)  {
9352     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
9353     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
9354     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
9355     for (j=y; j<y+n; ++j) {
9356       for (i=x; i<x+m, ++i) {
9357         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9358       }
9359     }
9360     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
9361     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
9362   } else {
9363     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9364   }
9365   ...
9366 .ve
9367 
9368     Checking compatibility might be expensive for a given implementation of DM,
9369     or might be impossible to unambiguously confirm or deny. For this reason,
9370     this function may decline to determine compatibility, and hence users should
9371     always check the "set" output parameter.
9372 
9373     A DM is always compatible with itself.
9374 
9375     In the current implementation, DMs which live on "unequal" communicators
9376     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9377     incompatible.
9378 
9379     This function is labeled "Collective," as information about all subdomains
9380     is required on each rank. However, in DM implementations which store all this
9381     information locally, this function may be merely "Logically Collective".
9382 
9383     Developer Notes:
9384     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9385     iff B is compatible with A. Thus, this function checks the implementations
9386     of both dm and dmc (if they are of different types), attempting to determine
9387     compatibility. It is left to DM implementers to ensure that symmetry is
9388     preserved. The simplest way to do this is, when implementing type-specific
9389     logic for this function, is to check for existing logic in the implementation
9390     of other DM types and let *set = PETSC_FALSE if found.
9391 
9392     Level: advanced
9393 
9394 .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9395 @*/
9396 
9397 PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9398 {
9399   PetscMPIInt    compareResult;
9400   DMType         type,type2;
9401   PetscBool      sameType;
9402 
9403   PetscFunctionBegin;
9404   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
9405   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
9406 
9407   /* Declare a DM compatible with itself */
9408   if (dm1 == dm2) {
9409     *set = PETSC_TRUE;
9410     *compatible = PETSC_TRUE;
9411     PetscFunctionReturn(0);
9412   }
9413 
9414   /* Declare a DM incompatible with a DM that lives on an "unequal"
9415      communicator. Note that this does not preclude compatibility with
9416      DMs living on "congruent" or "similar" communicators, but this must be
9417      determined by the implementation-specific logic */
9418   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult));
9419   if (compareResult == MPI_UNEQUAL) {
9420     *set = PETSC_TRUE;
9421     *compatible = PETSC_FALSE;
9422     PetscFunctionReturn(0);
9423   }
9424 
9425   /* Pass to the implementation-specific routine, if one exists. */
9426   if (dm1->ops->getcompatibility) {
9427     PetscCall((*dm1->ops->getcompatibility)(dm1,dm2,compatible,set));
9428     if (*set) PetscFunctionReturn(0);
9429   }
9430 
9431   /* If dm1 and dm2 are of different types, then attempt to check compatibility
9432      with an implementation of this function from dm2 */
9433   PetscCall(DMGetType(dm1,&type));
9434   PetscCall(DMGetType(dm2,&type2));
9435   PetscCall(PetscStrcmp(type,type2,&sameType));
9436   if (!sameType && dm2->ops->getcompatibility) {
9437     PetscCall((*dm2->ops->getcompatibility)(dm2,dm1,compatible,set)); /* Note argument order */
9438   } else {
9439     *set = PETSC_FALSE;
9440   }
9441   PetscFunctionReturn(0);
9442 }
9443 
9444 /*@C
9445   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
9446 
9447   Logically Collective on DM
9448 
9449   Input Parameters:
9450 + DM - the DM
9451 . f - the monitor function
9452 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9453 - monitordestroy - [optional] routine that frees monitor context (may be NULL)
9454 
9455   Options Database Keys:
9456 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9457                             does not cancel those set via the options database.
9458 
9459   Notes:
9460   Several different monitoring routines may be set by calling
9461   DMMonitorSet() multiple times; all will be called in the
9462   order in which they were set.
9463 
9464   Fortran Notes:
9465   Only a single monitor function can be set for each DM object
9466 
9467   Level: intermediate
9468 
9469 .seealso: DMMonitorCancel()
9470 @*/
9471 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9472 {
9473   PetscInt       m;
9474 
9475   PetscFunctionBegin;
9476   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9477   for (m = 0; m < dm->numbermonitors; ++m) {
9478     PetscBool identical;
9479 
9480     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
9481     if (identical) PetscFunctionReturn(0);
9482   }
9483   PetscCheck(dm->numbermonitors < MAXDMMONITORS,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9484   dm->monitor[dm->numbermonitors]          = f;
9485   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9486   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9487   PetscFunctionReturn(0);
9488 }
9489 
9490 /*@
9491   DMMonitorCancel - Clears all the monitor functions for a DM object.
9492 
9493   Logically Collective on DM
9494 
9495   Input Parameter:
9496 . dm - the DM
9497 
9498   Options Database Key:
9499 . -dm_monitor_cancel - cancels all monitors that have been hardwired
9500   into a code by calls to DMonitorSet(), but does not cancel those
9501   set via the options database
9502 
9503   Notes:
9504   There is no way to clear one specific monitor from a DM object.
9505 
9506   Level: intermediate
9507 
9508 .seealso: DMMonitorSet()
9509 @*/
9510 PetscErrorCode DMMonitorCancel(DM dm)
9511 {
9512   PetscInt       m;
9513 
9514   PetscFunctionBegin;
9515   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9516   for (m = 0; m < dm->numbermonitors; ++m) {
9517     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
9518   }
9519   dm->numbermonitors = 0;
9520   PetscFunctionReturn(0);
9521 }
9522 
9523 /*@C
9524   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9525 
9526   Collective on DM
9527 
9528   Input Parameters:
9529 + dm   - DM object you wish to monitor
9530 . name - the monitor type one is seeking
9531 . help - message indicating what monitoring is done
9532 . manual - manual page for the monitor
9533 . monitor - the monitor function
9534 - 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
9535 
9536   Output Parameter:
9537 . flg - Flag set if the monitor was created
9538 
9539   Level: developer
9540 
9541 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9542           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9543           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9544           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9545           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9546           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9547           PetscOptionsFList(), PetscOptionsEList()
9548 @*/
9549 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9550 {
9551   PetscViewer       viewer;
9552   PetscViewerFormat format;
9553 
9554   PetscFunctionBegin;
9555   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9556   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg));
9557   if (*flg) {
9558     PetscViewerAndFormat *vf;
9559 
9560     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
9561     PetscCall(PetscObjectDereference((PetscObject) viewer));
9562     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
9563     PetscCall(DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy));
9564   }
9565   PetscFunctionReturn(0);
9566 }
9567 
9568 /*@
9569    DMMonitor - runs the user provided monitor routines, if they exist
9570 
9571    Collective on DM
9572 
9573    Input Parameters:
9574 .  dm - The DM
9575 
9576    Level: developer
9577 
9578 .seealso: DMMonitorSet()
9579 @*/
9580 PetscErrorCode DMMonitor(DM dm)
9581 {
9582   PetscInt       m;
9583 
9584   PetscFunctionBegin;
9585   if (!dm) PetscFunctionReturn(0);
9586   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9587   for (m = 0; m < dm->numbermonitors; ++m) {
9588     PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
9589   }
9590   PetscFunctionReturn(0);
9591 }
9592 
9593 /*@
9594   DMComputeError - Computes the error assuming the user has given exact solution functions
9595 
9596   Collective on DM
9597 
9598   Input Parameters:
9599 + dm     - The DM
9600 - sol    - The solution vector
9601 
9602   Input/Output Parameter:
9603 . errors - An array of length Nf, the number of fields, or NULL for no output; on output
9604            contains the error in each field
9605 
9606   Output Parameter:
9607 . errorVec - A vector to hold the cellwise error (may be NULL)
9608 
9609   Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().
9610 
9611   Level: developer
9612 
9613 .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
9614 @*/
9615 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9616 {
9617   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9618   void            **ctxs;
9619   PetscReal         time;
9620   PetscInt          Nf, f, Nds, s;
9621 
9622   PetscFunctionBegin;
9623   PetscCall(DMGetNumFields(dm, &Nf));
9624   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
9625   PetscCall(DMGetNumDS(dm, &Nds));
9626   for (s = 0; s < Nds; ++s) {
9627     PetscDS         ds;
9628     DMLabel         label;
9629     IS              fieldIS;
9630     const PetscInt *fields;
9631     PetscInt        dsNf;
9632 
9633     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
9634     PetscCall(PetscDSGetNumFields(ds, &dsNf));
9635     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
9636     for (f = 0; f < dsNf; ++f) {
9637       const PetscInt field = fields[f];
9638       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
9639     }
9640     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
9641   }
9642   for (f = 0; f < Nf; ++f) {
9643     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);
9644   }
9645   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
9646   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
9647   if (errorVec) {
9648     DM             edm;
9649     DMPolytopeType ct;
9650     PetscBool      simplex;
9651     PetscInt       dim, cStart, Nf;
9652 
9653     PetscCall(DMClone(dm, &edm));
9654     PetscCall(DMGetDimension(edm, &dim));
9655     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
9656     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9657     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
9658     PetscCall(DMGetNumFields(dm, &Nf));
9659     for (f = 0; f < Nf; ++f) {
9660       PetscFE         fe, efe;
9661       PetscQuadrature q;
9662       const char     *name;
9663 
9664       PetscCall(DMGetField(dm, f, NULL, (PetscObject *) &fe));
9665       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
9666       PetscCall(PetscObjectGetName((PetscObject) fe, &name));
9667       PetscCall(PetscObjectSetName((PetscObject) efe, name));
9668       PetscCall(PetscFEGetQuadrature(fe, &q));
9669       PetscCall(PetscFESetQuadrature(efe, q));
9670       PetscCall(DMSetField(edm, f, NULL, (PetscObject) efe));
9671       PetscCall(PetscFEDestroy(&efe));
9672     }
9673     PetscCall(DMCreateDS(edm));
9674 
9675     PetscCall(DMCreateGlobalVector(edm, errorVec));
9676     PetscCall(PetscObjectSetName((PetscObject) *errorVec, "Error"));
9677     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
9678     PetscCall(DMDestroy(&edm));
9679   }
9680   PetscCall(PetscFree2(exactSol, ctxs));
9681   PetscFunctionReturn(0);
9682 }
9683 
9684 /*@
9685   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM
9686 
9687   Not collective
9688 
9689   Input Parameter:
9690 . dm     - The DM
9691 
9692   Output Parameter:
9693 . numAux - The number of auxiliary data vectors
9694 
9695   Level: advanced
9696 
9697 .seealso: DMGetAuxiliaryLabels(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9698 @*/
9699 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9700 {
9701   PetscFunctionBegin;
9702   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9703   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
9704   PetscFunctionReturn(0);
9705 }
9706 
9707 /*@
9708   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
9709 
9710   Not collective
9711 
9712   Input Parameters:
9713 + dm     - The DM
9714 . label  - The DMLabel
9715 . value  - The label value indicating the region
9716 - part   - The equation part, or 0 if unused
9717 
9718   Output Parameter:
9719 . aux    - The Vec holding auxiliary field data
9720 
9721   Note: If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
9722 
9723   Level: advanced
9724 
9725 .seealso: DMSetAuxiliaryVec(), DMGetNumAuxiliaryVec()
9726 @*/
9727 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
9728 {
9729   PetscHashAuxKey key, wild = {NULL, 0, 0};
9730   PetscBool       has;
9731 
9732   PetscFunctionBegin;
9733   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9734   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9735   key.label = label;
9736   key.value = value;
9737   key.part  = part;
9738   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
9739   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key,  aux));
9740   else     PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
9741   PetscFunctionReturn(0);
9742 }
9743 
9744 /*@
9745   DMSetAuxiliaryVec - Set the auxiliary vector for region specified by the given label and value, and equation part
9746 
9747   Not collective
9748 
9749   Input Parameters:
9750 + dm     - The DM
9751 . label  - The DMLabel
9752 . value  - The label value indicating the region
9753 . part   - The equation part, or 0 if unused
9754 - aux    - The Vec holding auxiliary field data
9755 
9756   Level: advanced
9757 
9758 .seealso: DMGetAuxiliaryVec()
9759 @*/
9760 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
9761 {
9762   Vec             old;
9763   PetscHashAuxKey key;
9764 
9765   PetscFunctionBegin;
9766   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9767   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9768   key.label = label;
9769   key.value = value;
9770   key.part  = part;
9771   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9772   PetscCall(PetscObjectReference((PetscObject) aux));
9773   PetscCall(PetscObjectDereference((PetscObject) old));
9774   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9775   else      PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9776   PetscFunctionReturn(0);
9777 }
9778 
9779 /*@C
9780   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this DM
9781 
9782   Not collective
9783 
9784   Input Parameter:
9785 . dm      - The DM
9786 
9787   Output Parameters:
9788 + labels  - The DMLabels for each Vec
9789 . values  - The label values for each Vec
9790 - parts   - The equation parts for each Vec
9791 
9792   Note: The arrays passed in must be at least as large as DMGetNumAuxiliaryVec().
9793 
9794   Level: advanced
9795 
9796 .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9797 @*/
9798 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9799 {
9800   PetscHashAuxKey *keys;
9801   PetscInt         n, i, off = 0;
9802 
9803   PetscFunctionBegin;
9804   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9805   PetscValidPointer(labels, 2);
9806   PetscValidIntPointer(values, 3);
9807   PetscValidIntPointer(parts,  4);
9808   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9809   PetscCall(PetscMalloc1(n, &keys));
9810   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9811   for (i = 0; i < n; ++i) {labels[i] = keys[i].label; values[i] = keys[i].value; parts[i] = keys[i].part;}
9812   PetscCall(PetscFree(keys));
9813   PetscFunctionReturn(0);
9814 }
9815 
9816 /*@
9817   DMCopyAuxiliaryVec - Copy the auxiliary data to a new DM
9818 
9819   Not collective
9820 
9821   Input Parameter:
9822 . dm    - The DM
9823 
9824   Output Parameter:
9825 . dmNew - The new DM, now with the same auxiliary data
9826 
9827   Level: advanced
9828 
9829 .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9830 @*/
9831 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9832 {
9833   PetscFunctionBegin;
9834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9835   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9836   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9837   PetscFunctionReturn(0);
9838 }
9839 
9840 /*@C
9841   DMPolytopeMatchOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement
9842 
9843   Not collective
9844 
9845   Input Parameters:
9846 + ct         - The DMPolytopeType
9847 . sourceCone - The source arrangement of faces
9848 - targetCone - The target arrangement of faces
9849 
9850   Output Parameters:
9851 + ornt  - The orientation which will take the source arrangement to the target arrangement
9852 - found - Flag indicating that a suitable orientation was found
9853 
9854   Level: advanced
9855 
9856 .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchVertexOrientation()
9857 @*/
9858 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9859 {
9860   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9861   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9862   PetscInt       o, c;
9863 
9864   PetscFunctionBegin;
9865   if (!nO) {*ornt = 0; *found = PETSC_TRUE; PetscFunctionReturn(0);}
9866   for (o = -nO; o < nO; ++o) {
9867     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
9868 
9869     for (c = 0; c < cS; ++c) if (sourceCone[arr[c*2]] != targetCone[c]) break;
9870     if (c == cS) {*ornt = o; break;}
9871   }
9872   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9873   PetscFunctionReturn(0);
9874 }
9875 
9876 /*@C
9877   DMPolytopeGetOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement
9878 
9879   Not collective
9880 
9881   Input Parameters:
9882 + ct         - The DMPolytopeType
9883 . sourceCone - The source arrangement of faces
9884 - targetCone - The target arrangement of faces
9885 
9886   Output Parameters:
9887 . ornt  - The orientation which will take the source arrangement to the target arrangement
9888 
9889   Note: This function will fail if no suitable orientation can be found.
9890 
9891   Level: advanced
9892 
9893 .seealso: DMPolytopeMatchOrientation(), DMPolytopeGetVertexOrientation()
9894 @*/
9895 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9896 {
9897   PetscBool      found;
9898 
9899   PetscFunctionBegin;
9900   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9901   PetscCheck(found,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9902   PetscFunctionReturn(0);
9903 }
9904 
9905 /*@C
9906   DMPolytopeMatchVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement
9907 
9908   Not collective
9909 
9910   Input Parameters:
9911 + ct         - The DMPolytopeType
9912 . sourceVert - The source arrangement of vertices
9913 - targetVert - The target arrangement of vertices
9914 
9915   Output Parameters:
9916 + ornt  - The orientation which will take the source arrangement to the target arrangement
9917 - found - Flag indicating that a suitable orientation was found
9918 
9919   Level: advanced
9920 
9921 .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchOrientation()
9922 @*/
9923 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9924 {
9925   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9926   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9927   PetscInt       o, c;
9928 
9929   PetscFunctionBegin;
9930   if (!nO) {*ornt = 0; *found = PETSC_TRUE; PetscFunctionReturn(0);}
9931   for (o = -nO; o < nO; ++o) {
9932     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);
9933 
9934     for (c = 0; c < cS; ++c) if (sourceVert[arr[c]] != targetVert[c]) break;
9935     if (c == cS) {*ornt = o; break;}
9936   }
9937   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9938   PetscFunctionReturn(0);
9939 }
9940 
9941 /*@C
9942   DMPolytopeGetVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement
9943 
9944   Not collective
9945 
9946   Input Parameters:
9947 + ct         - The DMPolytopeType
9948 . sourceCone - The source arrangement of vertices
9949 - targetCone - The target arrangement of vertices
9950 
9951   Output Parameters:
9952 . ornt  - The orientation which will take the source arrangement to the target arrangement
9953 
9954   Note: This function will fail if no suitable orientation can be found.
9955 
9956   Level: advanced
9957 
9958 .seealso: DMPolytopeMatchVertexOrientation(), DMPolytopeGetOrientation()
9959 @*/
9960 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9961 {
9962   PetscBool      found;
9963 
9964   PetscFunctionBegin;
9965   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9966   PetscCheck(found,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9967   PetscFunctionReturn(0);
9968 }
9969 
9970 /*@C
9971   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9972 
9973   Not collective
9974 
9975   Input Parameters:
9976 + ct    - The DMPolytopeType
9977 - point - Coordinates of the point
9978 
9979   Output Parameters:
9980 . inside  - Flag indicating whether the point is inside the reference cell of given type
9981 
9982   Level: advanced
9983 
9984 .seealso: DMLocatePoints()
9985 @*/
9986 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9987 {
9988   PetscReal sum = 0.0;
9989   PetscInt  d;
9990 
9991   PetscFunctionBegin;
9992   *inside = PETSC_TRUE;
9993   switch (ct) {
9994   case DM_POLYTOPE_TRIANGLE:
9995   case DM_POLYTOPE_TETRAHEDRON:
9996     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9997       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
9998       sum += point[d];
9999     }
10000     if (sum > PETSC_SMALL) {*inside = PETSC_FALSE; break;}
10001     break;
10002   case DM_POLYTOPE_QUADRILATERAL:
10003   case DM_POLYTOPE_HEXAHEDRON:
10004     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
10005       if (PetscAbsReal(point[d]) > 1.+PETSC_SMALL) {*inside = PETSC_FALSE; break;}
10006     break;
10007   default:
10008     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
10009   }
10010   PetscFunctionReturn(0);
10011 }
10012