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