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