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