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