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