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