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