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