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