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