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