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