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