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