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