xref: /petsc/src/dm/interface/dm.c (revision bef158480efac06de457f7a665168877ab3c2fd7)
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", "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 - Get's 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 - Set's 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) SETERRQ(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type not supported");
6422   /* Make a fresh clone of the coordinate DM */
6423   ierr = DMClone(cdmOld, &cdmNew);CHKERRQ(ierr);
6424   ierr = DMSetField(cdmNew, 0, NULL, (PetscObject) disc);CHKERRQ(ierr);
6425   ierr = DMCreateDS(cdmNew);CHKERRQ(ierr);
6426   /* Project the coordinate vector from old to new space  */
6427   ierr = DMGetCoordinates(dm, &coordsOld);CHKERRQ(ierr);
6428   ierr = DMCreateGlobalVector(cdmNew, &coordsNew);CHKERRQ(ierr);
6429   ierr = DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);CHKERRQ(ierr);
6430   ierr = MatInterpolate(matInterp, coordsOld, coordsNew);CHKERRQ(ierr);
6431   ierr = MatDestroy(&matInterp);CHKERRQ(ierr);
6432   /* Set new coordinate structures */
6433   ierr = DMSetCoordinateField(dm, NULL);CHKERRQ(ierr);
6434   ierr = DMSetCoordinateDM(dm, cdmNew);CHKERRQ(ierr);
6435   ierr = DMSetCoordinates(dm, coordsNew);CHKERRQ(ierr);
6436   ierr = VecDestroy(&coordsNew);CHKERRQ(ierr);
6437   ierr = DMDestroy(&cdmNew);CHKERRQ(ierr);
6438   PetscFunctionReturn(0);
6439 }
6440 
6441 /*@C
6442   DMGetPeriodicity - Get the description of mesh periodicity
6443 
6444   Input Parameters:
6445 . dm      - The DM object
6446 
6447   Output Parameters:
6448 + per     - Whether the DM is periodic or not
6449 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6450 . L       - If we assume the mesh is a torus, this is the length of each coordinate
6451 - bd      - This describes the type of periodicity in each topological dimension
6452 
6453   Level: developer
6454 
6455 .seealso: DMGetPeriodicity()
6456 @*/
6457 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6458 {
6459   PetscFunctionBegin;
6460   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6461   if (per)     *per     = dm->periodic;
6462   if (L)       *L       = dm->L;
6463   if (maxCell) *maxCell = dm->maxCell;
6464   if (bd)      *bd      = dm->bdtype;
6465   PetscFunctionReturn(0);
6466 }
6467 
6468 /*@C
6469   DMSetPeriodicity - Set the description of mesh periodicity
6470 
6471   Input Parameters:
6472 + dm      - The DM object
6473 . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
6474 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6475 . L       - If we assume the mesh is a torus, this is the length of each coordinate
6476 - bd      - This describes the type of periodicity in each topological dimension
6477 
6478   Level: developer
6479 
6480 .seealso: DMGetPeriodicity()
6481 @*/
6482 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6483 {
6484   PetscInt       dim, d;
6485   PetscErrorCode ierr;
6486 
6487   PetscFunctionBegin;
6488   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6489   PetscValidLogicalCollectiveBool(dm,per,2);
6490   if (maxCell) {PetscValidRealPointer(maxCell,3);}
6491   if (L)       {PetscValidRealPointer(L,4);}
6492   if (bd)      {PetscValidPointer(bd,5);}
6493   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6494   if (maxCell) {
6495     if (!dm->maxCell) {ierr = PetscMalloc1(dim, &dm->maxCell);CHKERRQ(ierr);}
6496     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6497   }
6498   if (L) {
6499     if (!dm->L) {ierr = PetscMalloc1(dim, &dm->L);CHKERRQ(ierr);}
6500     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6501   }
6502   if (bd) {
6503     if (!dm->bdtype) {ierr = PetscMalloc1(dim, &dm->bdtype);CHKERRQ(ierr);}
6504     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6505   }
6506   dm->periodic = per;
6507   PetscFunctionReturn(0);
6508 }
6509 
6510 /*@
6511   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.
6512 
6513   Input Parameters:
6514 + dm     - The DM
6515 . in     - The input coordinate point (dim numbers)
6516 - endpoint - Include the endpoint L_i
6517 
6518   Output Parameter:
6519 . out - The localized coordinate point
6520 
6521   Level: developer
6522 
6523 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6524 @*/
6525 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6526 {
6527   PetscInt       dim, d;
6528   PetscErrorCode ierr;
6529 
6530   PetscFunctionBegin;
6531   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
6532   if (!dm->maxCell) {
6533     for (d = 0; d < dim; ++d) out[d] = in[d];
6534   } else {
6535     if (endpoint) {
6536       for (d = 0; d < dim; ++d) {
6537         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)) {
6538           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6539         } else {
6540           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6541         }
6542       }
6543     } else {
6544       for (d = 0; d < dim; ++d) {
6545         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6546       }
6547     }
6548   }
6549   PetscFunctionReturn(0);
6550 }
6551 
6552 /*
6553   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.
6554 
6555   Input Parameters:
6556 + dm     - The DM
6557 . dim    - The spatial dimension
6558 . anchor - The anchor point, the input point can be no more than maxCell away from it
6559 - in     - The input coordinate point (dim numbers)
6560 
6561   Output Parameter:
6562 . out - The localized coordinate point
6563 
6564   Level: developer
6565 
6566   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
6567 
6568 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6569 */
6570 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6571 {
6572   PetscInt d;
6573 
6574   PetscFunctionBegin;
6575   if (!dm->maxCell) {
6576     for (d = 0; d < dim; ++d) out[d] = in[d];
6577   } else {
6578     for (d = 0; d < dim; ++d) {
6579       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6580         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6581       } else {
6582         out[d] = in[d];
6583       }
6584     }
6585   }
6586   PetscFunctionReturn(0);
6587 }
6588 
6589 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6590 {
6591   PetscInt d;
6592 
6593   PetscFunctionBegin;
6594   if (!dm->maxCell) {
6595     for (d = 0; d < dim; ++d) out[d] = in[d];
6596   } else {
6597     for (d = 0; d < dim; ++d) {
6598       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6599         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6600       } else {
6601         out[d] = in[d];
6602       }
6603     }
6604   }
6605   PetscFunctionReturn(0);
6606 }
6607 
6608 /*
6609   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.
6610 
6611   Input Parameters:
6612 + dm     - The DM
6613 . dim    - The spatial dimension
6614 . anchor - The anchor point, the input point can be no more than maxCell away from it
6615 . in     - The input coordinate delta (dim numbers)
6616 - out    - The input coordinate point (dim numbers)
6617 
6618   Output Parameter:
6619 . out    - The localized coordinate in + out
6620 
6621   Level: developer
6622 
6623   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
6624 
6625 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6626 */
6627 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6628 {
6629   PetscInt d;
6630 
6631   PetscFunctionBegin;
6632   if (!dm->maxCell) {
6633     for (d = 0; d < dim; ++d) out[d] += in[d];
6634   } else {
6635     for (d = 0; d < dim; ++d) {
6636       const PetscReal maxC = dm->maxCell[d];
6637 
6638       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6639         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6640 
6641         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6642           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]));
6643         out[d] += newCoord;
6644       } else {
6645         out[d] += in[d];
6646       }
6647     }
6648   }
6649   PetscFunctionReturn(0);
6650 }
6651 
6652 /*@
6653   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6654 
6655   Not collective
6656 
6657   Input Parameter:
6658 . dm - The DM
6659 
6660   Output Parameter:
6661   areLocalized - True if localized
6662 
6663   Level: developer
6664 
6665 .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6666 @*/
6667 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6668 {
6669   DM             cdm;
6670   PetscSection   coordSection;
6671   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6672   PetscBool      isPlex, alreadyLocalized;
6673   PetscErrorCode ierr;
6674 
6675   PetscFunctionBegin;
6676   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6677   PetscValidBoolPointer(areLocalized, 2);
6678   *areLocalized = PETSC_FALSE;
6679 
6680   /* We need some generic way of refering to cells/vertices */
6681   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6682   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
6683   if (!isPlex) PetscFunctionReturn(0);
6684 
6685   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6686   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6687   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
6688   alreadyLocalized = PETSC_FALSE;
6689   for (c = cStart; c < cEnd; ++c) {
6690     if (c < sStart || c >= sEnd) continue;
6691     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
6692     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6693   }
6694   *areLocalized = alreadyLocalized;
6695   PetscFunctionReturn(0);
6696 }
6697 
6698 /*@
6699   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6700 
6701   Collective on dm
6702 
6703   Input Parameter:
6704 . dm - The DM
6705 
6706   Output Parameter:
6707   areLocalized - True if localized
6708 
6709   Level: developer
6710 
6711 .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6712 @*/
6713 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6714 {
6715   PetscBool      localized;
6716   PetscErrorCode ierr;
6717 
6718   PetscFunctionBegin;
6719   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6720   PetscValidBoolPointer(areLocalized, 2);
6721   ierr = DMGetCoordinatesLocalizedLocal(dm,&localized);CHKERRQ(ierr);
6722   ierr = MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6723   PetscFunctionReturn(0);
6724 }
6725 
6726 /*@
6727   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
6728 
6729   Collective on dm
6730 
6731   Input Parameter:
6732 . dm - The DM
6733 
6734   Level: developer
6735 
6736 .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6737 @*/
6738 PetscErrorCode DMLocalizeCoordinates(DM dm)
6739 {
6740   DM             cdm;
6741   PetscSection   coordSection, cSection;
6742   Vec            coordinates,  cVec;
6743   PetscScalar   *coords, *coords2, *anchor, *localized;
6744   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6745   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6746   PetscInt       maxHeight = 0, h;
6747   PetscInt       *pStart = NULL, *pEnd = NULL;
6748   PetscErrorCode ierr;
6749 
6750   PetscFunctionBegin;
6751   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6752   if (!dm->periodic) PetscFunctionReturn(0);
6753   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
6754   if (alreadyLocalized) PetscFunctionReturn(0);
6755 
6756   /* We need some generic way of refering to cells/vertices */
6757   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6758   {
6759     PetscBool isplex;
6760 
6761     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
6762     if (isplex) {
6763       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6764       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
6765       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6766       pEnd = &pStart[maxHeight + 1];
6767       newStart = vStart;
6768       newEnd   = vEnd;
6769       for (h = 0; h <= maxHeight; h++) {
6770         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
6771         newStart = PetscMin(newStart,pStart[h]);
6772         newEnd   = PetscMax(newEnd,pEnd[h]);
6773       }
6774     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6775   }
6776   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6777   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6778   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6779   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6780   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
6781 
6782   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
6783   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
6784   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
6785   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
6786   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
6787 
6788   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6789   localized = &anchor[bs];
6790   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6791   for (h = 0; h <= maxHeight; h++) {
6792     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6793 
6794     for (c = cStart; c < cEnd; ++c) {
6795       PetscScalar *cellCoords = NULL;
6796       PetscInt     b;
6797 
6798       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6799       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6800       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6801       for (d = 0; d < dof/bs; ++d) {
6802         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
6803         for (b = 0; b < bs; b++) {
6804           if (cellCoords[d*bs + b] != localized[b]) break;
6805         }
6806         if (b < bs) break;
6807       }
6808       if (d < dof/bs) {
6809         if (c >= sStart && c < sEnd) {
6810           PetscInt cdof;
6811 
6812           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6813           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6814         }
6815         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
6816         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
6817       }
6818       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6819     }
6820   }
6821   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6822   if (alreadyLocalizedGlobal) {
6823     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6824     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6825     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6826     PetscFunctionReturn(0);
6827   }
6828   for (v = vStart; v < vEnd; ++v) {
6829     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6830     ierr = PetscSectionSetDof(cSection, v, dof);CHKERRQ(ierr);
6831     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
6832   }
6833   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
6834   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
6835   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
6836   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
6837   ierr = VecSetBlockSize(cVec, bs);CHKERRQ(ierr);
6838   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
6839   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
6840   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6841   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
6842   for (v = vStart; v < vEnd; ++v) {
6843     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6844     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6845     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
6846     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6847   }
6848   for (h = 0; h <= maxHeight; h++) {
6849     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6850 
6851     for (c = cStart; c < cEnd; ++c) {
6852       PetscScalar *cellCoords = NULL;
6853       PetscInt     b, cdof;
6854 
6855       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
6856       if (!cdof) continue;
6857       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6858       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
6859       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6860       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
6861       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6862     }
6863   }
6864   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6865   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6866   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6867   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
6868   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
6869   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
6870   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
6871   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6872   PetscFunctionReturn(0);
6873 }
6874 
6875 /*@
6876   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6877 
6878   Collective on v (see explanation below)
6879 
6880   Input Parameters:
6881 + dm - The DM
6882 . v - The Vec of points
6883 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6884 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
6885 
6886   Output Parameter:
6887 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6888 - cells - The PetscSF containing the ranks and local indices of the containing points.
6889 
6890 
6891   Level: developer
6892 
6893   Notes:
6894   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6895   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
6896 
6897   If *cellSF is NULL on input, a PetscSF will be created.
6898   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
6899 
6900   An array that maps each point to its containing cell can be obtained with
6901 
6902 $    const PetscSFNode *cells;
6903 $    PetscInt           nFound;
6904 $    const PetscInt    *found;
6905 $
6906 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
6907 
6908   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6909   the index of the cell in its rank's local numbering.
6910 
6911 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6912 @*/
6913 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6914 {
6915   PetscErrorCode ierr;
6916 
6917   PetscFunctionBegin;
6918   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6919   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
6920   PetscValidPointer(cellSF,4);
6921   if (*cellSF) {
6922     PetscMPIInt result;
6923 
6924     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
6925     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
6926     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6927   } else {
6928     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
6929   }
6930   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6931   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6932   ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
6933   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6934   PetscFunctionReturn(0);
6935 }
6936 
6937 /*@
6938   DMGetOutputDM - Retrieve the DM associated with the layout for output
6939 
6940   Collective on dm
6941 
6942   Input Parameter:
6943 . dm - The original DM
6944 
6945   Output Parameter:
6946 . odm - The DM which provides the layout for output
6947 
6948   Level: intermediate
6949 
6950 .seealso: VecView(), DMGetGlobalSection()
6951 @*/
6952 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6953 {
6954   PetscSection   section;
6955   PetscBool      hasConstraints, ghasConstraints;
6956   PetscErrorCode ierr;
6957 
6958   PetscFunctionBegin;
6959   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6960   PetscValidPointer(odm,2);
6961   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
6962   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
6963   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
6964   if (!ghasConstraints) {
6965     *odm = dm;
6966     PetscFunctionReturn(0);
6967   }
6968   if (!dm->dmBC) {
6969     PetscSection newSection, gsection;
6970     PetscSF      sf;
6971 
6972     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
6973     ierr = DMCopyDisc(dm, dm->dmBC);CHKERRQ(ierr);
6974     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
6975     ierr = DMSetLocalSection(dm->dmBC, newSection);CHKERRQ(ierr);
6976     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
6977     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
6978     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
6979     ierr = DMSetGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
6980     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
6981   }
6982   *odm = dm->dmBC;
6983   PetscFunctionReturn(0);
6984 }
6985 
6986 /*@
6987   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6988 
6989   Input Parameter:
6990 . dm - The original DM
6991 
6992   Output Parameters:
6993 + num - The output sequence number
6994 - val - The output sequence value
6995 
6996   Level: intermediate
6997 
6998   Note: This is intended for output that should appear in sequence, for instance
6999   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7000 
7001 .seealso: VecView()
7002 @*/
7003 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7004 {
7005   PetscFunctionBegin;
7006   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7007   if (num) {PetscValidIntPointer(num,2); *num = dm->outputSequenceNum;}
7008   if (val) {PetscValidRealPointer(val,3);*val = dm->outputSequenceVal;}
7009   PetscFunctionReturn(0);
7010 }
7011 
7012 /*@
7013   DMSetOutputSequenceNumber - Set the sequence number/value for output
7014 
7015   Input Parameters:
7016 + dm - The original DM
7017 . num - The output sequence number
7018 - val - The output sequence value
7019 
7020   Level: intermediate
7021 
7022   Note: This is intended for output that should appear in sequence, for instance
7023   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7024 
7025 .seealso: VecView()
7026 @*/
7027 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7028 {
7029   PetscFunctionBegin;
7030   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7031   dm->outputSequenceNum = num;
7032   dm->outputSequenceVal = val;
7033   PetscFunctionReturn(0);
7034 }
7035 
7036 /*@C
7037   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
7038 
7039   Input Parameters:
7040 + dm   - The original DM
7041 . name - The sequence name
7042 - num  - The output sequence number
7043 
7044   Output Parameter:
7045 . val  - The output sequence value
7046 
7047   Level: intermediate
7048 
7049   Note: This is intended for output that should appear in sequence, for instance
7050   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7051 
7052 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7053 @*/
7054 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7055 {
7056   PetscBool      ishdf5;
7057   PetscErrorCode ierr;
7058 
7059   PetscFunctionBegin;
7060   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7061   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
7062   PetscValidRealPointer(val,4);
7063   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
7064   if (ishdf5) {
7065 #if defined(PETSC_HAVE_HDF5)
7066     PetscScalar value;
7067 
7068     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
7069     *val = PetscRealPart(value);
7070 #endif
7071   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7072   PetscFunctionReturn(0);
7073 }
7074 
7075 /*@
7076   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
7077 
7078   Not collective
7079 
7080   Input Parameter:
7081 . dm - The DM
7082 
7083   Output Parameter:
7084 . useNatural - The flag to build the mapping to a natural order during distribution
7085 
7086   Level: beginner
7087 
7088 .seealso: DMSetUseNatural(), DMCreate()
7089 @*/
7090 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7091 {
7092   PetscFunctionBegin;
7093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7094   PetscValidBoolPointer(useNatural, 2);
7095   *useNatural = dm->useNatural;
7096   PetscFunctionReturn(0);
7097 }
7098 
7099 /*@
7100   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
7101 
7102   Collective on dm
7103 
7104   Input Parameters:
7105 + dm - The DM
7106 - useNatural - The flag to build the mapping to a natural order during distribution
7107 
7108   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
7109 
7110   Level: beginner
7111 
7112 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7113 @*/
7114 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7115 {
7116   PetscFunctionBegin;
7117   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7118   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
7119   dm->useNatural = useNatural;
7120   PetscFunctionReturn(0);
7121 }
7122 
7123 
7124 /*@C
7125   DMCreateLabel - Create a label of the given name if it does not already exist
7126 
7127   Not Collective
7128 
7129   Input Parameters:
7130 + dm   - The DM object
7131 - name - The label name
7132 
7133   Level: intermediate
7134 
7135 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7136 @*/
7137 PetscErrorCode DMCreateLabel(DM dm, const char name[])
7138 {
7139   PetscBool      flg;
7140   DMLabel        label;
7141   PetscErrorCode ierr;
7142 
7143   PetscFunctionBegin;
7144   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7145   PetscValidCharPointer(name, 2);
7146   ierr = DMHasLabel(dm, name, &flg);CHKERRQ(ierr);
7147   if (!flg) {
7148     ierr = DMLabelCreate(PETSC_COMM_SELF, name, &label);CHKERRQ(ierr);
7149     ierr = DMAddLabel(dm, label);CHKERRQ(ierr);
7150     ierr = DMLabelDestroy(&label);CHKERRQ(ierr);
7151   }
7152   PetscFunctionReturn(0);
7153 }
7154 
7155 /*@C
7156   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
7157 
7158   Not Collective
7159 
7160   Input Parameters:
7161 + dm   - The DM object
7162 . name - The label name
7163 - point - The mesh point
7164 
7165   Output Parameter:
7166 . value - The label value for this point, or -1 if the point is not in the label
7167 
7168   Level: beginner
7169 
7170 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7171 @*/
7172 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7173 {
7174   DMLabel        label;
7175   PetscErrorCode ierr;
7176 
7177   PetscFunctionBegin;
7178   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7179   PetscValidCharPointer(name, 2);
7180   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7181   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7182   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
7183   PetscFunctionReturn(0);
7184 }
7185 
7186 /*@C
7187   DMSetLabelValue - Add a point to a Sieve Label with given value
7188 
7189   Not Collective
7190 
7191   Input Parameters:
7192 + dm   - The DM object
7193 . name - The label name
7194 . point - The mesh point
7195 - value - The label value for this point
7196 
7197   Output Parameter:
7198 
7199   Level: beginner
7200 
7201 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7202 @*/
7203 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7204 {
7205   DMLabel        label;
7206   PetscErrorCode ierr;
7207 
7208   PetscFunctionBegin;
7209   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7210   PetscValidCharPointer(name, 2);
7211   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7212   if (!label) {
7213     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
7214     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7215   }
7216   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
7217   PetscFunctionReturn(0);
7218 }
7219 
7220 /*@C
7221   DMClearLabelValue - Remove a point from 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: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7236 @*/
7237 PetscErrorCode DMClearLabelValue(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) PetscFunctionReturn(0);
7247   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
7248   PetscFunctionReturn(0);
7249 }
7250 
7251 /*@C
7252   DMGetLabelSize - Get the number of different integer ids in a Label
7253 
7254   Not Collective
7255 
7256   Input Parameters:
7257 + dm   - The DM object
7258 - name - The label name
7259 
7260   Output Parameter:
7261 . size - The number of different integer ids, or 0 if the label does not exist
7262 
7263   Level: beginner
7264 
7265 .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7266 @*/
7267 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7268 {
7269   DMLabel        label;
7270   PetscErrorCode ierr;
7271 
7272   PetscFunctionBegin;
7273   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7274   PetscValidCharPointer(name, 2);
7275   PetscValidIntPointer(size, 3);
7276   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7277   *size = 0;
7278   if (!label) PetscFunctionReturn(0);
7279   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
7280   PetscFunctionReturn(0);
7281 }
7282 
7283 /*@C
7284   DMGetLabelIdIS - Get the integer ids in a label
7285 
7286   Not Collective
7287 
7288   Input Parameters:
7289 + mesh - The DM object
7290 - name - The label name
7291 
7292   Output Parameter:
7293 . ids - The integer ids, or NULL if the label does not exist
7294 
7295   Level: beginner
7296 
7297 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7298 @*/
7299 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7300 {
7301   DMLabel        label;
7302   PetscErrorCode ierr;
7303 
7304   PetscFunctionBegin;
7305   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7306   PetscValidCharPointer(name, 2);
7307   PetscValidPointer(ids, 3);
7308   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7309   *ids = NULL;
7310  if (label) {
7311     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
7312   } else {
7313     /* returning an empty IS */
7314     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
7315   }
7316   PetscFunctionReturn(0);
7317 }
7318 
7319 /*@C
7320   DMGetStratumSize - Get the number of points in a label stratum
7321 
7322   Not Collective
7323 
7324   Input Parameters:
7325 + dm - The DM object
7326 . name - The label name
7327 - value - The stratum value
7328 
7329   Output Parameter:
7330 . size - The stratum size
7331 
7332   Level: beginner
7333 
7334 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7335 @*/
7336 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7337 {
7338   DMLabel        label;
7339   PetscErrorCode ierr;
7340 
7341   PetscFunctionBegin;
7342   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7343   PetscValidCharPointer(name, 2);
7344   PetscValidIntPointer(size, 4);
7345   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7346   *size = 0;
7347   if (!label) PetscFunctionReturn(0);
7348   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
7349   PetscFunctionReturn(0);
7350 }
7351 
7352 /*@C
7353   DMGetStratumIS - Get the points in a label stratum
7354 
7355   Not Collective
7356 
7357   Input Parameters:
7358 + dm - The DM object
7359 . name - The label name
7360 - value - The stratum value
7361 
7362   Output Parameter:
7363 . points - The stratum points, or NULL if the label does not exist or does not have that value
7364 
7365   Level: beginner
7366 
7367 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7368 @*/
7369 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7370 {
7371   DMLabel        label;
7372   PetscErrorCode ierr;
7373 
7374   PetscFunctionBegin;
7375   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7376   PetscValidCharPointer(name, 2);
7377   PetscValidPointer(points, 4);
7378   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7379   *points = NULL;
7380   if (!label) PetscFunctionReturn(0);
7381   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
7382   PetscFunctionReturn(0);
7383 }
7384 
7385 /*@C
7386   DMSetStratumIS - Set the points in a label stratum
7387 
7388   Not Collective
7389 
7390   Input Parameters:
7391 + dm - The DM object
7392 . name - The label name
7393 . value - The stratum value
7394 - points - The stratum points
7395 
7396   Level: beginner
7397 
7398 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7399 @*/
7400 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7401 {
7402   DMLabel        label;
7403   PetscErrorCode ierr;
7404 
7405   PetscFunctionBegin;
7406   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7407   PetscValidCharPointer(name, 2);
7408   PetscValidPointer(points, 4);
7409   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7410   if (!label) PetscFunctionReturn(0);
7411   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
7412   PetscFunctionReturn(0);
7413 }
7414 
7415 /*@C
7416   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
7417 
7418   Not Collective
7419 
7420   Input Parameters:
7421 + dm   - The DM object
7422 . name - The label name
7423 - value - The label value for this point
7424 
7425   Output Parameter:
7426 
7427   Level: beginner
7428 
7429 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7430 @*/
7431 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7432 {
7433   DMLabel        label;
7434   PetscErrorCode ierr;
7435 
7436   PetscFunctionBegin;
7437   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7438   PetscValidCharPointer(name, 2);
7439   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7440   if (!label) PetscFunctionReturn(0);
7441   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
7442   PetscFunctionReturn(0);
7443 }
7444 
7445 /*@
7446   DMGetNumLabels - Return the number of labels defined by the mesh
7447 
7448   Not Collective
7449 
7450   Input Parameter:
7451 . dm   - The DM object
7452 
7453   Output Parameter:
7454 . numLabels - the number of Labels
7455 
7456   Level: intermediate
7457 
7458 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7459 @*/
7460 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7461 {
7462   DMLabelLink next = dm->labels;
7463   PetscInt  n    = 0;
7464 
7465   PetscFunctionBegin;
7466   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7467   PetscValidIntPointer(numLabels, 2);
7468   while (next) {++n; next = next->next;}
7469   *numLabels = n;
7470   PetscFunctionReturn(0);
7471 }
7472 
7473 /*@C
7474   DMGetLabelName - Return the name of nth label
7475 
7476   Not Collective
7477 
7478   Input Parameters:
7479 + dm - The DM object
7480 - n  - the label number
7481 
7482   Output Parameter:
7483 . name - the label name
7484 
7485   Level: intermediate
7486 
7487 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7488 @*/
7489 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7490 {
7491   DMLabelLink    next = dm->labels;
7492   PetscInt       l    = 0;
7493   PetscErrorCode ierr;
7494 
7495   PetscFunctionBegin;
7496   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7497   PetscValidPointer(name, 3);
7498   while (next) {
7499     if (l == n) {
7500       ierr = PetscObjectGetName((PetscObject) next->label, name);CHKERRQ(ierr);
7501       PetscFunctionReturn(0);
7502     }
7503     ++l;
7504     next = next->next;
7505   }
7506   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7507 }
7508 
7509 /*@C
7510   DMHasLabel - Determine whether the mesh has a label of a given name
7511 
7512   Not Collective
7513 
7514   Input Parameters:
7515 + dm   - The DM object
7516 - name - The label name
7517 
7518   Output Parameter:
7519 . hasLabel - PETSC_TRUE if the label is present
7520 
7521   Level: intermediate
7522 
7523 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7524 @*/
7525 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7526 {
7527   DMLabelLink    next = dm->labels;
7528   const char    *lname;
7529   PetscErrorCode ierr;
7530 
7531   PetscFunctionBegin;
7532   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7533   PetscValidCharPointer(name, 2);
7534   PetscValidBoolPointer(hasLabel, 3);
7535   *hasLabel = PETSC_FALSE;
7536   while (next) {
7537     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7538     ierr = PetscStrcmp(name, lname, hasLabel);CHKERRQ(ierr);
7539     if (*hasLabel) break;
7540     next = next->next;
7541   }
7542   PetscFunctionReturn(0);
7543 }
7544 
7545 /*@C
7546   DMGetLabel - Return the label of a given name, or NULL
7547 
7548   Not Collective
7549 
7550   Input Parameters:
7551 + dm   - The DM object
7552 - name - The label name
7553 
7554   Output Parameter:
7555 . label - The DMLabel, or NULL if the label is absent
7556 
7557   Level: intermediate
7558 
7559 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7560 @*/
7561 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7562 {
7563   DMLabelLink    next = dm->labels;
7564   PetscBool      hasLabel;
7565   const char    *lname;
7566   PetscErrorCode ierr;
7567 
7568   PetscFunctionBegin;
7569   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7570   PetscValidCharPointer(name, 2);
7571   PetscValidPointer(label, 3);
7572   *label = NULL;
7573   while (next) {
7574     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7575     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
7576     if (hasLabel) {
7577       *label = next->label;
7578       break;
7579     }
7580     next = next->next;
7581   }
7582   PetscFunctionReturn(0);
7583 }
7584 
7585 /*@C
7586   DMGetLabelByNum - Return the nth label
7587 
7588   Not Collective
7589 
7590   Input Parameters:
7591 + dm - The DM object
7592 - n  - the label number
7593 
7594   Output Parameter:
7595 . label - the label
7596 
7597   Level: intermediate
7598 
7599 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7600 @*/
7601 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7602 {
7603   DMLabelLink next = dm->labels;
7604   PetscInt    l    = 0;
7605 
7606   PetscFunctionBegin;
7607   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7608   PetscValidPointer(label, 3);
7609   while (next) {
7610     if (l == n) {
7611       *label = next->label;
7612       PetscFunctionReturn(0);
7613     }
7614     ++l;
7615     next = next->next;
7616   }
7617   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7618 }
7619 
7620 /*@C
7621   DMAddLabel - Add the label to this mesh
7622 
7623   Not Collective
7624 
7625   Input Parameters:
7626 + dm   - The DM object
7627 - label - The DMLabel
7628 
7629   Level: developer
7630 
7631 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7632 @*/
7633 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7634 {
7635   DMLabelLink    l, *p, tmpLabel;
7636   PetscBool      hasLabel;
7637   const char    *lname;
7638   PetscBool      flg;
7639   PetscErrorCode ierr;
7640 
7641   PetscFunctionBegin;
7642   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7643   ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
7644   ierr = DMHasLabel(dm, lname, &hasLabel);CHKERRQ(ierr);
7645   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7646   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
7647   tmpLabel->label  = label;
7648   tmpLabel->output = PETSC_TRUE;
7649   for (p=&dm->labels; (l=*p); p=&l->next) {}
7650   *p = tmpLabel;
7651   ierr = PetscObjectReference((PetscObject)label);CHKERRQ(ierr);
7652   ierr = PetscStrcmp(lname, "depth", &flg);CHKERRQ(ierr);
7653   if (flg) dm->depthLabel = label;
7654   ierr = PetscStrcmp(lname, "celltype", &flg);CHKERRQ(ierr);
7655   if (flg) dm->celltypeLabel = label;
7656   PetscFunctionReturn(0);
7657 }
7658 
7659 /*@C
7660   DMRemoveLabel - Remove the label given by name from this mesh
7661 
7662   Not Collective
7663 
7664   Input Parameters:
7665 + dm   - The DM object
7666 - name - The label name
7667 
7668   Output Parameter:
7669 . label - The DMLabel, or NULL if the label is absent
7670 
7671   Level: developer
7672 
7673   Notes:
7674   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7675   DMLabelDestroy() on the label.
7676 
7677   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7678   call DMLabelDestroy(). Instead, the label is returned and the user is
7679   responsible of calling DMLabelDestroy() at some point.
7680 
7681 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7682 @*/
7683 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7684 {
7685   DMLabelLink    link, *pnext;
7686   PetscBool      hasLabel;
7687   const char    *lname;
7688   PetscErrorCode ierr;
7689 
7690   PetscFunctionBegin;
7691   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7692   PetscValidCharPointer(name, 2);
7693   if (label) {
7694     PetscValidPointer(label, 3);
7695     *label = NULL;
7696   }
7697   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7698     ierr = PetscObjectGetName((PetscObject) link->label, &lname);CHKERRQ(ierr);
7699     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
7700     if (hasLabel) {
7701       *pnext = link->next; /* Remove from list */
7702       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
7703       if (hasLabel) dm->depthLabel = NULL;
7704       ierr = PetscStrcmp(name, "celltype", &hasLabel);CHKERRQ(ierr);
7705       if (hasLabel) dm->celltypeLabel = NULL;
7706       if (label) *label = link->label;
7707       else       {ierr = DMLabelDestroy(&link->label);CHKERRQ(ierr);}
7708       ierr = PetscFree(link);CHKERRQ(ierr);
7709       break;
7710     }
7711   }
7712   PetscFunctionReturn(0);
7713 }
7714 
7715 /*@
7716   DMRemoveLabelBySelf - Remove the label from this mesh
7717 
7718   Not Collective
7719 
7720   Input Parameters:
7721 + dm   - The DM object
7722 . label - (Optional) The DMLabel to be removed from the DM
7723 - failNotFound - Should it fail if the label is not found in the DM?
7724 
7725   Level: developer
7726 
7727   Notes:
7728   Only exactly the same instance is removed if found, name match is ignored.
7729   If the DM has an exclusive reference to the label, it gets destroyed and
7730   *label nullified.
7731 
7732 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7733 @*/
7734 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7735 {
7736   DMLabelLink    link, *pnext;
7737   PetscBool      hasLabel = PETSC_FALSE;
7738   PetscErrorCode ierr;
7739 
7740   PetscFunctionBegin;
7741   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7742   PetscValidPointer(label, 2);
7743   if (!*label && !failNotFound) PetscFunctionReturn(0);
7744   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7745   PetscValidLogicalCollectiveBool(dm,failNotFound,3);
7746   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7747     if (*label == link->label) {
7748       hasLabel = PETSC_TRUE;
7749       *pnext = link->next; /* Remove from list */
7750       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7751       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7752       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7753       ierr = DMLabelDestroy(&link->label);CHKERRQ(ierr);
7754       ierr = PetscFree(link);CHKERRQ(ierr);
7755       break;
7756     }
7757   }
7758   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7759   PetscFunctionReturn(0);
7760 }
7761 
7762 /*@C
7763   DMGetLabelOutput - Get the output flag for a given label
7764 
7765   Not Collective
7766 
7767   Input Parameters:
7768 + dm   - The DM object
7769 - name - The label name
7770 
7771   Output Parameter:
7772 . output - The flag for output
7773 
7774   Level: developer
7775 
7776 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7777 @*/
7778 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7779 {
7780   DMLabelLink    next = dm->labels;
7781   const char    *lname;
7782   PetscErrorCode ierr;
7783 
7784   PetscFunctionBegin;
7785   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7786   PetscValidPointer(name, 2);
7787   PetscValidPointer(output, 3);
7788   while (next) {
7789     PetscBool flg;
7790 
7791     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7792     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7793     if (flg) {*output = next->output; PetscFunctionReturn(0);}
7794     next = next->next;
7795   }
7796   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7797 }
7798 
7799 /*@C
7800   DMSetLabelOutput - Set the output flag for a given label
7801 
7802   Not Collective
7803 
7804   Input Parameters:
7805 + dm     - The DM object
7806 . name   - The label name
7807 - output - The flag for output
7808 
7809   Level: developer
7810 
7811 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7812 @*/
7813 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7814 {
7815   DMLabelLink    next = dm->labels;
7816   const char    *lname;
7817   PetscErrorCode ierr;
7818 
7819   PetscFunctionBegin;
7820   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7821   PetscValidCharPointer(name, 2);
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) {next->output = 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 /*@
7834   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
7835 
7836   Collective on dmA
7837 
7838   Input Parameter:
7839 + dmA - The DM object with initial labels
7840 . dmB - The DM object with copied labels
7841 . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7842 - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
7843 
7844   Level: intermediate
7845 
7846   Note: This is typically used when interpolating or otherwise adding to a mesh
7847 
7848 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7849 @*/
7850 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7851 {
7852   DMLabel        label, labelNew;
7853   const char    *name;
7854   PetscBool      flg;
7855   DMLabelLink    link;
7856   PetscErrorCode ierr;
7857 
7858   PetscFunctionBegin;
7859   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7860   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7861   PetscValidLogicalCollectiveEnum(dmA, mode,3);
7862   PetscValidLogicalCollectiveBool(dmA, all, 4);
7863   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7864   if (dmA == dmB) PetscFunctionReturn(0);
7865   for (link=dmA->labels; link; link=link->next) {
7866     label=link->label;
7867     ierr = PetscObjectGetName((PetscObject)label, &name);CHKERRQ(ierr);
7868     if (!all) {
7869       ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
7870       if (flg) continue;
7871       ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
7872       if (flg) continue;
7873       ierr = PetscStrcmp(name, "celltype", &flg);CHKERRQ(ierr);
7874       if (flg) continue;
7875     }
7876     if (mode==PETSC_COPY_VALUES) {
7877       ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
7878     } else {
7879       labelNew = label;
7880     }
7881     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
7882     if (mode==PETSC_COPY_VALUES) {ierr = DMLabelDestroy(&labelNew);CHKERRQ(ierr);}
7883   }
7884   PetscFunctionReturn(0);
7885 }
7886 
7887 /*@
7888   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
7889 
7890   Input Parameter:
7891 . dm - The DM object
7892 
7893   Output Parameter:
7894 . cdm - The coarse DM
7895 
7896   Level: intermediate
7897 
7898 .seealso: DMSetCoarseDM()
7899 @*/
7900 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7901 {
7902   PetscFunctionBegin;
7903   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7904   PetscValidPointer(cdm, 2);
7905   *cdm = dm->coarseMesh;
7906   PetscFunctionReturn(0);
7907 }
7908 
7909 /*@
7910   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
7911 
7912   Input Parameters:
7913 + dm - The DM object
7914 - cdm - The coarse DM
7915 
7916   Level: intermediate
7917 
7918 .seealso: DMGetCoarseDM()
7919 @*/
7920 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7921 {
7922   PetscErrorCode ierr;
7923 
7924   PetscFunctionBegin;
7925   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7926   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7927   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
7928   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
7929   dm->coarseMesh = cdm;
7930   PetscFunctionReturn(0);
7931 }
7932 
7933 /*@
7934   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
7935 
7936   Input Parameter:
7937 . dm - The DM object
7938 
7939   Output Parameter:
7940 . fdm - The fine DM
7941 
7942   Level: intermediate
7943 
7944 .seealso: DMSetFineDM()
7945 @*/
7946 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7947 {
7948   PetscFunctionBegin;
7949   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7950   PetscValidPointer(fdm, 2);
7951   *fdm = dm->fineMesh;
7952   PetscFunctionReturn(0);
7953 }
7954 
7955 /*@
7956   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
7957 
7958   Input Parameters:
7959 + dm - The DM object
7960 - fdm - The fine DM
7961 
7962   Level: intermediate
7963 
7964 .seealso: DMGetFineDM()
7965 @*/
7966 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7967 {
7968   PetscErrorCode ierr;
7969 
7970   PetscFunctionBegin;
7971   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7972   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7973   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
7974   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
7975   dm->fineMesh = fdm;
7976   PetscFunctionReturn(0);
7977 }
7978 
7979 /*=== DMBoundary code ===*/
7980 
7981 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7982 {
7983   PetscInt       d;
7984   PetscErrorCode ierr;
7985 
7986   PetscFunctionBegin;
7987   for (d = 0; d < dm->Nds; ++d) {
7988     ierr = PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);CHKERRQ(ierr);
7989   }
7990   PetscFunctionReturn(0);
7991 }
7992 
7993 /*@C
7994   DMAddBoundary - Add a boundary condition to the model
7995 
7996   Collective on dm
7997 
7998   Input Parameters:
7999 + dm          - The DM, with a PetscDS that matches the problem being constrained
8000 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8001 . name        - The BC name
8002 . labelname   - The label defining constrained points
8003 . field       - The field to constrain
8004 . numcomps    - The number of constrained field components (0 will constrain all fields)
8005 . comps       - An array of constrained component numbers
8006 . bcFunc      - A pointwise function giving boundary values
8007 . bcFunc_t    - A pointwise function giving the time deriative of the boundary values, or NULL
8008 . numids      - The number of DMLabel ids for constrained points
8009 . ids         - An array of ids for constrained points
8010 - ctx         - An optional user context for bcFunc
8011 
8012   Options Database Keys:
8013 + -bc_<boundary name> <num> - Overrides the boundary ids
8014 - -bc_<boundary name>_comp <num> - Overrides the boundary components
8015 
8016   Note:
8017   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:
8018 
8019 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8020 
8021   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:
8022 
8023 $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8024 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8025 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8026 $        PetscReal time, const PetscReal x[], PetscScalar bcval[])
8027 
8028 + dim - the spatial dimension
8029 . Nf - the number of fields
8030 . uOff - the offset into u[] and u_t[] for each field
8031 . uOff_x - the offset into u_x[] for each field
8032 . u - each field evaluated at the current point
8033 . u_t - the time derivative of each field evaluated at the current point
8034 . u_x - the gradient of each field evaluated at the current point
8035 . aOff - the offset into a[] and a_t[] for each auxiliary field
8036 . aOff_x - the offset into a_x[] for each auxiliary field
8037 . a - each auxiliary field evaluated at the current point
8038 . a_t - the time derivative of each auxiliary field evaluated at the current point
8039 . a_x - the gradient of auxiliary each field evaluated at the current point
8040 . t - current time
8041 . x - coordinates of the current point
8042 . numConstants - number of constant parameters
8043 . constants - constant parameters
8044 - bcval - output values at the current point
8045 
8046   Level: developer
8047 
8048 .seealso: DMGetBoundary(), PetscDSAddBoundary()
8049 @*/
8050 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)
8051 {
8052   PetscDS        ds;
8053   PetscErrorCode ierr;
8054 
8055   PetscFunctionBegin;
8056   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8057   PetscValidLogicalCollectiveEnum(dm, type, 2);
8058   PetscValidLogicalCollectiveInt(dm, field, 5);
8059   PetscValidLogicalCollectiveInt(dm, numcomps, 6);
8060   PetscValidLogicalCollectiveInt(dm, numids, 9);
8061   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
8062   ierr = DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);CHKERRQ(ierr);
8063   ierr = PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, bcFunc_t, numids, ids, ctx);CHKERRQ(ierr);
8064   PetscFunctionReturn(0);
8065 }
8066 
8067 /*@
8068   DMGetNumBoundary - Get the number of registered BC
8069 
8070   Input Parameters:
8071 . dm - The mesh object
8072 
8073   Output Parameters:
8074 . numBd - The number of BC
8075 
8076   Level: intermediate
8077 
8078 .seealso: DMAddBoundary(), DMGetBoundary()
8079 @*/
8080 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
8081 {
8082   PetscDS        ds;
8083   PetscErrorCode ierr;
8084 
8085   PetscFunctionBegin;
8086   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8087   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
8088   ierr = PetscDSGetNumBoundary(ds, numBd);CHKERRQ(ierr);
8089   PetscFunctionReturn(0);
8090 }
8091 
8092 /*@C
8093   DMGetBoundary - Get a model boundary condition
8094 
8095   Input Parameters:
8096 + dm          - The mesh object
8097 - bd          - The BC number
8098 
8099   Output Parameters:
8100 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8101 . name        - The BC name
8102 . labelname   - The label defining constrained points
8103 . field       - The field to constrain
8104 . numcomps    - The number of constrained field components
8105 . comps       - An array of constrained component numbers
8106 . bcFunc      - A pointwise function giving boundary values
8107 . bcFunc_t    - A pointwise function giving the time derviative of the boundary values
8108 . numids      - The number of DMLabel ids for constrained points
8109 . ids         - An array of ids for constrained points
8110 - ctx         - An optional user context for bcFunc
8111 
8112   Options Database Keys:
8113 + -bc_<boundary name> <num> - Overrides the boundary ids
8114 - -bc_<boundary name>_comp <num> - Overrides the boundary components
8115 
8116   Level: developer
8117 
8118 .seealso: DMAddBoundary()
8119 @*/
8120 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)
8121 {
8122   PetscDS        ds;
8123   PetscErrorCode ierr;
8124 
8125   PetscFunctionBegin;
8126   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8127   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
8128   ierr = PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, func_t, numids, ids, ctx);CHKERRQ(ierr);
8129   PetscFunctionReturn(0);
8130 }
8131 
8132 static PetscErrorCode DMPopulateBoundary(DM dm)
8133 {
8134   PetscDS        ds;
8135   DMBoundary    *lastnext;
8136   DSBoundary     dsbound;
8137   PetscErrorCode ierr;
8138 
8139   PetscFunctionBegin;
8140   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
8141   dsbound = ds->boundary;
8142   if (dm->boundary) {
8143     DMBoundary next = dm->boundary;
8144 
8145     /* quick check to see if the PetscDS has changed */
8146     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
8147     /* the PetscDS has changed: tear down and rebuild */
8148     while (next) {
8149       DMBoundary b = next;
8150 
8151       next = b->next;
8152       ierr = PetscFree(b);CHKERRQ(ierr);
8153     }
8154     dm->boundary = NULL;
8155   }
8156 
8157   lastnext = &(dm->boundary);
8158   while (dsbound) {
8159     DMBoundary dmbound;
8160 
8161     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
8162     dmbound->dsboundary = dsbound;
8163     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
8164     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
8165     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8166     *lastnext = dmbound;
8167     lastnext = &(dmbound->next);
8168     dsbound = dsbound->next;
8169   }
8170   PetscFunctionReturn(0);
8171 }
8172 
8173 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8174 {
8175   DMBoundary     b;
8176   PetscErrorCode ierr;
8177 
8178   PetscFunctionBegin;
8179   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8180   PetscValidBoolPointer(isBd, 3);
8181   *isBd = PETSC_FALSE;
8182   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
8183   b = dm->boundary;
8184   while (b && !(*isBd)) {
8185     DMLabel    label = b->label;
8186     DSBoundary dsb = b->dsboundary;
8187 
8188     if (label) {
8189       PetscInt i;
8190 
8191       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
8192         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
8193       }
8194     }
8195     b = b->next;
8196   }
8197   PetscFunctionReturn(0);
8198 }
8199 
8200 /*@C
8201   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
8202 
8203   Collective on DM
8204 
8205   Input Parameters:
8206 + dm      - The DM
8207 . time    - The time
8208 . funcs   - The coordinate functions to evaluate, one per field
8209 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8210 - mode    - The insertion mode for values
8211 
8212   Output Parameter:
8213 . X - vector
8214 
8215    Calling sequence of func:
8216 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8217 
8218 +  dim - The spatial dimension
8219 .  x   - The coordinates
8220 .  Nf  - The number of fields
8221 .  u   - The output field values
8222 -  ctx - optional user-defined function context
8223 
8224   Level: developer
8225 
8226 .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8227 @*/
8228 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8229 {
8230   Vec            localX;
8231   PetscErrorCode ierr;
8232 
8233   PetscFunctionBegin;
8234   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8235   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
8236   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
8237   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
8238   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
8239   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
8240   PetscFunctionReturn(0);
8241 }
8242 
8243 /*@C
8244   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
8245 
8246   Not collective
8247 
8248   Input Parameters:
8249 + dm      - The DM
8250 . time    - The time
8251 . funcs   - The coordinate functions to evaluate, one per field
8252 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8253 - mode    - The insertion mode for values
8254 
8255   Output Parameter:
8256 . localX - vector
8257 
8258    Calling sequence of func:
8259 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8260 
8261 +  dim - The spatial dimension
8262 .  x   - The coordinates
8263 .  Nf  - The number of fields
8264 .  u   - The output field values
8265 -  ctx - optional user-defined function context
8266 
8267   Level: developer
8268 
8269 .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8270 @*/
8271 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8272 {
8273   PetscErrorCode ierr;
8274 
8275   PetscFunctionBegin;
8276   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8277   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
8278   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8279   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
8280   PetscFunctionReturn(0);
8281 }
8282 
8283 /*@C
8284   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.
8285 
8286   Collective on DM
8287 
8288   Input Parameters:
8289 + dm      - The DM
8290 . time    - The time
8291 . label   - The DMLabel selecting the portion of the mesh for projection
8292 . funcs   - The coordinate functions to evaluate, one per field
8293 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8294 - mode    - The insertion mode for values
8295 
8296   Output Parameter:
8297 . X - vector
8298 
8299    Calling sequence of func:
8300 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8301 
8302 +  dim - The spatial dimension
8303 .  x   - The coordinates
8304 .  Nf  - The number of fields
8305 .  u   - The output field values
8306 -  ctx - optional user-defined function context
8307 
8308   Level: developer
8309 
8310 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8311 @*/
8312 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)
8313 {
8314   Vec            localX;
8315   PetscErrorCode ierr;
8316 
8317   PetscFunctionBegin;
8318   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8319   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
8320   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
8321   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
8322   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
8323   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
8324   PetscFunctionReturn(0);
8325 }
8326 
8327 /*@C
8328   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.
8329 
8330   Not collective
8331 
8332   Input Parameters:
8333 + dm      - The DM
8334 . time    - The time
8335 . label   - The DMLabel selecting the portion of the mesh for projection
8336 . funcs   - The coordinate functions to evaluate, one per field
8337 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8338 - mode    - The insertion mode for values
8339 
8340   Output Parameter:
8341 . localX - vector
8342 
8343    Calling sequence of func:
8344 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8345 
8346 +  dim - The spatial dimension
8347 .  x   - The coordinates
8348 .  Nf  - The number of fields
8349 .  u   - The output field values
8350 -  ctx - optional user-defined function context
8351 
8352   Level: developer
8353 
8354 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8355 @*/
8356 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)
8357 {
8358   PetscErrorCode ierr;
8359 
8360   PetscFunctionBegin;
8361   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8362   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
8363   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8364   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
8365   PetscFunctionReturn(0);
8366 }
8367 
8368 /*@C
8369   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
8370 
8371   Not collective
8372 
8373   Input Parameters:
8374 + dm      - The DM
8375 . time    - The time
8376 . localU  - The input field vector
8377 . funcs   - The functions to evaluate, one per field
8378 - mode    - The insertion mode for values
8379 
8380   Output Parameter:
8381 . localX  - The output vector
8382 
8383    Calling sequence of func:
8384 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8385 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8386 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8387 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8388 
8389 +  dim          - The spatial dimension
8390 .  Nf           - The number of input fields
8391 .  NfAux        - The number of input auxiliary fields
8392 .  uOff         - The offset of each field in u[]
8393 .  uOff_x       - The offset of each field in u_x[]
8394 .  u            - The field values at this point in space
8395 .  u_t          - The field time derivative at this point in space (or NULL)
8396 .  u_x          - The field derivatives at this point in space
8397 .  aOff         - The offset of each auxiliary field in u[]
8398 .  aOff_x       - The offset of each auxiliary field in u_x[]
8399 .  a            - The auxiliary field values at this point in space
8400 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8401 .  a_x          - The auxiliary field derivatives at this point in space
8402 .  t            - The current time
8403 .  x            - The coordinates of this point
8404 .  numConstants - The number of constants
8405 .  constants    - The value of each constant
8406 -  f            - The value of the function at this point in space
8407 
8408   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.
8409   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
8410   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8411   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8412 
8413   Level: intermediate
8414 
8415 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8416 @*/
8417 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8418                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8419                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8420                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8421                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8422                                    InsertMode mode, Vec localX)
8423 {
8424   PetscErrorCode ierr;
8425 
8426   PetscFunctionBegin;
8427   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8428   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
8429   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
8430   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8431   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
8432   PetscFunctionReturn(0);
8433 }
8434 
8435 /*@C
8436   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.
8437 
8438   Not collective
8439 
8440   Input Parameters:
8441 + dm      - The DM
8442 . time    - The time
8443 . label   - The DMLabel marking the portion of the domain to output
8444 . numIds  - The number of label ids to use
8445 . ids     - The label ids to use for marking
8446 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8447 . comps   - The components to set in the output, or NULL for all components
8448 . localU  - The input field vector
8449 . funcs   - The functions to evaluate, one per field
8450 - mode    - The insertion mode for values
8451 
8452   Output Parameter:
8453 . localX  - The output vector
8454 
8455    Calling sequence of func:
8456 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8457 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8458 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8459 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8460 
8461 +  dim          - The spatial dimension
8462 .  Nf           - The number of input fields
8463 .  NfAux        - The number of input auxiliary fields
8464 .  uOff         - The offset of each field in u[]
8465 .  uOff_x       - The offset of each field in u_x[]
8466 .  u            - The field values at this point in space
8467 .  u_t          - The field time derivative at this point in space (or NULL)
8468 .  u_x          - The field derivatives at this point in space
8469 .  aOff         - The offset of each auxiliary field in u[]
8470 .  aOff_x       - The offset of each auxiliary field in u_x[]
8471 .  a            - The auxiliary field values at this point in space
8472 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8473 .  a_x          - The auxiliary field derivatives at this point in space
8474 .  t            - The current time
8475 .  x            - The coordinates of this point
8476 .  numConstants - The number of constants
8477 .  constants    - The value of each constant
8478 -  f            - The value of the function at this point in space
8479 
8480   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.
8481   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
8482   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8483   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8484 
8485   Level: intermediate
8486 
8487 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8488 @*/
8489 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8490                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8491                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8492                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8493                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8494                                         InsertMode mode, Vec localX)
8495 {
8496   PetscErrorCode ierr;
8497 
8498   PetscFunctionBegin;
8499   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8500   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
8501   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
8502   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8503   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
8504   PetscFunctionReturn(0);
8505 }
8506 
8507 /*@C
8508   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.
8509 
8510   Not collective
8511 
8512   Input Parameters:
8513 + dm      - The DM
8514 . time    - The time
8515 . label   - The DMLabel marking the portion of the domain boundary to output
8516 . numIds  - The number of label ids to use
8517 . ids     - The label ids to use for marking
8518 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8519 . comps   - The components to set in the output, or NULL for all components
8520 . localU  - The input field vector
8521 . funcs   - The functions to evaluate, one per field
8522 - mode    - The insertion mode for values
8523 
8524   Output Parameter:
8525 . localX  - The output vector
8526 
8527    Calling sequence of func:
8528 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8529 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8530 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8531 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8532 
8533 +  dim          - The spatial dimension
8534 .  Nf           - The number of input fields
8535 .  NfAux        - The number of input auxiliary fields
8536 .  uOff         - The offset of each field in u[]
8537 .  uOff_x       - The offset of each field in u_x[]
8538 .  u            - The field values at this point in space
8539 .  u_t          - The field time derivative at this point in space (or NULL)
8540 .  u_x          - The field derivatives at this point in space
8541 .  aOff         - The offset of each auxiliary field in u[]
8542 .  aOff_x       - The offset of each auxiliary field in u_x[]
8543 .  a            - The auxiliary field values at this point in space
8544 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8545 .  a_x          - The auxiliary field derivatives at this point in space
8546 .  t            - The current time
8547 .  x            - The coordinates of this point
8548 .  n            - The face normal
8549 .  numConstants - The number of constants
8550 .  constants    - The value of each constant
8551 -  f            - The value of the function at this point in space
8552 
8553   Note:
8554   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8555   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
8556   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8557   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8558 
8559   Level: intermediate
8560 
8561 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8562 @*/
8563 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8564                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8565                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8566                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8567                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8568                                           InsertMode mode, Vec localX)
8569 {
8570   PetscErrorCode ierr;
8571 
8572   PetscFunctionBegin;
8573   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8574   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
8575   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
8576   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
8577   ierr = (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
8578   PetscFunctionReturn(0);
8579 }
8580 
8581 /*@C
8582   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8583 
8584   Input Parameters:
8585 + dm    - The DM
8586 . time  - The time
8587 . funcs - The functions to evaluate for each field component
8588 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8589 - X     - The coefficient vector u_h, a global vector
8590 
8591   Output Parameter:
8592 . diff - The diff ||u - u_h||_2
8593 
8594   Level: developer
8595 
8596 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8597 @*/
8598 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8599 {
8600   PetscErrorCode ierr;
8601 
8602   PetscFunctionBegin;
8603   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8604   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8605   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8606   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
8607   PetscFunctionReturn(0);
8608 }
8609 
8610 /*@C
8611   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8612 
8613   Collective on dm
8614 
8615   Input Parameters:
8616 + dm    - The DM
8617 , time  - The time
8618 . funcs - The gradient functions to evaluate for each field component
8619 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8620 . X     - The coefficient vector u_h, a global vector
8621 - n     - The vector to project along
8622 
8623   Output Parameter:
8624 . diff - The diff ||(grad u - grad u_h) . n||_2
8625 
8626   Level: developer
8627 
8628 .seealso: DMProjectFunction(), DMComputeL2Diff()
8629 @*/
8630 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)
8631 {
8632   PetscErrorCode ierr;
8633 
8634   PetscFunctionBegin;
8635   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8636   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8637   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8638   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
8639   PetscFunctionReturn(0);
8640 }
8641 
8642 /*@C
8643   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8644 
8645   Collective on dm
8646 
8647   Input Parameters:
8648 + dm    - The DM
8649 . time  - The time
8650 . funcs - The functions to evaluate for each field component
8651 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8652 - X     - The coefficient vector u_h, a global vector
8653 
8654   Output Parameter:
8655 . diff - The array of differences, ||u^f - u^f_h||_2
8656 
8657   Level: developer
8658 
8659 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8660 @*/
8661 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8662 {
8663   PetscErrorCode ierr;
8664 
8665   PetscFunctionBegin;
8666   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8667   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8668   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
8669   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
8670   PetscFunctionReturn(0);
8671 }
8672 
8673 /*@C
8674   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
8675                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
8676 
8677   Collective on dm
8678 
8679   Input parameters:
8680 + dm - the pre-adaptation DM object
8681 - label - label with the flags
8682 
8683   Output parameters:
8684 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
8685 
8686   Level: intermediate
8687 
8688 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8689 @*/
8690 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8691 {
8692   PetscErrorCode ierr;
8693 
8694   PetscFunctionBegin;
8695   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8696   PetscValidPointer(label,2);
8697   PetscValidPointer(dmAdapt,3);
8698   *dmAdapt = NULL;
8699   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8700   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
8701   PetscFunctionReturn(0);
8702 }
8703 
8704 /*@C
8705   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
8706 
8707   Input Parameters:
8708 + dm - The DM object
8709 . metric - The metric to which the mesh is adapted, defined vertex-wise.
8710 - 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_".
8711 
8712   Output Parameter:
8713 . dmAdapt  - Pointer to the DM object containing the adapted mesh
8714 
8715   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
8716 
8717   Level: advanced
8718 
8719 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8720 @*/
8721 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8722 {
8723   PetscErrorCode ierr;
8724 
8725   PetscFunctionBegin;
8726   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8727   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
8728   if (bdLabel) PetscValidPointer(bdLabel, 3);
8729   PetscValidPointer(dmAdapt, 4);
8730   *dmAdapt = NULL;
8731   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8732   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
8733   PetscFunctionReturn(0);
8734 }
8735 
8736 /*@C
8737  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
8738 
8739  Not Collective
8740 
8741  Input Parameter:
8742 .  dm    - The DM
8743 
8744  Output Parameters:
8745 +  nranks - the number of neighbours
8746 -  ranks - the neighbors ranks
8747 
8748  Notes:
8749  Do not free the array, it is freed when the DM is destroyed.
8750 
8751  Level: beginner
8752 
8753  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
8754 @*/
8755 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
8756 {
8757   PetscErrorCode ierr;
8758 
8759   PetscFunctionBegin;
8760   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8761   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
8762   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
8763   PetscFunctionReturn(0);
8764 }
8765 
8766 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8767 
8768 /*
8769     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8770     This has be a different function because it requires DM which is not defined in the Mat library
8771 */
8772 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
8773 {
8774   PetscErrorCode ierr;
8775 
8776   PetscFunctionBegin;
8777   if (coloring->ctype == IS_COLORING_LOCAL) {
8778     Vec x1local;
8779     DM  dm;
8780     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
8781     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
8782     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
8783     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
8784     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
8785     x1   = x1local;
8786   }
8787   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
8788   if (coloring->ctype == IS_COLORING_LOCAL) {
8789     DM  dm;
8790     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
8791     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
8792   }
8793   PetscFunctionReturn(0);
8794 }
8795 
8796 /*@
8797     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
8798 
8799     Input Parameter:
8800 .    coloring - the MatFDColoring object
8801 
8802     Developer Notes:
8803     this routine exists because the PETSc Mat library does not know about the DM objects
8804 
8805     Level: advanced
8806 
8807 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
8808 @*/
8809 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
8810 {
8811   PetscFunctionBegin;
8812   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8813   PetscFunctionReturn(0);
8814 }
8815 
8816 /*@
8817     DMGetCompatibility - determine if two DMs are compatible
8818 
8819     Collective
8820 
8821     Input Parameters:
8822 +    dm1 - the first DM
8823 -    dm2 - the second DM
8824 
8825     Output Parameters:
8826 +    compatible - whether or not the two DMs are compatible
8827 -    set - whether or not the compatible value was set
8828 
8829     Notes:
8830     Two DMs are deemed compatible if they represent the same parallel decomposition
8831     of the same topology. This implies that the section (field data) on one
8832     "makes sense" with respect to the topology and parallel decomposition of the other.
8833     Loosely speaking, compatible DMs represent the same domain and parallel
8834     decomposition, but hold different data.
8835 
8836     Typically, one would confirm compatibility if intending to simultaneously iterate
8837     over a pair of vectors obtained from different DMs.
8838 
8839     For example, two DMDA objects are compatible if they have the same local
8840     and global sizes and the same stencil width. They can have different numbers
8841     of degrees of freedom per node. Thus, one could use the node numbering from
8842     either DM in bounds for a loop over vectors derived from either DM.
8843 
8844     Consider the operation of summing data living on a 2-dof DMDA to data living
8845     on a 1-dof DMDA, which should be compatible, as in the following snippet.
8846 .vb
8847   ...
8848   ierr = DMGetCompatibility(da1,da2,&compatible,&set);CHKERRQ(ierr);
8849   if (set && compatible)  {
8850     ierr = DMDAVecGetArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
8851     ierr = DMDAVecGetArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
8852     ierr = DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);CHKERRQ(ierr);
8853     for (j=y; j<y+n; ++j) {
8854       for (i=x; i<x+m, ++i) {
8855         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8856       }
8857     }
8858     ierr = DMDAVecRestoreArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
8859     ierr = DMDAVecRestoreArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
8860   } else {
8861     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8862   }
8863   ...
8864 .ve
8865 
8866     Checking compatibility might be expensive for a given implementation of DM,
8867     or might be impossible to unambiguously confirm or deny. For this reason,
8868     this function may decline to determine compatibility, and hence users should
8869     always check the "set" output parameter.
8870 
8871     A DM is always compatible with itself.
8872 
8873     In the current implementation, DMs which live on "unequal" communicators
8874     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8875     incompatible.
8876 
8877     This function is labeled "Collective," as information about all subdomains
8878     is required on each rank. However, in DM implementations which store all this
8879     information locally, this function may be merely "Logically Collective".
8880 
8881     Developer Notes:
8882     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
8883     iff B is compatible with A. Thus, this function checks the implementations
8884     of both dm and dmc (if they are of different types), attempting to determine
8885     compatibility. It is left to DM implementers to ensure that symmetry is
8886     preserved. The simplest way to do this is, when implementing type-specific
8887     logic for this function, is to check for existing logic in the implementation
8888     of other DM types and let *set = PETSC_FALSE if found.
8889 
8890     Level: advanced
8891 
8892 .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
8893 @*/
8894 
8895 PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
8896 {
8897   PetscErrorCode ierr;
8898   PetscMPIInt    compareResult;
8899   DMType         type,type2;
8900   PetscBool      sameType;
8901 
8902   PetscFunctionBegin;
8903   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
8904   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
8905 
8906   /* Declare a DM compatible with itself */
8907   if (dm1 == dm2) {
8908     *set = PETSC_TRUE;
8909     *compatible = PETSC_TRUE;
8910     PetscFunctionReturn(0);
8911   }
8912 
8913   /* Declare a DM incompatible with a DM that lives on an "unequal"
8914      communicator. Note that this does not preclude compatibility with
8915      DMs living on "congruent" or "similar" communicators, but this must be
8916      determined by the implementation-specific logic */
8917   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);CHKERRQ(ierr);
8918   if (compareResult == MPI_UNEQUAL) {
8919     *set = PETSC_TRUE;
8920     *compatible = PETSC_FALSE;
8921     PetscFunctionReturn(0);
8922   }
8923 
8924   /* Pass to the implementation-specific routine, if one exists. */
8925   if (dm1->ops->getcompatibility) {
8926     ierr = (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);CHKERRQ(ierr);
8927     if (*set) PetscFunctionReturn(0);
8928   }
8929 
8930   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8931      with an implementation of this function from dm2 */
8932   ierr = DMGetType(dm1,&type);CHKERRQ(ierr);
8933   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
8934   ierr = PetscStrcmp(type,type2,&sameType);CHKERRQ(ierr);
8935   if (!sameType && dm2->ops->getcompatibility) {
8936     ierr = (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set);CHKERRQ(ierr); /* Note argument order */
8937   } else {
8938     *set = PETSC_FALSE;
8939   }
8940   PetscFunctionReturn(0);
8941 }
8942 
8943 /*@C
8944   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
8945 
8946   Logically Collective on DM
8947 
8948   Input Parameters:
8949 + DM - the DM
8950 . f - the monitor function
8951 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8952 - monitordestroy - [optional] routine that frees monitor context (may be NULL)
8953 
8954   Options Database Keys:
8955 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
8956                             does not cancel those set via the options database.
8957 
8958   Notes:
8959   Several different monitoring routines may be set by calling
8960   DMMonitorSet() multiple times; all will be called in the
8961   order in which they were set.
8962 
8963   Fortran Notes:
8964   Only a single monitor function can be set for each DM object
8965 
8966   Level: intermediate
8967 
8968 .seealso: DMMonitorCancel()
8969 @*/
8970 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
8971 {
8972   PetscInt       m;
8973   PetscErrorCode ierr;
8974 
8975   PetscFunctionBegin;
8976   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8977   for (m = 0; m < dm->numbermonitors; ++m) {
8978     PetscBool identical;
8979 
8980     ierr = PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);CHKERRQ(ierr);
8981     if (identical) PetscFunctionReturn(0);
8982   }
8983   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8984   dm->monitor[dm->numbermonitors]          = f;
8985   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8986   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
8987   PetscFunctionReturn(0);
8988 }
8989 
8990 /*@
8991   DMMonitorCancel - Clears all the monitor functions for a DM object.
8992 
8993   Logically Collective on DM
8994 
8995   Input Parameter:
8996 . dm - the DM
8997 
8998   Options Database Key:
8999 . -dm_monitor_cancel - cancels all monitors that have been hardwired
9000   into a code by calls to DMonitorSet(), but does not cancel those
9001   set via the options database
9002 
9003   Notes:
9004   There is no way to clear one specific monitor from a DM object.
9005 
9006   Level: intermediate
9007 
9008 .seealso: DMMonitorSet()
9009 @*/
9010 PetscErrorCode DMMonitorCancel(DM dm)
9011 {
9012   PetscErrorCode ierr;
9013   PetscInt       m;
9014 
9015   PetscFunctionBegin;
9016   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9017   for (m = 0; m < dm->numbermonitors; ++m) {
9018     if (dm->monitordestroy[m]) {ierr = (*dm->monitordestroy[m])(&dm->monitorcontext[m]);CHKERRQ(ierr);}
9019   }
9020   dm->numbermonitors = 0;
9021   PetscFunctionReturn(0);
9022 }
9023 
9024 /*@C
9025   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9026 
9027   Collective on DM
9028 
9029   Input Parameters:
9030 + dm   - DM object you wish to monitor
9031 . name - the monitor type one is seeking
9032 . help - message indicating what monitoring is done
9033 . manual - manual page for the monitor
9034 . monitor - the monitor function
9035 - 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
9036 
9037   Output Parameter:
9038 . flg - Flag set if the monitor was created
9039 
9040   Level: developer
9041 
9042 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9043           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9044           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9045           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9046           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9047           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9048           PetscOptionsFList(), PetscOptionsEList()
9049 @*/
9050 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9051 {
9052   PetscViewer       viewer;
9053   PetscViewerFormat format;
9054   PetscErrorCode    ierr;
9055 
9056   PetscFunctionBegin;
9057   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9058   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);CHKERRQ(ierr);
9059   if (*flg) {
9060     PetscViewerAndFormat *vf;
9061 
9062     ierr = PetscViewerAndFormatCreate(viewer, format, &vf);CHKERRQ(ierr);
9063     ierr = PetscObjectDereference((PetscObject) viewer);CHKERRQ(ierr);
9064     if (monitorsetup) {ierr = (*monitorsetup)(dm, vf);CHKERRQ(ierr);}
9065     ierr = DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);CHKERRQ(ierr);
9066   }
9067   PetscFunctionReturn(0);
9068 }
9069 
9070 /*@
9071    DMMonitor - runs the user provided monitor routines, if they exist
9072 
9073    Collective on DM
9074 
9075    Input Parameters:
9076 .  dm - The DM
9077 
9078    Level: developer
9079 
9080 .seealso: DMMonitorSet()
9081 @*/
9082 PetscErrorCode DMMonitor(DM dm)
9083 {
9084   PetscInt       m;
9085   PetscErrorCode ierr;
9086 
9087   PetscFunctionBegin;
9088   if (!dm) PetscFunctionReturn(0);
9089   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9090   for (m = 0; m < dm->numbermonitors; ++m) {
9091     ierr = (*dm->monitor[m])(dm, dm->monitorcontext[m]);CHKERRQ(ierr);
9092   }
9093   PetscFunctionReturn(0);
9094 }
9095