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