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