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