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