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