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