xref: /petsc/src/dm/interface/dm.c (revision 00d952a436fee6bdf6e70eb3e77eb53947e929d9)
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   DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM
5293 
5294   Collective on dm
5295 
5296   Input Parameter:
5297 . dm - The DM
5298 
5299   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
5300 
5301   Level: intermediate
5302 
5303 .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5304 @*/
5305 PetscErrorCode DMCreateDS(DM dm)
5306 {
5307   MPI_Comm       comm;
5308   PetscDS        dsDef;
5309   DMLabel       *labelSet;
5310   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef;
5311   PetscBool      doSetup = PETSC_TRUE;
5312   PetscErrorCode ierr;
5313 
5314   PetscFunctionBegin;
5315   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5316   if (!dm->fields) PetscFunctionReturn(0);
5317   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
5318   ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr);
5319   /* Determine how many regions we have */
5320   ierr = PetscMalloc1(Nf, &labelSet);CHKERRQ(ierr);
5321   Nl   = 0;
5322   Ndef = 0;
5323   for (f = 0; f < Nf; ++f) {
5324     DMLabel  label = dm->fields[f].label;
5325     PetscInt l;
5326 
5327     if (!label) {++Ndef; continue;}
5328     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5329     if (l < Nl) continue;
5330     labelSet[Nl++] = label;
5331   }
5332   /* Create default DS if there are no labels to intersect with */
5333   ierr = DMGetRegionDS(dm, NULL, NULL, &dsDef);CHKERRQ(ierr);
5334   if (!dsDef && Ndef && !Nl) {
5335     IS        fields;
5336     PetscInt *fld, nf;
5337 
5338     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5339     if (nf) {
5340       ierr = PetscMalloc1(nf, &fld);CHKERRQ(ierr);
5341       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5342       ierr = ISCreate(PETSC_COMM_SELF, &fields);CHKERRQ(ierr);
5343       ierr = PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");CHKERRQ(ierr);
5344       ierr = ISSetType(fields, ISGENERAL);CHKERRQ(ierr);
5345       ierr = ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);CHKERRQ(ierr);
5346 
5347       ierr = PetscDSCreate(comm, &dsDef);CHKERRQ(ierr);
5348       ierr = DMSetRegionDS(dm, NULL, fields, dsDef);CHKERRQ(ierr);
5349       ierr = PetscDSDestroy(&dsDef);CHKERRQ(ierr);
5350       ierr = ISDestroy(&fields);CHKERRQ(ierr);
5351     }
5352   }
5353   ierr = DMGetRegionDS(dm, NULL, NULL, &dsDef);CHKERRQ(ierr);
5354   if (dsDef) {ierr = PetscDSSetCoordinateDimension(dsDef, dE);CHKERRQ(ierr);}
5355   /* Intersect labels with default fields */
5356   if (Ndef && Nl) {
5357     DM              plex;
5358     DMLabel         cellLabel;
5359     IS              fieldIS, allcellIS, defcellIS = NULL;
5360     PetscInt       *fields;
5361     const PetscInt *cells;
5362     PetscInt        depth, nf = 0, n, c;
5363 
5364     ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
5365     ierr = DMPlexGetDepth(plex, &depth);CHKERRQ(ierr);
5366     ierr = DMGetStratumIS(plex, "dim", depth, &allcellIS);CHKERRQ(ierr);
5367     if (!allcellIS) {ierr = DMGetStratumIS(plex, "depth", depth, &allcellIS);CHKERRQ(ierr);}
5368     for (l = 0; l < Nl; ++l) {
5369       DMLabel label = labelSet[l];
5370       IS      pointIS;
5371 
5372       ierr = ISDestroy(&defcellIS);CHKERRQ(ierr);
5373       ierr = DMLabelGetStratumIS(label, 1, &pointIS);CHKERRQ(ierr);
5374       ierr = ISDifference(allcellIS, pointIS, &defcellIS);CHKERRQ(ierr);
5375       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
5376     }
5377     ierr = ISDestroy(&allcellIS);CHKERRQ(ierr);
5378 
5379     ierr = DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);CHKERRQ(ierr);
5380     ierr = ISGetLocalSize(defcellIS, &n);CHKERRQ(ierr);
5381     ierr = ISGetIndices(defcellIS, &cells);CHKERRQ(ierr);
5382     for (c = 0; c < n; ++c) {ierr = DMLabelSetValue(cellLabel, cells[c], 1);CHKERRQ(ierr);}
5383     ierr = ISRestoreIndices(defcellIS, &cells);CHKERRQ(ierr);
5384     ierr = ISDestroy(&defcellIS);CHKERRQ(ierr);
5385     ierr = DMPlexLabelComplete(plex, cellLabel);CHKERRQ(ierr);
5386 
5387     ierr = PetscMalloc1(Ndef, &fields);CHKERRQ(ierr);
5388     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5389     ierr = ISCreate(PETSC_COMM_SELF, &fieldIS);CHKERRQ(ierr);
5390     ierr = PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");CHKERRQ(ierr);
5391     ierr = ISSetType(fieldIS, ISGENERAL);CHKERRQ(ierr);
5392     ierr = ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);CHKERRQ(ierr);
5393 
5394     ierr = PetscDSCreate(comm, &dsDef);CHKERRQ(ierr);
5395     ierr = DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);CHKERRQ(ierr);
5396     ierr = DMLabelDestroy(&cellLabel);CHKERRQ(ierr);
5397     ierr = PetscDSSetCoordinateDimension(dsDef, dE);CHKERRQ(ierr);
5398     ierr = PetscDSDestroy(&dsDef);CHKERRQ(ierr);
5399     ierr = ISDestroy(&fieldIS);CHKERRQ(ierr);
5400     ierr = DMDestroy(&plex);CHKERRQ(ierr);
5401   }
5402   /* Create label DSes
5403      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5404   */
5405   /* TODO Should check that labels are disjoint */
5406   for (l = 0; l < Nl; ++l) {
5407     DMLabel   label = labelSet[l];
5408     PetscDS   ds;
5409     IS        fields;
5410     PetscInt *fld, nf;
5411 
5412     ierr = PetscDSCreate(comm, &ds);CHKERRQ(ierr);
5413     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5414     ierr = PetscMalloc1(nf, &fld);CHKERRQ(ierr);
5415     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5416     ierr = ISCreate(PETSC_COMM_SELF, &fields);CHKERRQ(ierr);
5417     ierr = PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");CHKERRQ(ierr);
5418     ierr = ISSetType(fields, ISGENERAL);CHKERRQ(ierr);
5419     ierr = ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);CHKERRQ(ierr);
5420     ierr = DMSetRegionDS(dm, label, fields, ds);CHKERRQ(ierr);
5421     ierr = ISDestroy(&fields);CHKERRQ(ierr);
5422     ierr = PetscDSSetCoordinateDimension(ds, dE);CHKERRQ(ierr);
5423     {
5424       DMPolytopeType ct;
5425       PetscInt       lStart, lEnd;
5426       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;
5427 
5428       ierr = DMLabelGetBounds(label, &lStart, &lEnd);CHKERRQ(ierr);
5429       if (lStart >= 0) {
5430         ierr = DMPlexGetCellType(dm, lStart, &ct);CHKERRQ(ierr);
5431         switch (ct) {
5432           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5433           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5434           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5435           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5436             isHybridLocal = PETSC_TRUE;break;
5437           default: break;
5438         }
5439       }
5440       ierr = MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);CHKERRQ(ierr);
5441       ierr = PetscDSSetHybrid(ds, isHybrid);CHKERRQ(ierr);
5442     }
5443     ierr = PetscDSDestroy(&ds);CHKERRQ(ierr);
5444   }
5445   ierr = PetscFree(labelSet);CHKERRQ(ierr);
5446   /* Set fields in DSes */
5447   for (s = 0; s < dm->Nds; ++s) {
5448     PetscDS         ds     = dm->probs[s].ds;
5449     IS              fields = dm->probs[s].fields;
5450     const PetscInt *fld;
5451     PetscInt        nf;
5452 
5453     ierr = ISGetLocalSize(fields, &nf);CHKERRQ(ierr);
5454     ierr = ISGetIndices(fields, &fld);CHKERRQ(ierr);
5455     for (f = 0; f < nf; ++f) {
5456       PetscObject  disc  = dm->fields[fld[f]].disc;
5457       PetscBool    isHybrid;
5458       PetscClassId id;
5459 
5460       ierr = PetscDSGetHybrid(ds, &isHybrid);CHKERRQ(ierr);
5461       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5462       if (isHybrid && f < nf-1) {ierr = PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);CHKERRQ(ierr);}
5463       ierr = PetscDSSetDiscretization(ds, f, disc);CHKERRQ(ierr);
5464       /* We allow people to have placeholder fields and construct the Section by hand */
5465       ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr);
5466       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5467     }
5468     ierr = ISRestoreIndices(fields, &fld);CHKERRQ(ierr);
5469   }
5470   /* Setup DSes */
5471   if (doSetup) {
5472     for (s = 0; s < dm->Nds; ++s) {ierr = PetscDSSetUp(dm->probs[s].ds);CHKERRQ(ierr);}
5473   }
5474   PetscFunctionReturn(0);
5475 }
5476 
5477 /*@
5478   DMCopyDS - Copy the discrete systems for the DM into another DM
5479 
5480   Collective on dm
5481 
5482   Input Parameter:
5483 . dm - The DM
5484 
5485   Output Parameter:
5486 . newdm - The DM
5487 
5488   Level: advanced
5489 
5490 .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5491 @*/
5492 PetscErrorCode DMCopyDS(DM dm, DM newdm)
5493 {
5494   PetscInt       Nds, s;
5495   PetscErrorCode ierr;
5496 
5497   PetscFunctionBegin;
5498   if (dm == newdm) PetscFunctionReturn(0);
5499   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
5500   ierr = DMClearDS(newdm);CHKERRQ(ierr);
5501   for (s = 0; s < Nds; ++s) {
5502     DMLabel  label;
5503     IS       fields;
5504     PetscDS  ds;
5505     PetscInt Nbd, bd;
5506 
5507     ierr = DMGetRegionNumDS(dm, s, &label, &fields, &ds);CHKERRQ(ierr);
5508     ierr = DMSetRegionDS(newdm, label, fields, ds);CHKERRQ(ierr);
5509     ierr = PetscDSGetNumBoundary(ds, &Nbd);CHKERRQ(ierr);
5510     for (bd = 0; bd < Nbd; ++bd) {
5511       const char *labelname, *name;
5512       PetscInt    field;
5513 
5514       /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5515       ierr = PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5516       ierr = DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);CHKERRQ(ierr);
5517     }
5518   }
5519   PetscFunctionReturn(0);
5520 }
5521 
5522 /*@
5523   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
5524 
5525   Collective on dm
5526 
5527   Input Parameter:
5528 . dm - The DM
5529 
5530   Output Parameter:
5531 . newdm - The DM
5532 
5533   Level: advanced
5534 
5535 .seealso: DMCopyFields(), DMCopyDS()
5536 @*/
5537 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5538 {
5539   PetscErrorCode ierr;
5540 
5541   PetscFunctionBegin;
5542   ierr = DMCopyFields(dm, newdm);CHKERRQ(ierr);
5543   ierr = DMCopyDS(dm, newdm);CHKERRQ(ierr);
5544   PetscFunctionReturn(0);
5545 }
5546 
5547 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5548 {
5549   DM dm_coord,dmc_coord;
5550   PetscErrorCode ierr;
5551   Vec coords,ccoords;
5552   Mat inject;
5553   PetscFunctionBegin;
5554   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5555   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
5556   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5557   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
5558   if (coords && !ccoords) {
5559     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
5560     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5561     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
5562     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
5563     ierr = MatDestroy(&inject);CHKERRQ(ierr);
5564     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
5565     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5566   }
5567   PetscFunctionReturn(0);
5568 }
5569 
5570 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5571 {
5572   DM dm_coord,subdm_coord;
5573   PetscErrorCode ierr;
5574   Vec coords,ccoords,clcoords;
5575   VecScatter *scat_i,*scat_g;
5576   PetscFunctionBegin;
5577   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5578   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
5579   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5580   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
5581   if (coords && !ccoords) {
5582     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
5583     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5584     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
5585     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
5586     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
5587     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5588     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5589     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5590     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5591     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
5592     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
5593     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
5594     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
5595     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5596     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
5597     ierr = PetscFree(scat_i);CHKERRQ(ierr);
5598     ierr = PetscFree(scat_g);CHKERRQ(ierr);
5599   }
5600   PetscFunctionReturn(0);
5601 }
5602 
5603 /*@
5604   DMGetDimension - Return the topological dimension of the DM
5605 
5606   Not collective
5607 
5608   Input Parameter:
5609 . dm - The DM
5610 
5611   Output Parameter:
5612 . dim - The topological dimension
5613 
5614   Level: beginner
5615 
5616 .seealso: DMSetDimension(), DMCreate()
5617 @*/
5618 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5619 {
5620   PetscFunctionBegin;
5621   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5622   PetscValidIntPointer(dim, 2);
5623   *dim = dm->dim;
5624   PetscFunctionReturn(0);
5625 }
5626 
5627 /*@
5628   DMSetDimension - Set the topological dimension of the DM
5629 
5630   Collective on dm
5631 
5632   Input Parameters:
5633 + dm - The DM
5634 - dim - The topological dimension
5635 
5636   Level: beginner
5637 
5638 .seealso: DMGetDimension(), DMCreate()
5639 @*/
5640 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5641 {
5642   PetscDS        ds;
5643   PetscErrorCode ierr;
5644 
5645   PetscFunctionBegin;
5646   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5647   PetscValidLogicalCollectiveInt(dm, dim, 2);
5648   dm->dim = dim;
5649   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5650   if (ds->dimEmbed < 0) {ierr = PetscDSSetCoordinateDimension(ds, dm->dim);CHKERRQ(ierr);}
5651   PetscFunctionReturn(0);
5652 }
5653 
5654 /*@
5655   DMGetDimPoints - Get the half-open interval for all points of a given dimension
5656 
5657   Collective on dm
5658 
5659   Input Parameters:
5660 + dm - the DM
5661 - dim - the dimension
5662 
5663   Output Parameters:
5664 + pStart - The first point of the given dimension
5665 - pEnd - The first point following points of the given dimension
5666 
5667   Note:
5668   The points are vertices in the Hasse diagram encoding the topology. This is explained in
5669   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
5670   then the interval is empty.
5671 
5672   Level: intermediate
5673 
5674 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5675 @*/
5676 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5677 {
5678   PetscInt       d;
5679   PetscErrorCode ierr;
5680 
5681   PetscFunctionBegin;
5682   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5683   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
5684   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5685   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5686   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
5687   PetscFunctionReturn(0);
5688 }
5689 
5690 /*@
5691   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
5692 
5693   Collective on dm
5694 
5695   Input Parameters:
5696 + dm - the DM
5697 - c - coordinate vector
5698 
5699   Notes:
5700   The coordinates do include those for ghost points, which are in the local vector.
5701 
5702   The vector c should be destroyed by the caller.
5703 
5704   Level: intermediate
5705 
5706 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5707 @*/
5708 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5709 {
5710   PetscErrorCode ierr;
5711 
5712   PetscFunctionBegin;
5713   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5714   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5715   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5716   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5717   dm->coordinates = c;
5718   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5719   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5720   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5721   PetscFunctionReturn(0);
5722 }
5723 
5724 /*@
5725   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
5726 
5727   Not collective
5728 
5729    Input Parameters:
5730 +  dm - the DM
5731 -  c - coordinate vector
5732 
5733   Notes:
5734   The coordinates of ghost points can be set using DMSetCoordinates()
5735   followed by DMGetCoordinatesLocal(). This is intended to enable the
5736   setting of ghost coordinates outside of the domain.
5737 
5738   The vector c should be destroyed by the caller.
5739 
5740   Level: intermediate
5741 
5742 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5743 @*/
5744 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5745 {
5746   PetscErrorCode ierr;
5747 
5748   PetscFunctionBegin;
5749   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5750   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5751   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5752   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5753 
5754   dm->coordinatesLocal = c;
5755 
5756   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5757   PetscFunctionReturn(0);
5758 }
5759 
5760 /*@
5761   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
5762 
5763   Collective on dm
5764 
5765   Input Parameter:
5766 . dm - the DM
5767 
5768   Output Parameter:
5769 . c - global coordinate vector
5770 
5771   Note:
5772   This is a borrowed reference, so the user should NOT destroy this vector
5773 
5774   Each process has only the local coordinates (does NOT have the ghost coordinates).
5775 
5776   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5777   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5778 
5779   Level: intermediate
5780 
5781 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5782 @*/
5783 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5784 {
5785   PetscErrorCode ierr;
5786 
5787   PetscFunctionBegin;
5788   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5789   PetscValidPointer(c,2);
5790   if (!dm->coordinates && dm->coordinatesLocal) {
5791     DM        cdm = NULL;
5792     PetscBool localized;
5793 
5794     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5795     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
5796     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
5797     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
5798     if (localized) {
5799       PetscInt cdim;
5800 
5801       ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
5802       ierr = VecSetBlockSize(dm->coordinates, cdim);CHKERRQ(ierr);
5803     }
5804     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
5805     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
5806     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
5807   }
5808   *c = dm->coordinates;
5809   PetscFunctionReturn(0);
5810 }
5811 
5812 /*@
5813   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
5814 
5815   Collective on dm
5816 
5817   Input Parameter:
5818 . dm - the DM
5819 
5820   Level: advanced
5821 
5822 .seealso: DMGetCoordinatesLocalNoncollective()
5823 @*/
5824 PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
5825 {
5826   PetscErrorCode ierr;
5827 
5828   PetscFunctionBegin;
5829   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5830   if (!dm->coordinatesLocal && dm->coordinates) {
5831     DM        cdm = NULL;
5832     PetscBool localized;
5833 
5834     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5835     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
5836     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
5837     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
5838     if (localized) {
5839       PetscInt cdim;
5840 
5841       ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
5842       ierr = VecSetBlockSize(dm->coordinates, cdim);CHKERRQ(ierr);
5843     }
5844     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
5845     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
5846     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
5847   }
5848   PetscFunctionReturn(0);
5849 }
5850 
5851 /*@
5852   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
5853 
5854   Collective on dm
5855 
5856   Input Parameter:
5857 . dm - the DM
5858 
5859   Output Parameter:
5860 . c - coordinate vector
5861 
5862   Note:
5863   This is a borrowed reference, so the user should NOT destroy this vector
5864 
5865   Each process has the local and ghost coordinates
5866 
5867   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5868   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5869 
5870   Level: intermediate
5871 
5872 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
5873 @*/
5874 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
5875 {
5876   PetscErrorCode ierr;
5877 
5878   PetscFunctionBegin;
5879   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5880   PetscValidPointer(c,2);
5881   ierr = DMGetCoordinatesLocalSetUp(dm);CHKERRQ(ierr);
5882   *c = dm->coordinatesLocal;
5883   PetscFunctionReturn(0);
5884 }
5885 
5886 /*@
5887   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
5888 
5889   Not collective
5890 
5891   Input Parameter:
5892 . dm - the DM
5893 
5894   Output Parameter:
5895 . c - coordinate vector
5896 
5897   Level: advanced
5898 
5899 .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5900 @*/
5901 PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
5902 {
5903   PetscFunctionBegin;
5904   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5905   PetscValidPointer(c,2);
5906   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
5907   *c = dm->coordinatesLocal;
5908   PetscFunctionReturn(0);
5909 }
5910 
5911 /*@
5912   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
5913 
5914   Not collective
5915 
5916   Input Parameter:
5917 + dm - the DM
5918 - p - the IS of points whose coordinates will be returned
5919 
5920   Output Parameter:
5921 + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
5922 - pCoord - the Vec with coordinates of points in p
5923 
5924   Note:
5925   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
5926 
5927   This creates a new vector, so the user SHOULD destroy this vector
5928 
5929   Each process has the local and ghost coordinates
5930 
5931   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5932   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5933 
5934   Level: advanced
5935 
5936 .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5937 @*/
5938 PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
5939 {
5940   PetscSection        cs, newcs;
5941   Vec                 coords;
5942   const PetscScalar   *arr;
5943   PetscScalar         *newarr=NULL;
5944   PetscInt            n;
5945   PetscErrorCode      ierr;
5946 
5947   PetscFunctionBegin;
5948   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5949   PetscValidHeaderSpecific(p, IS_CLASSID, 2);
5950   if (pCoordSection) PetscValidPointer(pCoordSection, 3);
5951   if (pCoord) PetscValidPointer(pCoord, 4);
5952   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
5953   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
5954   cs = dm->coordinateDM->localSection;
5955   coords = dm->coordinatesLocal;
5956   ierr = VecGetArrayRead(coords, &arr);CHKERRQ(ierr);
5957   ierr = PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);CHKERRQ(ierr);
5958   ierr = VecRestoreArrayRead(coords, &arr);CHKERRQ(ierr);
5959   if (pCoord) {
5960     ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr);
5961     /* set array in two steps to mimic PETSC_OWN_POINTER */
5962     ierr = VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);CHKERRQ(ierr);
5963     ierr = VecReplaceArray(*pCoord, newarr);CHKERRQ(ierr);
5964   } else {
5965     ierr = PetscFree(newarr);CHKERRQ(ierr);
5966   }
5967   if (pCoordSection) {*pCoordSection = newcs;}
5968   else               {ierr = PetscSectionDestroy(&newcs);CHKERRQ(ierr);}
5969   PetscFunctionReturn(0);
5970 }
5971 
5972 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
5973 {
5974   PetscErrorCode ierr;
5975 
5976   PetscFunctionBegin;
5977   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5978   PetscValidPointer(field,2);
5979   if (!dm->coordinateField) {
5980     if (dm->ops->createcoordinatefield) {
5981       ierr = (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);CHKERRQ(ierr);
5982     }
5983   }
5984   *field = dm->coordinateField;
5985   PetscFunctionReturn(0);
5986 }
5987 
5988 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
5989 {
5990   PetscErrorCode ierr;
5991 
5992   PetscFunctionBegin;
5993   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5994   if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2);
5995   ierr = PetscObjectReference((PetscObject)field);CHKERRQ(ierr);
5996   ierr = DMFieldDestroy(&dm->coordinateField);CHKERRQ(ierr);
5997   dm->coordinateField = field;
5998   PetscFunctionReturn(0);
5999 }
6000 
6001 /*@
6002   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
6003 
6004   Collective on dm
6005 
6006   Input Parameter:
6007 . dm - the DM
6008 
6009   Output Parameter:
6010 . cdm - coordinate DM
6011 
6012   Level: intermediate
6013 
6014 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6015 @*/
6016 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6017 {
6018   PetscErrorCode ierr;
6019 
6020   PetscFunctionBegin;
6021   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6022   PetscValidPointer(cdm,2);
6023   if (!dm->coordinateDM) {
6024     DM cdm;
6025 
6026     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6027     ierr = (*dm->ops->createcoordinatedm)(dm, &cdm);CHKERRQ(ierr);
6028     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6029      * until the call to CreateCoordinateDM) */
6030     ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
6031     dm->coordinateDM = cdm;
6032   }
6033   *cdm = dm->coordinateDM;
6034   PetscFunctionReturn(0);
6035 }
6036 
6037 /*@
6038   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
6039 
6040   Logically Collective on dm
6041 
6042   Input Parameters:
6043 + dm - the DM
6044 - cdm - coordinate DM
6045 
6046   Level: intermediate
6047 
6048 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6049 @*/
6050 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6051 {
6052   PetscErrorCode ierr;
6053 
6054   PetscFunctionBegin;
6055   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6056   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
6057   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
6058   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
6059   dm->coordinateDM = cdm;
6060   PetscFunctionReturn(0);
6061 }
6062 
6063 /*@
6064   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
6065 
6066   Not Collective
6067 
6068   Input Parameter:
6069 . dm - The DM object
6070 
6071   Output Parameter:
6072 . dim - The embedding dimension
6073 
6074   Level: intermediate
6075 
6076 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6077 @*/
6078 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6079 {
6080   PetscFunctionBegin;
6081   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6082   PetscValidIntPointer(dim, 2);
6083   if (dm->dimEmbed == PETSC_DEFAULT) {
6084     dm->dimEmbed = dm->dim;
6085   }
6086   *dim = dm->dimEmbed;
6087   PetscFunctionReturn(0);
6088 }
6089 
6090 /*@
6091   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
6092 
6093   Not Collective
6094 
6095   Input Parameters:
6096 + dm  - The DM object
6097 - dim - The embedding dimension
6098 
6099   Level: intermediate
6100 
6101 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6102 @*/
6103 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6104 {
6105   PetscDS        ds;
6106   PetscErrorCode ierr;
6107 
6108   PetscFunctionBegin;
6109   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6110   dm->dimEmbed = dim;
6111   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
6112   ierr = PetscDSSetCoordinateDimension(ds, dim);CHKERRQ(ierr);
6113   PetscFunctionReturn(0);
6114 }
6115 
6116 /*@
6117   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6118 
6119   Collective on dm
6120 
6121   Input Parameter:
6122 . dm - The DM object
6123 
6124   Output Parameter:
6125 . section - The PetscSection object
6126 
6127   Level: intermediate
6128 
6129 .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6130 @*/
6131 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6132 {
6133   DM             cdm;
6134   PetscErrorCode ierr;
6135 
6136   PetscFunctionBegin;
6137   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6138   PetscValidPointer(section, 2);
6139   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6140   ierr = DMGetLocalSection(cdm, section);CHKERRQ(ierr);
6141   PetscFunctionReturn(0);
6142 }
6143 
6144 /*@
6145   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
6146 
6147   Not Collective
6148 
6149   Input Parameters:
6150 + dm      - The DM object
6151 . dim     - The embedding dimension, or PETSC_DETERMINE
6152 - section - The PetscSection object
6153 
6154   Level: intermediate
6155 
6156 .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6157 @*/
6158 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6159 {
6160   DM             cdm;
6161   PetscErrorCode ierr;
6162 
6163   PetscFunctionBegin;
6164   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6165   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
6166   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6167   ierr = DMSetLocalSection(cdm, section);CHKERRQ(ierr);
6168   if (dim == PETSC_DETERMINE) {
6169     PetscInt d = PETSC_DEFAULT;
6170     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
6171 
6172     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6173     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6174     pStart = PetscMax(vStart, pStart);
6175     pEnd   = PetscMin(vEnd, pEnd);
6176     for (v = pStart; v < pEnd; ++v) {
6177       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
6178       if (dd) {d = dd; break;}
6179     }
6180     if (d >= 0) {ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);}
6181   }
6182   PetscFunctionReturn(0);
6183 }
6184 
6185 /*@C
6186   DMGetPeriodicity - Get the description of mesh periodicity
6187 
6188   Input Parameters:
6189 . dm      - The DM object
6190 
6191   Output Parameters:
6192 + per     - Whether the DM is periodic or not
6193 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6194 . L       - If we assume the mesh is a torus, this is the length of each coordinate
6195 - bd      - This describes the type of periodicity in each topological dimension
6196 
6197   Level: developer
6198 
6199 .seealso: DMGetPeriodicity()
6200 @*/
6201 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6202 {
6203   PetscFunctionBegin;
6204   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6205   if (per)     *per     = dm->periodic;
6206   if (L)       *L       = dm->L;
6207   if (maxCell) *maxCell = dm->maxCell;
6208   if (bd)      *bd      = dm->bdtype;
6209   PetscFunctionReturn(0);
6210 }
6211 
6212 /*@C
6213   DMSetPeriodicity - Set the description of mesh periodicity
6214 
6215   Input Parameters:
6216 + dm      - The DM object
6217 . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
6218 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6219 . L       - If we assume the mesh is a torus, this is the length of each coordinate
6220 - bd      - This describes the type of periodicity in each topological dimension
6221 
6222   Level: developer
6223 
6224 .seealso: DMGetPeriodicity()
6225 @*/
6226 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6227 {
6228   PetscInt       dim, d;
6229   PetscErrorCode ierr;
6230 
6231   PetscFunctionBegin;
6232   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6233   PetscValidLogicalCollectiveBool(dm,per,2);
6234   if (maxCell) {PetscValidRealPointer(maxCell,3);}
6235   if (L)       {PetscValidRealPointer(L,4);}
6236   if (bd)      {PetscValidPointer(bd,5);}
6237   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6238   if (maxCell) {
6239     if (!dm->maxCell) {ierr = PetscMalloc1(dim, &dm->maxCell);CHKERRQ(ierr);}
6240     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6241   }
6242   if (L) {
6243     if (!dm->L) {ierr = PetscMalloc1(dim, &dm->L);CHKERRQ(ierr);}
6244     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6245   }
6246   if (bd) {
6247     if (!dm->bdtype) {ierr = PetscMalloc1(dim, &dm->bdtype);CHKERRQ(ierr);}
6248     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6249   }
6250   dm->periodic = per;
6251   PetscFunctionReturn(0);
6252 }
6253 
6254 /*@
6255   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.
6256 
6257   Input Parameters:
6258 + dm     - The DM
6259 . in     - The input coordinate point (dim numbers)
6260 - endpoint - Include the endpoint L_i
6261 
6262   Output Parameter:
6263 . out - The localized coordinate point
6264 
6265   Level: developer
6266 
6267 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6268 @*/
6269 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6270 {
6271   PetscInt       dim, d;
6272   PetscErrorCode ierr;
6273 
6274   PetscFunctionBegin;
6275   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
6276   if (!dm->maxCell) {
6277     for (d = 0; d < dim; ++d) out[d] = in[d];
6278   } else {
6279     if (endpoint) {
6280       for (d = 0; d < dim; ++d) {
6281         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)) {
6282           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6283         } else {
6284           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6285         }
6286       }
6287     } else {
6288       for (d = 0; d < dim; ++d) {
6289         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6290       }
6291     }
6292   }
6293   PetscFunctionReturn(0);
6294 }
6295 
6296 /*
6297   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.
6298 
6299   Input Parameters:
6300 + dm     - The DM
6301 . dim    - The spatial dimension
6302 . anchor - The anchor point, the input point can be no more than maxCell away from it
6303 - in     - The input coordinate point (dim numbers)
6304 
6305   Output Parameter:
6306 . out - The localized coordinate point
6307 
6308   Level: developer
6309 
6310   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
6311 
6312 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6313 */
6314 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6315 {
6316   PetscInt d;
6317 
6318   PetscFunctionBegin;
6319   if (!dm->maxCell) {
6320     for (d = 0; d < dim; ++d) out[d] = in[d];
6321   } else {
6322     for (d = 0; d < dim; ++d) {
6323       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6324         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6325       } else {
6326         out[d] = in[d];
6327       }
6328     }
6329   }
6330   PetscFunctionReturn(0);
6331 }
6332 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6333 {
6334   PetscInt d;
6335 
6336   PetscFunctionBegin;
6337   if (!dm->maxCell) {
6338     for (d = 0; d < dim; ++d) out[d] = in[d];
6339   } else {
6340     for (d = 0; d < dim; ++d) {
6341       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6342         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6343       } else {
6344         out[d] = in[d];
6345       }
6346     }
6347   }
6348   PetscFunctionReturn(0);
6349 }
6350 
6351 /*
6352   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.
6353 
6354   Input Parameters:
6355 + dm     - The DM
6356 . dim    - The spatial dimension
6357 . anchor - The anchor point, the input point can be no more than maxCell away from it
6358 . in     - The input coordinate delta (dim numbers)
6359 - out    - The input coordinate point (dim numbers)
6360 
6361   Output Parameter:
6362 . out    - The localized coordinate in + out
6363 
6364   Level: developer
6365 
6366   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
6367 
6368 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6369 */
6370 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6371 {
6372   PetscInt d;
6373 
6374   PetscFunctionBegin;
6375   if (!dm->maxCell) {
6376     for (d = 0; d < dim; ++d) out[d] += in[d];
6377   } else {
6378     for (d = 0; d < dim; ++d) {
6379       const PetscReal maxC = dm->maxCell[d];
6380 
6381       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6382         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6383 
6384         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6385           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]));
6386         out[d] += newCoord;
6387       } else {
6388         out[d] += in[d];
6389       }
6390     }
6391   }
6392   PetscFunctionReturn(0);
6393 }
6394 
6395 /*@
6396   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6397 
6398   Not collective
6399 
6400   Input Parameter:
6401 . dm - The DM
6402 
6403   Output Parameter:
6404   areLocalized - True if localized
6405 
6406   Level: developer
6407 
6408 .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6409 @*/
6410 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6411 {
6412   DM             cdm;
6413   PetscSection   coordSection;
6414   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6415   PetscBool      isPlex, alreadyLocalized;
6416   PetscErrorCode ierr;
6417 
6418   PetscFunctionBegin;
6419   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6420   PetscValidBoolPointer(areLocalized, 2);
6421   *areLocalized = PETSC_FALSE;
6422 
6423   /* We need some generic way of refering to cells/vertices */
6424   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6425   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
6426   if (!isPlex) PetscFunctionReturn(0);
6427 
6428   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6429   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6430   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
6431   alreadyLocalized = PETSC_FALSE;
6432   for (c = cStart; c < cEnd; ++c) {
6433     if (c < sStart || c >= sEnd) continue;
6434     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
6435     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6436   }
6437   *areLocalized = alreadyLocalized;
6438   PetscFunctionReturn(0);
6439 }
6440 
6441 /*@
6442   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6443 
6444   Collective on dm
6445 
6446   Input Parameter:
6447 . dm - The DM
6448 
6449   Output Parameter:
6450   areLocalized - True if localized
6451 
6452   Level: developer
6453 
6454 .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6455 @*/
6456 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6457 {
6458   PetscBool      localized;
6459   PetscErrorCode ierr;
6460 
6461   PetscFunctionBegin;
6462   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6463   PetscValidBoolPointer(areLocalized, 2);
6464   ierr = DMGetCoordinatesLocalizedLocal(dm,&localized);CHKERRQ(ierr);
6465   ierr = MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6466   PetscFunctionReturn(0);
6467 }
6468 
6469 /*@
6470   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
6471 
6472   Collective on dm
6473 
6474   Input Parameter:
6475 . dm - The DM
6476 
6477   Level: developer
6478 
6479 .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6480 @*/
6481 PetscErrorCode DMLocalizeCoordinates(DM dm)
6482 {
6483   DM             cdm;
6484   PetscSection   coordSection, cSection;
6485   Vec            coordinates,  cVec;
6486   PetscScalar   *coords, *coords2, *anchor, *localized;
6487   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6488   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6489   PetscInt       maxHeight = 0, h;
6490   PetscInt       *pStart = NULL, *pEnd = NULL;
6491   PetscErrorCode ierr;
6492 
6493   PetscFunctionBegin;
6494   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6495   if (!dm->periodic) PetscFunctionReturn(0);
6496   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
6497   if (alreadyLocalized) PetscFunctionReturn(0);
6498 
6499   /* We need some generic way of refering to cells/vertices */
6500   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6501   {
6502     PetscBool isplex;
6503 
6504     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
6505     if (isplex) {
6506       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6507       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
6508       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6509       pEnd = &pStart[maxHeight + 1];
6510       newStart = vStart;
6511       newEnd   = vEnd;
6512       for (h = 0; h <= maxHeight; h++) {
6513         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
6514         newStart = PetscMin(newStart,pStart[h]);
6515         newEnd   = PetscMax(newEnd,pEnd[h]);
6516       }
6517     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6518   }
6519   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6520   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6521   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6522   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6523   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
6524 
6525   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
6526   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
6527   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
6528   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
6529   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
6530 
6531   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6532   localized = &anchor[bs];
6533   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6534   for (h = 0; h <= maxHeight; h++) {
6535     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6536 
6537     for (c = cStart; c < cEnd; ++c) {
6538       PetscScalar *cellCoords = NULL;
6539       PetscInt     b;
6540 
6541       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6542       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6543       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6544       for (d = 0; d < dof/bs; ++d) {
6545         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
6546         for (b = 0; b < bs; b++) {
6547           if (cellCoords[d*bs + b] != localized[b]) break;
6548         }
6549         if (b < bs) break;
6550       }
6551       if (d < dof/bs) {
6552         if (c >= sStart && c < sEnd) {
6553           PetscInt cdof;
6554 
6555           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6556           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6557         }
6558         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
6559         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
6560       }
6561       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6562     }
6563   }
6564   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6565   if (alreadyLocalizedGlobal) {
6566     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6567     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6568     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6569     PetscFunctionReturn(0);
6570   }
6571   for (v = vStart; v < vEnd; ++v) {
6572     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6573     ierr = PetscSectionSetDof(cSection, v, dof);CHKERRQ(ierr);
6574     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
6575   }
6576   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
6577   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
6578   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
6579   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
6580   ierr = VecSetBlockSize(cVec, bs);CHKERRQ(ierr);
6581   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
6582   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
6583   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6584   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
6585   for (v = vStart; v < vEnd; ++v) {
6586     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6587     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6588     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
6589     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6590   }
6591   for (h = 0; h <= maxHeight; h++) {
6592     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6593 
6594     for (c = cStart; c < cEnd; ++c) {
6595       PetscScalar *cellCoords = NULL;
6596       PetscInt     b, cdof;
6597 
6598       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
6599       if (!cdof) continue;
6600       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6601       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
6602       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6603       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
6604       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6605     }
6606   }
6607   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6608   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6609   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6610   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
6611   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
6612   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
6613   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
6614   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6615   PetscFunctionReturn(0);
6616 }
6617 
6618 /*@
6619   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6620 
6621   Collective on v (see explanation below)
6622 
6623   Input Parameters:
6624 + dm - The DM
6625 . v - The Vec of points
6626 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6627 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
6628 
6629   Output Parameter:
6630 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6631 - cells - The PetscSF containing the ranks and local indices of the containing points.
6632 
6633 
6634   Level: developer
6635 
6636   Notes:
6637   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6638   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
6639 
6640   If *cellSF is NULL on input, a PetscSF will be created.
6641   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
6642 
6643   An array that maps each point to its containing cell can be obtained with
6644 
6645 $    const PetscSFNode *cells;
6646 $    PetscInt           nFound;
6647 $    const PetscInt    *found;
6648 $
6649 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
6650 
6651   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6652   the index of the cell in its rank's local numbering.
6653 
6654 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6655 @*/
6656 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6657 {
6658   PetscErrorCode ierr;
6659 
6660   PetscFunctionBegin;
6661   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6662   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
6663   PetscValidPointer(cellSF,4);
6664   if (*cellSF) {
6665     PetscMPIInt result;
6666 
6667     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
6668     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
6669     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6670   } else {
6671     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
6672   }
6673   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6674   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6675   ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
6676   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6677   PetscFunctionReturn(0);
6678 }
6679 
6680 /*@
6681   DMGetOutputDM - Retrieve the DM associated with the layout for output
6682 
6683   Collective on dm
6684 
6685   Input Parameter:
6686 . dm - The original DM
6687 
6688   Output Parameter:
6689 . odm - The DM which provides the layout for output
6690 
6691   Level: intermediate
6692 
6693 .seealso: VecView(), DMGetGlobalSection()
6694 @*/
6695 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6696 {
6697   PetscSection   section;
6698   PetscBool      hasConstraints, ghasConstraints;
6699   PetscErrorCode ierr;
6700 
6701   PetscFunctionBegin;
6702   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6703   PetscValidPointer(odm,2);
6704   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
6705   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
6706   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
6707   if (!ghasConstraints) {
6708     *odm = dm;
6709     PetscFunctionReturn(0);
6710   }
6711   if (!dm->dmBC) {
6712     PetscSection newSection, gsection;
6713     PetscSF      sf;
6714 
6715     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
6716     ierr = DMCopyDisc(dm, dm->dmBC);CHKERRQ(ierr);
6717     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
6718     ierr = DMSetLocalSection(dm->dmBC, newSection);CHKERRQ(ierr);
6719     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
6720     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
6721     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
6722     ierr = DMSetGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
6723     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
6724   }
6725   *odm = dm->dmBC;
6726   PetscFunctionReturn(0);
6727 }
6728 
6729 /*@
6730   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6731 
6732   Input Parameter:
6733 . dm - The original DM
6734 
6735   Output Parameters:
6736 + num - The output sequence number
6737 - val - The output sequence value
6738 
6739   Level: intermediate
6740 
6741   Note: This is intended for output that should appear in sequence, for instance
6742   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6743 
6744 .seealso: VecView()
6745 @*/
6746 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6747 {
6748   PetscFunctionBegin;
6749   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6750   if (num) {PetscValidIntPointer(num,2); *num = dm->outputSequenceNum;}
6751   if (val) {PetscValidRealPointer(val,3);*val = dm->outputSequenceVal;}
6752   PetscFunctionReturn(0);
6753 }
6754 
6755 /*@
6756   DMSetOutputSequenceNumber - Set the sequence number/value for output
6757 
6758   Input Parameters:
6759 + dm - The original DM
6760 . num - The output sequence number
6761 - val - The output sequence value
6762 
6763   Level: intermediate
6764 
6765   Note: This is intended for output that should appear in sequence, for instance
6766   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6767 
6768 .seealso: VecView()
6769 @*/
6770 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6771 {
6772   PetscFunctionBegin;
6773   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6774   dm->outputSequenceNum = num;
6775   dm->outputSequenceVal = val;
6776   PetscFunctionReturn(0);
6777 }
6778 
6779 /*@C
6780   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
6781 
6782   Input Parameters:
6783 + dm   - The original DM
6784 . name - The sequence name
6785 - num  - The output sequence number
6786 
6787   Output Parameter:
6788 . val  - The output sequence value
6789 
6790   Level: intermediate
6791 
6792   Note: This is intended for output that should appear in sequence, for instance
6793   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6794 
6795 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
6796 @*/
6797 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6798 {
6799   PetscBool      ishdf5;
6800   PetscErrorCode ierr;
6801 
6802   PetscFunctionBegin;
6803   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6804   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
6805   PetscValidRealPointer(val,4);
6806   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
6807   if (ishdf5) {
6808 #if defined(PETSC_HAVE_HDF5)
6809     PetscScalar value;
6810 
6811     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
6812     *val = PetscRealPart(value);
6813 #endif
6814   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6815   PetscFunctionReturn(0);
6816 }
6817 
6818 /*@
6819   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
6820 
6821   Not collective
6822 
6823   Input Parameter:
6824 . dm - The DM
6825 
6826   Output Parameter:
6827 . useNatural - The flag to build the mapping to a natural order during distribution
6828 
6829   Level: beginner
6830 
6831 .seealso: DMSetUseNatural(), DMCreate()
6832 @*/
6833 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6834 {
6835   PetscFunctionBegin;
6836   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6837   PetscValidBoolPointer(useNatural, 2);
6838   *useNatural = dm->useNatural;
6839   PetscFunctionReturn(0);
6840 }
6841 
6842 /*@
6843   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
6844 
6845   Collective on dm
6846 
6847   Input Parameters:
6848 + dm - The DM
6849 - useNatural - The flag to build the mapping to a natural order during distribution
6850 
6851   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
6852 
6853   Level: beginner
6854 
6855 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
6856 @*/
6857 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6858 {
6859   PetscFunctionBegin;
6860   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6861   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6862   dm->useNatural = useNatural;
6863   PetscFunctionReturn(0);
6864 }
6865 
6866 
6867 /*@C
6868   DMCreateLabel - Create a label of the given name if it does not already exist
6869 
6870   Not Collective
6871 
6872   Input Parameters:
6873 + dm   - The DM object
6874 - name - The label name
6875 
6876   Level: intermediate
6877 
6878 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6879 @*/
6880 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6881 {
6882   PetscBool      flg;
6883   DMLabel        label;
6884   PetscErrorCode ierr;
6885 
6886   PetscFunctionBegin;
6887   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6888   PetscValidCharPointer(name, 2);
6889   ierr = DMHasLabel(dm, name, &flg);CHKERRQ(ierr);
6890   if (!flg) {
6891     ierr = DMLabelCreate(PETSC_COMM_SELF, name, &label);CHKERRQ(ierr);
6892     ierr = DMAddLabel(dm, label);CHKERRQ(ierr);
6893     ierr = DMLabelDestroy(&label);CHKERRQ(ierr);
6894   }
6895   PetscFunctionReturn(0);
6896 }
6897 
6898 /*@C
6899   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
6900 
6901   Not Collective
6902 
6903   Input Parameters:
6904 + dm   - The DM object
6905 . name - The label name
6906 - point - The mesh point
6907 
6908   Output Parameter:
6909 . value - The label value for this point, or -1 if the point is not in the label
6910 
6911   Level: beginner
6912 
6913 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
6914 @*/
6915 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6916 {
6917   DMLabel        label;
6918   PetscErrorCode ierr;
6919 
6920   PetscFunctionBegin;
6921   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6922   PetscValidCharPointer(name, 2);
6923   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6924   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6925   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
6926   PetscFunctionReturn(0);
6927 }
6928 
6929 /*@C
6930   DMSetLabelValue - Add a point to a Sieve Label with given value
6931 
6932   Not Collective
6933 
6934   Input Parameters:
6935 + dm   - The DM object
6936 . name - The label name
6937 . point - The mesh point
6938 - value - The label value for this point
6939 
6940   Output Parameter:
6941 
6942   Level: beginner
6943 
6944 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
6945 @*/
6946 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6947 {
6948   DMLabel        label;
6949   PetscErrorCode ierr;
6950 
6951   PetscFunctionBegin;
6952   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6953   PetscValidCharPointer(name, 2);
6954   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6955   if (!label) {
6956     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
6957     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6958   }
6959   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
6960   PetscFunctionReturn(0);
6961 }
6962 
6963 /*@C
6964   DMClearLabelValue - Remove a point from a Sieve Label with given value
6965 
6966   Not Collective
6967 
6968   Input Parameters:
6969 + dm   - The DM object
6970 . name - The label name
6971 . point - The mesh point
6972 - value - The label value for this point
6973 
6974   Output Parameter:
6975 
6976   Level: beginner
6977 
6978 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
6979 @*/
6980 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6981 {
6982   DMLabel        label;
6983   PetscErrorCode ierr;
6984 
6985   PetscFunctionBegin;
6986   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6987   PetscValidCharPointer(name, 2);
6988   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6989   if (!label) PetscFunctionReturn(0);
6990   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
6991   PetscFunctionReturn(0);
6992 }
6993 
6994 /*@C
6995   DMGetLabelSize - Get the number of different integer ids in a Label
6996 
6997   Not Collective
6998 
6999   Input Parameters:
7000 + dm   - The DM object
7001 - name - The label name
7002 
7003   Output Parameter:
7004 . size - The number of different integer ids, or 0 if the label does not exist
7005 
7006   Level: beginner
7007 
7008 .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7009 @*/
7010 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7011 {
7012   DMLabel        label;
7013   PetscErrorCode ierr;
7014 
7015   PetscFunctionBegin;
7016   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7017   PetscValidCharPointer(name, 2);
7018   PetscValidIntPointer(size, 3);
7019   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7020   *size = 0;
7021   if (!label) PetscFunctionReturn(0);
7022   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
7023   PetscFunctionReturn(0);
7024 }
7025 
7026 /*@C
7027   DMGetLabelIdIS - Get the integer ids in a label
7028 
7029   Not Collective
7030 
7031   Input Parameters:
7032 + mesh - The DM object
7033 - name - The label name
7034 
7035   Output Parameter:
7036 . ids - The integer ids, or NULL if the label does not exist
7037 
7038   Level: beginner
7039 
7040 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7041 @*/
7042 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7043 {
7044   DMLabel        label;
7045   PetscErrorCode ierr;
7046 
7047   PetscFunctionBegin;
7048   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7049   PetscValidCharPointer(name, 2);
7050   PetscValidPointer(ids, 3);
7051   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7052   *ids = NULL;
7053  if (label) {
7054     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
7055   } else {
7056     /* returning an empty IS */
7057     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
7058   }
7059   PetscFunctionReturn(0);
7060 }
7061 
7062 /*@C
7063   DMGetStratumSize - Get the number of points in a label stratum
7064 
7065   Not Collective
7066 
7067   Input Parameters:
7068 + dm - The DM object
7069 . name - The label name
7070 - value - The stratum value
7071 
7072   Output Parameter:
7073 . size - The stratum size
7074 
7075   Level: beginner
7076 
7077 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7078 @*/
7079 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7080 {
7081   DMLabel        label;
7082   PetscErrorCode ierr;
7083 
7084   PetscFunctionBegin;
7085   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7086   PetscValidCharPointer(name, 2);
7087   PetscValidIntPointer(size, 4);
7088   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7089   *size = 0;
7090   if (!label) PetscFunctionReturn(0);
7091   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
7092   PetscFunctionReturn(0);
7093 }
7094 
7095 /*@C
7096   DMGetStratumIS - Get the points in a label stratum
7097 
7098   Not Collective
7099 
7100   Input Parameters:
7101 + dm - The DM object
7102 . name - The label name
7103 - value - The stratum value
7104 
7105   Output Parameter:
7106 . points - The stratum points, or NULL if the label does not exist or does not have that value
7107 
7108   Level: beginner
7109 
7110 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7111 @*/
7112 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7113 {
7114   DMLabel        label;
7115   PetscErrorCode ierr;
7116 
7117   PetscFunctionBegin;
7118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7119   PetscValidCharPointer(name, 2);
7120   PetscValidPointer(points, 4);
7121   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7122   *points = NULL;
7123   if (!label) PetscFunctionReturn(0);
7124   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
7125   PetscFunctionReturn(0);
7126 }
7127 
7128 /*@C
7129   DMSetStratumIS - Set the points in a label stratum
7130 
7131   Not Collective
7132 
7133   Input Parameters:
7134 + dm - The DM object
7135 . name - The label name
7136 . value - The stratum value
7137 - points - The stratum points
7138 
7139   Level: beginner
7140 
7141 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7142 @*/
7143 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7144 {
7145   DMLabel        label;
7146   PetscErrorCode ierr;
7147 
7148   PetscFunctionBegin;
7149   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7150   PetscValidCharPointer(name, 2);
7151   PetscValidPointer(points, 4);
7152   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7153   if (!label) PetscFunctionReturn(0);
7154   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
7155   PetscFunctionReturn(0);
7156 }
7157 
7158 /*@C
7159   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
7160 
7161   Not Collective
7162 
7163   Input Parameters:
7164 + dm   - The DM object
7165 . name - The label name
7166 - value - The label value for this point
7167 
7168   Output Parameter:
7169 
7170   Level: beginner
7171 
7172 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7173 @*/
7174 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7175 {
7176   DMLabel        label;
7177   PetscErrorCode ierr;
7178 
7179   PetscFunctionBegin;
7180   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7181   PetscValidCharPointer(name, 2);
7182   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7183   if (!label) PetscFunctionReturn(0);
7184   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
7185   PetscFunctionReturn(0);
7186 }
7187 
7188 /*@
7189   DMGetNumLabels - Return the number of labels defined by the mesh
7190 
7191   Not Collective
7192 
7193   Input Parameter:
7194 . dm   - The DM object
7195 
7196   Output Parameter:
7197 . numLabels - the number of Labels
7198 
7199   Level: intermediate
7200 
7201 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7202 @*/
7203 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7204 {
7205   DMLabelLink next = dm->labels;
7206   PetscInt  n    = 0;
7207 
7208   PetscFunctionBegin;
7209   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7210   PetscValidIntPointer(numLabels, 2);
7211   while (next) {++n; next = next->next;}
7212   *numLabels = n;
7213   PetscFunctionReturn(0);
7214 }
7215 
7216 /*@C
7217   DMGetLabelName - Return the name of nth label
7218 
7219   Not Collective
7220 
7221   Input Parameters:
7222 + dm - The DM object
7223 - n  - the label number
7224 
7225   Output Parameter:
7226 . name - the label name
7227 
7228   Level: intermediate
7229 
7230 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7231 @*/
7232 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7233 {
7234   DMLabelLink    next = dm->labels;
7235   PetscInt       l    = 0;
7236   PetscErrorCode ierr;
7237 
7238   PetscFunctionBegin;
7239   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7240   PetscValidPointer(name, 3);
7241   while (next) {
7242     if (l == n) {
7243       ierr = PetscObjectGetName((PetscObject) next->label, name);CHKERRQ(ierr);
7244       PetscFunctionReturn(0);
7245     }
7246     ++l;
7247     next = next->next;
7248   }
7249   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7250 }
7251 
7252 /*@C
7253   DMHasLabel - Determine whether the mesh has a label of a given name
7254 
7255   Not Collective
7256 
7257   Input Parameters:
7258 + dm   - The DM object
7259 - name - The label name
7260 
7261   Output Parameter:
7262 . hasLabel - PETSC_TRUE if the label is present
7263 
7264   Level: intermediate
7265 
7266 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7267 @*/
7268 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7269 {
7270   DMLabelLink    next = dm->labels;
7271   const char    *lname;
7272   PetscErrorCode ierr;
7273 
7274   PetscFunctionBegin;
7275   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7276   PetscValidCharPointer(name, 2);
7277   PetscValidBoolPointer(hasLabel, 3);
7278   *hasLabel = PETSC_FALSE;
7279   while (next) {
7280     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7281     ierr = PetscStrcmp(name, lname, hasLabel);CHKERRQ(ierr);
7282     if (*hasLabel) break;
7283     next = next->next;
7284   }
7285   PetscFunctionReturn(0);
7286 }
7287 
7288 /*@C
7289   DMGetLabel - Return the label of a given name, or NULL
7290 
7291   Not Collective
7292 
7293   Input Parameters:
7294 + dm   - The DM object
7295 - name - The label name
7296 
7297   Output Parameter:
7298 . label - The DMLabel, or NULL if the label is absent
7299 
7300   Level: intermediate
7301 
7302 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7303 @*/
7304 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7305 {
7306   DMLabelLink    next = dm->labels;
7307   PetscBool      hasLabel;
7308   const char    *lname;
7309   PetscErrorCode ierr;
7310 
7311   PetscFunctionBegin;
7312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7313   PetscValidCharPointer(name, 2);
7314   PetscValidPointer(label, 3);
7315   *label = NULL;
7316   while (next) {
7317     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7318     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
7319     if (hasLabel) {
7320       *label = next->label;
7321       break;
7322     }
7323     next = next->next;
7324   }
7325   PetscFunctionReturn(0);
7326 }
7327 
7328 /*@C
7329   DMGetLabelByNum - Return the nth label
7330 
7331   Not Collective
7332 
7333   Input Parameters:
7334 + dm - The DM object
7335 - n  - the label number
7336 
7337   Output Parameter:
7338 . label - the label
7339 
7340   Level: intermediate
7341 
7342 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7343 @*/
7344 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7345 {
7346   DMLabelLink next = dm->labels;
7347   PetscInt    l    = 0;
7348 
7349   PetscFunctionBegin;
7350   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7351   PetscValidPointer(label, 3);
7352   while (next) {
7353     if (l == n) {
7354       *label = next->label;
7355       PetscFunctionReturn(0);
7356     }
7357     ++l;
7358     next = next->next;
7359   }
7360   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7361 }
7362 
7363 /*@C
7364   DMAddLabel - Add the label to this mesh
7365 
7366   Not Collective
7367 
7368   Input Parameters:
7369 + dm   - The DM object
7370 - label - The DMLabel
7371 
7372   Level: developer
7373 
7374 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7375 @*/
7376 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7377 {
7378   DMLabelLink    l, *p, tmpLabel;
7379   PetscBool      hasLabel;
7380   const char    *lname;
7381   PetscBool      flg;
7382   PetscErrorCode ierr;
7383 
7384   PetscFunctionBegin;
7385   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7386   ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
7387   ierr = DMHasLabel(dm, lname, &hasLabel);CHKERRQ(ierr);
7388   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7389   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
7390   tmpLabel->label  = label;
7391   tmpLabel->output = PETSC_TRUE;
7392   for (p=&dm->labels; (l=*p); p=&l->next) {}
7393   *p = tmpLabel;
7394   ierr = PetscObjectReference((PetscObject)label);CHKERRQ(ierr);
7395   ierr = PetscStrcmp(lname, "depth", &flg);CHKERRQ(ierr);
7396   if (flg) dm->depthLabel = label;
7397   ierr = PetscStrcmp(lname, "celltype", &flg);CHKERRQ(ierr);
7398   if (flg) dm->celltypeLabel = label;
7399   PetscFunctionReturn(0);
7400 }
7401 
7402 /*@C
7403   DMRemoveLabel - Remove the label given by name from this mesh
7404 
7405   Not Collective
7406 
7407   Input Parameters:
7408 + dm   - The DM object
7409 - name - The label name
7410 
7411   Output Parameter:
7412 . label - The DMLabel, or NULL if the label is absent
7413 
7414   Level: developer
7415 
7416   Notes:
7417   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7418   DMLabelDestroy() on the label.
7419 
7420   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7421   call DMLabelDestroy(). Instead, the label is returned and the user is
7422   responsible of calling DMLabelDestroy() at some point.
7423 
7424 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7425 @*/
7426 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7427 {
7428   DMLabelLink    link, *pnext;
7429   PetscBool      hasLabel;
7430   const char    *lname;
7431   PetscErrorCode ierr;
7432 
7433   PetscFunctionBegin;
7434   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7435   PetscValidCharPointer(name, 2);
7436   if (label) {
7437     PetscValidPointer(label, 3);
7438     *label = NULL;
7439   }
7440   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7441     ierr = PetscObjectGetName((PetscObject) link->label, &lname);CHKERRQ(ierr);
7442     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
7443     if (hasLabel) {
7444       *pnext = link->next; /* Remove from list */
7445       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
7446       if (hasLabel) dm->depthLabel = NULL;
7447       ierr = PetscStrcmp(name, "celltype", &hasLabel);CHKERRQ(ierr);
7448       if (hasLabel) dm->celltypeLabel = NULL;
7449       if (label) *label = link->label;
7450       else       {ierr = DMLabelDestroy(&link->label);CHKERRQ(ierr);}
7451       ierr = PetscFree(link);CHKERRQ(ierr);
7452       break;
7453     }
7454   }
7455   PetscFunctionReturn(0);
7456 }
7457 
7458 /*@
7459   DMRemoveLabelBySelf - Remove the label from this mesh
7460 
7461   Not Collective
7462 
7463   Input Parameters:
7464 + dm   - The DM object
7465 . label - (Optional) The DMLabel to be removed from the DM
7466 - failNotFound - Should it fail if the label is not found in the DM?
7467 
7468   Level: developer
7469 
7470   Notes:
7471   Only exactly the same instance is removed if found, name match is ignored.
7472   If the DM has an exclusive reference to the label, it gets destroyed and
7473   *label nullified.
7474 
7475 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7476 @*/
7477 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7478 {
7479   DMLabelLink    link, *pnext;
7480   PetscBool      hasLabel = PETSC_FALSE;
7481   PetscErrorCode ierr;
7482 
7483   PetscFunctionBegin;
7484   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7485   PetscValidPointer(label, 2);
7486   if (!*label && !failNotFound) PetscFunctionReturn(0);
7487   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7488   PetscValidLogicalCollectiveBool(dm,failNotFound,3);
7489   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7490     if (*label == link->label) {
7491       hasLabel = PETSC_TRUE;
7492       *pnext = link->next; /* Remove from list */
7493       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7494       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7495       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7496       ierr = DMLabelDestroy(&link->label);CHKERRQ(ierr);
7497       ierr = PetscFree(link);CHKERRQ(ierr);
7498       break;
7499     }
7500   }
7501   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7502   PetscFunctionReturn(0);
7503 }
7504 
7505 /*@C
7506   DMGetLabelOutput - Get the output flag for a given label
7507 
7508   Not Collective
7509 
7510   Input Parameters:
7511 + dm   - The DM object
7512 - name - The label name
7513 
7514   Output Parameter:
7515 . output - The flag for output
7516 
7517   Level: developer
7518 
7519 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7520 @*/
7521 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7522 {
7523   DMLabelLink    next = dm->labels;
7524   const char    *lname;
7525   PetscErrorCode ierr;
7526 
7527   PetscFunctionBegin;
7528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7529   PetscValidPointer(name, 2);
7530   PetscValidPointer(output, 3);
7531   while (next) {
7532     PetscBool flg;
7533 
7534     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7535     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7536     if (flg) {*output = next->output; PetscFunctionReturn(0);}
7537     next = next->next;
7538   }
7539   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7540 }
7541 
7542 /*@C
7543   DMSetLabelOutput - Set the output flag for a given label
7544 
7545   Not Collective
7546 
7547   Input Parameters:
7548 + dm     - The DM object
7549 . name   - The label name
7550 - output - The flag for output
7551 
7552   Level: developer
7553 
7554 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7555 @*/
7556 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7557 {
7558   DMLabelLink    next = dm->labels;
7559   const char    *lname;
7560   PetscErrorCode ierr;
7561 
7562   PetscFunctionBegin;
7563   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7564   PetscValidCharPointer(name, 2);
7565   while (next) {
7566     PetscBool flg;
7567 
7568     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7569     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7570     if (flg) {next->output = output; PetscFunctionReturn(0);}
7571     next = next->next;
7572   }
7573   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7574 }
7575 
7576 /*@
7577   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
7578 
7579   Collective on dmA
7580 
7581   Input Parameter:
7582 + dmA - The DM object with initial labels
7583 . dmB - The DM object with copied labels
7584 . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7585 - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
7586 
7587   Level: intermediate
7588 
7589   Note: This is typically used when interpolating or otherwise adding to a mesh
7590 
7591 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7592 @*/
7593 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7594 {
7595   DMLabel        label, labelNew;
7596   const char    *name;
7597   PetscBool      flg;
7598   DMLabelLink    link;
7599   PetscErrorCode ierr;
7600 
7601   PetscFunctionBegin;
7602   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7603   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7604   PetscValidLogicalCollectiveEnum(dmA, mode,3);
7605   PetscValidLogicalCollectiveBool(dmA, all, 4);
7606   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7607   if (dmA == dmB) PetscFunctionReturn(0);
7608   for (link=dmA->labels; link; link=link->next) {
7609     label=link->label;
7610     ierr = PetscObjectGetName((PetscObject)label, &name);CHKERRQ(ierr);
7611     if (!all) {
7612       ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
7613       if (flg) continue;
7614       ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
7615       if (flg) continue;
7616       ierr = PetscStrcmp(name, "celltype", &flg);CHKERRQ(ierr);
7617       if (flg) continue;
7618     }
7619     if (mode==PETSC_COPY_VALUES) {
7620       ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
7621     } else {
7622       labelNew = label;
7623     }
7624     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
7625     if (mode==PETSC_COPY_VALUES) {ierr = DMLabelDestroy(&labelNew);CHKERRQ(ierr);}
7626   }
7627   PetscFunctionReturn(0);
7628 }
7629 
7630 /*@
7631   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
7632 
7633   Input Parameter:
7634 . dm - The DM object
7635 
7636   Output Parameter:
7637 . cdm - The coarse DM
7638 
7639   Level: intermediate
7640 
7641 .seealso: DMSetCoarseDM()
7642 @*/
7643 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7644 {
7645   PetscFunctionBegin;
7646   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7647   PetscValidPointer(cdm, 2);
7648   *cdm = dm->coarseMesh;
7649   PetscFunctionReturn(0);
7650 }
7651 
7652 /*@
7653   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
7654 
7655   Input Parameters:
7656 + dm - The DM object
7657 - cdm - The coarse DM
7658 
7659   Level: intermediate
7660 
7661 .seealso: DMGetCoarseDM()
7662 @*/
7663 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7664 {
7665   PetscErrorCode ierr;
7666 
7667   PetscFunctionBegin;
7668   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7669   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7670   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
7671   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
7672   dm->coarseMesh = cdm;
7673   PetscFunctionReturn(0);
7674 }
7675 
7676 /*@
7677   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
7678 
7679   Input Parameter:
7680 . dm - The DM object
7681 
7682   Output Parameter:
7683 . fdm - The fine DM
7684 
7685   Level: intermediate
7686 
7687 .seealso: DMSetFineDM()
7688 @*/
7689 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7690 {
7691   PetscFunctionBegin;
7692   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7693   PetscValidPointer(fdm, 2);
7694   *fdm = dm->fineMesh;
7695   PetscFunctionReturn(0);
7696 }
7697 
7698 /*@
7699   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
7700 
7701   Input Parameters:
7702 + dm - The DM object
7703 - fdm - The fine DM
7704 
7705   Level: intermediate
7706 
7707 .seealso: DMGetFineDM()
7708 @*/
7709 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7710 {
7711   PetscErrorCode ierr;
7712 
7713   PetscFunctionBegin;
7714   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7715   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7716   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
7717   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
7718   dm->fineMesh = fdm;
7719   PetscFunctionReturn(0);
7720 }
7721 
7722 /*=== DMBoundary code ===*/
7723 
7724 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7725 {
7726   PetscInt       d;
7727   PetscErrorCode ierr;
7728 
7729   PetscFunctionBegin;
7730   for (d = 0; d < dm->Nds; ++d) {
7731     ierr = PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);CHKERRQ(ierr);
7732   }
7733   PetscFunctionReturn(0);
7734 }
7735 
7736 /*@C
7737   DMAddBoundary - Add a boundary condition to the model
7738 
7739   Collective on dm
7740 
7741   Input Parameters:
7742 + dm          - The DM, with a PetscDS that matches the problem being constrained
7743 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7744 . name        - The BC name
7745 . labelname   - The label defining constrained points
7746 . field       - The field to constrain
7747 . numcomps    - The number of constrained field components (0 will constrain all fields)
7748 . comps       - An array of constrained component numbers
7749 . bcFunc      - A pointwise function giving boundary values
7750 . numids      - The number of DMLabel ids for constrained points
7751 . ids         - An array of ids for constrained points
7752 - ctx         - An optional user context for bcFunc
7753 
7754   Options Database Keys:
7755 + -bc_<boundary name> <num> - Overrides the boundary ids
7756 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7757 
7758   Level: developer
7759 
7760 .seealso: DMGetBoundary()
7761 @*/
7762 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)
7763 {
7764   PetscDS        ds;
7765   PetscErrorCode ierr;
7766 
7767   PetscFunctionBegin;
7768   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7769   PetscValidLogicalCollectiveEnum(dm, type, 2);
7770   PetscValidLogicalCollectiveInt(dm, field, 5);
7771   PetscValidLogicalCollectiveInt(dm, numcomps, 6);
7772   PetscValidLogicalCollectiveInt(dm, numids, 9);
7773   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7774   ierr = DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);CHKERRQ(ierr);
7775   ierr = PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, numids, ids, ctx);CHKERRQ(ierr);
7776   PetscFunctionReturn(0);
7777 }
7778 
7779 /*@
7780   DMGetNumBoundary - Get the number of registered BC
7781 
7782   Input Parameters:
7783 . dm - The mesh object
7784 
7785   Output Parameters:
7786 . numBd - The number of BC
7787 
7788   Level: intermediate
7789 
7790 .seealso: DMAddBoundary(), DMGetBoundary()
7791 @*/
7792 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
7793 {
7794   PetscDS        ds;
7795   PetscErrorCode ierr;
7796 
7797   PetscFunctionBegin;
7798   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7799   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7800   ierr = PetscDSGetNumBoundary(ds, numBd);CHKERRQ(ierr);
7801   PetscFunctionReturn(0);
7802 }
7803 
7804 /*@C
7805   DMGetBoundary - Get a model boundary condition
7806 
7807   Input Parameters:
7808 + dm          - The mesh object
7809 - bd          - The BC number
7810 
7811   Output Parameters:
7812 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7813 . name        - The BC name
7814 . labelname   - The label defining constrained points
7815 . field       - The field to constrain
7816 . numcomps    - The number of constrained field components
7817 . comps       - An array of constrained component numbers
7818 . bcFunc      - A pointwise function giving boundary values
7819 . numids      - The number of DMLabel ids for constrained points
7820 . ids         - An array of ids for constrained points
7821 - ctx         - An optional user context for bcFunc
7822 
7823   Options Database Keys:
7824 + -bc_<boundary name> <num> - Overrides the boundary ids
7825 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7826 
7827   Level: developer
7828 
7829 .seealso: DMAddBoundary()
7830 @*/
7831 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)
7832 {
7833   PetscDS        ds;
7834   PetscErrorCode ierr;
7835 
7836   PetscFunctionBegin;
7837   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7838   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7839   ierr = PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, numids, ids, ctx);CHKERRQ(ierr);
7840   PetscFunctionReturn(0);
7841 }
7842 
7843 static PetscErrorCode DMPopulateBoundary(DM dm)
7844 {
7845   PetscDS        ds;
7846   DMBoundary    *lastnext;
7847   DSBoundary     dsbound;
7848   PetscErrorCode ierr;
7849 
7850   PetscFunctionBegin;
7851   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7852   dsbound = ds->boundary;
7853   if (dm->boundary) {
7854     DMBoundary next = dm->boundary;
7855 
7856     /* quick check to see if the PetscDS has changed */
7857     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
7858     /* the PetscDS has changed: tear down and rebuild */
7859     while (next) {
7860       DMBoundary b = next;
7861 
7862       next = b->next;
7863       ierr = PetscFree(b);CHKERRQ(ierr);
7864     }
7865     dm->boundary = NULL;
7866   }
7867 
7868   lastnext = &(dm->boundary);
7869   while (dsbound) {
7870     DMBoundary dmbound;
7871 
7872     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
7873     dmbound->dsboundary = dsbound;
7874     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
7875     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
7876     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7877     *lastnext = dmbound;
7878     lastnext = &(dmbound->next);
7879     dsbound = dsbound->next;
7880   }
7881   PetscFunctionReturn(0);
7882 }
7883 
7884 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7885 {
7886   DMBoundary     b;
7887   PetscErrorCode ierr;
7888 
7889   PetscFunctionBegin;
7890   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7891   PetscValidBoolPointer(isBd, 3);
7892   *isBd = PETSC_FALSE;
7893   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
7894   b = dm->boundary;
7895   while (b && !(*isBd)) {
7896     DMLabel    label = b->label;
7897     DSBoundary dsb = b->dsboundary;
7898 
7899     if (label) {
7900       PetscInt i;
7901 
7902       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
7903         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
7904       }
7905     }
7906     b = b->next;
7907   }
7908   PetscFunctionReturn(0);
7909 }
7910 
7911 /*@C
7912   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
7913 
7914   Collective on DM
7915 
7916   Input Parameters:
7917 + dm      - The DM
7918 . time    - The time
7919 . funcs   - The coordinate functions to evaluate, one per field
7920 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7921 - mode    - The insertion mode for values
7922 
7923   Output Parameter:
7924 . X - vector
7925 
7926    Calling sequence of func:
7927 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7928 
7929 +  dim - The spatial dimension
7930 .  x   - The coordinates
7931 .  Nf  - The number of fields
7932 .  u   - The output field values
7933 -  ctx - optional user-defined function context
7934 
7935   Level: developer
7936 
7937 .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7938 @*/
7939 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7940 {
7941   Vec            localX;
7942   PetscErrorCode ierr;
7943 
7944   PetscFunctionBegin;
7945   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7946   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
7947   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7948   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
7949   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
7950   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
7951   PetscFunctionReturn(0);
7952 }
7953 
7954 /*@C
7955   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
7956 
7957   Not collective
7958 
7959   Input Parameters:
7960 + dm      - The DM
7961 . time    - The time
7962 . funcs   - The coordinate functions to evaluate, one per field
7963 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7964 - mode    - The insertion mode for values
7965 
7966   Output Parameter:
7967 . localX - vector
7968 
7969    Calling sequence of func:
7970 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7971 
7972 +  dim - The spatial dimension
7973 .  x   - The coordinates
7974 .  Nf  - The number of fields
7975 .  u   - The output field values
7976 -  ctx - optional user-defined function context
7977 
7978   Level: developer
7979 
7980 .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
7981 @*/
7982 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7983 {
7984   PetscErrorCode ierr;
7985 
7986   PetscFunctionBegin;
7987   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7988   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
7989   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
7990   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7991   PetscFunctionReturn(0);
7992 }
7993 
7994 /*@C
7995   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.
7996 
7997   Collective on DM
7998 
7999   Input Parameters:
8000 + dm      - The DM
8001 . time    - The time
8002 . label   - The DMLabel selecting the portion of the mesh for projection
8003 . funcs   - The coordinate functions to evaluate, one per field
8004 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8005 - mode    - The insertion mode for values
8006 
8007   Output Parameter:
8008 . X - vector
8009 
8010    Calling sequence of func:
8011 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8012 
8013 +  dim - The spatial dimension
8014 .  x   - The coordinates
8015 .  Nf  - The number of fields
8016 .  u   - The output field values
8017 -  ctx - optional user-defined function context
8018 
8019   Level: developer
8020 
8021 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8022 @*/
8023 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)
8024 {
8025   Vec            localX;
8026   PetscErrorCode ierr;
8027 
8028   PetscFunctionBegin;
8029   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8030   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
8031   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
8032   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
8033   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
8034   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
8035   PetscFunctionReturn(0);
8036 }
8037 
8038 /*@C
8039   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.
8040 
8041   Not collective
8042 
8043   Input Parameters:
8044 + dm      - The DM
8045 . time    - The time
8046 . label   - The DMLabel selecting the portion of the mesh for projection
8047 . funcs   - The coordinate functions to evaluate, one per field
8048 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8049 - mode    - The insertion mode for values
8050 
8051   Output Parameter:
8052 . localX - vector
8053 
8054    Calling sequence of func:
8055 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8056 
8057 +  dim - The spatial dimension
8058 .  x   - The coordinates
8059 .  Nf  - The number of fields
8060 .  u   - The output field values
8061 -  ctx - optional user-defined function context
8062 
8063   Level: developer
8064 
8065 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8066 @*/
8067 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)
8068 {
8069   PetscErrorCode ierr;
8070 
8071   PetscFunctionBegin;
8072   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8073   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
8074   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8075   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
8076   PetscFunctionReturn(0);
8077 }
8078 
8079 /*@C
8080   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
8081 
8082   Not collective
8083 
8084   Input Parameters:
8085 + dm      - The DM
8086 . time    - The time
8087 . localU  - The input field vector
8088 . funcs   - The functions to evaluate, one per field
8089 - mode    - The insertion mode for values
8090 
8091   Output Parameter:
8092 . localX  - The output vector
8093 
8094    Calling sequence of func:
8095 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8096 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8097 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8098 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8099 
8100 +  dim          - The spatial dimension
8101 .  Nf           - The number of input fields
8102 .  NfAux        - The number of input auxiliary fields
8103 .  uOff         - The offset of each field in u[]
8104 .  uOff_x       - The offset of each field in u_x[]
8105 .  u            - The field values at this point in space
8106 .  u_t          - The field time derivative at this point in space (or NULL)
8107 .  u_x          - The field derivatives at this point in space
8108 .  aOff         - The offset of each auxiliary field in u[]
8109 .  aOff_x       - The offset of each auxiliary field in u_x[]
8110 .  a            - The auxiliary field values at this point in space
8111 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8112 .  a_x          - The auxiliary field derivatives at this point in space
8113 .  t            - The current time
8114 .  x            - The coordinates of this point
8115 .  numConstants - The number of constants
8116 .  constants    - The value of each constant
8117 -  f            - The value of the function at this point in space
8118 
8119   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.
8120   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
8121   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8122   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8123 
8124   Level: intermediate
8125 
8126 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8127 @*/
8128 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8129                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8130                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8131                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8132                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8133                                    InsertMode mode, Vec localX)
8134 {
8135   PetscErrorCode ierr;
8136 
8137   PetscFunctionBegin;
8138   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8139   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
8140   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
8141   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8142   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
8143   PetscFunctionReturn(0);
8144 }
8145 
8146 /*@C
8147   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.
8148 
8149   Not collective
8150 
8151   Input Parameters:
8152 + dm      - The DM
8153 . time    - The time
8154 . label   - The DMLabel marking the portion of the domain to output
8155 . numIds  - The number of label ids to use
8156 . ids     - The label ids to use for marking
8157 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8158 . comps   - The components to set in the output, or NULL for all components
8159 . localU  - The input field vector
8160 . funcs   - The functions to evaluate, one per field
8161 - mode    - The insertion mode for values
8162 
8163   Output Parameter:
8164 . localX  - The output vector
8165 
8166    Calling sequence of func:
8167 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8168 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8169 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8170 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8171 
8172 +  dim          - The spatial dimension
8173 .  Nf           - The number of input fields
8174 .  NfAux        - The number of input auxiliary fields
8175 .  uOff         - The offset of each field in u[]
8176 .  uOff_x       - The offset of each field in u_x[]
8177 .  u            - The field values at this point in space
8178 .  u_t          - The field time derivative at this point in space (or NULL)
8179 .  u_x          - The field derivatives at this point in space
8180 .  aOff         - The offset of each auxiliary field in u[]
8181 .  aOff_x       - The offset of each auxiliary field in u_x[]
8182 .  a            - The auxiliary field values at this point in space
8183 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8184 .  a_x          - The auxiliary field derivatives at this point in space
8185 .  t            - The current time
8186 .  x            - The coordinates of this point
8187 .  numConstants - The number of constants
8188 .  constants    - The value of each constant
8189 -  f            - The value of the function at this point in space
8190 
8191   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.
8192   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
8193   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8194   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8195 
8196   Level: intermediate
8197 
8198 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8199 @*/
8200 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8201                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8202                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8203                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8204                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8205                                         InsertMode mode, Vec localX)
8206 {
8207   PetscErrorCode ierr;
8208 
8209   PetscFunctionBegin;
8210   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8211   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
8212   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
8213   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8214   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
8215   PetscFunctionReturn(0);
8216 }
8217 
8218 /*@C
8219   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.
8220 
8221   Not collective
8222 
8223   Input Parameters:
8224 + dm      - The DM
8225 . time    - The time
8226 . label   - The DMLabel marking the portion of the domain boundary to output
8227 . numIds  - The number of label ids to use
8228 . ids     - The label ids to use for marking
8229 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8230 . comps   - The components to set in the output, or NULL for all components
8231 . localU  - The input field vector
8232 . funcs   - The functions to evaluate, one per field
8233 - mode    - The insertion mode for values
8234 
8235   Output Parameter:
8236 . localX  - The output vector
8237 
8238    Calling sequence of func:
8239 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8240 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8241 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8242 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8243 
8244 +  dim          - The spatial dimension
8245 .  Nf           - The number of input fields
8246 .  NfAux        - The number of input auxiliary fields
8247 .  uOff         - The offset of each field in u[]
8248 .  uOff_x       - The offset of each field in u_x[]
8249 .  u            - The field values at this point in space
8250 .  u_t          - The field time derivative at this point in space (or NULL)
8251 .  u_x          - The field derivatives at this point in space
8252 .  aOff         - The offset of each auxiliary field in u[]
8253 .  aOff_x       - The offset of each auxiliary field in u_x[]
8254 .  a            - The auxiliary field values at this point in space
8255 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8256 .  a_x          - The auxiliary field derivatives at this point in space
8257 .  t            - The current time
8258 .  x            - The coordinates of this point
8259 .  n            - The face normal
8260 .  numConstants - The number of constants
8261 .  constants    - The value of each constant
8262 -  f            - The value of the function at this point in space
8263 
8264   Note:
8265   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8266   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
8267   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8268   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8269 
8270   Level: intermediate
8271 
8272 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8273 @*/
8274 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8275                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8276                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8277                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8278                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8279                                           InsertMode mode, Vec localX)
8280 {
8281   PetscErrorCode ierr;
8282 
8283   PetscFunctionBegin;
8284   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8285   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
8286   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
8287   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
8288   ierr = (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
8289   PetscFunctionReturn(0);
8290 }
8291 
8292 /*@C
8293   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8294 
8295   Input Parameters:
8296 + dm    - The DM
8297 . time  - The time
8298 . funcs - The functions to evaluate for each field component
8299 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8300 - X     - The coefficient vector u_h, a global vector
8301 
8302   Output Parameter:
8303 . diff - The diff ||u - u_h||_2
8304 
8305   Level: developer
8306 
8307 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8308 @*/
8309 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8310 {
8311   PetscErrorCode ierr;
8312 
8313   PetscFunctionBegin;
8314   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8315   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8316   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8317   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
8318   PetscFunctionReturn(0);
8319 }
8320 
8321 /*@C
8322   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8323 
8324   Collective on dm
8325 
8326   Input Parameters:
8327 + dm    - The DM
8328 , time  - The time
8329 . funcs - The gradient functions to evaluate for each field component
8330 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8331 . X     - The coefficient vector u_h, a global vector
8332 - n     - The vector to project along
8333 
8334   Output Parameter:
8335 . diff - The diff ||(grad u - grad u_h) . n||_2
8336 
8337   Level: developer
8338 
8339 .seealso: DMProjectFunction(), DMComputeL2Diff()
8340 @*/
8341 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)
8342 {
8343   PetscErrorCode ierr;
8344 
8345   PetscFunctionBegin;
8346   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8347   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8348   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8349   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
8350   PetscFunctionReturn(0);
8351 }
8352 
8353 /*@C
8354   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8355 
8356   Collective on dm
8357 
8358   Input Parameters:
8359 + dm    - The DM
8360 . time  - The time
8361 . funcs - The functions to evaluate for each field component
8362 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8363 - X     - The coefficient vector u_h, a global vector
8364 
8365   Output Parameter:
8366 . diff - The array of differences, ||u^f - u^f_h||_2
8367 
8368   Level: developer
8369 
8370 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8371 @*/
8372 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8373 {
8374   PetscErrorCode ierr;
8375 
8376   PetscFunctionBegin;
8377   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8378   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8379   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
8380   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
8381   PetscFunctionReturn(0);
8382 }
8383 
8384 /*@C
8385   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
8386                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
8387 
8388   Collective on dm
8389 
8390   Input parameters:
8391 + dm - the pre-adaptation DM object
8392 - label - label with the flags
8393 
8394   Output parameters:
8395 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
8396 
8397   Level: intermediate
8398 
8399 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8400 @*/
8401 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8402 {
8403   PetscErrorCode ierr;
8404 
8405   PetscFunctionBegin;
8406   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8407   PetscValidPointer(label,2);
8408   PetscValidPointer(dmAdapt,3);
8409   *dmAdapt = NULL;
8410   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8411   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
8412   PetscFunctionReturn(0);
8413 }
8414 
8415 /*@C
8416   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
8417 
8418   Input Parameters:
8419 + dm - The DM object
8420 . metric - The metric to which the mesh is adapted, defined vertex-wise.
8421 - 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_".
8422 
8423   Output Parameter:
8424 . dmAdapt  - Pointer to the DM object containing the adapted mesh
8425 
8426   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
8427 
8428   Level: advanced
8429 
8430 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8431 @*/
8432 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8433 {
8434   PetscErrorCode ierr;
8435 
8436   PetscFunctionBegin;
8437   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8438   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
8439   if (bdLabel) PetscValidPointer(bdLabel, 3);
8440   PetscValidPointer(dmAdapt, 4);
8441   *dmAdapt = NULL;
8442   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8443   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
8444   PetscFunctionReturn(0);
8445 }
8446 
8447 /*@C
8448  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
8449 
8450  Not Collective
8451 
8452  Input Parameter:
8453 .  dm    - The DM
8454 
8455  Output Parameters:
8456 +  nranks - the number of neighbours
8457 -  ranks - the neighbors ranks
8458 
8459  Notes:
8460  Do not free the array, it is freed when the DM is destroyed.
8461 
8462  Level: beginner
8463 
8464  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
8465 @*/
8466 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
8467 {
8468   PetscErrorCode ierr;
8469 
8470   PetscFunctionBegin;
8471   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8472   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
8473   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
8474   PetscFunctionReturn(0);
8475 }
8476 
8477 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8478 
8479 /*
8480     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8481     This has be a different function because it requires DM which is not defined in the Mat library
8482 */
8483 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
8484 {
8485   PetscErrorCode ierr;
8486 
8487   PetscFunctionBegin;
8488   if (coloring->ctype == IS_COLORING_LOCAL) {
8489     Vec x1local;
8490     DM  dm;
8491     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
8492     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
8493     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
8494     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
8495     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
8496     x1   = x1local;
8497   }
8498   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
8499   if (coloring->ctype == IS_COLORING_LOCAL) {
8500     DM  dm;
8501     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
8502     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
8503   }
8504   PetscFunctionReturn(0);
8505 }
8506 
8507 /*@
8508     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
8509 
8510     Input Parameter:
8511 .    coloring - the MatFDColoring object
8512 
8513     Developer Notes:
8514     this routine exists because the PETSc Mat library does not know about the DM objects
8515 
8516     Level: advanced
8517 
8518 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
8519 @*/
8520 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
8521 {
8522   PetscFunctionBegin;
8523   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8524   PetscFunctionReturn(0);
8525 }
8526 
8527 /*@
8528     DMGetCompatibility - determine if two DMs are compatible
8529 
8530     Collective
8531 
8532     Input Parameters:
8533 +    dm1 - the first DM
8534 -    dm2 - the second DM
8535 
8536     Output Parameters:
8537 +    compatible - whether or not the two DMs are compatible
8538 -    set - whether or not the compatible value was set
8539 
8540     Notes:
8541     Two DMs are deemed compatible if they represent the same parallel decomposition
8542     of the same topology. This implies that the section (field data) on one
8543     "makes sense" with respect to the topology and parallel decomposition of the other.
8544     Loosely speaking, compatible DMs represent the same domain and parallel
8545     decomposition, but hold different data.
8546 
8547     Typically, one would confirm compatibility if intending to simultaneously iterate
8548     over a pair of vectors obtained from different DMs.
8549 
8550     For example, two DMDA objects are compatible if they have the same local
8551     and global sizes and the same stencil width. They can have different numbers
8552     of degrees of freedom per node. Thus, one could use the node numbering from
8553     either DM in bounds for a loop over vectors derived from either DM.
8554 
8555     Consider the operation of summing data living on a 2-dof DMDA to data living
8556     on a 1-dof DMDA, which should be compatible, as in the following snippet.
8557 .vb
8558   ...
8559   ierr = DMGetCompatibility(da1,da2,&compatible,&set);CHKERRQ(ierr);
8560   if (set && compatible)  {
8561     ierr = DMDAVecGetArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
8562     ierr = DMDAVecGetArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
8563     ierr = DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);CHKERRQ(ierr);
8564     for (j=y; j<y+n; ++j) {
8565       for (i=x; i<x+m, ++i) {
8566         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8567       }
8568     }
8569     ierr = DMDAVecRestoreArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
8570     ierr = DMDAVecRestoreArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
8571   } else {
8572     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8573   }
8574   ...
8575 .ve
8576 
8577     Checking compatibility might be expensive for a given implementation of DM,
8578     or might be impossible to unambiguously confirm or deny. For this reason,
8579     this function may decline to determine compatibility, and hence users should
8580     always check the "set" output parameter.
8581 
8582     A DM is always compatible with itself.
8583 
8584     In the current implementation, DMs which live on "unequal" communicators
8585     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8586     incompatible.
8587 
8588     This function is labeled "Collective," as information about all subdomains
8589     is required on each rank. However, in DM implementations which store all this
8590     information locally, this function may be merely "Logically Collective".
8591 
8592     Developer Notes:
8593     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
8594     iff B is compatible with A. Thus, this function checks the implementations
8595     of both dm and dmc (if they are of different types), attempting to determine
8596     compatibility. It is left to DM implementers to ensure that symmetry is
8597     preserved. The simplest way to do this is, when implementing type-specific
8598     logic for this function, is to check for existing logic in the implementation
8599     of other DM types and let *set = PETSC_FALSE if found.
8600 
8601     Level: advanced
8602 
8603 .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
8604 @*/
8605 
8606 PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
8607 {
8608   PetscErrorCode ierr;
8609   PetscMPIInt    compareResult;
8610   DMType         type,type2;
8611   PetscBool      sameType;
8612 
8613   PetscFunctionBegin;
8614   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
8615   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
8616 
8617   /* Declare a DM compatible with itself */
8618   if (dm1 == dm2) {
8619     *set = PETSC_TRUE;
8620     *compatible = PETSC_TRUE;
8621     PetscFunctionReturn(0);
8622   }
8623 
8624   /* Declare a DM incompatible with a DM that lives on an "unequal"
8625      communicator. Note that this does not preclude compatibility with
8626      DMs living on "congruent" or "similar" communicators, but this must be
8627      determined by the implementation-specific logic */
8628   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);CHKERRQ(ierr);
8629   if (compareResult == MPI_UNEQUAL) {
8630     *set = PETSC_TRUE;
8631     *compatible = PETSC_FALSE;
8632     PetscFunctionReturn(0);
8633   }
8634 
8635   /* Pass to the implementation-specific routine, if one exists. */
8636   if (dm1->ops->getcompatibility) {
8637     ierr = (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);CHKERRQ(ierr);
8638     if (*set) PetscFunctionReturn(0);
8639   }
8640 
8641   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8642      with an implementation of this function from dm2 */
8643   ierr = DMGetType(dm1,&type);CHKERRQ(ierr);
8644   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
8645   ierr = PetscStrcmp(type,type2,&sameType);CHKERRQ(ierr);
8646   if (!sameType && dm2->ops->getcompatibility) {
8647     ierr = (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set);CHKERRQ(ierr); /* Note argument order */
8648   } else {
8649     *set = PETSC_FALSE;
8650   }
8651   PetscFunctionReturn(0);
8652 }
8653 
8654 /*@C
8655   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
8656 
8657   Logically Collective on DM
8658 
8659   Input Parameters:
8660 + DM - the DM
8661 . f - the monitor function
8662 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8663 - monitordestroy - [optional] routine that frees monitor context (may be NULL)
8664 
8665   Options Database Keys:
8666 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
8667                             does not cancel those set via the options database.
8668 
8669   Notes:
8670   Several different monitoring routines may be set by calling
8671   DMMonitorSet() multiple times; all will be called in the
8672   order in which they were set.
8673 
8674   Fortran Notes:
8675   Only a single monitor function can be set for each DM object
8676 
8677   Level: intermediate
8678 
8679 .seealso: DMMonitorCancel()
8680 @*/
8681 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
8682 {
8683   PetscInt       m;
8684   PetscErrorCode ierr;
8685 
8686   PetscFunctionBegin;
8687   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8688   for (m = 0; m < dm->numbermonitors; ++m) {
8689     PetscBool identical;
8690 
8691     ierr = PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);CHKERRQ(ierr);
8692     if (identical) PetscFunctionReturn(0);
8693   }
8694   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8695   dm->monitor[dm->numbermonitors]          = f;
8696   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8697   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
8698   PetscFunctionReturn(0);
8699 }
8700 
8701 /*@
8702   DMMonitorCancel - Clears all the monitor functions for a DM object.
8703 
8704   Logically Collective on DM
8705 
8706   Input Parameter:
8707 . dm - the DM
8708 
8709   Options Database Key:
8710 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8711   into a code by calls to DMonitorSet(), but does not cancel those
8712   set via the options database
8713 
8714   Notes:
8715   There is no way to clear one specific monitor from a DM object.
8716 
8717   Level: intermediate
8718 
8719 .seealso: DMMonitorSet()
8720 @*/
8721 PetscErrorCode DMMonitorCancel(DM dm)
8722 {
8723   PetscErrorCode ierr;
8724   PetscInt       m;
8725 
8726   PetscFunctionBegin;
8727   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8728   for (m = 0; m < dm->numbermonitors; ++m) {
8729     if (dm->monitordestroy[m]) {ierr = (*dm->monitordestroy[m])(&dm->monitorcontext[m]);CHKERRQ(ierr);}
8730   }
8731   dm->numbermonitors = 0;
8732   PetscFunctionReturn(0);
8733 }
8734 
8735 /*@C
8736   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8737 
8738   Collective on DM
8739 
8740   Input Parameters:
8741 + dm   - DM object you wish to monitor
8742 . name - the monitor type one is seeking
8743 . help - message indicating what monitoring is done
8744 . manual - manual page for the monitor
8745 . monitor - the monitor function
8746 - 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
8747 
8748   Output Parameter:
8749 . flg - Flag set if the monitor was created
8750 
8751   Level: developer
8752 
8753 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
8754           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
8755           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
8756           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
8757           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
8758           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
8759           PetscOptionsFList(), PetscOptionsEList()
8760 @*/
8761 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8762 {
8763   PetscViewer       viewer;
8764   PetscViewerFormat format;
8765   PetscErrorCode    ierr;
8766 
8767   PetscFunctionBegin;
8768   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8769   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);CHKERRQ(ierr);
8770   if (*flg) {
8771     PetscViewerAndFormat *vf;
8772 
8773     ierr = PetscViewerAndFormatCreate(viewer, format, &vf);CHKERRQ(ierr);
8774     ierr = PetscObjectDereference((PetscObject) viewer);CHKERRQ(ierr);
8775     if (monitorsetup) {ierr = (*monitorsetup)(dm, vf);CHKERRQ(ierr);}
8776     ierr = DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);CHKERRQ(ierr);
8777   }
8778   PetscFunctionReturn(0);
8779 }
8780 
8781 /*@
8782    DMMonitor - runs the user provided monitor routines, if they exist
8783 
8784    Collective on DM
8785 
8786    Input Parameters:
8787 .  dm - The DM
8788 
8789    Level: developer
8790 
8791 .seealso: DMMonitorSet()
8792 @*/
8793 PetscErrorCode DMMonitor(DM dm)
8794 {
8795   PetscInt       m;
8796   PetscErrorCode ierr;
8797 
8798   PetscFunctionBegin;
8799   if (!dm) PetscFunctionReturn(0);
8800   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8801   for (m = 0; m < dm->numbermonitors; ++m) {
8802     ierr = (*dm->monitor[m])(dm, dm->monitorcontext[m]);CHKERRQ(ierr);
8803   }
8804   PetscFunctionReturn(0);
8805 }
8806