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