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