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