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