xref: /petsc/src/dm/interface/dm.c (revision 367003a68d4e38a62ba2a0620cd4e6f42aa373fd)
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   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4020   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
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 (pCoord) {
4658     ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr);
4659     /* set array in two steps to mimic PETSC_OWN_POINTER */
4660     ierr = VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);CHKERRQ(ierr);
4661     ierr = VecReplaceArray(*pCoord, newarr);CHKERRQ(ierr);
4662   } else {
4663     ierr = PetscFree(newarr);CHKERRQ(ierr);
4664   }
4665   if (pCoordSection) {*pCoordSection = newcs;}
4666   else               {ierr = PetscSectionDestroy(&newcs);CHKERRQ(ierr);}
4667   PetscFunctionReturn(0);
4668 }
4669 
4670 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
4671 {
4672   PetscErrorCode ierr;
4673 
4674   PetscFunctionBegin;
4675   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4676   PetscValidPointer(field,2);
4677   if (!dm->coordinateField) {
4678     if (dm->ops->createcoordinatefield) {
4679       ierr = (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);CHKERRQ(ierr);
4680     }
4681   }
4682   *field = dm->coordinateField;
4683   PetscFunctionReturn(0);
4684 }
4685 
4686 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
4687 {
4688   PetscErrorCode ierr;
4689 
4690   PetscFunctionBegin;
4691   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4692   if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2);
4693   ierr = PetscObjectReference((PetscObject)field);CHKERRQ(ierr);
4694   ierr = DMFieldDestroy(&dm->coordinateField);CHKERRQ(ierr);
4695   dm->coordinateField = field;
4696   PetscFunctionReturn(0);
4697 }
4698 
4699 /*@
4700   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
4701 
4702   Collective on DM
4703 
4704   Input Parameter:
4705 . dm - the DM
4706 
4707   Output Parameter:
4708 . cdm - coordinate DM
4709 
4710   Level: intermediate
4711 
4712 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4713 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4714 @*/
4715 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
4716 {
4717   PetscErrorCode ierr;
4718 
4719   PetscFunctionBegin;
4720   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4721   PetscValidPointer(cdm,2);
4722   if (!dm->coordinateDM) {
4723     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
4724     ierr = (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);CHKERRQ(ierr);
4725   }
4726   *cdm = dm->coordinateDM;
4727   PetscFunctionReturn(0);
4728 }
4729 
4730 /*@
4731   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
4732 
4733   Logically Collective on DM
4734 
4735   Input Parameters:
4736 + dm - the DM
4737 - cdm - coordinate DM
4738 
4739   Level: intermediate
4740 
4741 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4742 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4743 @*/
4744 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
4745 {
4746   PetscErrorCode ierr;
4747 
4748   PetscFunctionBegin;
4749   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4750   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
4751   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
4752   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
4753   dm->coordinateDM = cdm;
4754   PetscFunctionReturn(0);
4755 }
4756 
4757 /*@
4758   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
4759 
4760   Not Collective
4761 
4762   Input Parameter:
4763 . dm - The DM object
4764 
4765   Output Parameter:
4766 . dim - The embedding dimension
4767 
4768   Level: intermediate
4769 
4770 .keywords: mesh, coordinates
4771 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetSection(), DMSetSection()
4772 @*/
4773 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
4774 {
4775   PetscFunctionBegin;
4776   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4777   PetscValidPointer(dim, 2);
4778   if (dm->dimEmbed == PETSC_DEFAULT) {
4779     dm->dimEmbed = dm->dim;
4780   }
4781   *dim = dm->dimEmbed;
4782   PetscFunctionReturn(0);
4783 }
4784 
4785 /*@
4786   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
4787 
4788   Not Collective
4789 
4790   Input Parameters:
4791 + dm  - The DM object
4792 - dim - The embedding dimension
4793 
4794   Level: intermediate
4795 
4796 .keywords: mesh, coordinates
4797 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetSection(), DMSetSection()
4798 @*/
4799 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
4800 {
4801   PetscErrorCode ierr;
4802 
4803   PetscFunctionBegin;
4804   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4805   dm->dimEmbed = dim;
4806   ierr = PetscDSSetCoordinateDimension(dm->prob, dm->dimEmbed);CHKERRQ(ierr);
4807   PetscFunctionReturn(0);
4808 }
4809 
4810 /*@
4811   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
4812 
4813   Collective on DM
4814 
4815   Input Parameter:
4816 . dm - The DM object
4817 
4818   Output Parameter:
4819 . section - The PetscSection object
4820 
4821   Level: intermediate
4822 
4823 .keywords: mesh, coordinates
4824 .seealso: DMGetCoordinateDM(), DMGetSection(), DMSetSection()
4825 @*/
4826 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
4827 {
4828   DM             cdm;
4829   PetscErrorCode ierr;
4830 
4831   PetscFunctionBegin;
4832   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4833   PetscValidPointer(section, 2);
4834   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4835   ierr = DMGetSection(cdm, section);CHKERRQ(ierr);
4836   PetscFunctionReturn(0);
4837 }
4838 
4839 /*@
4840   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
4841 
4842   Not Collective
4843 
4844   Input Parameters:
4845 + dm      - The DM object
4846 . dim     - The embedding dimension, or PETSC_DETERMINE
4847 - section - The PetscSection object
4848 
4849   Level: intermediate
4850 
4851 .keywords: mesh, coordinates
4852 .seealso: DMGetCoordinateSection(), DMGetSection(), DMSetSection()
4853 @*/
4854 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
4855 {
4856   DM             cdm;
4857   PetscErrorCode ierr;
4858 
4859   PetscFunctionBegin;
4860   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4861   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
4862   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4863   ierr = DMSetSection(cdm, section);CHKERRQ(ierr);
4864   if (dim == PETSC_DETERMINE) {
4865     PetscInt d = PETSC_DEFAULT;
4866     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
4867 
4868     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4869     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4870     pStart = PetscMax(vStart, pStart);
4871     pEnd   = PetscMin(vEnd, pEnd);
4872     for (v = pStart; v < pEnd; ++v) {
4873       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
4874       if (dd) {d = dd; break;}
4875     }
4876     if (d < 0) d = PETSC_DEFAULT;
4877     ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);
4878   }
4879   PetscFunctionReturn(0);
4880 }
4881 
4882 /*@C
4883   DMGetPeriodicity - Get the description of mesh periodicity
4884 
4885   Input Parameters:
4886 . dm      - The DM object
4887 
4888   Output Parameters:
4889 + per     - Whether the DM is periodic or not
4890 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4891 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4892 - bd      - This describes the type of periodicity in each topological dimension
4893 
4894   Level: developer
4895 
4896 .seealso: DMGetPeriodicity()
4897 @*/
4898 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
4899 {
4900   PetscFunctionBegin;
4901   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4902   if (per)     *per     = dm->periodic;
4903   if (L)       *L       = dm->L;
4904   if (maxCell) *maxCell = dm->maxCell;
4905   if (bd)      *bd      = dm->bdtype;
4906   PetscFunctionReturn(0);
4907 }
4908 
4909 /*@C
4910   DMSetPeriodicity - Set the description of mesh periodicity
4911 
4912   Input Parameters:
4913 + dm      - The DM object
4914 . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
4915 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4916 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4917 - bd      - This describes the type of periodicity in each topological dimension
4918 
4919   Level: developer
4920 
4921 .seealso: DMGetPeriodicity()
4922 @*/
4923 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
4924 {
4925   PetscInt       dim, d;
4926   PetscErrorCode ierr;
4927 
4928   PetscFunctionBegin;
4929   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4930   PetscValidLogicalCollectiveBool(dm,per,2);
4931   if (maxCell) {
4932     PetscValidPointer(maxCell,3);
4933     PetscValidPointer(L,4);
4934     PetscValidPointer(bd,5);
4935   }
4936   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
4937   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4938   if (maxCell) {
4939     ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
4940     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
4941     dm->periodic = PETSC_TRUE;
4942   } else {
4943     dm->periodic = per;
4944   }
4945   PetscFunctionReturn(0);
4946 }
4947 
4948 /*@
4949   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.
4950 
4951   Input Parameters:
4952 + dm     - The DM
4953 . in     - The input coordinate point (dim numbers)
4954 - endpoint - Include the endpoint L_i
4955 
4956   Output Parameter:
4957 . out - The localized coordinate point
4958 
4959   Level: developer
4960 
4961 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4962 @*/
4963 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
4964 {
4965   PetscInt       dim, d;
4966   PetscErrorCode ierr;
4967 
4968   PetscFunctionBegin;
4969   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
4970   if (!dm->maxCell) {
4971     for (d = 0; d < dim; ++d) out[d] = in[d];
4972   } else {
4973     if (endpoint) {
4974       for (d = 0; d < dim; ++d) {
4975         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)) {
4976           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
4977         } else {
4978           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4979         }
4980       }
4981     } else {
4982       for (d = 0; d < dim; ++d) {
4983         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4984       }
4985     }
4986   }
4987   PetscFunctionReturn(0);
4988 }
4989 
4990 /*
4991   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.
4992 
4993   Input Parameters:
4994 + dm     - The DM
4995 . dim    - The spatial dimension
4996 . anchor - The anchor point, the input point can be no more than maxCell away from it
4997 - in     - The input coordinate point (dim numbers)
4998 
4999   Output Parameter:
5000 . out - The localized coordinate point
5001 
5002   Level: developer
5003 
5004   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
5005 
5006 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
5007 */
5008 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
5009 {
5010   PetscInt d;
5011 
5012   PetscFunctionBegin;
5013   if (!dm->maxCell) {
5014     for (d = 0; d < dim; ++d) out[d] = in[d];
5015   } else {
5016     for (d = 0; d < dim; ++d) {
5017       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
5018         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
5019       } else {
5020         out[d] = in[d];
5021       }
5022     }
5023   }
5024   PetscFunctionReturn(0);
5025 }
5026 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
5027 {
5028   PetscInt d;
5029 
5030   PetscFunctionBegin;
5031   if (!dm->maxCell) {
5032     for (d = 0; d < dim; ++d) out[d] = in[d];
5033   } else {
5034     for (d = 0; d < dim; ++d) {
5035       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
5036         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
5037       } else {
5038         out[d] = in[d];
5039       }
5040     }
5041   }
5042   PetscFunctionReturn(0);
5043 }
5044 
5045 /*
5046   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.
5047 
5048   Input Parameters:
5049 + dm     - The DM
5050 . dim    - The spatial dimension
5051 . anchor - The anchor point, the input point can be no more than maxCell away from it
5052 . in     - The input coordinate delta (dim numbers)
5053 - out    - The input coordinate point (dim numbers)
5054 
5055   Output Parameter:
5056 . out    - The localized coordinate in + out
5057 
5058   Level: developer
5059 
5060   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
5061 
5062 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
5063 */
5064 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
5065 {
5066   PetscInt d;
5067 
5068   PetscFunctionBegin;
5069   if (!dm->maxCell) {
5070     for (d = 0; d < dim; ++d) out[d] += in[d];
5071   } else {
5072     for (d = 0; d < dim; ++d) {
5073       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
5074         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
5075       } else {
5076         out[d] += in[d];
5077       }
5078     }
5079   }
5080   PetscFunctionReturn(0);
5081 }
5082 
5083 /*@
5084   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
5085 
5086   Input Parameter:
5087 . dm - The DM
5088 
5089   Output Parameter:
5090   areLocalized - True if localized
5091 
5092   Level: developer
5093 
5094 .seealso: DMLocalizeCoordinates()
5095 @*/
5096 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
5097 {
5098   DM             cdm;
5099   PetscSection   coordSection;
5100   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
5101   PetscBool      isPlex, alreadyLocalized;
5102   PetscErrorCode ierr;
5103 
5104   PetscFunctionBegin;
5105   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5106   PetscValidPointer(areLocalized, 2);
5107 
5108   *areLocalized = PETSC_FALSE;
5109   if (!dm->periodic) PetscFunctionReturn(0); /* This is a hideous optimization hack! */
5110 
5111   /* We need some generic way of refering to cells/vertices */
5112   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5113   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5114   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
5115   if (!isPlex) SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
5116 
5117   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5118   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
5119   alreadyLocalized = PETSC_FALSE;
5120   for (c = cStart; c < cEnd; ++c) {
5121     if (c < sStart || c >= sEnd) continue;
5122     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
5123     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
5124   }
5125   ierr = MPIU_Allreduce(&alreadyLocalized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
5126   PetscFunctionReturn(0);
5127 }
5128 
5129 
5130 /*@
5131   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
5132 
5133   Input Parameter:
5134 . dm - The DM
5135 
5136   Level: developer
5137 
5138 .seealso: DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
5139 @*/
5140 PetscErrorCode DMLocalizeCoordinates(DM dm)
5141 {
5142   DM             cdm;
5143   PetscSection   coordSection, cSection;
5144   Vec            coordinates,  cVec;
5145   PetscScalar   *coords, *coords2, *anchor, *localized;
5146   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
5147   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
5148   PetscInt       maxHeight = 0, h;
5149   PetscInt       *pStart = NULL, *pEnd = NULL;
5150   PetscErrorCode ierr;
5151 
5152   PetscFunctionBegin;
5153   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5154   if (!dm->periodic) PetscFunctionReturn(0);
5155   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
5156   if (alreadyLocalized) PetscFunctionReturn(0);
5157 
5158   /* We need some generic way of refering to cells/vertices */
5159   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5160   {
5161     PetscBool isplex;
5162 
5163     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
5164     if (isplex) {
5165       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5166       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
5167       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
5168       pEnd = &pStart[maxHeight + 1];
5169       newStart = vStart;
5170       newEnd   = vEnd;
5171       for (h = 0; h <= maxHeight; h++) {
5172         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
5173         newStart = PetscMin(newStart,pStart[h]);
5174         newEnd   = PetscMax(newEnd,pEnd[h]);
5175       }
5176     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
5177   }
5178   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5179   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
5180   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5181   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
5182   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
5183 
5184   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
5185   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
5186   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
5187   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
5188   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
5189 
5190   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
5191   localized = &anchor[bs];
5192   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
5193   for (h = 0; h <= maxHeight; h++) {
5194     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
5195 
5196     for (c = cStart; c < cEnd; ++c) {
5197       PetscScalar *cellCoords = NULL;
5198       PetscInt     b;
5199 
5200       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
5201       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5202       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
5203       for (d = 0; d < dof/bs; ++d) {
5204         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
5205         for (b = 0; b < bs; b++) {
5206           if (cellCoords[d*bs + b] != localized[b]) break;
5207         }
5208         if (b < bs) break;
5209       }
5210       if (d < dof/bs) {
5211         if (c >= sStart && c < sEnd) {
5212           PetscInt cdof;
5213 
5214           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
5215           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
5216         }
5217         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
5218         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
5219       }
5220       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5221     }
5222   }
5223   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
5224   if (alreadyLocalizedGlobal) {
5225     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
5226     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
5227     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
5228     PetscFunctionReturn(0);
5229   }
5230   for (v = vStart; v < vEnd; ++v) {
5231     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
5232     ierr = PetscSectionSetDof(cSection, v, dof);CHKERRQ(ierr);
5233     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
5234   }
5235   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
5236   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
5237   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
5238   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
5239   ierr = VecSetBlockSize(cVec, bs);CHKERRQ(ierr);
5240   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
5241   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
5242   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
5243   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
5244   for (v = vStart; v < vEnd; ++v) {
5245     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
5246     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5247     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
5248     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
5249   }
5250   for (h = 0; h <= maxHeight; h++) {
5251     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
5252 
5253     for (c = cStart; c < cEnd; ++c) {
5254       PetscScalar *cellCoords = NULL;
5255       PetscInt     b, cdof;
5256 
5257       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
5258       if (!cdof) continue;
5259       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5260       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
5261       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
5262       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
5263       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
5264     }
5265   }
5266   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
5267   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
5268   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
5269   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
5270   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
5271   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
5272   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
5273   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
5274   PetscFunctionReturn(0);
5275 }
5276 
5277 /*@
5278   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
5279 
5280   Collective on Vec v (see explanation below)
5281 
5282   Input Parameters:
5283 + dm - The DM
5284 . v - The Vec of points
5285 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
5286 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
5287 
5288   Output Parameter:
5289 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
5290 - cells - The PetscSF containing the ranks and local indices of the containing points.
5291 
5292 
5293   Level: developer
5294 
5295   Notes:
5296   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
5297   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
5298 
5299   If *cellSF is NULL on input, a PetscSF will be created.
5300   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
5301 
5302   An array that maps each point to its containing cell can be obtained with
5303 
5304 $    const PetscSFNode *cells;
5305 $    PetscInt           nFound;
5306 $    const PetscInt    *found;
5307 $
5308 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
5309 
5310   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
5311   the index of the cell in its rank's local numbering.
5312 
5313 .keywords: point location, mesh
5314 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
5315 @*/
5316 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
5317 {
5318   PetscErrorCode ierr;
5319 
5320   PetscFunctionBegin;
5321   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5322   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
5323   PetscValidPointer(cellSF,4);
5324   if (*cellSF) {
5325     PetscMPIInt result;
5326 
5327     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
5328     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
5329     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
5330   } else {
5331     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
5332   }
5333   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
5334   if (dm->ops->locatepoints) {
5335     ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
5336   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
5337   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
5338   PetscFunctionReturn(0);
5339 }
5340 
5341 /*@
5342   DMGetOutputDM - Retrieve the DM associated with the layout for output
5343 
5344   Input Parameter:
5345 . dm - The original DM
5346 
5347   Output Parameter:
5348 . odm - The DM which provides the layout for output
5349 
5350   Level: intermediate
5351 
5352 .seealso: VecView(), DMGetGlobalSection()
5353 @*/
5354 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
5355 {
5356   PetscSection   section;
5357   PetscBool      hasConstraints, ghasConstraints;
5358   PetscErrorCode ierr;
5359 
5360   PetscFunctionBegin;
5361   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5362   PetscValidPointer(odm,2);
5363   ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
5364   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
5365   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
5366   if (!ghasConstraints) {
5367     *odm = dm;
5368     PetscFunctionReturn(0);
5369   }
5370   if (!dm->dmBC) {
5371     PetscDS      ds;
5372     PetscSection newSection, gsection;
5373     PetscSF      sf;
5374 
5375     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
5376     ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5377     ierr = DMSetDS(dm->dmBC, ds);CHKERRQ(ierr);
5378     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
5379     ierr = DMSetSection(dm->dmBC, newSection);CHKERRQ(ierr);
5380     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
5381     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
5382     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
5383     ierr = DMSetGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
5384     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
5385   }
5386   *odm = dm->dmBC;
5387   PetscFunctionReturn(0);
5388 }
5389 
5390 /*@
5391   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
5392 
5393   Input Parameter:
5394 . dm - The original DM
5395 
5396   Output Parameters:
5397 + num - The output sequence number
5398 - val - The output sequence value
5399 
5400   Level: intermediate
5401 
5402   Note: This is intended for output that should appear in sequence, for instance
5403   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5404 
5405 .seealso: VecView()
5406 @*/
5407 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
5408 {
5409   PetscFunctionBegin;
5410   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5411   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
5412   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
5413   PetscFunctionReturn(0);
5414 }
5415 
5416 /*@
5417   DMSetOutputSequenceNumber - Set the sequence number/value for output
5418 
5419   Input Parameters:
5420 + dm - The original DM
5421 . num - The output sequence number
5422 - val - The output sequence value
5423 
5424   Level: intermediate
5425 
5426   Note: This is intended for output that should appear in sequence, for instance
5427   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5428 
5429 .seealso: VecView()
5430 @*/
5431 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
5432 {
5433   PetscFunctionBegin;
5434   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5435   dm->outputSequenceNum = num;
5436   dm->outputSequenceVal = val;
5437   PetscFunctionReturn(0);
5438 }
5439 
5440 /*@C
5441   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
5442 
5443   Input Parameters:
5444 + dm   - The original DM
5445 . name - The sequence name
5446 - num  - The output sequence number
5447 
5448   Output Parameter:
5449 . val  - The output sequence value
5450 
5451   Level: intermediate
5452 
5453   Note: This is intended for output that should appear in sequence, for instance
5454   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
5455 
5456 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
5457 @*/
5458 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
5459 {
5460   PetscBool      ishdf5;
5461   PetscErrorCode ierr;
5462 
5463   PetscFunctionBegin;
5464   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5465   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
5466   PetscValidPointer(val,4);
5467   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
5468   if (ishdf5) {
5469 #if defined(PETSC_HAVE_HDF5)
5470     PetscScalar value;
5471 
5472     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
5473     *val = PetscRealPart(value);
5474 #endif
5475   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
5476   PetscFunctionReturn(0);
5477 }
5478 
5479 /*@
5480   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
5481 
5482   Not collective
5483 
5484   Input Parameter:
5485 . dm - The DM
5486 
5487   Output Parameter:
5488 . useNatural - The flag to build the mapping to a natural order during distribution
5489 
5490   Level: beginner
5491 
5492 .seealso: DMSetUseNatural(), DMCreate()
5493 @*/
5494 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
5495 {
5496   PetscFunctionBegin;
5497   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5498   PetscValidPointer(useNatural, 2);
5499   *useNatural = dm->useNatural;
5500   PetscFunctionReturn(0);
5501 }
5502 
5503 /*@
5504   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
5505 
5506   Collective on dm
5507 
5508   Input Parameters:
5509 + dm - The DM
5510 - useNatural - The flag to build the mapping to a natural order during distribution
5511 
5512   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
5513 
5514   Level: beginner
5515 
5516 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
5517 @*/
5518 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
5519 {
5520   PetscFunctionBegin;
5521   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5522   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
5523   dm->useNatural = useNatural;
5524   PetscFunctionReturn(0);
5525 }
5526 
5527 
5528 /*@C
5529   DMCreateLabel - Create a label of the given name if it does not already exist
5530 
5531   Not Collective
5532 
5533   Input Parameters:
5534 + dm   - The DM object
5535 - name - The label name
5536 
5537   Level: intermediate
5538 
5539 .keywords: mesh
5540 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5541 @*/
5542 PetscErrorCode DMCreateLabel(DM dm, const char name[])
5543 {
5544   DMLabelLink    next  = dm->labels->next;
5545   PetscBool      flg   = PETSC_FALSE;
5546   PetscErrorCode ierr;
5547 
5548   PetscFunctionBegin;
5549   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5550   PetscValidCharPointer(name, 2);
5551   while (next) {
5552     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5553     if (flg) break;
5554     next = next->next;
5555   }
5556   if (!flg) {
5557     DMLabelLink tmpLabel;
5558 
5559     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5560     ierr = DMLabelCreate(name, &tmpLabel->label);CHKERRQ(ierr);
5561     tmpLabel->output = PETSC_TRUE;
5562     tmpLabel->next   = dm->labels->next;
5563     dm->labels->next = tmpLabel;
5564   }
5565   PetscFunctionReturn(0);
5566 }
5567 
5568 /*@C
5569   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
5570 
5571   Not Collective
5572 
5573   Input Parameters:
5574 + dm   - The DM object
5575 . name - The label name
5576 - point - The mesh point
5577 
5578   Output Parameter:
5579 . value - The label value for this point, or -1 if the point is not in the label
5580 
5581   Level: beginner
5582 
5583 .keywords: mesh
5584 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
5585 @*/
5586 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
5587 {
5588   DMLabel        label;
5589   PetscErrorCode ierr;
5590 
5591   PetscFunctionBegin;
5592   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5593   PetscValidCharPointer(name, 2);
5594   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5595   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
5596   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
5597   PetscFunctionReturn(0);
5598 }
5599 
5600 /*@C
5601   DMSetLabelValue - Add a point to a Sieve Label with given value
5602 
5603   Not Collective
5604 
5605   Input Parameters:
5606 + dm   - The DM object
5607 . name - The label name
5608 . point - The mesh point
5609 - value - The label value for this point
5610 
5611   Output Parameter:
5612 
5613   Level: beginner
5614 
5615 .keywords: mesh
5616 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
5617 @*/
5618 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5619 {
5620   DMLabel        label;
5621   PetscErrorCode ierr;
5622 
5623   PetscFunctionBegin;
5624   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5625   PetscValidCharPointer(name, 2);
5626   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5627   if (!label) {
5628     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
5629     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5630   }
5631   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
5632   PetscFunctionReturn(0);
5633 }
5634 
5635 /*@C
5636   DMClearLabelValue - Remove a point from a Sieve Label with given value
5637 
5638   Not Collective
5639 
5640   Input Parameters:
5641 + dm   - The DM object
5642 . name - The label name
5643 . point - The mesh point
5644 - value - The label value for this point
5645 
5646   Output Parameter:
5647 
5648   Level: beginner
5649 
5650 .keywords: mesh
5651 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
5652 @*/
5653 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5654 {
5655   DMLabel        label;
5656   PetscErrorCode ierr;
5657 
5658   PetscFunctionBegin;
5659   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5660   PetscValidCharPointer(name, 2);
5661   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5662   if (!label) PetscFunctionReturn(0);
5663   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
5664   PetscFunctionReturn(0);
5665 }
5666 
5667 /*@C
5668   DMGetLabelSize - Get the number of different integer ids in a Label
5669 
5670   Not Collective
5671 
5672   Input Parameters:
5673 + dm   - The DM object
5674 - name - The label name
5675 
5676   Output Parameter:
5677 . size - The number of different integer ids, or 0 if the label does not exist
5678 
5679   Level: beginner
5680 
5681 .keywords: mesh
5682 .seealso: DMLabeGetNumValues(), DMSetLabelValue()
5683 @*/
5684 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
5685 {
5686   DMLabel        label;
5687   PetscErrorCode ierr;
5688 
5689   PetscFunctionBegin;
5690   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5691   PetscValidCharPointer(name, 2);
5692   PetscValidPointer(size, 3);
5693   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5694   *size = 0;
5695   if (!label) PetscFunctionReturn(0);
5696   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
5697   PetscFunctionReturn(0);
5698 }
5699 
5700 /*@C
5701   DMGetLabelIdIS - Get the integer ids in a label
5702 
5703   Not Collective
5704 
5705   Input Parameters:
5706 + mesh - The DM object
5707 - name - The label name
5708 
5709   Output Parameter:
5710 . ids - The integer ids, or NULL if the label does not exist
5711 
5712   Level: beginner
5713 
5714 .keywords: mesh
5715 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
5716 @*/
5717 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
5718 {
5719   DMLabel        label;
5720   PetscErrorCode ierr;
5721 
5722   PetscFunctionBegin;
5723   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5724   PetscValidCharPointer(name, 2);
5725   PetscValidPointer(ids, 3);
5726   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5727   *ids = NULL;
5728  if (label) {
5729     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
5730   } else {
5731     /* returning an empty IS */
5732     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
5733   }
5734   PetscFunctionReturn(0);
5735 }
5736 
5737 /*@C
5738   DMGetStratumSize - Get the number of points in a label stratum
5739 
5740   Not Collective
5741 
5742   Input Parameters:
5743 + dm - The DM object
5744 . name - The label name
5745 - value - The stratum value
5746 
5747   Output Parameter:
5748 . size - The stratum size
5749 
5750   Level: beginner
5751 
5752 .keywords: mesh
5753 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
5754 @*/
5755 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
5756 {
5757   DMLabel        label;
5758   PetscErrorCode ierr;
5759 
5760   PetscFunctionBegin;
5761   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5762   PetscValidCharPointer(name, 2);
5763   PetscValidPointer(size, 4);
5764   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5765   *size = 0;
5766   if (!label) PetscFunctionReturn(0);
5767   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
5768   PetscFunctionReturn(0);
5769 }
5770 
5771 /*@C
5772   DMGetStratumIS - Get the points in a label stratum
5773 
5774   Not Collective
5775 
5776   Input Parameters:
5777 + dm - The DM object
5778 . name - The label name
5779 - value - The stratum value
5780 
5781   Output Parameter:
5782 . points - The stratum points, or NULL if the label does not exist or does not have that value
5783 
5784   Level: beginner
5785 
5786 .keywords: mesh
5787 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
5788 @*/
5789 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
5790 {
5791   DMLabel        label;
5792   PetscErrorCode ierr;
5793 
5794   PetscFunctionBegin;
5795   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5796   PetscValidCharPointer(name, 2);
5797   PetscValidPointer(points, 4);
5798   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5799   *points = NULL;
5800   if (!label) PetscFunctionReturn(0);
5801   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
5802   PetscFunctionReturn(0);
5803 }
5804 
5805 /*@C
5806   DMSetStratumIS - Set the points in a label stratum
5807 
5808   Not Collective
5809 
5810   Input Parameters:
5811 + dm - The DM object
5812 . name - The label name
5813 . value - The stratum value
5814 - points - The stratum points
5815 
5816   Level: beginner
5817 
5818 .keywords: mesh
5819 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
5820 @*/
5821 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
5822 {
5823   DMLabel        label;
5824   PetscErrorCode ierr;
5825 
5826   PetscFunctionBegin;
5827   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5828   PetscValidCharPointer(name, 2);
5829   PetscValidPointer(points, 4);
5830   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5831   if (!label) PetscFunctionReturn(0);
5832   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
5833   PetscFunctionReturn(0);
5834 }
5835 
5836 /*@C
5837   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
5838 
5839   Not Collective
5840 
5841   Input Parameters:
5842 + dm   - The DM object
5843 . name - The label name
5844 - value - The label value for this point
5845 
5846   Output Parameter:
5847 
5848   Level: beginner
5849 
5850 .keywords: mesh
5851 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
5852 @*/
5853 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
5854 {
5855   DMLabel        label;
5856   PetscErrorCode ierr;
5857 
5858   PetscFunctionBegin;
5859   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5860   PetscValidCharPointer(name, 2);
5861   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5862   if (!label) PetscFunctionReturn(0);
5863   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
5864   PetscFunctionReturn(0);
5865 }
5866 
5867 /*@
5868   DMGetNumLabels - Return the number of labels defined by the mesh
5869 
5870   Not Collective
5871 
5872   Input Parameter:
5873 . dm   - The DM object
5874 
5875   Output Parameter:
5876 . numLabels - the number of Labels
5877 
5878   Level: intermediate
5879 
5880 .keywords: mesh
5881 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5882 @*/
5883 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
5884 {
5885   DMLabelLink next = dm->labels->next;
5886   PetscInt  n    = 0;
5887 
5888   PetscFunctionBegin;
5889   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5890   PetscValidPointer(numLabels, 2);
5891   while (next) {++n; next = next->next;}
5892   *numLabels = n;
5893   PetscFunctionReturn(0);
5894 }
5895 
5896 /*@C
5897   DMGetLabelName - Return the name of nth label
5898 
5899   Not Collective
5900 
5901   Input Parameters:
5902 + dm - The DM object
5903 - n  - the label number
5904 
5905   Output Parameter:
5906 . name - the label name
5907 
5908   Level: intermediate
5909 
5910 .keywords: mesh
5911 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5912 @*/
5913 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
5914 {
5915   DMLabelLink next = dm->labels->next;
5916   PetscInt  l    = 0;
5917 
5918   PetscFunctionBegin;
5919   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5920   PetscValidPointer(name, 3);
5921   while (next) {
5922     if (l == n) {
5923       *name = next->label->name;
5924       PetscFunctionReturn(0);
5925     }
5926     ++l;
5927     next = next->next;
5928   }
5929   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5930 }
5931 
5932 /*@C
5933   DMHasLabel - Determine whether the mesh has a label of a given name
5934 
5935   Not Collective
5936 
5937   Input Parameters:
5938 + dm   - The DM object
5939 - name - The label name
5940 
5941   Output Parameter:
5942 . hasLabel - PETSC_TRUE if the label is present
5943 
5944   Level: intermediate
5945 
5946 .keywords: mesh
5947 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5948 @*/
5949 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
5950 {
5951   DMLabelLink    next = dm->labels->next;
5952   PetscErrorCode ierr;
5953 
5954   PetscFunctionBegin;
5955   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5956   PetscValidCharPointer(name, 2);
5957   PetscValidPointer(hasLabel, 3);
5958   *hasLabel = PETSC_FALSE;
5959   while (next) {
5960     ierr = PetscStrcmp(name, next->label->name, hasLabel);CHKERRQ(ierr);
5961     if (*hasLabel) break;
5962     next = next->next;
5963   }
5964   PetscFunctionReturn(0);
5965 }
5966 
5967 /*@C
5968   DMGetLabel - Return the label of a given name, or NULL
5969 
5970   Not Collective
5971 
5972   Input Parameters:
5973 + dm   - The DM object
5974 - name - The label name
5975 
5976   Output Parameter:
5977 . label - The DMLabel, or NULL if the label is absent
5978 
5979   Level: intermediate
5980 
5981 .keywords: mesh
5982 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5983 @*/
5984 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
5985 {
5986   DMLabelLink    next = dm->labels->next;
5987   PetscBool      hasLabel;
5988   PetscErrorCode ierr;
5989 
5990   PetscFunctionBegin;
5991   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5992   PetscValidCharPointer(name, 2);
5993   PetscValidPointer(label, 3);
5994   *label = NULL;
5995   while (next) {
5996     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5997     if (hasLabel) {
5998       *label = next->label;
5999       break;
6000     }
6001     next = next->next;
6002   }
6003   PetscFunctionReturn(0);
6004 }
6005 
6006 /*@C
6007   DMGetLabelByNum - Return the nth label
6008 
6009   Not Collective
6010 
6011   Input Parameters:
6012 + dm - The DM object
6013 - n  - the label number
6014 
6015   Output Parameter:
6016 . label - the label
6017 
6018   Level: intermediate
6019 
6020 .keywords: mesh
6021 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6022 @*/
6023 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
6024 {
6025   DMLabelLink next = dm->labels->next;
6026   PetscInt    l    = 0;
6027 
6028   PetscFunctionBegin;
6029   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6030   PetscValidPointer(label, 3);
6031   while (next) {
6032     if (l == n) {
6033       *label = next->label;
6034       PetscFunctionReturn(0);
6035     }
6036     ++l;
6037     next = next->next;
6038   }
6039   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
6040 }
6041 
6042 /*@C
6043   DMAddLabel - Add the label to this mesh
6044 
6045   Not Collective
6046 
6047   Input Parameters:
6048 + dm   - The DM object
6049 - label - The DMLabel
6050 
6051   Level: developer
6052 
6053 .keywords: mesh
6054 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6055 @*/
6056 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
6057 {
6058   DMLabelLink    tmpLabel;
6059   PetscBool      hasLabel;
6060   PetscErrorCode ierr;
6061 
6062   PetscFunctionBegin;
6063   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6064   ierr = DMHasLabel(dm, label->name, &hasLabel);CHKERRQ(ierr);
6065   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", label->name);
6066   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
6067   tmpLabel->label  = label;
6068   tmpLabel->output = PETSC_TRUE;
6069   tmpLabel->next   = dm->labels->next;
6070   dm->labels->next = tmpLabel;
6071   PetscFunctionReturn(0);
6072 }
6073 
6074 /*@C
6075   DMRemoveLabel - Remove the label from this mesh
6076 
6077   Not Collective
6078 
6079   Input Parameters:
6080 + dm   - The DM object
6081 - name - The label name
6082 
6083   Output Parameter:
6084 . label - The DMLabel, or NULL if the label is absent
6085 
6086   Level: developer
6087 
6088 .keywords: mesh
6089 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6090 @*/
6091 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
6092 {
6093   DMLabelLink    next = dm->labels->next;
6094   DMLabelLink    last = NULL;
6095   PetscBool      hasLabel;
6096   PetscErrorCode ierr;
6097 
6098   PetscFunctionBegin;
6099   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6100   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
6101   *label = NULL;
6102   if (!hasLabel) PetscFunctionReturn(0);
6103   while (next) {
6104     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
6105     if (hasLabel) {
6106       if (last) last->next       = next->next;
6107       else      dm->labels->next = next->next;
6108       next->next = NULL;
6109       *label     = next->label;
6110       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
6111       if (hasLabel) {
6112         dm->depthLabel = NULL;
6113       }
6114       ierr = PetscFree(next);CHKERRQ(ierr);
6115       break;
6116     }
6117     last = next;
6118     next = next->next;
6119   }
6120   PetscFunctionReturn(0);
6121 }
6122 
6123 /*@C
6124   DMGetLabelOutput - Get the output flag for a given label
6125 
6126   Not Collective
6127 
6128   Input Parameters:
6129 + dm   - The DM object
6130 - name - The label name
6131 
6132   Output Parameter:
6133 . output - The flag for output
6134 
6135   Level: developer
6136 
6137 .keywords: mesh
6138 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6139 @*/
6140 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
6141 {
6142   DMLabelLink    next = dm->labels->next;
6143   PetscErrorCode ierr;
6144 
6145   PetscFunctionBegin;
6146   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6147   PetscValidPointer(name, 2);
6148   PetscValidPointer(output, 3);
6149   while (next) {
6150     PetscBool flg;
6151 
6152     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
6153     if (flg) {*output = next->output; PetscFunctionReturn(0);}
6154     next = next->next;
6155   }
6156   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
6157 }
6158 
6159 /*@C
6160   DMSetLabelOutput - Set the output flag for a given label
6161 
6162   Not Collective
6163 
6164   Input Parameters:
6165 + dm     - The DM object
6166 . name   - The label name
6167 - output - The flag for output
6168 
6169   Level: developer
6170 
6171 .keywords: mesh
6172 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6173 @*/
6174 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
6175 {
6176   DMLabelLink    next = dm->labels->next;
6177   PetscErrorCode ierr;
6178 
6179   PetscFunctionBegin;
6180   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6181   PetscValidPointer(name, 2);
6182   while (next) {
6183     PetscBool flg;
6184 
6185     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
6186     if (flg) {next->output = output; PetscFunctionReturn(0);}
6187     next = next->next;
6188   }
6189   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
6190 }
6191 
6192 
6193 /*@
6194   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
6195 
6196   Collective on DM
6197 
6198   Input Parameter:
6199 . dmA - The DM object with initial labels
6200 
6201   Output Parameter:
6202 . dmB - The DM object with copied labels
6203 
6204   Level: intermediate
6205 
6206   Note: This is typically used when interpolating or otherwise adding to a mesh
6207 
6208 .keywords: mesh
6209 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
6210 @*/
6211 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
6212 {
6213   PetscInt       numLabels, l;
6214   PetscErrorCode ierr;
6215 
6216   PetscFunctionBegin;
6217   if (dmA == dmB) PetscFunctionReturn(0);
6218   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
6219   for (l = 0; l < numLabels; ++l) {
6220     DMLabel     label, labelNew;
6221     const char *name;
6222     PetscBool   flg;
6223 
6224     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
6225     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
6226     if (flg) continue;
6227     ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
6228     if (flg) continue;
6229     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
6230     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
6231     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
6232   }
6233   PetscFunctionReturn(0);
6234 }
6235 
6236 /*@
6237   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
6238 
6239   Input Parameter:
6240 . dm - The DM object
6241 
6242   Output Parameter:
6243 . cdm - The coarse DM
6244 
6245   Level: intermediate
6246 
6247 .seealso: DMSetCoarseDM()
6248 @*/
6249 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
6250 {
6251   PetscFunctionBegin;
6252   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6253   PetscValidPointer(cdm, 2);
6254   *cdm = dm->coarseMesh;
6255   PetscFunctionReturn(0);
6256 }
6257 
6258 /*@
6259   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
6260 
6261   Input Parameters:
6262 + dm - The DM object
6263 - cdm - The coarse DM
6264 
6265   Level: intermediate
6266 
6267 .seealso: DMGetCoarseDM()
6268 @*/
6269 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
6270 {
6271   PetscErrorCode ierr;
6272 
6273   PetscFunctionBegin;
6274   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6275   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
6276   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
6277   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
6278   dm->coarseMesh = cdm;
6279   PetscFunctionReturn(0);
6280 }
6281 
6282 /*@
6283   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
6284 
6285   Input Parameter:
6286 . dm - The DM object
6287 
6288   Output Parameter:
6289 . fdm - The fine DM
6290 
6291   Level: intermediate
6292 
6293 .seealso: DMSetFineDM()
6294 @*/
6295 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
6296 {
6297   PetscFunctionBegin;
6298   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6299   PetscValidPointer(fdm, 2);
6300   *fdm = dm->fineMesh;
6301   PetscFunctionReturn(0);
6302 }
6303 
6304 /*@
6305   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
6306 
6307   Input Parameters:
6308 + dm - The DM object
6309 - fdm - The fine DM
6310 
6311   Level: intermediate
6312 
6313 .seealso: DMGetFineDM()
6314 @*/
6315 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
6316 {
6317   PetscErrorCode ierr;
6318 
6319   PetscFunctionBegin;
6320   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6321   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
6322   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
6323   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
6324   dm->fineMesh = fdm;
6325   PetscFunctionReturn(0);
6326 }
6327 
6328 /*=== DMBoundary code ===*/
6329 
6330 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
6331 {
6332   PetscErrorCode ierr;
6333 
6334   PetscFunctionBegin;
6335   ierr = PetscDSCopyBoundary(dm->prob,dmNew->prob);CHKERRQ(ierr);
6336   PetscFunctionReturn(0);
6337 }
6338 
6339 /*@C
6340   DMAddBoundary - Add a boundary condition to the model
6341 
6342   Input Parameters:
6343 + dm          - The DM, with a PetscDS that matches the problem being constrained
6344 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
6345 . name        - The BC name
6346 . labelname   - The label defining constrained points
6347 . field       - The field to constrain
6348 . numcomps    - The number of constrained field components
6349 . comps       - An array of constrained component numbers
6350 . bcFunc      - A pointwise function giving boundary values
6351 . numids      - The number of DMLabel ids for constrained points
6352 . ids         - An array of ids for constrained points
6353 - ctx         - An optional user context for bcFunc
6354 
6355   Options Database Keys:
6356 + -bc_<boundary name> <num> - Overrides the boundary ids
6357 - -bc_<boundary name>_comp <num> - Overrides the boundary components
6358 
6359   Level: developer
6360 
6361 .seealso: DMGetBoundary()
6362 @*/
6363 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)
6364 {
6365   PetscErrorCode ierr;
6366 
6367   PetscFunctionBegin;
6368   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6369   ierr = PetscDSAddBoundary(dm->prob,type,name,labelname,field,numcomps,comps,bcFunc,numids,ids,ctx);CHKERRQ(ierr);
6370   PetscFunctionReturn(0);
6371 }
6372 
6373 /*@
6374   DMGetNumBoundary - Get the number of registered BC
6375 
6376   Input Parameters:
6377 . dm - The mesh object
6378 
6379   Output Parameters:
6380 . numBd - The number of BC
6381 
6382   Level: intermediate
6383 
6384 .seealso: DMAddBoundary(), DMGetBoundary()
6385 @*/
6386 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
6387 {
6388   PetscErrorCode ierr;
6389 
6390   PetscFunctionBegin;
6391   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6392   ierr = PetscDSGetNumBoundary(dm->prob,numBd);CHKERRQ(ierr);
6393   PetscFunctionReturn(0);
6394 }
6395 
6396 /*@C
6397   DMGetBoundary - Get a model boundary condition
6398 
6399   Input Parameters:
6400 + dm          - The mesh object
6401 - bd          - The BC number
6402 
6403   Output Parameters:
6404 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
6405 . name        - The BC name
6406 . labelname   - The label defining constrained points
6407 . field       - The field to constrain
6408 . numcomps    - The number of constrained field components
6409 . comps       - An array of constrained component numbers
6410 . bcFunc      - A pointwise function giving boundary values
6411 . numids      - The number of DMLabel ids for constrained points
6412 . ids         - An array of ids for constrained points
6413 - ctx         - An optional user context for bcFunc
6414 
6415   Options Database Keys:
6416 + -bc_<boundary name> <num> - Overrides the boundary ids
6417 - -bc_<boundary name>_comp <num> - Overrides the boundary components
6418 
6419   Level: developer
6420 
6421 .seealso: DMAddBoundary()
6422 @*/
6423 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)
6424 {
6425   PetscErrorCode ierr;
6426 
6427   PetscFunctionBegin;
6428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6429   ierr = PetscDSGetBoundary(dm->prob,bd,type,name,labelname,field,numcomps,comps,func,numids,ids,ctx);CHKERRQ(ierr);
6430   PetscFunctionReturn(0);
6431 }
6432 
6433 static PetscErrorCode DMPopulateBoundary(DM dm)
6434 {
6435   DMBoundary *lastnext;
6436   DSBoundary dsbound;
6437   PetscErrorCode ierr;
6438 
6439   PetscFunctionBegin;
6440   dsbound = dm->prob->boundary;
6441   if (dm->boundary) {
6442     DMBoundary next = dm->boundary;
6443 
6444     /* quick check to see if the PetscDS has changed */
6445     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
6446     /* the PetscDS has changed: tear down and rebuild */
6447     while (next) {
6448       DMBoundary b = next;
6449 
6450       next = b->next;
6451       ierr = PetscFree(b);CHKERRQ(ierr);
6452     }
6453     dm->boundary = NULL;
6454   }
6455 
6456   lastnext = &(dm->boundary);
6457   while (dsbound) {
6458     DMBoundary dmbound;
6459 
6460     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
6461     dmbound->dsboundary = dsbound;
6462     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
6463     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
6464     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
6465     *lastnext = dmbound;
6466     lastnext = &(dmbound->next);
6467     dsbound = dsbound->next;
6468   }
6469   PetscFunctionReturn(0);
6470 }
6471 
6472 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
6473 {
6474   DMBoundary     b;
6475   PetscErrorCode ierr;
6476 
6477   PetscFunctionBegin;
6478   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6479   PetscValidPointer(isBd, 3);
6480   *isBd = PETSC_FALSE;
6481   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
6482   b = dm->boundary;
6483   while (b && !(*isBd)) {
6484     DMLabel    label = b->label;
6485     DSBoundary dsb = b->dsboundary;
6486 
6487     if (label) {
6488       PetscInt i;
6489 
6490       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
6491         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
6492       }
6493     }
6494     b = b->next;
6495   }
6496   PetscFunctionReturn(0);
6497 }
6498 
6499 /*@C
6500   DMProjectFunction - This projects the given function into the function space provided.
6501 
6502   Input Parameters:
6503 + dm      - The DM
6504 . time    - The time
6505 . funcs   - The coordinate functions to evaluate, one per field
6506 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
6507 - mode    - The insertion mode for values
6508 
6509   Output Parameter:
6510 . X - vector
6511 
6512    Calling sequence of func:
6513 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
6514 
6515 +  dim - The spatial dimension
6516 .  x   - The coordinates
6517 .  Nf  - The number of fields
6518 .  u   - The output field values
6519 -  ctx - optional user-defined function context
6520 
6521   Level: developer
6522 
6523 .seealso: DMComputeL2Diff()
6524 @*/
6525 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
6526 {
6527   Vec            localX;
6528   PetscErrorCode ierr;
6529 
6530   PetscFunctionBegin;
6531   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6532   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
6533   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6534   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
6535   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
6536   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
6537   PetscFunctionReturn(0);
6538 }
6539 
6540 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
6541 {
6542   PetscErrorCode ierr;
6543 
6544   PetscFunctionBegin;
6545   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6546   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
6547   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
6548   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6549   PetscFunctionReturn(0);
6550 }
6551 
6552 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)
6553 {
6554   Vec            localX;
6555   PetscErrorCode ierr;
6556 
6557   PetscFunctionBegin;
6558   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6559   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
6560   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6561   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
6562   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
6563   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
6564   PetscFunctionReturn(0);
6565 }
6566 
6567 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)
6568 {
6569   PetscErrorCode ierr;
6570 
6571   PetscFunctionBegin;
6572   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6573   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
6574   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
6575   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
6576   PetscFunctionReturn(0);
6577 }
6578 
6579 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
6580                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
6581                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6582                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6583                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6584                                    InsertMode mode, Vec localX)
6585 {
6586   PetscErrorCode ierr;
6587 
6588   PetscFunctionBegin;
6589   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6590   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
6591   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
6592   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6593   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
6594   PetscFunctionReturn(0);
6595 }
6596 
6597 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
6598                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
6599                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6600                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6601                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6602                                         InsertMode mode, Vec localX)
6603 {
6604   PetscErrorCode ierr;
6605 
6606   PetscFunctionBegin;
6607   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6608   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
6609   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
6610   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6611   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
6612   PetscFunctionReturn(0);
6613 }
6614 
6615 /*@C
6616   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
6617 
6618   Input Parameters:
6619 + dm    - The DM
6620 . time  - The time
6621 . funcs - The functions to evaluate for each field component
6622 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6623 - X     - The coefficient vector u_h, a global vector
6624 
6625   Output Parameter:
6626 . diff - The diff ||u - u_h||_2
6627 
6628   Level: developer
6629 
6630 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6631 @*/
6632 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
6633 {
6634   PetscErrorCode ierr;
6635 
6636   PetscFunctionBegin;
6637   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6638   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6639   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
6640   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6641   PetscFunctionReturn(0);
6642 }
6643 
6644 /*@C
6645   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
6646 
6647   Input Parameters:
6648 + dm    - The DM
6649 , time  - The time
6650 . funcs - The gradient functions to evaluate for each field component
6651 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6652 . X     - The coefficient vector u_h, a global vector
6653 - n     - The vector to project along
6654 
6655   Output Parameter:
6656 . diff - The diff ||(grad u - grad u_h) . n||_2
6657 
6658   Level: developer
6659 
6660 .seealso: DMProjectFunction(), DMComputeL2Diff()
6661 @*/
6662 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)
6663 {
6664   PetscErrorCode ierr;
6665 
6666   PetscFunctionBegin;
6667   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6668   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6669   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
6670   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
6671   PetscFunctionReturn(0);
6672 }
6673 
6674 /*@C
6675   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
6676 
6677   Input Parameters:
6678 + dm    - The DM
6679 . time  - The time
6680 . funcs - The functions to evaluate for each field component
6681 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6682 - X     - The coefficient vector u_h, a global vector
6683 
6684   Output Parameter:
6685 . diff - The array of differences, ||u^f - u^f_h||_2
6686 
6687   Level: developer
6688 
6689 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6690 @*/
6691 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
6692 {
6693   PetscErrorCode ierr;
6694 
6695   PetscFunctionBegin;
6696   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6697   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6698   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
6699   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6700   PetscFunctionReturn(0);
6701 }
6702 
6703 /*@C
6704   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
6705                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
6706 
6707   Collective on dm
6708 
6709   Input parameters:
6710 + dm - the pre-adaptation DM object
6711 - label - label with the flags
6712 
6713   Output parameters:
6714 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
6715 
6716   Level: intermediate
6717 
6718 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
6719 @*/
6720 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
6721 {
6722   PetscErrorCode ierr;
6723 
6724   PetscFunctionBegin;
6725   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6726   PetscValidPointer(label,2);
6727   PetscValidPointer(dmAdapt,3);
6728   *dmAdapt = NULL;
6729   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
6730   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
6731   PetscFunctionReturn(0);
6732 }
6733 
6734 /*@C
6735   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
6736 
6737   Input Parameters:
6738 + dm - The DM object
6739 . metric - The metric to which the mesh is adapted, defined vertex-wise.
6740 - 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_".
6741 
6742   Output Parameter:
6743 . dmAdapt  - Pointer to the DM object containing the adapted mesh
6744 
6745   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
6746 
6747   Level: advanced
6748 
6749 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
6750 @*/
6751 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
6752 {
6753   PetscErrorCode ierr;
6754 
6755   PetscFunctionBegin;
6756   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6757   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
6758   if (bdLabel) PetscValidPointer(bdLabel, 3);
6759   PetscValidPointer(dmAdapt, 4);
6760   *dmAdapt = NULL;
6761   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
6762   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
6763   PetscFunctionReturn(0);
6764 }
6765 
6766 /*@C
6767  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
6768 
6769  Not Collective
6770 
6771  Input Parameter:
6772  . dm    - The DM
6773 
6774  Output Parameter:
6775  . nranks - the number of neighbours
6776  . ranks - the neighbors ranks
6777 
6778  Notes:
6779  Do not free the array, it is freed when the DM is destroyed.
6780 
6781  Level: beginner
6782 
6783  .seealso: DMDAGetNeighbors(), PetscSFGetRanks()
6784 @*/
6785 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
6786 {
6787   PetscErrorCode ierr;
6788 
6789   PetscFunctionBegin;
6790   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6791   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
6792   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
6793   PetscFunctionReturn(0);
6794 }
6795 
6796 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
6797 
6798 /*
6799     Converts the input vector to a ghosted vector and then calls the standard coloring code.
6800     This has be a different function because it requires DM which is not defined in the Mat library
6801 */
6802 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
6803 {
6804   PetscErrorCode ierr;
6805 
6806   PetscFunctionBegin;
6807   if (coloring->ctype == IS_COLORING_LOCAL) {
6808     Vec x1local;
6809     DM  dm;
6810     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6811     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
6812     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
6813     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6814     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6815     x1   = x1local;
6816   }
6817   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
6818   if (coloring->ctype == IS_COLORING_LOCAL) {
6819     DM  dm;
6820     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6821     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
6822   }
6823   PetscFunctionReturn(0);
6824 }
6825 
6826 /*@
6827     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
6828 
6829     Input Parameter:
6830 .    coloring - the MatFDColoring object
6831 
6832     Developer Notes:
6833     this routine exists because the PETSc Mat library does not know about the DM objects
6834 
6835     Level: advanced
6836 
6837 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
6838 @*/
6839 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
6840 {
6841   PetscFunctionBegin;
6842   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
6843   PetscFunctionReturn(0);
6844 }
6845 
6846 /*@
6847     DMGetCompatibility - determine if two DMs are compatible
6848 
6849     Collective
6850 
6851     Input Parameters:
6852 +    dm - the first DM
6853 -    dm2 - the second DM
6854 
6855     Output Parameters:
6856 +    compatible - whether or not the two DMs are compatible
6857 -    set - whether or not the compatible value was set
6858 
6859     Notes:
6860     Two DMs are deemed compatible if they represent the same parallel decomposition
6861     of the same topology. This implies that the the section (field data) on one
6862     "makes sense" with respect to the topology and parallel decomposition of the other.
6863     Loosely speaking, compatibile DMs represent the same domain, with the same parallel
6864     decomposition, with different data.
6865 
6866     Typically, one would confirm compatibility if intending to simultaneously iterate
6867     over a pair of vectors obtained from different DMs.
6868 
6869     For example, two DMDA objects are compatible if they have the same local
6870     and global sizes and the same stencil width. They can have different numbers
6871     of degrees of freedom per node. Thus, one could use the node numbering from
6872     either DM in bounds for a loop over vectors derived from either DM.
6873 
6874     Consider the operation of summing data living on a 2-dof DMDA to data living
6875     on a 1-dof DMDA, which should be compatible, as in the following snippet.
6876 .vb
6877   ...
6878   ierr = DMGetCompatibility(da1,da2,&compatible,&set);CHKERRQ(ierr);
6879   if (set && compatible)  {
6880     ierr = DMDAVecGetArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
6881     ierr = DMDAVecGetArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
6882     ierr = DMDAGetCorners(da1,&x,&y,NULL,&m,&n);CHKERRQ(ierr);
6883     for (j=y; j<y+n; ++j) {
6884       for (i=x; i<x+m, ++i) {
6885         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
6886       }
6887     }
6888     ierr = DMDAVecRestoreArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
6889     ierr = DMDAVecRestoreArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
6890   } else {
6891     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
6892   }
6893   ...
6894 .ve
6895 
6896     Checking compatibility might be expensive for a given implementation of DM,
6897     or might be impossible to unambiguously confirm or deny. For this reason,
6898     this function may decline to determine compatibility, and hence users should
6899     always check the "set" output parameter.
6900 
6901     A DM is always compatible with itself.
6902 
6903     In the current implementation, DMs which live on "unequal" communicators
6904     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
6905     incompatible.
6906 
6907     This function is labeled "Collective," as information about all subdomains
6908     is required on each rank. However, in DM implementations which store all this
6909     information locally, this function may be merely "Logically Collective".
6910 
6911     Developer Notes:
6912     Compatibility is assumed to be a symmetric concept; if DM A is compatible with DM B,
6913     the DM B is compatible with DM A. Thus, this function checks the implementations
6914     of both dm and dm2 (if they are of different types), attempting to determine
6915     compatibility. It is left to DM implementers to ensure that symmetry is
6916     preserved. The simplest way to do this is, when implementing type-specific
6917     logic for this function, to check for existing logic in the implementation
6918     of other DM types and let *set = PETSC_FALSE if found; the logic of this
6919     function will then call that logic.
6920 
6921     Level: advanced
6922 
6923 .seealso: DM, DMDACreateCompatibleDMDA()
6924 @*/
6925 
6926 PetscErrorCode DMGetCompatibility(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
6927 {
6928   PetscErrorCode ierr;
6929   PetscMPIInt    compareResult;
6930   DMType         type,type2;
6931   PetscBool      sameType;
6932 
6933   PetscFunctionBegin;
6934   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6935   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
6936 
6937   /* Declare a DM compatible with itself */
6938   if (dm == dm2) {
6939     *set = PETSC_TRUE;
6940     *compatible = PETSC_TRUE;
6941     PetscFunctionReturn(0);
6942   }
6943 
6944   /* Declare a DM incompatible with a DM that lives on an "unequal"
6945      communicator. Note that this does not preclude compatibility with
6946      DMs living on "congruent" or "similar" communicators, but this must be
6947      determined by the implementation-specific logic */
6948   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)dm),PetscObjectComm((PetscObject)dm2),&compareResult);CHKERRQ(ierr);
6949   if (compareResult == MPI_UNEQUAL) {
6950     *set = PETSC_TRUE;
6951     *compatible = PETSC_FALSE;
6952     PetscFunctionReturn(0);
6953   }
6954 
6955   /* Pass to the implementation-specific routine, if one exists. */
6956   if (dm->ops->getcompatibility) {
6957     ierr = (*dm->ops->getcompatibility)(dm,dm2,compatible,set);CHKERRQ(ierr);
6958     if (*set) {
6959       PetscFunctionReturn(0);
6960     }
6961   }
6962 
6963   /* If dm and dm2 are of different types, then attempt to check compatibility
6964      with an implementation of this function from dm2 */
6965   ierr = DMGetType(dm,&type);CHKERRQ(ierr);
6966   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
6967   ierr = PetscStrcmp(type,type2,&sameType);CHKERRQ(ierr);
6968   if (!sameType && dm2->ops->getcompatibility) {
6969     ierr = (*dm2->ops->getcompatibility)(dm2,dm,compatible,set);CHKERRQ(ierr); /* Note argument order */
6970   } else {
6971     *set = PETSC_FALSE;
6972   }
6973   PetscFunctionReturn(0);
6974 }
6975