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