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