xref: /petsc/src/dm/interface/dm.c (revision 5bd6fc02caea44eac9fd5acb69b907ce7b1b33d5)
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   } else {
4194     ierr = DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);CHKERRQ(ierr);
4195   }
4196   PetscFunctionReturn(0);
4197 }
4198 
4199 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4200 {
4201   RegionField   *tmpr;
4202   PetscInt       Nf = dm->Nf, f;
4203   PetscErrorCode ierr;
4204 
4205   PetscFunctionBegin;
4206   if (Nf >= NfNew) PetscFunctionReturn(0);
4207   ierr = PetscMalloc1(NfNew, &tmpr);CHKERRQ(ierr);
4208   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4209   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL;}
4210   ierr = PetscFree(dm->fields);CHKERRQ(ierr);
4211   dm->Nf     = NfNew;
4212   dm->fields = tmpr;
4213   PetscFunctionReturn(0);
4214 }
4215 
4216 /*@
4217   DMClearFields - Remove all fields from the DM
4218 
4219   Logically collective on DM
4220 
4221   Input Parameter:
4222 . dm - The DM
4223 
4224   Level: intermediate
4225 
4226 .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4227 @*/
4228 PetscErrorCode DMClearFields(DM dm)
4229 {
4230   PetscInt       f;
4231   PetscErrorCode ierr;
4232 
4233   PetscFunctionBegin;
4234   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4235   for (f = 0; f < dm->Nf; ++f) {
4236     ierr = PetscObjectDestroy(&dm->fields[f].disc);CHKERRQ(ierr);
4237     ierr = DMLabelDestroy(&dm->fields[f].label);CHKERRQ(ierr);
4238   }
4239   ierr = PetscFree(dm->fields);CHKERRQ(ierr);
4240   dm->fields = NULL;
4241   dm->Nf     = 0;
4242   PetscFunctionReturn(0);
4243 }
4244 
4245 /*@
4246   DMGetNumFields - Get the number of fields in the DM
4247 
4248   Not collective
4249 
4250   Input Parameter:
4251 . dm - The DM
4252 
4253   Output Parameter:
4254 . Nf - The number of fields
4255 
4256   Level: intermediate
4257 
4258 .seealso: DMSetNumFields(), DMSetField()
4259 @*/
4260 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4261 {
4262   PetscFunctionBegin;
4263   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4264   PetscValidPointer(numFields, 2);
4265   *numFields = dm->Nf;
4266   PetscFunctionReturn(0);
4267 }
4268 
4269 /*@
4270   DMSetNumFields - Set the number of fields in the DM
4271 
4272   Logically collective on DM
4273 
4274   Input Parameters:
4275 + dm - The DM
4276 - Nf - The number of fields
4277 
4278   Level: intermediate
4279 
4280 .seealso: DMGetNumFields(), DMSetField()
4281 @*/
4282 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4283 {
4284   PetscInt       Nf, f;
4285   PetscErrorCode ierr;
4286 
4287   PetscFunctionBegin;
4288   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4289   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4290   for (f = Nf; f < numFields; ++f) {
4291     PetscContainer obj;
4292 
4293     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
4294     ierr = DMAddField(dm, NULL, (PetscObject) obj);CHKERRQ(ierr);
4295     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
4296   }
4297   PetscFunctionReturn(0);
4298 }
4299 
4300 /*@
4301   DMGetField - Return the discretization object for a given DM field
4302 
4303   Not collective
4304 
4305   Input Parameters:
4306 + dm - The DM
4307 - f  - The field number
4308 
4309   Output Parameters:
4310 + label - The label indicating the support of the field, or NULL for the entire mesh
4311 - field - The discretization object
4312 
4313   Level: intermediate
4314 
4315 .seealso: DMAddField(), DMSetField()
4316 @*/
4317 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4318 {
4319   PetscFunctionBegin;
4320   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4321   PetscValidPointer(field, 3);
4322   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);
4323   if (label) *label = dm->fields[f].label;
4324   if (field) *field = dm->fields[f].disc;
4325   PetscFunctionReturn(0);
4326 }
4327 
4328 /*@
4329   DMSetField - Set the discretization object for a given DM field
4330 
4331   Logically collective on DM
4332 
4333   Input Parameters:
4334 + dm    - The DM
4335 . f     - The field number
4336 . label - The label indicating the support of the field, or NULL for the entire mesh
4337 - field - The discretization object
4338 
4339   Level: intermediate
4340 
4341 .seealso: DMAddField(), DMGetField()
4342 @*/
4343 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4344 {
4345   PetscErrorCode ierr;
4346 
4347   PetscFunctionBegin;
4348   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4349   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
4350   PetscValidHeader(field, 4);
4351   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4352   ierr = DMFieldEnlarge_Static(dm, f+1);CHKERRQ(ierr);
4353   ierr = DMLabelDestroy(&dm->fields[f].label);CHKERRQ(ierr);
4354   ierr = PetscObjectDestroy(&dm->fields[f].disc);CHKERRQ(ierr);
4355   dm->fields[f].label = label;
4356   dm->fields[f].disc  = field;
4357   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
4358   ierr = PetscObjectReference((PetscObject) field);CHKERRQ(ierr);
4359   ierr = DMSetDefaultAdjacency_Private(dm, f, field);CHKERRQ(ierr);
4360   ierr = DMClearDS(dm);CHKERRQ(ierr);
4361   PetscFunctionReturn(0);
4362 }
4363 
4364 /*@
4365   DMAddField - Add the discretization object for the given DM field
4366 
4367   Logically collective on DM
4368 
4369   Input Parameters:
4370 + dm    - The DM
4371 . label - The label indicating the support of the field, or NULL for the entire mesh
4372 - field - The discretization object
4373 
4374   Level: intermediate
4375 
4376 .seealso: DMSetField(), DMGetField()
4377 @*/
4378 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4379 {
4380   PetscInt       Nf = dm->Nf;
4381   PetscErrorCode ierr;
4382 
4383   PetscFunctionBegin;
4384   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4385   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
4386   PetscValidHeader(field, 3);
4387   ierr = DMFieldEnlarge_Static(dm, Nf+1);CHKERRQ(ierr);
4388   dm->fields[Nf].label = label;
4389   dm->fields[Nf].disc  = field;
4390   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
4391   ierr = PetscObjectReference((PetscObject) field);CHKERRQ(ierr);
4392   ierr = DMSetDefaultAdjacency_Private(dm, Nf, field);CHKERRQ(ierr);
4393   ierr = DMClearDS(dm);CHKERRQ(ierr);
4394   PetscFunctionReturn(0);
4395 }
4396 
4397 /*@
4398   DMCopyFields - Copy the discretizations for the DM into another DM
4399 
4400   Collective on DM
4401 
4402   Input Parameter:
4403 . dm - The DM
4404 
4405   Output Parameter:
4406 . newdm - The DM
4407 
4408   Level: advanced
4409 
4410 .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4411 @*/
4412 PetscErrorCode DMCopyFields(DM dm, DM newdm)
4413 {
4414   PetscInt       Nf, f;
4415   PetscErrorCode ierr;
4416 
4417   PetscFunctionBegin;
4418   if (dm == newdm) PetscFunctionReturn(0);
4419   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4420   ierr = DMClearFields(newdm);CHKERRQ(ierr);
4421   for (f = 0; f < Nf; ++f) {
4422     DMLabel     label;
4423     PetscObject field;
4424     PetscBool   useCone, useClosure;
4425 
4426     ierr = DMGetField(dm, f, &label, &field);CHKERRQ(ierr);
4427     ierr = DMSetField(newdm, f, label, field);CHKERRQ(ierr);
4428     ierr = DMGetAdjacency(dm, f, &useCone, &useClosure);CHKERRQ(ierr);
4429     ierr = DMSetAdjacency(newdm, f, useCone, useClosure);CHKERRQ(ierr);
4430   }
4431   PetscFunctionReturn(0);
4432 }
4433 
4434 /*@
4435   DMGetAdjacency - Returns the flags for determining variable influence
4436 
4437   Not collective
4438 
4439   Input Parameters:
4440 + dm - The DM object
4441 - f  - The field number, or PETSC_DEFAULT for the default adjacency
4442 
4443   Output Parameter:
4444 + useCone    - Flag for variable influence starting with the cone operation
4445 - useClosure - Flag for variable influence using transitive closure
4446 
4447   Notes:
4448 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4449 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4450 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4451 
4452   Level: developer
4453 
4454 .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4455 @*/
4456 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4457 {
4458   PetscFunctionBegin;
4459   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4460   if (useCone) PetscValidPointer(useCone, 3);
4461   if (useClosure) PetscValidPointer(useClosure, 4);
4462   if (f < 0) {
4463     if (useCone)    *useCone    = dm->adjacency[0];
4464     if (useClosure) *useClosure = dm->adjacency[1];
4465   } else {
4466     PetscInt       Nf;
4467     PetscErrorCode ierr;
4468 
4469     ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4470     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4471     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4472     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4473   }
4474   PetscFunctionReturn(0);
4475 }
4476 
4477 /*@
4478   DMSetAdjacency - Set the flags for determining variable influence
4479 
4480   Not collective
4481 
4482   Input Parameters:
4483 + dm         - The DM object
4484 . f          - The field number
4485 . useCone    - Flag for variable influence starting with the cone operation
4486 - useClosure - Flag for variable influence using transitive closure
4487 
4488   Notes:
4489 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4490 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4491 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4492 
4493   Level: developer
4494 
4495 .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4496 @*/
4497 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4498 {
4499   PetscFunctionBegin;
4500   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4501   if (f < 0) {
4502     dm->adjacency[0] = useCone;
4503     dm->adjacency[1] = useClosure;
4504   } else {
4505     PetscInt       Nf;
4506     PetscErrorCode ierr;
4507 
4508     ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4509     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4510     dm->fields[f].adjacency[0] = useCone;
4511     dm->fields[f].adjacency[1] = useClosure;
4512   }
4513   PetscFunctionReturn(0);
4514 }
4515 
4516 /*@
4517   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
4518 
4519   Not collective
4520 
4521   Input Parameters:
4522 . dm - The DM object
4523 
4524   Output Parameter:
4525 + useCone    - Flag for variable influence starting with the cone operation
4526 - useClosure - Flag for variable influence using transitive closure
4527 
4528   Notes:
4529 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4530 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4531 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4532 
4533   Level: developer
4534 
4535 .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4536 @*/
4537 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4538 {
4539   PetscInt       Nf;
4540   PetscErrorCode ierr;
4541 
4542   PetscFunctionBegin;
4543   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4544   if (useCone) PetscValidPointer(useCone, 3);
4545   if (useClosure) PetscValidPointer(useClosure, 4);
4546   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4547   if (!Nf) {
4548     ierr = DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);CHKERRQ(ierr);
4549   } else {
4550     ierr = DMGetAdjacency(dm, 0, useCone, useClosure);CHKERRQ(ierr);
4551   }
4552   PetscFunctionReturn(0);
4553 }
4554 
4555 /*@
4556   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
4557 
4558   Not collective
4559 
4560   Input Parameters:
4561 + dm         - The DM object
4562 . useCone    - Flag for variable influence starting with the cone operation
4563 - useClosure - Flag for variable influence using transitive closure
4564 
4565   Notes:
4566 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4567 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4568 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4569 
4570   Level: developer
4571 
4572 .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
4573 @*/
4574 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
4575 {
4576   PetscInt       Nf;
4577   PetscErrorCode ierr;
4578 
4579   PetscFunctionBegin;
4580   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4581   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4582   if (!Nf) {
4583     ierr = DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);CHKERRQ(ierr);
4584   } else {
4585     ierr = DMSetAdjacency(dm, 0, useCone, useClosure);CHKERRQ(ierr);
4586   }
4587   PetscFunctionReturn(0);
4588 }
4589 
4590 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
4591 {
4592   DMSpace       *tmpd;
4593   PetscInt       Nds = dm->Nds, s;
4594   PetscErrorCode ierr;
4595 
4596   PetscFunctionBegin;
4597   if (Nds >= NdsNew) PetscFunctionReturn(0);
4598   ierr = PetscMalloc1(NdsNew, &tmpd);CHKERRQ(ierr);
4599   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
4600   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL;}
4601   ierr = PetscFree(dm->probs);CHKERRQ(ierr);
4602   dm->Nds   = NdsNew;
4603   dm->probs = tmpd;
4604   PetscFunctionReturn(0);
4605 }
4606 
4607 /*@
4608   DMGetNumDS - Get the number of discrete systems in the DM
4609 
4610   Not collective
4611 
4612   Input Parameter:
4613 . dm - The DM
4614 
4615   Output Parameter:
4616 . Nds - The number of PetscDS objects
4617 
4618   Level: intermediate
4619 
4620 .seealso: DMGetDS(), DMGetCellDS()
4621 @*/
4622 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
4623 {
4624   PetscFunctionBegin;
4625   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4626   PetscValidPointer(Nds, 2);
4627   *Nds = dm->Nds;
4628   PetscFunctionReturn(0);
4629 }
4630 
4631 /*@
4632   DMClearDS - Remove all discrete systems from the DM
4633 
4634   Logically collective on DM
4635 
4636   Input Parameter:
4637 . dm - The DM
4638 
4639   Level: intermediate
4640 
4641 .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
4642 @*/
4643 PetscErrorCode DMClearDS(DM dm)
4644 {
4645   PetscInt       s;
4646   PetscErrorCode ierr;
4647 
4648   PetscFunctionBegin;
4649   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4650   for (s = 0; s < dm->Nds; ++s) {
4651     ierr = PetscDSDestroy(&dm->probs[s].ds);CHKERRQ(ierr);
4652     ierr = DMLabelDestroy(&dm->probs[s].label);CHKERRQ(ierr);
4653   }
4654   ierr = PetscFree(dm->probs);CHKERRQ(ierr);
4655   dm->probs = NULL;
4656   dm->Nds   = 0;
4657   PetscFunctionReturn(0);
4658 }
4659 
4660 /*@
4661   DMGetDS - Get the default PetscDS
4662 
4663   Not collective
4664 
4665   Input Parameter:
4666 . dm    - The DM
4667 
4668   Output Parameter:
4669 . prob - The default PetscDS
4670 
4671   Level: intermediate
4672 
4673 .seealso: DMGetCellDS(), DMGetRegionDS()
4674 @*/
4675 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
4676 {
4677   PetscErrorCode ierr;
4678 
4679   PetscFunctionBeginHot;
4680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4681   PetscValidPointer(prob, 2);
4682   if (dm->Nds <= 0) {
4683     PetscDS ds;
4684 
4685     ierr = PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);CHKERRQ(ierr);
4686     ierr = DMSetRegionDS(dm, NULL, ds);CHKERRQ(ierr);
4687     ierr = PetscDSDestroy(&ds);CHKERRQ(ierr);
4688   }
4689   *prob = dm->probs[0].ds;
4690   PetscFunctionReturn(0);
4691 }
4692 
4693 /*@
4694   DMGetCellDS - Get the PetscDS defined on a given cell
4695 
4696   Not collective
4697 
4698   Input Parameters:
4699 + dm    - The DM
4700 - point - Cell for the DS
4701 
4702   Output Parameter:
4703 . prob - The PetscDS defined on the given cell
4704 
4705   Level: developer
4706 
4707 .seealso: DMGetDS(), DMSetRegionDS()
4708 @*/
4709 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
4710 {
4711   PetscDS        probDef = NULL;
4712   PetscInt       s;
4713   PetscErrorCode ierr;
4714 
4715   PetscFunctionBeginHot;
4716   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4717   PetscValidPointer(prob, 3);
4718   *prob = NULL;
4719   for (s = 0; s < dm->Nds; ++s) {
4720     PetscInt val;
4721 
4722     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
4723     else {
4724       ierr = DMLabelGetValue(dm->probs[s].label, point, &val);CHKERRQ(ierr);
4725       if (val >= 0) {*prob = dm->probs[s].ds; break;}
4726     }
4727   }
4728   if (!*prob) *prob = probDef;
4729   PetscFunctionReturn(0);
4730 }
4731 
4732 /*@
4733   DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
4734 
4735   Not collective
4736 
4737   Input Parameters:
4738 + dm    - The DM
4739 - label - The DMLabel defining the mesh region, or NULL for the entire mesh
4740 
4741   Output Parameter:
4742 . prob - The PetscDS defined on the given region
4743 
4744   Note: If the label is missing, this function returns an error
4745 
4746   Level: advanced
4747 
4748 .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
4749 @*/
4750 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, PetscDS *ds)
4751 {
4752   PetscInt Nds = dm->Nds, s;
4753 
4754   PetscFunctionBegin;
4755   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4756   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
4757   PetscValidPointer(ds, 3);
4758   *ds = NULL;
4759   for (s = 0; s < Nds; ++s) {
4760     if (dm->probs[s].label == label) {*ds = dm->probs[s].ds; PetscFunctionReturn(0);}
4761   }
4762   PetscFunctionReturn(0);
4763 }
4764 
4765 /*@
4766   DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
4767 
4768   Not collective
4769 
4770   Input Parameters:
4771 + dm  - The DM
4772 - num - The region number, in [0, Nds)
4773 
4774   Output Parameters:
4775 + label - The region label
4776 - prob  - The PetscDS defined on the given region
4777 
4778   Level: advanced
4779 
4780 .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
4781 @*/
4782 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, PetscDS *ds)
4783 {
4784   PetscInt       Nds;
4785   PetscErrorCode ierr;
4786 
4787   PetscFunctionBegin;
4788   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4789   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
4790   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
4791   if (label) {
4792     PetscValidPointer(label, 3);
4793     *label = dm->probs[num].label;
4794   }
4795   if (ds) {
4796     PetscValidPointer(ds, 4);
4797     *ds = dm->probs[num].ds;
4798   }
4799   PetscFunctionReturn(0);
4800 }
4801 
4802 /*@
4803   DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel
4804 
4805   Collective on DM
4806 
4807   Input Parameters:
4808 + dm    - The DM
4809 . label - The DMLabel defining the mesh region, or NULL for the entire mesh
4810 - prob - The PetscDS defined on the given cell
4811 
4812   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
4813 
4814   Level: advanced
4815 
4816 .seealso: DMGetRegionDS(), DMGetDS(), DMGetCellDS()
4817 @*/
4818 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, PetscDS ds)
4819 {
4820   PetscInt       Nds = dm->Nds, s;
4821   PetscErrorCode ierr;
4822 
4823   PetscFunctionBegin;
4824   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4825   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
4826   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 3);
4827   for (s = 0; s < Nds; ++s) {
4828     if (dm->probs[s].label == label) {
4829       dm->probs[s].ds = ds;
4830       PetscFunctionReturn(0);
4831     }
4832   }
4833   ierr = DMDSEnlarge_Static(dm, Nds+1);CHKERRQ(ierr);
4834   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
4835   ierr = PetscObjectReference((PetscObject) ds);CHKERRQ(ierr);
4836   if (!label) {
4837     /* Put the NULL label at the front, so it is returned as the default */
4838     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
4839     Nds = 0;
4840   }
4841   dm->probs[Nds].label = label;
4842   dm->probs[Nds].ds    = ds;
4843   PetscFunctionReturn(0);
4844 }
4845 
4846 /*@
4847   DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM
4848 
4849   Collective on DM
4850 
4851   Input Parameter:
4852 . dm - The DM
4853 
4854   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
4855 
4856   Level: intermediate
4857 
4858 .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
4859 @*/
4860 PetscErrorCode DMCreateDS(DM dm)
4861 {
4862   MPI_Comm       comm;
4863   PetscDS        prob, probh = NULL;
4864   PetscInt       dimEmbed, f, s, field = 0, fieldh = 0;
4865   PetscBool      doSetup = PETSC_TRUE;
4866   PetscErrorCode ierr;
4867 
4868   PetscFunctionBegin;
4869   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4870   if (!dm->fields) PetscFunctionReturn(0);
4871   /* Can only handle two label cases right now:
4872    1) NULL
4873    2) Hybrid cells
4874   */
4875   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
4876   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
4877   /* Create default DS */
4878   ierr = DMGetRegionDS(dm, NULL, &prob);CHKERRQ(ierr);
4879   if (!prob) {
4880     ierr = PetscDSCreate(comm, &prob);CHKERRQ(ierr);
4881     ierr = DMSetRegionDS(dm, NULL, prob);CHKERRQ(ierr);
4882     ierr = PetscDSDestroy(&prob);CHKERRQ(ierr);
4883     ierr = DMGetRegionDS(dm, NULL, &prob);CHKERRQ(ierr);
4884   }
4885   ierr = PetscDSSetCoordinateDimension(prob, dimEmbed);CHKERRQ(ierr);
4886   /* Optionally create hybrid DS */
4887   for (f = 0; f < dm->Nf; ++f) {
4888     DMLabel  label = dm->fields[f].label;
4889     PetscInt lStart, lEnd;
4890 
4891     if (label) {
4892       DM       plex;
4893       PetscInt depth, pMax[4];
4894 
4895       ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
4896       ierr = DMPlexGetDepth(plex, &depth);CHKERRQ(ierr);
4897       ierr = DMPlexGetHybridBounds(plex, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);CHKERRQ(ierr);
4898       ierr = DMDestroy(&plex);CHKERRQ(ierr);
4899 
4900       ierr = DMLabelGetBounds(label, &lStart, &lEnd);CHKERRQ(ierr);
4901       if (lStart < pMax[depth]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only support labels over hybrid cells right now");
4902       ierr = PetscDSCreate(comm, &probh);CHKERRQ(ierr);
4903       ierr = DMSetRegionDS(dm, label, probh);CHKERRQ(ierr);
4904       ierr = PetscDSSetHybrid(probh, PETSC_TRUE);CHKERRQ(ierr);
4905       ierr = PetscDSSetCoordinateDimension(probh, dimEmbed);CHKERRQ(ierr);
4906       break;
4907     }
4908   }
4909   /* Set fields in DSes */
4910   for (f = 0; f < dm->Nf; ++f) {
4911     DMLabel     label = dm->fields[f].label;
4912     PetscObject disc  = dm->fields[f].disc;
4913 
4914     if (!label) {
4915       ierr = PetscDSSetDiscretization(prob,  field++,  disc);CHKERRQ(ierr);
4916       if (probh) {
4917         PetscFE subfe;
4918 
4919         ierr = PetscFEGetHeightSubspace((PetscFE) disc, 1, &subfe);CHKERRQ(ierr);
4920         ierr = PetscDSSetDiscretization(probh, fieldh++, (PetscObject) subfe);CHKERRQ(ierr);
4921       }
4922     } else {
4923       ierr = PetscDSSetDiscretization(probh, fieldh++, disc);CHKERRQ(ierr);
4924     }
4925     /* We allow people to have placeholder fields and construct the Section by hand */
4926     {
4927       PetscClassId id;
4928 
4929       ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr);
4930       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
4931     }
4932   }
4933   ierr = PetscDSDestroy(&probh);CHKERRQ(ierr);
4934   /* Setup DSes */
4935   if (doSetup) {
4936     for (s = 0; s < dm->Nds; ++s) {ierr = PetscDSSetUp(dm->probs[s].ds);CHKERRQ(ierr);}
4937   }
4938   PetscFunctionReturn(0);
4939 }
4940 
4941 /*@
4942   DMCopyDS - Copy the discrete systems for the DM into another DM
4943 
4944   Collective on DM
4945 
4946   Input Parameter:
4947 . dm - The DM
4948 
4949   Output Parameter:
4950 . newdm - The DM
4951 
4952   Level: advanced
4953 
4954 .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
4955 @*/
4956 PetscErrorCode DMCopyDS(DM dm, DM newdm)
4957 {
4958   PetscInt       Nds, s;
4959   PetscErrorCode ierr;
4960 
4961   PetscFunctionBegin;
4962   if (dm == newdm) PetscFunctionReturn(0);
4963   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
4964   ierr = DMClearDS(newdm);CHKERRQ(ierr);
4965   for (s = 0; s < Nds; ++s) {
4966     DMLabel label;
4967     PetscDS ds;
4968 
4969     ierr = DMGetRegionNumDS(dm, s, &label, &ds);CHKERRQ(ierr);
4970     ierr = DMSetRegionDS(newdm, label, ds);CHKERRQ(ierr);
4971   }
4972   PetscFunctionReturn(0);
4973 }
4974 
4975 /*@
4976   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
4977 
4978   Collective on DM
4979 
4980   Input Parameter:
4981 . dm - The DM
4982 
4983   Output Parameter:
4984 . newdm - The DM
4985 
4986   Level: advanced
4987 
4988 .seealso: DMCopyFields(), DMCopyDS()
4989 @*/
4990 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
4991 {
4992   PetscErrorCode ierr;
4993 
4994   PetscFunctionBegin;
4995   if (dm == newdm) PetscFunctionReturn(0);
4996   ierr = DMCopyFields(dm, newdm);CHKERRQ(ierr);
4997   ierr = DMCopyDS(dm, newdm);CHKERRQ(ierr);
4998   PetscFunctionReturn(0);
4999 }
5000 
5001 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5002 {
5003   DM dm_coord,dmc_coord;
5004   PetscErrorCode ierr;
5005   Vec coords,ccoords;
5006   Mat inject;
5007   PetscFunctionBegin;
5008   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5009   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
5010   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5011   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
5012   if (coords && !ccoords) {
5013     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
5014     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5015     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
5016     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
5017     ierr = MatDestroy(&inject);CHKERRQ(ierr);
5018     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
5019     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5020   }
5021   PetscFunctionReturn(0);
5022 }
5023 
5024 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5025 {
5026   DM dm_coord,subdm_coord;
5027   PetscErrorCode ierr;
5028   Vec coords,ccoords,clcoords;
5029   VecScatter *scat_i,*scat_g;
5030   PetscFunctionBegin;
5031   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5032   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
5033   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5034   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
5035   if (coords && !ccoords) {
5036     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
5037     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5038     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
5039     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
5040     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
5041     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5042     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5043     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5044     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5045     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
5046     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
5047     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
5048     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
5049     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5050     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
5051     ierr = PetscFree(scat_i);CHKERRQ(ierr);
5052     ierr = PetscFree(scat_g);CHKERRQ(ierr);
5053   }
5054   PetscFunctionReturn(0);
5055 }
5056 
5057 /*@
5058   DMGetDimension - Return the topological dimension of the DM
5059 
5060   Not collective
5061 
5062   Input Parameter:
5063 . dm - The DM
5064 
5065   Output Parameter:
5066 . dim - The topological dimension
5067 
5068   Level: beginner
5069 
5070 .seealso: DMSetDimension(), DMCreate()
5071 @*/
5072 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5073 {
5074   PetscFunctionBegin;
5075   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5076   PetscValidPointer(dim, 2);
5077   *dim = dm->dim;
5078   PetscFunctionReturn(0);
5079 }
5080 
5081 /*@
5082   DMSetDimension - Set the topological dimension of the DM
5083 
5084   Collective on dm
5085 
5086   Input Parameters:
5087 + dm - The DM
5088 - dim - The topological dimension
5089 
5090   Level: beginner
5091 
5092 .seealso: DMGetDimension(), DMCreate()
5093 @*/
5094 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5095 {
5096   PetscDS        ds;
5097   PetscErrorCode ierr;
5098 
5099   PetscFunctionBegin;
5100   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5101   PetscValidLogicalCollectiveInt(dm, dim, 2);
5102   dm->dim = dim;
5103   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5104   if (ds->dimEmbed < 0) {ierr = PetscDSSetCoordinateDimension(ds, dm->dim);CHKERRQ(ierr);}
5105   PetscFunctionReturn(0);
5106 }
5107 
5108 /*@
5109   DMGetDimPoints - Get the half-open interval for all points of a given dimension
5110 
5111   Collective on DM
5112 
5113   Input Parameters:
5114 + dm - the DM
5115 - dim - the dimension
5116 
5117   Output Parameters:
5118 + pStart - The first point of the given dimension
5119 . pEnd - The first point following points of the given dimension
5120 
5121   Note:
5122   The points are vertices in the Hasse diagram encoding the topology. This is explained in
5123   http://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
5124   then the interval is empty.
5125 
5126   Level: intermediate
5127 
5128 .keywords: point, Hasse Diagram, dimension
5129 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5130 @*/
5131 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5132 {
5133   PetscInt       d;
5134   PetscErrorCode ierr;
5135 
5136   PetscFunctionBegin;
5137   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5138   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
5139   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5140   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
5141   PetscFunctionReturn(0);
5142 }
5143 
5144 /*@
5145   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
5146 
5147   Collective on DM
5148 
5149   Input Parameters:
5150 + dm - the DM
5151 - c - coordinate vector
5152 
5153   Notes:
5154   The coordinates do include those for ghost points, which are in the local vector.
5155 
5156   The vector c should be destroyed by the caller.
5157 
5158   Level: intermediate
5159 
5160 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5161 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5162 @*/
5163 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5164 {
5165   PetscErrorCode ierr;
5166 
5167   PetscFunctionBegin;
5168   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5169   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5170   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5171   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5172   dm->coordinates = c;
5173   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5174   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5175   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5176   PetscFunctionReturn(0);
5177 }
5178 
5179 /*@
5180   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
5181 
5182   Not collective
5183 
5184    Input Parameters:
5185 +  dm - the DM
5186 -  c - coordinate vector
5187 
5188   Notes:
5189   The coordinates of ghost points can be set using DMSetCoordinates()
5190   followed by DMGetCoordinatesLocal(). This is intended to enable the
5191   setting of ghost coordinates outside of the domain.
5192 
5193   The vector c should be destroyed by the caller.
5194 
5195   Level: intermediate
5196 
5197 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5198 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5199 @*/
5200 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5201 {
5202   PetscErrorCode ierr;
5203 
5204   PetscFunctionBegin;
5205   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5206   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5207   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5208   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5209 
5210   dm->coordinatesLocal = c;
5211 
5212   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5213   PetscFunctionReturn(0);
5214 }
5215 
5216 /*@
5217   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
5218 
5219   Collective on DM
5220 
5221   Input Parameter:
5222 . dm - the DM
5223 
5224   Output Parameter:
5225 . c - global coordinate vector
5226 
5227   Note:
5228   This is a borrowed reference, so the user should NOT destroy this vector
5229 
5230   Each process has only the local coordinates (does NOT have the ghost coordinates).
5231 
5232   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5233   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5234 
5235   Level: intermediate
5236 
5237 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5238 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5239 @*/
5240 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5241 {
5242   PetscErrorCode ierr;
5243 
5244   PetscFunctionBegin;
5245   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5246   PetscValidPointer(c,2);
5247   if (!dm->coordinates && dm->coordinatesLocal) {
5248     DM cdm = NULL;
5249 
5250     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5251     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
5252     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
5253     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
5254     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
5255   }
5256   *c = dm->coordinates;
5257   PetscFunctionReturn(0);
5258 }
5259 
5260 /*@
5261   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
5262 
5263   Collective on DM
5264 
5265   Input Parameter:
5266 . dm - the DM
5267 
5268   Level: advanced
5269 
5270 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5271 .seealso: DMGetCoordinatesLocalNoncollective()
5272 @*/
5273 PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
5274 {
5275   DM cdm = NULL;
5276   PetscErrorCode ierr;
5277 
5278   PetscFunctionBegin;
5279   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5280   if (!dm->coordinatesLocal && dm->coordinates) {
5281     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5282     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
5283     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
5284     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
5285     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
5286   }
5287   PetscFunctionReturn(0);
5288 }
5289 
5290 /*@
5291   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
5292 
5293   Collective on DM
5294 
5295   Input Parameter:
5296 . dm - the DM
5297 
5298   Output Parameter:
5299 . c - coordinate vector
5300 
5301   Note:
5302   This is a borrowed reference, so the user should NOT destroy this vector
5303 
5304   Each process has the local and ghost coordinates
5305 
5306   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5307   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5308 
5309   Level: intermediate
5310 
5311 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5312 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
5313 @*/
5314 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
5315 {
5316   PetscErrorCode ierr;
5317 
5318   PetscFunctionBegin;
5319   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5320   PetscValidPointer(c,2);
5321   ierr = DMGetCoordinatesLocalSetUp(dm);CHKERRQ(ierr);
5322   *c = dm->coordinatesLocal;
5323   PetscFunctionReturn(0);
5324 }
5325 
5326 /*@
5327   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
5328 
5329   Not collective
5330 
5331   Input Parameter:
5332 . dm - the DM
5333 
5334   Output Parameter:
5335 . c - coordinate vector
5336 
5337   Level: advanced
5338 
5339 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5340 .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5341 @*/
5342 PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
5343 {
5344   PetscFunctionBegin;
5345   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5346   PetscValidPointer(c,2);
5347   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
5348   *c = dm->coordinatesLocal;
5349   PetscFunctionReturn(0);
5350 }
5351 
5352 /*@
5353   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
5354 
5355   Not collective
5356 
5357   Input Parameter:
5358 + dm - the DM
5359 - p - the IS of points whose coordinates will be returned
5360 
5361   Output Parameter:
5362 + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
5363 - pCoord - the Vec with coordinates of points in p
5364 
5365   Note:
5366   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
5367 
5368   This creates a new vector, so the user SHOULD destroy this vector
5369 
5370   Each process has the local and ghost coordinates
5371 
5372   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5373   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5374 
5375   Level: advanced
5376 
5377 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5378 .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5379 @*/
5380 PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
5381 {
5382   PetscSection        cs, newcs;
5383   Vec                 coords;
5384   const PetscScalar   *arr;
5385   PetscScalar         *newarr=NULL;
5386   PetscInt            n;
5387   PetscErrorCode      ierr;
5388 
5389   PetscFunctionBegin;
5390   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5391   PetscValidHeaderSpecific(p, IS_CLASSID, 2);
5392   if (pCoordSection) PetscValidPointer(pCoordSection, 3);
5393   if (pCoord) PetscValidPointer(pCoord, 4);
5394   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
5395   if (!dm->coordinateDM || !dm->coordinateDM->defaultSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
5396   cs = dm->coordinateDM->defaultSection;
5397   coords = dm->coordinatesLocal;
5398   ierr = VecGetArrayRead(coords, &arr);CHKERRQ(ierr);
5399   ierr = PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);CHKERRQ(ierr);
5400   ierr = VecRestoreArrayRead(coords, &arr);CHKERRQ(ierr);
5401   if (pCoord) {
5402     ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr);
5403     /* set array in two steps to mimic PETSC_OWN_POINTER */
5404     ierr = VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);CHKERRQ(ierr);
5405     ierr = VecReplaceArray(*pCoord, newarr);CHKERRQ(ierr);
5406   } else {
5407     ierr = PetscFree(newarr);CHKERRQ(ierr);
5408   }
5409   if (pCoordSection) {*pCoordSection = newcs;}
5410   else               {ierr = PetscSectionDestroy(&newcs);CHKERRQ(ierr);}
5411   PetscFunctionReturn(0);
5412 }
5413 
5414 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
5415 {
5416   PetscErrorCode ierr;
5417 
5418   PetscFunctionBegin;
5419   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5420   PetscValidPointer(field,2);
5421   if (!dm->coordinateField) {
5422     if (dm->ops->createcoordinatefield) {
5423       ierr = (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);CHKERRQ(ierr);
5424     }
5425   }
5426   *field = dm->coordinateField;
5427   PetscFunctionReturn(0);
5428 }
5429 
5430 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
5431 {
5432   PetscErrorCode ierr;
5433 
5434   PetscFunctionBegin;
5435   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5436   if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2);
5437   ierr = PetscObjectReference((PetscObject)field);CHKERRQ(ierr);
5438   ierr = DMFieldDestroy(&dm->coordinateField);CHKERRQ(ierr);
5439   dm->coordinateField = field;
5440   PetscFunctionReturn(0);
5441 }
5442 
5443 /*@
5444   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
5445 
5446   Collective on DM
5447 
5448   Input Parameter:
5449 . dm - the DM
5450 
5451   Output Parameter:
5452 . cdm - coordinate DM
5453 
5454   Level: intermediate
5455 
5456 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5457 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5458 @*/
5459 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
5460 {
5461   PetscErrorCode ierr;
5462 
5463   PetscFunctionBegin;
5464   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5465   PetscValidPointer(cdm,2);
5466   if (!dm->coordinateDM) {
5467     DM cdm;
5468 
5469     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
5470     ierr = (*dm->ops->createcoordinatedm)(dm, &cdm);CHKERRQ(ierr);
5471     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
5472      * until the call to CreateCoordinateDM) */
5473     ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
5474     dm->coordinateDM = cdm;
5475   }
5476   *cdm = dm->coordinateDM;
5477   PetscFunctionReturn(0);
5478 }
5479 
5480 /*@
5481   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
5482 
5483   Logically Collective on DM
5484 
5485   Input Parameters:
5486 + dm - the DM
5487 - cdm - coordinate DM
5488 
5489   Level: intermediate
5490 
5491 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5492 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5493 @*/
5494 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
5495 {
5496   PetscErrorCode ierr;
5497 
5498   PetscFunctionBegin;
5499   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5500   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
5501   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
5502   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
5503   dm->coordinateDM = cdm;
5504   PetscFunctionReturn(0);
5505 }
5506 
5507 /*@
5508   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
5509 
5510   Not Collective
5511 
5512   Input Parameter:
5513 . dm - The DM object
5514 
5515   Output Parameter:
5516 . dim - The embedding dimension
5517 
5518   Level: intermediate
5519 
5520 .keywords: mesh, coordinates
5521 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetSection(), DMSetSection()
5522 @*/
5523 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
5524 {
5525   PetscFunctionBegin;
5526   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5527   PetscValidPointer(dim, 2);
5528   if (dm->dimEmbed == PETSC_DEFAULT) {
5529     dm->dimEmbed = dm->dim;
5530   }
5531   *dim = dm->dimEmbed;
5532   PetscFunctionReturn(0);
5533 }
5534 
5535 /*@
5536   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
5537 
5538   Not Collective
5539 
5540   Input Parameters:
5541 + dm  - The DM object
5542 - dim - The embedding dimension
5543 
5544   Level: intermediate
5545 
5546 .keywords: mesh, coordinates
5547 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetSection(), DMSetSection()
5548 @*/
5549 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
5550 {
5551   PetscDS        ds;
5552   PetscErrorCode ierr;
5553 
5554   PetscFunctionBegin;
5555   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5556   dm->dimEmbed = dim;
5557   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5558   ierr = PetscDSSetCoordinateDimension(ds, dim);CHKERRQ(ierr);
5559   PetscFunctionReturn(0);
5560 }
5561 
5562 /*@
5563   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
5564 
5565   Collective on DM
5566 
5567   Input Parameter:
5568 . dm - The DM object
5569 
5570   Output Parameter:
5571 . section - The PetscSection object
5572 
5573   Level: intermediate
5574 
5575 .keywords: mesh, coordinates
5576 .seealso: DMGetCoordinateDM(), DMGetSection(), DMSetSection()
5577 @*/
5578 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
5579 {
5580   DM             cdm;
5581   PetscErrorCode ierr;
5582 
5583   PetscFunctionBegin;
5584   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5585   PetscValidPointer(section, 2);
5586   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5587   ierr = DMGetSection(cdm, section);CHKERRQ(ierr);
5588   PetscFunctionReturn(0);
5589 }
5590 
5591 /*@
5592   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
5593 
5594   Not Collective
5595 
5596   Input Parameters:
5597 + dm      - The DM object
5598 . dim     - The embedding dimension, or PETSC_DETERMINE
5599 - section - The PetscSection object
5600 
5601   Level: intermediate
5602 
5603 .keywords: mesh, coordinates
5604 .seealso: DMGetCoordinateSection(), DMGetSection(), DMSetSection()
5605 @*/
5606 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
5607 {
5608   DM             cdm;
5609   PetscErrorCode ierr;
5610 
5611   PetscFunctionBegin;
5612   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5613   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
5614   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5615   ierr = DMSetSection(cdm, section);CHKERRQ(ierr);
5616   if (dim == PETSC_DETERMINE) {
5617     PetscInt d = PETSC_DEFAULT;
5618     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
5619 
5620     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5621     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5622     pStart = PetscMax(vStart, pStart);
5623     pEnd   = PetscMin(vEnd, pEnd);
5624     for (v = pStart; v < pEnd; ++v) {
5625       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
5626       if (dd) {d = dd; break;}
5627     }
5628     if (d >= 0) {ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);}
5629   }
5630   PetscFunctionReturn(0);
5631 }
5632 
5633 /*@C
5634   DMGetPeriodicity - Get the description of mesh periodicity
5635 
5636   Input Parameters:
5637 . dm      - The DM object
5638 
5639   Output Parameters:
5640 + per     - Whether the DM is periodic or not
5641 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
5642 . L       - If we assume the mesh is a torus, this is the length of each coordinate
5643 - bd      - This describes the type of periodicity in each topological dimension
5644 
5645   Level: developer
5646 
5647 .seealso: DMGetPeriodicity()
5648 @*/
5649 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
5650 {
5651   PetscFunctionBegin;
5652   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5653   if (per)     *per     = dm->periodic;
5654   if (L)       *L       = dm->L;
5655   if (maxCell) *maxCell = dm->maxCell;
5656   if (bd)      *bd      = dm->bdtype;
5657   PetscFunctionReturn(0);
5658 }
5659 
5660 /*@C
5661   DMSetPeriodicity - Set the description of mesh periodicity
5662 
5663   Input Parameters:
5664 + dm      - The DM object
5665 . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
5666 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
5667 . L       - If we assume the mesh is a torus, this is the length of each coordinate
5668 - bd      - This describes the type of periodicity in each topological dimension
5669 
5670   Level: developer
5671 
5672 .seealso: DMGetPeriodicity()
5673 @*/
5674 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
5675 {
5676   PetscInt       dim, d;
5677   PetscErrorCode ierr;
5678 
5679   PetscFunctionBegin;
5680   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5681   PetscValidLogicalCollectiveBool(dm,per,2);
5682   if (maxCell) {
5683     PetscValidPointer(maxCell,3);
5684     PetscValidPointer(L,4);
5685     PetscValidPointer(bd,5);
5686   }
5687   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
5688   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5689   if (maxCell) {
5690     ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
5691     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
5692   }
5693   dm->periodic = per;
5694   PetscFunctionReturn(0);
5695 }
5696 
5697 /*@
5698   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.
5699 
5700   Input Parameters:
5701 + dm     - The DM
5702 . in     - The input coordinate point (dim numbers)
5703 - endpoint - Include the endpoint L_i
5704 
5705   Output Parameter:
5706 . out - The localized coordinate point
5707 
5708   Level: developer
5709 
5710 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
5711 @*/
5712 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
5713 {
5714   PetscInt       dim, d;
5715   PetscErrorCode ierr;
5716 
5717   PetscFunctionBegin;
5718   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
5719   if (!dm->maxCell) {
5720     for (d = 0; d < dim; ++d) out[d] = in[d];
5721   } else {
5722     if (endpoint) {
5723       for (d = 0; d < dim; ++d) {
5724         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)) {
5725           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
5726         } else {
5727           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
5728         }
5729       }
5730     } else {
5731       for (d = 0; d < dim; ++d) {
5732         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
5733       }
5734     }
5735   }
5736   PetscFunctionReturn(0);
5737 }
5738 
5739 /*
5740   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.
5741 
5742   Input Parameters:
5743 + dm     - The DM
5744 . dim    - The spatial dimension
5745 . anchor - The anchor point, the input point can be no more than maxCell away from it
5746 - in     - The input coordinate point (dim numbers)
5747 
5748   Output Parameter:
5749 . out - The localized coordinate point
5750 
5751   Level: developer
5752 
5753   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
5754 
5755 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
5756 */
5757 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
5758 {
5759   PetscInt d;
5760 
5761   PetscFunctionBegin;
5762   if (!dm->maxCell) {
5763     for (d = 0; d < dim; ++d) out[d] = in[d];
5764   } else {
5765     for (d = 0; d < dim; ++d) {
5766       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
5767         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
5768       } else {
5769         out[d] = in[d];
5770       }
5771     }
5772   }
5773   PetscFunctionReturn(0);
5774 }
5775 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
5776 {
5777   PetscInt d;
5778 
5779   PetscFunctionBegin;
5780   if (!dm->maxCell) {
5781     for (d = 0; d < dim; ++d) out[d] = in[d];
5782   } else {
5783     for (d = 0; d < dim; ++d) {
5784       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
5785         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
5786       } else {
5787         out[d] = in[d];
5788       }
5789     }
5790   }
5791   PetscFunctionReturn(0);
5792 }
5793 
5794 /*
5795   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.
5796 
5797   Input Parameters:
5798 + dm     - The DM
5799 . dim    - The spatial dimension
5800 . anchor - The anchor point, the input point can be no more than maxCell away from it
5801 . in     - The input coordinate delta (dim numbers)
5802 - out    - The input coordinate point (dim numbers)
5803 
5804   Output Parameter:
5805 . out    - The localized coordinate in + out
5806 
5807   Level: developer
5808 
5809   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
5810 
5811 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
5812 */
5813 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
5814 {
5815   PetscInt d;
5816 
5817   PetscFunctionBegin;
5818   if (!dm->maxCell) {
5819     for (d = 0; d < dim; ++d) out[d] += in[d];
5820   } else {
5821     for (d = 0; d < dim; ++d) {
5822       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
5823         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
5824       } else {
5825         out[d] += in[d];
5826       }
5827     }
5828   }
5829   PetscFunctionReturn(0);
5830 }
5831 
5832 /*@
5833   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
5834 
5835   Not collective
5836 
5837   Input Parameter:
5838 . dm - The DM
5839 
5840   Output Parameter:
5841   areLocalized - True if localized
5842 
5843   Level: developer
5844 
5845 .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
5846 @*/
5847 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
5848 {
5849   DM             cdm;
5850   PetscSection   coordSection;
5851   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
5852   PetscBool      isPlex, alreadyLocalized;
5853   PetscErrorCode ierr;
5854 
5855   PetscFunctionBegin;
5856   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5857   PetscValidPointer(areLocalized, 2);
5858   *areLocalized = PETSC_FALSE;
5859 
5860   /* We need some generic way of refering to cells/vertices */
5861   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5862   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5863   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
5864   if (!isPlex) SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
5865 
5866   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5867   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
5868   alreadyLocalized = PETSC_FALSE;
5869   for (c = cStart; c < cEnd; ++c) {
5870     if (c < sStart || c >= sEnd) continue;
5871     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
5872     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
5873   }
5874   *areLocalized = alreadyLocalized;
5875   PetscFunctionReturn(0);
5876 }
5877 
5878 /*@
5879   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
5880 
5881   Collective on dm
5882 
5883   Input Parameter:
5884 . dm - The DM
5885 
5886   Output Parameter:
5887   areLocalized - True if localized
5888 
5889   Level: developer
5890 
5891 .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
5892 @*/
5893 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
5894 {
5895   PetscBool      localized;
5896   PetscErrorCode ierr;
5897 
5898   PetscFunctionBegin;
5899   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5900   PetscValidPointer(areLocalized, 2);
5901   ierr = DMGetCoordinatesLocalizedLocal(dm,&localized);CHKERRQ(ierr);
5902   ierr = MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
5903   PetscFunctionReturn(0);
5904 }
5905 
5906 /*@
5907   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
5908 
5909   Collective on dm
5910 
5911   Input Parameter:
5912 . dm - The DM
5913 
5914   Level: developer
5915 
5916 .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
5917 @*/
5918 PetscErrorCode DMLocalizeCoordinates(DM dm)
5919 {
5920   DM             cdm;
5921   PetscSection   coordSection, cSection;
5922   Vec            coordinates,  cVec;
5923   PetscScalar   *coords, *coords2, *anchor, *localized;
5924   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
5925   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
5926   PetscInt       maxHeight = 0, h;
5927   PetscInt       *pStart = NULL, *pEnd = NULL;
5928   PetscErrorCode ierr;
5929 
5930   PetscFunctionBegin;
5931   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5932   if (!dm->periodic) PetscFunctionReturn(0);
5933   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
5934   if (alreadyLocalized) PetscFunctionReturn(0);
5935 
5936   /* We need some generic way of refering to cells/vertices */
5937   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5938   {
5939     PetscBool isplex;
5940 
5941     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
5942     if (isplex) {
5943       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5944       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
5945       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
5946       pEnd = &pStart[maxHeight + 1];
5947       newStart = vStart;
5948       newEnd   = vEnd;
5949       for (h = 0; h <= maxHeight; h++) {
5950         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
5951         newStart = PetscMin(newStart,pStart[h]);
5952         newEnd   = PetscMax(newEnd,pEnd[h]);
5953       }
5954     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
5955   }
5956   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5957   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
5958   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5959   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
5960   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
5961 
5962   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
5963   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
5964   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
5965   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
5966   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
5967 
5968   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
5969   localized = &anchor[bs];
5970   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
5971   for (h = 0; h <= maxHeight; h++) {
5972     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
5973 
5974     for (c = cStart; c < cEnd; ++c) {
5975       PetscScalar *cellCoords = NULL;
5976       PetscInt     b;
5977 
5978       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
5979       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5980       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
5981       for (d = 0; d < dof/bs; ++d) {
5982         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
5983         for (b = 0; b < bs; b++) {
5984           if (cellCoords[d*bs + b] != localized[b]) break;
5985         }
5986         if (b < bs) break;
5987       }
5988       if (d < dof/bs) {
5989         if (c >= sStart && c < sEnd) {
5990           PetscInt cdof;
5991 
5992           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
5993           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
5994         }
5995         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
5996         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
5997       }
5998       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5999     }
6000   }
6001   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6002   if (alreadyLocalizedGlobal) {
6003     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6004     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6005     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6006     PetscFunctionReturn(0);
6007   }
6008   for (v = vStart; v < vEnd; ++v) {
6009     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6010     ierr = PetscSectionSetDof(cSection, v, dof);CHKERRQ(ierr);
6011     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
6012   }
6013   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
6014   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
6015   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
6016   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
6017   ierr = VecSetBlockSize(cVec, bs);CHKERRQ(ierr);
6018   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
6019   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
6020   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6021   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
6022   for (v = vStart; v < vEnd; ++v) {
6023     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6024     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6025     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
6026     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6027   }
6028   for (h = 0; h <= maxHeight; h++) {
6029     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6030 
6031     for (c = cStart; c < cEnd; ++c) {
6032       PetscScalar *cellCoords = NULL;
6033       PetscInt     b, cdof;
6034 
6035       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
6036       if (!cdof) continue;
6037       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6038       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
6039       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6040       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
6041       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6042     }
6043   }
6044   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6045   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6046   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6047   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
6048   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
6049   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
6050   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
6051   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6052   PetscFunctionReturn(0);
6053 }
6054 
6055 /*@
6056   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6057 
6058   Collective on Vec v (see explanation below)
6059 
6060   Input Parameters:
6061 + dm - The DM
6062 . v - The Vec of points
6063 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6064 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
6065 
6066   Output Parameter:
6067 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6068 - cells - The PetscSF containing the ranks and local indices of the containing points.
6069 
6070 
6071   Level: developer
6072 
6073   Notes:
6074   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6075   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
6076 
6077   If *cellSF is NULL on input, a PetscSF will be created.
6078   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
6079 
6080   An array that maps each point to its containing cell can be obtained with
6081 
6082 $    const PetscSFNode *cells;
6083 $    PetscInt           nFound;
6084 $    const PetscInt    *found;
6085 $
6086 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
6087 
6088   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6089   the index of the cell in its rank's local numbering.
6090 
6091 .keywords: point location, mesh
6092 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6093 @*/
6094 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6095 {
6096   PetscErrorCode ierr;
6097 
6098   PetscFunctionBegin;
6099   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6100   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
6101   PetscValidPointer(cellSF,4);
6102   if (*cellSF) {
6103     PetscMPIInt result;
6104 
6105     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
6106     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
6107     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6108   } else {
6109     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
6110   }
6111   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6112   if (dm->ops->locatepoints) {
6113     ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
6114   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6115   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6116   PetscFunctionReturn(0);
6117 }
6118 
6119 /*@
6120   DMGetOutputDM - Retrieve the DM associated with the layout for output
6121 
6122   Collective on dm
6123 
6124   Input Parameter:
6125 . dm - The original DM
6126 
6127   Output Parameter:
6128 . odm - The DM which provides the layout for output
6129 
6130   Level: intermediate
6131 
6132 .seealso: VecView(), DMGetGlobalSection()
6133 @*/
6134 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6135 {
6136   PetscSection   section;
6137   PetscBool      hasConstraints, ghasConstraints;
6138   PetscErrorCode ierr;
6139 
6140   PetscFunctionBegin;
6141   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6142   PetscValidPointer(odm,2);
6143   ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
6144   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
6145   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
6146   if (!ghasConstraints) {
6147     *odm = dm;
6148     PetscFunctionReturn(0);
6149   }
6150   if (!dm->dmBC) {
6151     PetscSection newSection, gsection;
6152     PetscSF      sf;
6153 
6154     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
6155     ierr = DMCopyDisc(dm, dm->dmBC);CHKERRQ(ierr);
6156     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
6157     ierr = DMSetSection(dm->dmBC, newSection);CHKERRQ(ierr);
6158     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
6159     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
6160     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
6161     ierr = DMSetGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
6162     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
6163   }
6164   *odm = dm->dmBC;
6165   PetscFunctionReturn(0);
6166 }
6167 
6168 /*@
6169   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6170 
6171   Input Parameter:
6172 . dm - The original DM
6173 
6174   Output Parameters:
6175 + num - The output sequence number
6176 - val - The output sequence value
6177 
6178   Level: intermediate
6179 
6180   Note: This is intended for output that should appear in sequence, for instance
6181   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6182 
6183 .seealso: VecView()
6184 @*/
6185 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6186 {
6187   PetscFunctionBegin;
6188   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6189   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
6190   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
6191   PetscFunctionReturn(0);
6192 }
6193 
6194 /*@
6195   DMSetOutputSequenceNumber - Set the sequence number/value for output
6196 
6197   Input Parameters:
6198 + dm - The original DM
6199 . num - The output sequence number
6200 - val - The output sequence value
6201 
6202   Level: intermediate
6203 
6204   Note: This is intended for output that should appear in sequence, for instance
6205   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6206 
6207 .seealso: VecView()
6208 @*/
6209 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6210 {
6211   PetscFunctionBegin;
6212   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6213   dm->outputSequenceNum = num;
6214   dm->outputSequenceVal = val;
6215   PetscFunctionReturn(0);
6216 }
6217 
6218 /*@C
6219   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
6220 
6221   Input Parameters:
6222 + dm   - The original DM
6223 . name - The sequence name
6224 - num  - The output sequence number
6225 
6226   Output Parameter:
6227 . val  - The output sequence value
6228 
6229   Level: intermediate
6230 
6231   Note: This is intended for output that should appear in sequence, for instance
6232   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6233 
6234 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
6235 @*/
6236 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6237 {
6238   PetscBool      ishdf5;
6239   PetscErrorCode ierr;
6240 
6241   PetscFunctionBegin;
6242   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6243   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
6244   PetscValidPointer(val,4);
6245   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
6246   if (ishdf5) {
6247 #if defined(PETSC_HAVE_HDF5)
6248     PetscScalar value;
6249 
6250     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
6251     *val = PetscRealPart(value);
6252 #endif
6253   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6254   PetscFunctionReturn(0);
6255 }
6256 
6257 /*@
6258   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
6259 
6260   Not collective
6261 
6262   Input Parameter:
6263 . dm - The DM
6264 
6265   Output Parameter:
6266 . useNatural - The flag to build the mapping to a natural order during distribution
6267 
6268   Level: beginner
6269 
6270 .seealso: DMSetUseNatural(), DMCreate()
6271 @*/
6272 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6273 {
6274   PetscFunctionBegin;
6275   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6276   PetscValidPointer(useNatural, 2);
6277   *useNatural = dm->useNatural;
6278   PetscFunctionReturn(0);
6279 }
6280 
6281 /*@
6282   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
6283 
6284   Collective on dm
6285 
6286   Input Parameters:
6287 + dm - The DM
6288 - useNatural - The flag to build the mapping to a natural order during distribution
6289 
6290   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
6291 
6292   Level: beginner
6293 
6294 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
6295 @*/
6296 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6297 {
6298   PetscFunctionBegin;
6299   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6300   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6301   dm->useNatural = useNatural;
6302   PetscFunctionReturn(0);
6303 }
6304 
6305 
6306 /*@C
6307   DMCreateLabel - Create a label of the given name if it does not already exist
6308 
6309   Not Collective
6310 
6311   Input Parameters:
6312 + dm   - The DM object
6313 - name - The label name
6314 
6315   Level: intermediate
6316 
6317 .keywords: mesh
6318 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6319 @*/
6320 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6321 {
6322   DMLabelLink    next  = dm->labels->next;
6323   PetscBool      flg   = PETSC_FALSE;
6324   const char    *lname;
6325   PetscErrorCode ierr;
6326 
6327   PetscFunctionBegin;
6328   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6329   PetscValidCharPointer(name, 2);
6330   while (next) {
6331     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6332     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
6333     if (flg) break;
6334     next = next->next;
6335   }
6336   if (!flg) {
6337     DMLabelLink tmpLabel;
6338 
6339     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
6340     ierr = DMLabelCreate(PETSC_COMM_SELF, name, &tmpLabel->label);CHKERRQ(ierr);
6341     tmpLabel->output = PETSC_TRUE;
6342     tmpLabel->next   = dm->labels->next;
6343     dm->labels->next = tmpLabel;
6344   }
6345   PetscFunctionReturn(0);
6346 }
6347 
6348 /*@C
6349   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
6350 
6351   Not Collective
6352 
6353   Input Parameters:
6354 + dm   - The DM object
6355 . name - The label name
6356 - point - The mesh point
6357 
6358   Output Parameter:
6359 . value - The label value for this point, or -1 if the point is not in the label
6360 
6361   Level: beginner
6362 
6363 .keywords: mesh
6364 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
6365 @*/
6366 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6367 {
6368   DMLabel        label;
6369   PetscErrorCode ierr;
6370 
6371   PetscFunctionBegin;
6372   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6373   PetscValidCharPointer(name, 2);
6374   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6375   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6376   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
6377   PetscFunctionReturn(0);
6378 }
6379 
6380 /*@C
6381   DMSetLabelValue - Add a point to a Sieve Label with given value
6382 
6383   Not Collective
6384 
6385   Input Parameters:
6386 + dm   - The DM object
6387 . name - The label name
6388 . point - The mesh point
6389 - value - The label value for this point
6390 
6391   Output Parameter:
6392 
6393   Level: beginner
6394 
6395 .keywords: mesh
6396 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
6397 @*/
6398 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6399 {
6400   DMLabel        label;
6401   PetscErrorCode ierr;
6402 
6403   PetscFunctionBegin;
6404   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6405   PetscValidCharPointer(name, 2);
6406   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6407   if (!label) {
6408     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
6409     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6410   }
6411   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
6412   PetscFunctionReturn(0);
6413 }
6414 
6415 /*@C
6416   DMClearLabelValue - Remove a point from a Sieve Label with given value
6417 
6418   Not Collective
6419 
6420   Input Parameters:
6421 + dm   - The DM object
6422 . name - The label name
6423 . point - The mesh point
6424 - value - The label value for this point
6425 
6426   Output Parameter:
6427 
6428   Level: beginner
6429 
6430 .keywords: mesh
6431 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
6432 @*/
6433 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6434 {
6435   DMLabel        label;
6436   PetscErrorCode ierr;
6437 
6438   PetscFunctionBegin;
6439   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6440   PetscValidCharPointer(name, 2);
6441   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6442   if (!label) PetscFunctionReturn(0);
6443   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
6444   PetscFunctionReturn(0);
6445 }
6446 
6447 /*@C
6448   DMGetLabelSize - Get the number of different integer ids in a Label
6449 
6450   Not Collective
6451 
6452   Input Parameters:
6453 + dm   - The DM object
6454 - name - The label name
6455 
6456   Output Parameter:
6457 . size - The number of different integer ids, or 0 if the label does not exist
6458 
6459   Level: beginner
6460 
6461 .keywords: mesh
6462 .seealso: DMLabelGetNumValues(), DMSetLabelValue()
6463 @*/
6464 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6465 {
6466   DMLabel        label;
6467   PetscErrorCode ierr;
6468 
6469   PetscFunctionBegin;
6470   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6471   PetscValidCharPointer(name, 2);
6472   PetscValidPointer(size, 3);
6473   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6474   *size = 0;
6475   if (!label) PetscFunctionReturn(0);
6476   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
6477   PetscFunctionReturn(0);
6478 }
6479 
6480 /*@C
6481   DMGetLabelIdIS - Get the integer ids in a label
6482 
6483   Not Collective
6484 
6485   Input Parameters:
6486 + mesh - The DM object
6487 - name - The label name
6488 
6489   Output Parameter:
6490 . ids - The integer ids, or NULL if the label does not exist
6491 
6492   Level: beginner
6493 
6494 .keywords: mesh
6495 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
6496 @*/
6497 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6498 {
6499   DMLabel        label;
6500   PetscErrorCode ierr;
6501 
6502   PetscFunctionBegin;
6503   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6504   PetscValidCharPointer(name, 2);
6505   PetscValidPointer(ids, 3);
6506   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6507   *ids = NULL;
6508  if (label) {
6509     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
6510   } else {
6511     /* returning an empty IS */
6512     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
6513   }
6514   PetscFunctionReturn(0);
6515 }
6516 
6517 /*@C
6518   DMGetStratumSize - Get the number of points in a label stratum
6519 
6520   Not Collective
6521 
6522   Input Parameters:
6523 + dm - The DM object
6524 . name - The label name
6525 - value - The stratum value
6526 
6527   Output Parameter:
6528 . size - The stratum size
6529 
6530   Level: beginner
6531 
6532 .keywords: mesh
6533 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
6534 @*/
6535 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6536 {
6537   DMLabel        label;
6538   PetscErrorCode ierr;
6539 
6540   PetscFunctionBegin;
6541   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6542   PetscValidCharPointer(name, 2);
6543   PetscValidPointer(size, 4);
6544   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6545   *size = 0;
6546   if (!label) PetscFunctionReturn(0);
6547   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
6548   PetscFunctionReturn(0);
6549 }
6550 
6551 /*@C
6552   DMGetStratumIS - Get the points in a label stratum
6553 
6554   Not Collective
6555 
6556   Input Parameters:
6557 + dm - The DM object
6558 . name - The label name
6559 - value - The stratum value
6560 
6561   Output Parameter:
6562 . points - The stratum points, or NULL if the label does not exist or does not have that value
6563 
6564   Level: beginner
6565 
6566 .keywords: mesh
6567 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
6568 @*/
6569 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6570 {
6571   DMLabel        label;
6572   PetscErrorCode ierr;
6573 
6574   PetscFunctionBegin;
6575   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6576   PetscValidCharPointer(name, 2);
6577   PetscValidPointer(points, 4);
6578   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6579   *points = NULL;
6580   if (!label) PetscFunctionReturn(0);
6581   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
6582   PetscFunctionReturn(0);
6583 }
6584 
6585 /*@C
6586   DMSetStratumIS - Set the points in a label stratum
6587 
6588   Not Collective
6589 
6590   Input Parameters:
6591 + dm - The DM object
6592 . name - The label name
6593 . value - The stratum value
6594 - points - The stratum points
6595 
6596   Level: beginner
6597 
6598 .keywords: mesh
6599 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
6600 @*/
6601 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6602 {
6603   DMLabel        label;
6604   PetscErrorCode ierr;
6605 
6606   PetscFunctionBegin;
6607   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6608   PetscValidCharPointer(name, 2);
6609   PetscValidPointer(points, 4);
6610   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6611   if (!label) PetscFunctionReturn(0);
6612   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
6613   PetscFunctionReturn(0);
6614 }
6615 
6616 /*@C
6617   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
6618 
6619   Not Collective
6620 
6621   Input Parameters:
6622 + dm   - The DM object
6623 . name - The label name
6624 - value - The label value for this point
6625 
6626   Output Parameter:
6627 
6628   Level: beginner
6629 
6630 .keywords: mesh
6631 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
6632 @*/
6633 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6634 {
6635   DMLabel        label;
6636   PetscErrorCode ierr;
6637 
6638   PetscFunctionBegin;
6639   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6640   PetscValidCharPointer(name, 2);
6641   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6642   if (!label) PetscFunctionReturn(0);
6643   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
6644   PetscFunctionReturn(0);
6645 }
6646 
6647 /*@
6648   DMGetNumLabels - Return the number of labels defined by the mesh
6649 
6650   Not Collective
6651 
6652   Input Parameter:
6653 . dm   - The DM object
6654 
6655   Output Parameter:
6656 . numLabels - the number of Labels
6657 
6658   Level: intermediate
6659 
6660 .keywords: mesh
6661 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6662 @*/
6663 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6664 {
6665   DMLabelLink next = dm->labels->next;
6666   PetscInt  n    = 0;
6667 
6668   PetscFunctionBegin;
6669   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6670   PetscValidPointer(numLabels, 2);
6671   while (next) {++n; next = next->next;}
6672   *numLabels = n;
6673   PetscFunctionReturn(0);
6674 }
6675 
6676 /*@C
6677   DMGetLabelName - Return the name of nth label
6678 
6679   Not Collective
6680 
6681   Input Parameters:
6682 + dm - The DM object
6683 - n  - the label number
6684 
6685   Output Parameter:
6686 . name - the label name
6687 
6688   Level: intermediate
6689 
6690 .keywords: mesh
6691 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6692 @*/
6693 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
6694 {
6695   DMLabelLink    next = dm->labels->next;
6696   PetscInt       l    = 0;
6697   PetscErrorCode ierr;
6698 
6699   PetscFunctionBegin;
6700   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6701   PetscValidPointer(name, 3);
6702   while (next) {
6703     if (l == n) {
6704       ierr = PetscObjectGetName((PetscObject) next->label, name);CHKERRQ(ierr);
6705       PetscFunctionReturn(0);
6706     }
6707     ++l;
6708     next = next->next;
6709   }
6710   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
6711 }
6712 
6713 /*@C
6714   DMHasLabel - Determine whether the mesh has a label of a given name
6715 
6716   Not Collective
6717 
6718   Input Parameters:
6719 + dm   - The DM object
6720 - name - The label name
6721 
6722   Output Parameter:
6723 . hasLabel - PETSC_TRUE if the label is present
6724 
6725   Level: intermediate
6726 
6727 .keywords: mesh
6728 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6729 @*/
6730 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
6731 {
6732   DMLabelLink    next = dm->labels->next;
6733   const char    *lname;
6734   PetscErrorCode ierr;
6735 
6736   PetscFunctionBegin;
6737   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6738   PetscValidCharPointer(name, 2);
6739   PetscValidPointer(hasLabel, 3);
6740   *hasLabel = PETSC_FALSE;
6741   while (next) {
6742     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6743     ierr = PetscStrcmp(name, lname, hasLabel);CHKERRQ(ierr);
6744     if (*hasLabel) break;
6745     next = next->next;
6746   }
6747   PetscFunctionReturn(0);
6748 }
6749 
6750 /*@C
6751   DMGetLabel - Return the label of a given name, or NULL
6752 
6753   Not Collective
6754 
6755   Input Parameters:
6756 + dm   - The DM object
6757 - name - The label name
6758 
6759   Output Parameter:
6760 . label - The DMLabel, or NULL if the label is absent
6761 
6762   Level: intermediate
6763 
6764 .keywords: mesh
6765 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6766 @*/
6767 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
6768 {
6769   DMLabelLink    next = dm->labels->next;
6770   PetscBool      hasLabel;
6771   const char    *lname;
6772   PetscErrorCode ierr;
6773 
6774   PetscFunctionBegin;
6775   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6776   PetscValidCharPointer(name, 2);
6777   PetscValidPointer(label, 3);
6778   *label = NULL;
6779   while (next) {
6780     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6781     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
6782     if (hasLabel) {
6783       *label = next->label;
6784       break;
6785     }
6786     next = next->next;
6787   }
6788   PetscFunctionReturn(0);
6789 }
6790 
6791 /*@C
6792   DMGetLabelByNum - Return the nth label
6793 
6794   Not Collective
6795 
6796   Input Parameters:
6797 + dm - The DM object
6798 - n  - the label number
6799 
6800   Output Parameter:
6801 . label - the label
6802 
6803   Level: intermediate
6804 
6805 .keywords: mesh
6806 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6807 @*/
6808 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
6809 {
6810   DMLabelLink next = dm->labels->next;
6811   PetscInt    l    = 0;
6812 
6813   PetscFunctionBegin;
6814   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6815   PetscValidPointer(label, 3);
6816   while (next) {
6817     if (l == n) {
6818       *label = next->label;
6819       PetscFunctionReturn(0);
6820     }
6821     ++l;
6822     next = next->next;
6823   }
6824   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
6825 }
6826 
6827 /*@C
6828   DMAddLabel - Add the label to this mesh
6829 
6830   Not Collective
6831 
6832   Input Parameters:
6833 + dm   - The DM object
6834 - label - The DMLabel
6835 
6836   Level: developer
6837 
6838 .keywords: mesh
6839 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6840 @*/
6841 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
6842 {
6843   DMLabelLink    tmpLabel;
6844   PetscBool      hasLabel;
6845   const char    *lname;
6846   PetscErrorCode ierr;
6847 
6848   PetscFunctionBegin;
6849   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6850   ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
6851   ierr = DMHasLabel(dm, lname, &hasLabel);CHKERRQ(ierr);
6852   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
6853   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
6854   tmpLabel->label  = label;
6855   tmpLabel->output = PETSC_TRUE;
6856   tmpLabel->next   = dm->labels->next;
6857   dm->labels->next = tmpLabel;
6858   PetscFunctionReturn(0);
6859 }
6860 
6861 /*@C
6862   DMRemoveLabel - Remove the label from this mesh
6863 
6864   Not Collective
6865 
6866   Input Parameters:
6867 + dm   - The DM object
6868 - name - The label name
6869 
6870   Output Parameter:
6871 . label - The DMLabel, or NULL if the label is absent
6872 
6873   Level: developer
6874 
6875 .keywords: mesh
6876 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6877 @*/
6878 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
6879 {
6880   DMLabelLink    next = dm->labels->next;
6881   DMLabelLink    last = NULL;
6882   PetscBool      hasLabel;
6883   const char    *lname;
6884   PetscErrorCode ierr;
6885 
6886   PetscFunctionBegin;
6887   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6888   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
6889   *label = NULL;
6890   if (!hasLabel) PetscFunctionReturn(0);
6891   while (next) {
6892     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6893     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
6894     if (hasLabel) {
6895       if (last) last->next       = next->next;
6896       else      dm->labels->next = next->next;
6897       next->next = NULL;
6898       *label     = next->label;
6899       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
6900       if (hasLabel) {
6901         dm->depthLabel = NULL;
6902       }
6903       ierr = PetscFree(next);CHKERRQ(ierr);
6904       break;
6905     }
6906     last = next;
6907     next = next->next;
6908   }
6909   PetscFunctionReturn(0);
6910 }
6911 
6912 /*@C
6913   DMGetLabelOutput - Get the output flag for a given label
6914 
6915   Not Collective
6916 
6917   Input Parameters:
6918 + dm   - The DM object
6919 - name - The label name
6920 
6921   Output Parameter:
6922 . output - The flag for output
6923 
6924   Level: developer
6925 
6926 .keywords: mesh
6927 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6928 @*/
6929 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
6930 {
6931   DMLabelLink    next = dm->labels->next;
6932   const char    *lname;
6933   PetscErrorCode ierr;
6934 
6935   PetscFunctionBegin;
6936   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6937   PetscValidPointer(name, 2);
6938   PetscValidPointer(output, 3);
6939   while (next) {
6940     PetscBool flg;
6941 
6942     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6943     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
6944     if (flg) {*output = next->output; PetscFunctionReturn(0);}
6945     next = next->next;
6946   }
6947   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
6948 }
6949 
6950 /*@C
6951   DMSetLabelOutput - Set the output flag for a given label
6952 
6953   Not Collective
6954 
6955   Input Parameters:
6956 + dm     - The DM object
6957 . name   - The label name
6958 - output - The flag for output
6959 
6960   Level: developer
6961 
6962 .keywords: mesh
6963 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6964 @*/
6965 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
6966 {
6967   DMLabelLink    next = dm->labels->next;
6968   const char    *lname;
6969   PetscErrorCode ierr;
6970 
6971   PetscFunctionBegin;
6972   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6973   PetscValidPointer(name, 2);
6974   while (next) {
6975     PetscBool flg;
6976 
6977     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6978     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
6979     if (flg) {next->output = output; PetscFunctionReturn(0);}
6980     next = next->next;
6981   }
6982   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
6983 }
6984 
6985 
6986 /*@
6987   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
6988 
6989   Collective on DM
6990 
6991   Input Parameter:
6992 . dmA - The DM object with initial labels
6993 
6994   Output Parameter:
6995 . dmB - The DM object with copied labels
6996 
6997   Level: intermediate
6998 
6999   Note: This is typically used when interpolating or otherwise adding to a mesh
7000 
7001 .keywords: mesh
7002 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
7003 @*/
7004 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
7005 {
7006   PetscInt       numLabels, l;
7007   PetscErrorCode ierr;
7008 
7009   PetscFunctionBegin;
7010   if (dmA == dmB) PetscFunctionReturn(0);
7011   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
7012   for (l = 0; l < numLabels; ++l) {
7013     DMLabel     label, labelNew;
7014     const char *name;
7015     PetscBool   flg;
7016 
7017     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
7018     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
7019     if (flg) continue;
7020     ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
7021     if (flg) continue;
7022     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
7023     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
7024     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
7025   }
7026   PetscFunctionReturn(0);
7027 }
7028 
7029 /*@
7030   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
7031 
7032   Input Parameter:
7033 . dm - The DM object
7034 
7035   Output Parameter:
7036 . cdm - The coarse DM
7037 
7038   Level: intermediate
7039 
7040 .seealso: DMSetCoarseDM()
7041 @*/
7042 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7043 {
7044   PetscFunctionBegin;
7045   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7046   PetscValidPointer(cdm, 2);
7047   *cdm = dm->coarseMesh;
7048   PetscFunctionReturn(0);
7049 }
7050 
7051 /*@
7052   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
7053 
7054   Input Parameters:
7055 + dm - The DM object
7056 - cdm - The coarse DM
7057 
7058   Level: intermediate
7059 
7060 .seealso: DMGetCoarseDM()
7061 @*/
7062 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7063 {
7064   PetscErrorCode ierr;
7065 
7066   PetscFunctionBegin;
7067   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7068   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7069   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
7070   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
7071   dm->coarseMesh = cdm;
7072   PetscFunctionReturn(0);
7073 }
7074 
7075 /*@
7076   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
7077 
7078   Input Parameter:
7079 . dm - The DM object
7080 
7081   Output Parameter:
7082 . fdm - The fine DM
7083 
7084   Level: intermediate
7085 
7086 .seealso: DMSetFineDM()
7087 @*/
7088 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7089 {
7090   PetscFunctionBegin;
7091   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7092   PetscValidPointer(fdm, 2);
7093   *fdm = dm->fineMesh;
7094   PetscFunctionReturn(0);
7095 }
7096 
7097 /*@
7098   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
7099 
7100   Input Parameters:
7101 + dm - The DM object
7102 - fdm - The fine DM
7103 
7104   Level: intermediate
7105 
7106 .seealso: DMGetFineDM()
7107 @*/
7108 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7109 {
7110   PetscErrorCode ierr;
7111 
7112   PetscFunctionBegin;
7113   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7114   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7115   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
7116   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
7117   dm->fineMesh = fdm;
7118   PetscFunctionReturn(0);
7119 }
7120 
7121 /*=== DMBoundary code ===*/
7122 
7123 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7124 {
7125   PetscInt       d;
7126   PetscErrorCode ierr;
7127 
7128   PetscFunctionBegin;
7129   for (d = 0; d < dm->Nds; ++d) {
7130     ierr = PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);CHKERRQ(ierr);
7131   }
7132   PetscFunctionReturn(0);
7133 }
7134 
7135 /*@C
7136   DMAddBoundary - Add a boundary condition to the model
7137 
7138   Input Parameters:
7139 + dm          - The DM, with a PetscDS that matches the problem being constrained
7140 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7141 . name        - The BC name
7142 . labelname   - The label defining constrained points
7143 . field       - The field to constrain
7144 . numcomps    - The number of constrained field components (0 will constrain all fields)
7145 . comps       - An array of constrained component numbers
7146 . bcFunc      - A pointwise function giving boundary values
7147 . numids      - The number of DMLabel ids for constrained points
7148 . ids         - An array of ids for constrained points
7149 - ctx         - An optional user context for bcFunc
7150 
7151   Options Database Keys:
7152 + -bc_<boundary name> <num> - Overrides the boundary ids
7153 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7154 
7155   Level: developer
7156 
7157 .seealso: DMGetBoundary()
7158 @*/
7159 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)
7160 {
7161   PetscDS        ds;
7162   PetscErrorCode ierr;
7163 
7164   PetscFunctionBegin;
7165   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7166   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7167   ierr = PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, numids, ids, ctx);CHKERRQ(ierr);
7168   PetscFunctionReturn(0);
7169 }
7170 
7171 /*@
7172   DMGetNumBoundary - Get the number of registered BC
7173 
7174   Input Parameters:
7175 . dm - The mesh object
7176 
7177   Output Parameters:
7178 . numBd - The number of BC
7179 
7180   Level: intermediate
7181 
7182 .seealso: DMAddBoundary(), DMGetBoundary()
7183 @*/
7184 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
7185 {
7186   PetscDS        ds;
7187   PetscErrorCode ierr;
7188 
7189   PetscFunctionBegin;
7190   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7191   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7192   ierr = PetscDSGetNumBoundary(ds, numBd);CHKERRQ(ierr);
7193   PetscFunctionReturn(0);
7194 }
7195 
7196 /*@C
7197   DMGetBoundary - Get a model boundary condition
7198 
7199   Input Parameters:
7200 + dm          - The mesh object
7201 - bd          - The BC number
7202 
7203   Output Parameters:
7204 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7205 . name        - The BC name
7206 . labelname   - The label defining constrained points
7207 . field       - The field to constrain
7208 . numcomps    - The number of constrained field components
7209 . comps       - An array of constrained component numbers
7210 . bcFunc      - A pointwise function giving boundary values
7211 . numids      - The number of DMLabel ids for constrained points
7212 . ids         - An array of ids for constrained points
7213 - ctx         - An optional user context for bcFunc
7214 
7215   Options Database Keys:
7216 + -bc_<boundary name> <num> - Overrides the boundary ids
7217 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7218 
7219   Level: developer
7220 
7221 .seealso: DMAddBoundary()
7222 @*/
7223 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)
7224 {
7225   PetscDS        ds;
7226   PetscErrorCode ierr;
7227 
7228   PetscFunctionBegin;
7229   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7230   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7231   ierr = PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, numids, ids, ctx);CHKERRQ(ierr);
7232   PetscFunctionReturn(0);
7233 }
7234 
7235 static PetscErrorCode DMPopulateBoundary(DM dm)
7236 {
7237   PetscDS        ds;
7238   DMBoundary    *lastnext;
7239   DSBoundary     dsbound;
7240   PetscErrorCode ierr;
7241 
7242   PetscFunctionBegin;
7243   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7244   dsbound = ds->boundary;
7245   if (dm->boundary) {
7246     DMBoundary next = dm->boundary;
7247 
7248     /* quick check to see if the PetscDS has changed */
7249     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
7250     /* the PetscDS has changed: tear down and rebuild */
7251     while (next) {
7252       DMBoundary b = next;
7253 
7254       next = b->next;
7255       ierr = PetscFree(b);CHKERRQ(ierr);
7256     }
7257     dm->boundary = NULL;
7258   }
7259 
7260   lastnext = &(dm->boundary);
7261   while (dsbound) {
7262     DMBoundary dmbound;
7263 
7264     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
7265     dmbound->dsboundary = dsbound;
7266     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
7267     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
7268     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7269     *lastnext = dmbound;
7270     lastnext = &(dmbound->next);
7271     dsbound = dsbound->next;
7272   }
7273   PetscFunctionReturn(0);
7274 }
7275 
7276 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7277 {
7278   DMBoundary     b;
7279   PetscErrorCode ierr;
7280 
7281   PetscFunctionBegin;
7282   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7283   PetscValidPointer(isBd, 3);
7284   *isBd = PETSC_FALSE;
7285   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
7286   b = dm->boundary;
7287   while (b && !(*isBd)) {
7288     DMLabel    label = b->label;
7289     DSBoundary dsb = b->dsboundary;
7290 
7291     if (label) {
7292       PetscInt i;
7293 
7294       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
7295         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
7296       }
7297     }
7298     b = b->next;
7299   }
7300   PetscFunctionReturn(0);
7301 }
7302 
7303 /*@C
7304   DMProjectFunction - This projects the given function into the function space provided.
7305 
7306   Input Parameters:
7307 + dm      - The DM
7308 . time    - The time
7309 . funcs   - The coordinate functions to evaluate, one per field
7310 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7311 - mode    - The insertion mode for values
7312 
7313   Output Parameter:
7314 . X - vector
7315 
7316    Calling sequence of func:
7317 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7318 
7319 +  dim - The spatial dimension
7320 .  x   - The coordinates
7321 .  Nf  - The number of fields
7322 .  u   - The output field values
7323 -  ctx - optional user-defined function context
7324 
7325   Level: developer
7326 
7327 .seealso: DMComputeL2Diff()
7328 @*/
7329 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7330 {
7331   Vec            localX;
7332   PetscErrorCode ierr;
7333 
7334   PetscFunctionBegin;
7335   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7336   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
7337   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7338   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
7339   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
7340   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
7341   PetscFunctionReturn(0);
7342 }
7343 
7344 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7345 {
7346   PetscErrorCode ierr;
7347 
7348   PetscFunctionBegin;
7349   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7350   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
7351   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
7352   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7353   PetscFunctionReturn(0);
7354 }
7355 
7356 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)
7357 {
7358   Vec            localX;
7359   PetscErrorCode ierr;
7360 
7361   PetscFunctionBegin;
7362   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7363   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
7364   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7365   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
7366   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
7367   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
7368   PetscFunctionReturn(0);
7369 }
7370 
7371 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)
7372 {
7373   PetscErrorCode ierr;
7374 
7375   PetscFunctionBegin;
7376   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7377   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
7378   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
7379   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7380   PetscFunctionReturn(0);
7381 }
7382 
7383 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
7384                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
7385                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7386                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7387                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7388                                    InsertMode mode, Vec localX)
7389 {
7390   PetscErrorCode ierr;
7391 
7392   PetscFunctionBegin;
7393   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7394   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
7395   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
7396   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7397   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
7398   PetscFunctionReturn(0);
7399 }
7400 
7401 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
7402                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
7403                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7404                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7405                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7406                                         InsertMode mode, Vec localX)
7407 {
7408   PetscErrorCode ierr;
7409 
7410   PetscFunctionBegin;
7411   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7412   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
7413   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
7414   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7415   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
7416   PetscFunctionReturn(0);
7417 }
7418 
7419 /*@C
7420   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
7421 
7422   Input Parameters:
7423 + dm    - The DM
7424 . time  - The time
7425 . funcs - The functions to evaluate for each field component
7426 . ctxs  - Optional array of contexts to pass to each function, or NULL.
7427 - X     - The coefficient vector u_h, a global vector
7428 
7429   Output Parameter:
7430 . diff - The diff ||u - u_h||_2
7431 
7432   Level: developer
7433 
7434 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
7435 @*/
7436 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
7437 {
7438   PetscErrorCode ierr;
7439 
7440   PetscFunctionBegin;
7441   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7442   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
7443   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
7444   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
7445   PetscFunctionReturn(0);
7446 }
7447 
7448 /*@C
7449   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
7450 
7451   Input Parameters:
7452 + dm    - The DM
7453 , time  - The time
7454 . funcs - The gradient functions to evaluate for each field component
7455 . ctxs  - Optional array of contexts to pass to each function, or NULL.
7456 . X     - The coefficient vector u_h, a global vector
7457 - n     - The vector to project along
7458 
7459   Output Parameter:
7460 . diff - The diff ||(grad u - grad u_h) . n||_2
7461 
7462   Level: developer
7463 
7464 .seealso: DMProjectFunction(), DMComputeL2Diff()
7465 @*/
7466 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)
7467 {
7468   PetscErrorCode ierr;
7469 
7470   PetscFunctionBegin;
7471   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7472   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
7473   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
7474   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
7475   PetscFunctionReturn(0);
7476 }
7477 
7478 /*@C
7479   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
7480 
7481   Input Parameters:
7482 + dm    - The DM
7483 . time  - The time
7484 . funcs - The functions to evaluate for each field component
7485 . ctxs  - Optional array of contexts to pass to each function, or NULL.
7486 - X     - The coefficient vector u_h, a global vector
7487 
7488   Output Parameter:
7489 . diff - The array of differences, ||u^f - u^f_h||_2
7490 
7491   Level: developer
7492 
7493 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
7494 @*/
7495 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
7496 {
7497   PetscErrorCode ierr;
7498 
7499   PetscFunctionBegin;
7500   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7501   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
7502   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
7503   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
7504   PetscFunctionReturn(0);
7505 }
7506 
7507 /*@C
7508   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
7509                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
7510 
7511   Collective on dm
7512 
7513   Input parameters:
7514 + dm - the pre-adaptation DM object
7515 - label - label with the flags
7516 
7517   Output parameters:
7518 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
7519 
7520   Level: intermediate
7521 
7522 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
7523 @*/
7524 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
7525 {
7526   PetscErrorCode ierr;
7527 
7528   PetscFunctionBegin;
7529   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7530   PetscValidPointer(label,2);
7531   PetscValidPointer(dmAdapt,3);
7532   *dmAdapt = NULL;
7533   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
7534   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
7535   PetscFunctionReturn(0);
7536 }
7537 
7538 /*@C
7539   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
7540 
7541   Input Parameters:
7542 + dm - The DM object
7543 . metric - The metric to which the mesh is adapted, defined vertex-wise.
7544 - 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_".
7545 
7546   Output Parameter:
7547 . dmAdapt  - Pointer to the DM object containing the adapted mesh
7548 
7549   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
7550 
7551   Level: advanced
7552 
7553 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
7554 @*/
7555 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
7556 {
7557   PetscErrorCode ierr;
7558 
7559   PetscFunctionBegin;
7560   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7561   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
7562   if (bdLabel) PetscValidPointer(bdLabel, 3);
7563   PetscValidPointer(dmAdapt, 4);
7564   *dmAdapt = NULL;
7565   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
7566   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
7567   PetscFunctionReturn(0);
7568 }
7569 
7570 /*@C
7571  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
7572 
7573  Not Collective
7574 
7575  Input Parameter:
7576  . dm    - The DM
7577 
7578  Output Parameter:
7579  . nranks - the number of neighbours
7580  . ranks - the neighbors ranks
7581 
7582  Notes:
7583  Do not free the array, it is freed when the DM is destroyed.
7584 
7585  Level: beginner
7586 
7587  .seealso: DMDAGetNeighbors(), PetscSFGetRanks()
7588 @*/
7589 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
7590 {
7591   PetscErrorCode ierr;
7592 
7593   PetscFunctionBegin;
7594   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7595   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
7596   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
7597   PetscFunctionReturn(0);
7598 }
7599 
7600 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
7601 
7602 /*
7603     Converts the input vector to a ghosted vector and then calls the standard coloring code.
7604     This has be a different function because it requires DM which is not defined in the Mat library
7605 */
7606 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
7607 {
7608   PetscErrorCode ierr;
7609 
7610   PetscFunctionBegin;
7611   if (coloring->ctype == IS_COLORING_LOCAL) {
7612     Vec x1local;
7613     DM  dm;
7614     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
7615     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
7616     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
7617     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
7618     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
7619     x1   = x1local;
7620   }
7621   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
7622   if (coloring->ctype == IS_COLORING_LOCAL) {
7623     DM  dm;
7624     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
7625     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
7626   }
7627   PetscFunctionReturn(0);
7628 }
7629 
7630 /*@
7631     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
7632 
7633     Input Parameter:
7634 .    coloring - the MatFDColoring object
7635 
7636     Developer Notes:
7637     this routine exists because the PETSc Mat library does not know about the DM objects
7638 
7639     Level: advanced
7640 
7641 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
7642 @*/
7643 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
7644 {
7645   PetscFunctionBegin;
7646   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
7647   PetscFunctionReturn(0);
7648 }
7649 
7650 /*@
7651     DMGetCompatibility - determine if two DMs are compatible
7652 
7653     Collective
7654 
7655     Input Parameters:
7656 +    dm - the first DM
7657 -    dm2 - the second DM
7658 
7659     Output Parameters:
7660 +    compatible - whether or not the two DMs are compatible
7661 -    set - whether or not the compatible value was set
7662 
7663     Notes:
7664     Two DMs are deemed compatible if they represent the same parallel decomposition
7665     of the same topology. This implies that the the section (field data) on one
7666     "makes sense" with respect to the topology and parallel decomposition of the other.
7667     Loosely speaking, compatibile DMs represent the same domain, with the same parallel
7668     decomposition, with different data.
7669 
7670     Typically, one would confirm compatibility if intending to simultaneously iterate
7671     over a pair of vectors obtained from different DMs.
7672 
7673     For example, two DMDA objects are compatible if they have the same local
7674     and global sizes and the same stencil width. They can have different numbers
7675     of degrees of freedom per node. Thus, one could use the node numbering from
7676     either DM in bounds for a loop over vectors derived from either DM.
7677 
7678     Consider the operation of summing data living on a 2-dof DMDA to data living
7679     on a 1-dof DMDA, which should be compatible, as in the following snippet.
7680 .vb
7681   ...
7682   ierr = DMGetCompatibility(da1,da2,&compatible,&set);CHKERRQ(ierr);
7683   if (set && compatible)  {
7684     ierr = DMDAVecGetArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
7685     ierr = DMDAVecGetArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
7686     ierr = DMDAGetCorners(da1,&x,&y,NULL,&m,&n);CHKERRQ(ierr);
7687     for (j=y; j<y+n; ++j) {
7688       for (i=x; i<x+m, ++i) {
7689         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
7690       }
7691     }
7692     ierr = DMDAVecRestoreArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
7693     ierr = DMDAVecRestoreArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
7694   } else {
7695     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
7696   }
7697   ...
7698 .ve
7699 
7700     Checking compatibility might be expensive for a given implementation of DM,
7701     or might be impossible to unambiguously confirm or deny. For this reason,
7702     this function may decline to determine compatibility, and hence users should
7703     always check the "set" output parameter.
7704 
7705     A DM is always compatible with itself.
7706 
7707     In the current implementation, DMs which live on "unequal" communicators
7708     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
7709     incompatible.
7710 
7711     This function is labeled "Collective," as information about all subdomains
7712     is required on each rank. However, in DM implementations which store all this
7713     information locally, this function may be merely "Logically Collective".
7714 
7715     Developer Notes:
7716     Compatibility is assumed to be a symmetric concept; if DM A is compatible with DM B,
7717     the DM B is compatible with DM A. Thus, this function checks the implementations
7718     of both dm and dm2 (if they are of different types), attempting to determine
7719     compatibility. It is left to DM implementers to ensure that symmetry is
7720     preserved. The simplest way to do this is, when implementing type-specific
7721     logic for this function, to check for existing logic in the implementation
7722     of other DM types and let *set = PETSC_FALSE if found; the logic of this
7723     function will then call that logic.
7724 
7725     Level: advanced
7726 
7727 .seealso: DM, DMDACreateCompatibleDMDA()
7728 @*/
7729 
7730 PetscErrorCode DMGetCompatibility(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
7731 {
7732   PetscErrorCode ierr;
7733   PetscMPIInt    compareResult;
7734   DMType         type,type2;
7735   PetscBool      sameType;
7736 
7737   PetscFunctionBegin;
7738   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7739   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
7740 
7741   /* Declare a DM compatible with itself */
7742   if (dm == dm2) {
7743     *set = PETSC_TRUE;
7744     *compatible = PETSC_TRUE;
7745     PetscFunctionReturn(0);
7746   }
7747 
7748   /* Declare a DM incompatible with a DM that lives on an "unequal"
7749      communicator. Note that this does not preclude compatibility with
7750      DMs living on "congruent" or "similar" communicators, but this must be
7751      determined by the implementation-specific logic */
7752   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)dm),PetscObjectComm((PetscObject)dm2),&compareResult);CHKERRQ(ierr);
7753   if (compareResult == MPI_UNEQUAL) {
7754     *set = PETSC_TRUE;
7755     *compatible = PETSC_FALSE;
7756     PetscFunctionReturn(0);
7757   }
7758 
7759   /* Pass to the implementation-specific routine, if one exists. */
7760   if (dm->ops->getcompatibility) {
7761     ierr = (*dm->ops->getcompatibility)(dm,dm2,compatible,set);CHKERRQ(ierr);
7762     if (*set) {
7763       PetscFunctionReturn(0);
7764     }
7765   }
7766 
7767   /* If dm and dm2 are of different types, then attempt to check compatibility
7768      with an implementation of this function from dm2 */
7769   ierr = DMGetType(dm,&type);CHKERRQ(ierr);
7770   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
7771   ierr = PetscStrcmp(type,type2,&sameType);CHKERRQ(ierr);
7772   if (!sameType && dm2->ops->getcompatibility) {
7773     ierr = (*dm2->ops->getcompatibility)(dm2,dm,compatible,set);CHKERRQ(ierr); /* Note argument order */
7774   } else {
7775     *set = PETSC_FALSE;
7776   }
7777   PetscFunctionReturn(0);
7778 }
7779