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