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