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