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