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