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