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