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