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