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