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