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