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