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