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