xref: /petsc/src/dm/interface/dm.c (revision acdc6f615b227b127e4f2de403e4835e54387ffc)
1 #include <petsc/private/dmimpl.h>           /*I      "petscdm.h"          I*/
2 #include <petsc/private/dmlabelimpl.h>      /*I      "petscdmlabel.h"     I*/
3 #include <petscsf.h>
4 #include <petscds.h>
5 
6 PetscClassId  DM_CLASSID;
7 PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_CreateInterpolation;
8 
9 const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DM_BOUNDARY_",0};
10 
11 #undef __FUNCT__
12 #define __FUNCT__ "DMCreate"
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 = PetscCalloc1(1,&(v->labels));CHKERRQ(ierr);
75   v->labels->refct = 1;
76   *dm = v;
77   PetscFunctionReturn(0);
78 }
79 
80 #undef __FUNCT__
81 #define __FUNCT__ "DMClone"
82 /*@
83   DMClone - Creates a DM object with the same topology as the original.
84 
85   Collective on MPI_Comm
86 
87   Input Parameter:
88 . dm - The original DM object
89 
90   Output Parameter:
91 . newdm  - The new DM object
92 
93   Level: beginner
94 
95 .keywords: DM, topology, create
96 @*/
97 PetscErrorCode DMClone(DM dm, DM *newdm)
98 {
99   PetscSF        sf;
100   Vec            coords;
101   void          *ctx;
102   PetscInt       dim;
103   PetscErrorCode ierr;
104 
105   PetscFunctionBegin;
106   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
107   PetscValidPointer(newdm,2);
108   ierr = DMCreate(PetscObjectComm((PetscObject)dm), newdm);CHKERRQ(ierr);
109   ierr = PetscFree((*newdm)->labels);CHKERRQ(ierr);
110   dm->labels->refct++;
111   (*newdm)->labels = dm->labels;
112   (*newdm)->depthLabel = dm->depthLabel;
113   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
114   ierr = DMSetDimension(*newdm, dim);CHKERRQ(ierr);
115   if (dm->ops->clone) {
116     ierr = (*dm->ops->clone)(dm, newdm);CHKERRQ(ierr);
117   }
118   (*newdm)->setupcalled = PETSC_TRUE;
119   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
120   ierr = DMSetPointSF(*newdm, sf);CHKERRQ(ierr);
121   ierr = DMGetApplicationContext(dm, &ctx);CHKERRQ(ierr);
122   ierr = DMSetApplicationContext(*newdm, ctx);CHKERRQ(ierr);
123   ierr = DMGetCoordinatesLocal(dm, &coords);CHKERRQ(ierr);
124   if (coords) {
125     ierr = DMSetCoordinatesLocal(*newdm, coords);CHKERRQ(ierr);
126   } else {
127     ierr = DMGetCoordinates(dm, &coords);CHKERRQ(ierr);
128     if (coords) {ierr = DMSetCoordinates(*newdm, coords);CHKERRQ(ierr);}
129   }
130   if (dm->maxCell) {
131     const PetscReal *maxCell, *L;
132     const DMBoundaryType *bd;
133     ierr = DMGetPeriodicity(dm,     &maxCell, &L, &bd);CHKERRQ(ierr);
134     ierr = DMSetPeriodicity(*newdm,  maxCell,  L,  bd);CHKERRQ(ierr);
135   }
136   PetscFunctionReturn(0);
137 }
138 
139 #undef __FUNCT__
140 #define __FUNCT__ "DMSetVecType"
141 /*@C
142        DMSetVecType - Sets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
143 
144    Logically Collective on DM
145 
146    Input Parameter:
147 +  da - initial distributed array
148 .  ctype - the vector type, currently either VECSTANDARD or VECCUSP
149 
150    Options Database:
151 .   -dm_vec_type ctype
152 
153    Level: intermediate
154 
155 .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType()
156 @*/
157 PetscErrorCode  DMSetVecType(DM da,VecType ctype)
158 {
159   PetscErrorCode ierr;
160 
161   PetscFunctionBegin;
162   PetscValidHeaderSpecific(da,DM_CLASSID,1);
163   ierr = PetscFree(da->vectype);CHKERRQ(ierr);
164   ierr = PetscStrallocpy(ctype,(char**)&da->vectype);CHKERRQ(ierr);
165   PetscFunctionReturn(0);
166 }
167 
168 #undef __FUNCT__
169 #define __FUNCT__ "DMGetVecType"
170 /*@C
171        DMGetVecType - Gets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
172 
173    Logically Collective on DM
174 
175    Input Parameter:
176 .  da - initial distributed array
177 
178    Output Parameter:
179 .  ctype - the vector type
180 
181    Level: intermediate
182 
183 .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType
184 @*/
185 PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
186 {
187   PetscFunctionBegin;
188   PetscValidHeaderSpecific(da,DM_CLASSID,1);
189   *ctype = da->vectype;
190   PetscFunctionReturn(0);
191 }
192 
193 #undef __FUNCT__
194 #define __FUNCT__ "VecGetDM"
195 /*@
196   VecGetDM - Gets the DM defining the data layout of the vector
197 
198   Not collective
199 
200   Input Parameter:
201 . v - The Vec
202 
203   Output Parameter:
204 . dm - The DM
205 
206   Level: intermediate
207 
208 .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
209 @*/
210 PetscErrorCode VecGetDM(Vec v, DM *dm)
211 {
212   PetscErrorCode ierr;
213 
214   PetscFunctionBegin;
215   PetscValidHeaderSpecific(v,VEC_CLASSID,1);
216   PetscValidPointer(dm,2);
217   ierr = PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);CHKERRQ(ierr);
218   PetscFunctionReturn(0);
219 }
220 
221 #undef __FUNCT__
222 #define __FUNCT__ "VecSetDM"
223 /*@
224   VecSetDM - Sets the DM defining the data layout of the vector.
225 
226   Not collective
227 
228   Input Parameters:
229 + v - The Vec
230 - dm - The DM
231 
232   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.
233 
234   Level: intermediate
235 
236 .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
237 @*/
238 PetscErrorCode VecSetDM(Vec v, DM dm)
239 {
240   PetscErrorCode ierr;
241 
242   PetscFunctionBegin;
243   PetscValidHeaderSpecific(v,VEC_CLASSID,1);
244   if (dm) PetscValidHeaderSpecific(dm,DM_CLASSID,2);
245   ierr = PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);CHKERRQ(ierr);
246   PetscFunctionReturn(0);
247 }
248 
249 #undef __FUNCT__
250 #define __FUNCT__ "DMSetMatType"
251 /*@C
252        DMSetMatType - Sets the type of matrix created with DMCreateMatrix()
253 
254    Logically Collective on DM
255 
256    Input Parameter:
257 +  dm - the DM context
258 .  ctype - the matrix type
259 
260    Options Database:
261 .   -dm_mat_type ctype
262 
263    Level: intermediate
264 
265 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType()
266 @*/
267 PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
268 {
269   PetscErrorCode ierr;
270 
271   PetscFunctionBegin;
272   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
273   ierr = PetscFree(dm->mattype);CHKERRQ(ierr);
274   ierr = PetscStrallocpy(ctype,(char**)&dm->mattype);CHKERRQ(ierr);
275   PetscFunctionReturn(0);
276 }
277 
278 #undef __FUNCT__
279 #define __FUNCT__ "DMGetMatType"
280 /*@C
281        DMGetMatType - Gets the type of matrix created with DMCreateMatrix()
282 
283    Logically Collective on DM
284 
285    Input Parameter:
286 .  dm - the DM context
287 
288    Output Parameter:
289 .  ctype - the matrix type
290 
291    Options Database:
292 .   -dm_mat_type ctype
293 
294    Level: intermediate
295 
296 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType()
297 @*/
298 PetscErrorCode  DMGetMatType(DM dm,MatType *ctype)
299 {
300   PetscFunctionBegin;
301   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
302   *ctype = dm->mattype;
303   PetscFunctionReturn(0);
304 }
305 
306 #undef __FUNCT__
307 #define __FUNCT__ "MatGetDM"
308 /*@
309   MatGetDM - Gets the DM defining the data layout of the matrix
310 
311   Not collective
312 
313   Input Parameter:
314 . A - The Mat
315 
316   Output Parameter:
317 . dm - The DM
318 
319   Level: intermediate
320 
321 .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
322 @*/
323 PetscErrorCode MatGetDM(Mat A, DM *dm)
324 {
325   PetscErrorCode ierr;
326 
327   PetscFunctionBegin;
328   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
329   PetscValidPointer(dm,2);
330   ierr = PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);CHKERRQ(ierr);
331   PetscFunctionReturn(0);
332 }
333 
334 #undef __FUNCT__
335 #define __FUNCT__ "MatSetDM"
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 #undef __FUNCT__
361 #define __FUNCT__ "DMSetOptionsPrefix"
362 /*@C
363    DMSetOptionsPrefix - Sets the prefix used for searching for all
364    DM options in the database.
365 
366    Logically Collective on DM
367 
368    Input Parameter:
369 +  da - the DM context
370 -  prefix - the prefix to prepend to all option names
371 
372    Notes:
373    A hyphen (-) must NOT be given at the beginning of the prefix name.
374    The first character of all runtime options is AUTOMATICALLY the hyphen.
375 
376    Level: advanced
377 
378 .keywords: DM, set, options, prefix, database
379 
380 .seealso: DMSetFromOptions()
381 @*/
382 PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
383 {
384   PetscErrorCode ierr;
385 
386   PetscFunctionBegin;
387   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
388   ierr = PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);CHKERRQ(ierr);
389   if (dm->sf) {
390     ierr = PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);CHKERRQ(ierr);
391   }
392   if (dm->defaultSF) {
393     ierr = PetscObjectSetOptionsPrefix((PetscObject)dm->defaultSF,prefix);CHKERRQ(ierr);
394   }
395   PetscFunctionReturn(0);
396 }
397 
398 #undef __FUNCT__
399 #define __FUNCT__ "DMAppendOptionsPrefix"
400 /*@C
401    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
402    DM options in the database.
403 
404    Logically Collective on DM
405 
406    Input Parameters:
407 +  dm - the DM context
408 -  prefix - the prefix string to prepend to all DM option requests
409 
410    Notes:
411    A hyphen (-) must NOT be given at the beginning of the prefix name.
412    The first character of all runtime options is AUTOMATICALLY the hyphen.
413 
414    Level: advanced
415 
416 .keywords: DM, append, options, prefix, database
417 
418 .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
419 @*/
420 PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
421 {
422   PetscErrorCode ierr;
423 
424   PetscFunctionBegin;
425   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
426   ierr = PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);CHKERRQ(ierr);
427   PetscFunctionReturn(0);
428 }
429 
430 #undef __FUNCT__
431 #define __FUNCT__ "DMGetOptionsPrefix"
432 /*@C
433    DMGetOptionsPrefix - Gets the prefix used for searching for all
434    DM options in the database.
435 
436    Not Collective
437 
438    Input Parameters:
439 .  dm - the DM context
440 
441    Output Parameters:
442 .  prefix - pointer to the prefix string used is returned
443 
444    Notes: On the fortran side, the user should pass in a string 'prefix' of
445    sufficient length to hold the prefix.
446 
447    Level: advanced
448 
449 .keywords: DM, set, options, prefix, database
450 
451 .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
452 @*/
453 PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
454 {
455   PetscErrorCode ierr;
456 
457   PetscFunctionBegin;
458   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
459   ierr = PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);CHKERRQ(ierr);
460   PetscFunctionReturn(0);
461 }
462 
463 #undef __FUNCT__
464 #define __FUNCT__ "DMDestroy"
465 /*@
466     DMDestroy - Destroys a vector packer or DM.
467 
468     Collective on DM
469 
470     Input Parameter:
471 .   dm - the DM object to destroy
472 
473     Level: developer
474 
475 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
476 
477 @*/
478 PetscErrorCode  DMDestroy(DM *dm)
479 {
480   PetscInt       i, cnt = 0;
481   DMNamedVecLink nlink,nnext;
482   PetscErrorCode ierr;
483 
484   PetscFunctionBegin;
485   if (!*dm) PetscFunctionReturn(0);
486   PetscValidHeaderSpecific((*dm),DM_CLASSID,1);
487 
488   /* count all the circular references of DM and its contained Vecs */
489   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
490     if ((*dm)->localin[i])  cnt++;
491     if ((*dm)->globalin[i]) cnt++;
492   }
493   for (nlink=(*dm)->namedglobal; nlink; nlink=nlink->next) cnt++;
494   for (nlink=(*dm)->namedlocal; nlink; nlink=nlink->next) cnt++;
495   if ((*dm)->x) {
496     DM obj;
497     ierr = VecGetDM((*dm)->x, &obj);CHKERRQ(ierr);
498     if (obj == *dm) cnt++;
499   }
500 
501   if (--((PetscObject)(*dm))->refct - cnt > 0) {*dm = 0; PetscFunctionReturn(0);}
502   /*
503      Need this test because the dm references the vectors that
504      reference the dm, so destroying the dm calls destroy on the
505      vectors that cause another destroy on the dm
506   */
507   if (((PetscObject)(*dm))->refct < 0) PetscFunctionReturn(0);
508   ((PetscObject) (*dm))->refct = 0;
509   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
510     if ((*dm)->localout[i]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Destroying a DM that has a local vector obtained with DMGetLocalVector()");
511     ierr = VecDestroy(&(*dm)->localin[i]);CHKERRQ(ierr);
512   }
513   nnext=(*dm)->namedglobal;
514   (*dm)->namedglobal = NULL;
515   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
516     nnext = nlink->next;
517     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
518     ierr = PetscFree(nlink->name);CHKERRQ(ierr);
519     ierr = VecDestroy(&nlink->X);CHKERRQ(ierr);
520     ierr = PetscFree(nlink);CHKERRQ(ierr);
521   }
522   nnext=(*dm)->namedlocal;
523   (*dm)->namedlocal = NULL;
524   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
525     nnext = nlink->next;
526     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
527     ierr = PetscFree(nlink->name);CHKERRQ(ierr);
528     ierr = VecDestroy(&nlink->X);CHKERRQ(ierr);
529     ierr = PetscFree(nlink);CHKERRQ(ierr);
530   }
531 
532   /* Destroy the list of hooks */
533   {
534     DMCoarsenHookLink link,next;
535     for (link=(*dm)->coarsenhook; link; link=next) {
536       next = link->next;
537       ierr = PetscFree(link);CHKERRQ(ierr);
538     }
539     (*dm)->coarsenhook = NULL;
540   }
541   {
542     DMRefineHookLink link,next;
543     for (link=(*dm)->refinehook; link; link=next) {
544       next = link->next;
545       ierr = PetscFree(link);CHKERRQ(ierr);
546     }
547     (*dm)->refinehook = NULL;
548   }
549   {
550     DMSubDomainHookLink link,next;
551     for (link=(*dm)->subdomainhook; link; link=next) {
552       next = link->next;
553       ierr = PetscFree(link);CHKERRQ(ierr);
554     }
555     (*dm)->subdomainhook = NULL;
556   }
557   {
558     DMGlobalToLocalHookLink link,next;
559     for (link=(*dm)->gtolhook; link; link=next) {
560       next = link->next;
561       ierr = PetscFree(link);CHKERRQ(ierr);
562     }
563     (*dm)->gtolhook = NULL;
564   }
565   {
566     DMLocalToGlobalHookLink link,next;
567     for (link=(*dm)->ltoghook; link; link=next) {
568       next = link->next;
569       ierr = PetscFree(link);CHKERRQ(ierr);
570     }
571     (*dm)->ltoghook = NULL;
572   }
573   /* Destroy the work arrays */
574   {
575     DMWorkLink link,next;
576     if ((*dm)->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Work array still checked out");
577     for (link=(*dm)->workin; link; link=next) {
578       next = link->next;
579       ierr = PetscFree(link->mem);CHKERRQ(ierr);
580       ierr = PetscFree(link);CHKERRQ(ierr);
581     }
582     (*dm)->workin = NULL;
583   }
584   if (!--((*dm)->labels->refct)) {
585     DMLabelLink next = (*dm)->labels->next;
586 
587     /* destroy the labels */
588     while (next) {
589       DMLabelLink tmp = next->next;
590 
591       ierr = DMLabelDestroy(&next->label);CHKERRQ(ierr);
592       ierr = PetscFree(next);CHKERRQ(ierr);
593       next = tmp;
594     }
595     ierr = PetscFree((*dm)->labels);CHKERRQ(ierr);
596   }
597 
598   ierr = PetscObjectDestroy(&(*dm)->dmksp);CHKERRQ(ierr);
599   ierr = PetscObjectDestroy(&(*dm)->dmsnes);CHKERRQ(ierr);
600   ierr = PetscObjectDestroy(&(*dm)->dmts);CHKERRQ(ierr);
601 
602   if ((*dm)->ctx && (*dm)->ctxdestroy) {
603     ierr = (*(*dm)->ctxdestroy)(&(*dm)->ctx);CHKERRQ(ierr);
604   }
605   ierr = VecDestroy(&(*dm)->x);CHKERRQ(ierr);
606   ierr = MatFDColoringDestroy(&(*dm)->fd);CHKERRQ(ierr);
607   ierr = DMClearGlobalVectors(*dm);CHKERRQ(ierr);
608   ierr = ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);CHKERRQ(ierr);
609   ierr = PetscFree((*dm)->vectype);CHKERRQ(ierr);
610   ierr = PetscFree((*dm)->mattype);CHKERRQ(ierr);
611 
612   ierr = PetscSectionDestroy(&(*dm)->defaultSection);CHKERRQ(ierr);
613   ierr = PetscSectionDestroy(&(*dm)->defaultGlobalSection);CHKERRQ(ierr);
614   ierr = PetscLayoutDestroy(&(*dm)->map);CHKERRQ(ierr);
615   ierr = PetscSectionDestroy(&(*dm)->defaultConstraintSection);CHKERRQ(ierr);
616   ierr = MatDestroy(&(*dm)->defaultConstraintMat);CHKERRQ(ierr);
617   ierr = PetscSFDestroy(&(*dm)->sf);CHKERRQ(ierr);
618   ierr = PetscSFDestroy(&(*dm)->defaultSF);CHKERRQ(ierr);
619   ierr = PetscSFDestroy(&(*dm)->sfNatural);CHKERRQ(ierr);
620 
621   ierr = DMDestroy(&(*dm)->coarseMesh);CHKERRQ(ierr);
622   ierr = DMDestroy(&(*dm)->coordinateDM);CHKERRQ(ierr);
623   ierr = VecDestroy(&(*dm)->coordinates);CHKERRQ(ierr);
624   ierr = VecDestroy(&(*dm)->coordinatesLocal);CHKERRQ(ierr);
625   ierr = PetscFree3((*dm)->L,(*dm)->maxCell,(*dm)->bdtype);CHKERRQ(ierr);
626 
627   ierr = PetscDSDestroy(&(*dm)->prob);CHKERRQ(ierr);
628   ierr = DMDestroy(&(*dm)->dmBC);CHKERRQ(ierr);
629   /* if memory was published with SAWs then destroy it */
630   ierr = PetscObjectSAWsViewOff((PetscObject)*dm);CHKERRQ(ierr);
631 
632   ierr = (*(*dm)->ops->destroy)(*dm);CHKERRQ(ierr);
633   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
634   ierr = PetscHeaderDestroy(dm);CHKERRQ(ierr);
635   PetscFunctionReturn(0);
636 }
637 
638 #undef __FUNCT__
639 #define __FUNCT__ "DMSetUp"
640 /*@
641     DMSetUp - sets up the data structures inside a DM object
642 
643     Collective on DM
644 
645     Input Parameter:
646 .   dm - the DM object to setup
647 
648     Level: developer
649 
650 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
651 
652 @*/
653 PetscErrorCode  DMSetUp(DM dm)
654 {
655   PetscErrorCode ierr;
656 
657   PetscFunctionBegin;
658   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
659   if (dm->setupcalled) PetscFunctionReturn(0);
660   if (dm->ops->setup) {
661     ierr = (*dm->ops->setup)(dm);CHKERRQ(ierr);
662   }
663   dm->setupcalled = PETSC_TRUE;
664   PetscFunctionReturn(0);
665 }
666 
667 #undef __FUNCT__
668 #define __FUNCT__ "DMSetFromOptions"
669 /*@
670     DMSetFromOptions - sets parameters in a DM from the options database
671 
672     Collective on DM
673 
674     Input Parameter:
675 .   dm - the DM object to set options for
676 
677     Options Database:
678 +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
679 .   -dm_vec_type <type>  - type of vector to create inside DM
680 .   -dm_mat_type <type>  - type of matrix to create inside DM
681 -   -dm_coloring_type    - <global or ghosted>
682 
683     Level: developer
684 
685 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
686 
687 @*/
688 PetscErrorCode  DMSetFromOptions(DM dm)
689 {
690   char           typeName[256];
691   PetscBool      flg;
692   PetscErrorCode ierr;
693 
694   PetscFunctionBegin;
695   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
696   if (dm->sf) {
697     ierr = PetscSFSetFromOptions(dm->sf);CHKERRQ(ierr);
698   }
699   if (dm->defaultSF) {
700     ierr = PetscSFSetFromOptions(dm->defaultSF);CHKERRQ(ierr);
701   }
702   ierr = PetscObjectOptionsBegin((PetscObject)dm);CHKERRQ(ierr);
703   ierr = PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);CHKERRQ(ierr);
704   ierr = PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);CHKERRQ(ierr);
705   if (flg) {
706     ierr = DMSetVecType(dm,typeName);CHKERRQ(ierr);
707   }
708   ierr = PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);CHKERRQ(ierr);
709   if (flg) {
710     ierr = DMSetMatType(dm,typeName);CHKERRQ(ierr);
711   }
712   ierr = PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","ISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);CHKERRQ(ierr);
713   if (dm->ops->setfromoptions) {
714     ierr = (*dm->ops->setfromoptions)(PetscOptionsObject,dm);CHKERRQ(ierr);
715   }
716   /* process any options handlers added with PetscObjectAddOptionsHandler() */
717   ierr = PetscObjectProcessOptionsHandlers((PetscObject) dm);CHKERRQ(ierr);
718   ierr = PetscOptionsEnd();CHKERRQ(ierr);
719   PetscFunctionReturn(0);
720 }
721 
722 #undef __FUNCT__
723 #define __FUNCT__ "DMView"
724 /*@C
725     DMView - Views a DM
726 
727     Collective on DM
728 
729     Input Parameter:
730 +   dm - the DM object to view
731 -   v - the viewer
732 
733     Level: beginner
734 
735 .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
736 
737 @*/
738 PetscErrorCode  DMView(DM dm,PetscViewer v)
739 {
740   PetscErrorCode ierr;
741   PetscBool      isbinary;
742 
743   PetscFunctionBegin;
744   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
745   if (!v) {
746     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);CHKERRQ(ierr);
747   }
748   ierr = PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);CHKERRQ(ierr);
749   ierr = PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
750   if (isbinary) {
751     PetscInt classid = DM_FILE_CLASSID;
752     char     type[256];
753 
754     ierr = PetscViewerBinaryWrite(v,&classid,1,PETSC_INT,PETSC_FALSE);CHKERRQ(ierr);
755     ierr = PetscStrncpy(type,((PetscObject)dm)->type_name,256);CHKERRQ(ierr);
756     ierr = PetscViewerBinaryWrite(v,type,256,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr);
757   }
758   if (dm->ops->view) {
759     ierr = (*dm->ops->view)(dm,v);CHKERRQ(ierr);
760   }
761   PetscFunctionReturn(0);
762 }
763 
764 #undef __FUNCT__
765 #define __FUNCT__ "DMCreateGlobalVector"
766 /*@
767     DMCreateGlobalVector - Creates a global vector from a DM object
768 
769     Collective on DM
770 
771     Input Parameter:
772 .   dm - the DM object
773 
774     Output Parameter:
775 .   vec - the global vector
776 
777     Level: beginner
778 
779 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
780 
781 @*/
782 PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
783 {
784   PetscErrorCode ierr;
785 
786   PetscFunctionBegin;
787   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
788   ierr = (*dm->ops->createglobalvector)(dm,vec);CHKERRQ(ierr);
789   PetscFunctionReturn(0);
790 }
791 
792 #undef __FUNCT__
793 #define __FUNCT__ "DMCreateLocalVector"
794 /*@
795     DMCreateLocalVector - Creates a local vector from a DM object
796 
797     Not Collective
798 
799     Input Parameter:
800 .   dm - the DM object
801 
802     Output Parameter:
803 .   vec - the local vector
804 
805     Level: beginner
806 
807 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
808 
809 @*/
810 PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
811 {
812   PetscErrorCode ierr;
813 
814   PetscFunctionBegin;
815   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
816   ierr = (*dm->ops->createlocalvector)(dm,vec);CHKERRQ(ierr);
817   PetscFunctionReturn(0);
818 }
819 
820 #undef __FUNCT__
821 #define __FUNCT__ "DMGetLocalToGlobalMapping"
822 /*@
823    DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a DM.
824 
825    Collective on DM
826 
827    Input Parameter:
828 .  dm - the DM that provides the mapping
829 
830    Output Parameter:
831 .  ltog - the mapping
832 
833    Level: intermediate
834 
835    Notes:
836    This mapping can then be used by VecSetLocalToGlobalMapping() or
837    MatSetLocalToGlobalMapping().
838 
839 .seealso: DMCreateLocalVector()
840 @*/
841 PetscErrorCode  DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
842 {
843   PetscErrorCode ierr;
844 
845   PetscFunctionBegin;
846   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
847   PetscValidPointer(ltog,2);
848   if (!dm->ltogmap) {
849     PetscSection section, sectionGlobal;
850 
851     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
852     if (section) {
853       PetscInt *ltog;
854       PetscInt pStart, pEnd, size, p, l;
855 
856       ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
857       ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
858       ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
859       ierr = PetscMalloc1(size, &ltog);CHKERRQ(ierr); /* We want the local+overlap size */
860       for (p = pStart, l = 0; p < pEnd; ++p) {
861         PetscInt dof, off, c;
862 
863         /* Should probably use constrained dofs */
864         ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
865         ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr);
866         for (c = 0; c < dof; ++c, ++l) {
867           ltog[l] = off+c;
868         }
869       }
870       ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, 1,size, ltog, PETSC_OWN_POINTER, &dm->ltogmap);CHKERRQ(ierr);
871       ierr = PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);CHKERRQ(ierr);
872     } else {
873       if (!dm->ops->getlocaltoglobalmapping) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM can not create LocalToGlobalMapping");
874       ierr = (*dm->ops->getlocaltoglobalmapping)(dm);CHKERRQ(ierr);
875     }
876   }
877   *ltog = dm->ltogmap;
878   PetscFunctionReturn(0);
879 }
880 
881 #undef __FUNCT__
882 #define __FUNCT__ "DMGetBlockSize"
883 /*@
884    DMGetBlockSize - Gets the inherent block size associated with a DM
885 
886    Not Collective
887 
888    Input Parameter:
889 .  dm - the DM with block structure
890 
891    Output Parameter:
892 .  bs - the block size, 1 implies no exploitable block structure
893 
894    Level: intermediate
895 
896 .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
897 @*/
898 PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
899 {
900   PetscFunctionBegin;
901   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
902   PetscValidPointer(bs,2);
903   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
904   *bs = dm->bs;
905   PetscFunctionReturn(0);
906 }
907 
908 #undef __FUNCT__
909 #define __FUNCT__ "DMCreateInterpolation"
910 /*@
911     DMCreateInterpolation - Gets interpolation matrix between two DM objects
912 
913     Collective on DM
914 
915     Input Parameter:
916 +   dm1 - the DM object
917 -   dm2 - the second, finer DM object
918 
919     Output Parameter:
920 +  mat - the interpolation
921 -  vec - the scaling (optional)
922 
923     Level: developer
924 
925     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
926         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
927 
928         For DMDA objects you can use this interpolation (more precisely the interpolation from the DMGetCoordinateDM()) to interpolate the mesh coordinate vectors
929         EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
930 
931 
932 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen()
933 
934 @*/
935 PetscErrorCode  DMCreateInterpolation(DM dm1,DM dm2,Mat *mat,Vec *vec)
936 {
937   PetscErrorCode ierr;
938 
939   PetscFunctionBegin;
940   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
941   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
942   ierr = PetscLogEventBegin(DM_CreateInterpolation,dm1,dm2,0,0);CHKERRQ(ierr);
943   ierr = (*dm1->ops->createinterpolation)(dm1,dm2,mat,vec);CHKERRQ(ierr);
944   ierr = PetscLogEventEnd(DM_CreateInterpolation,dm1,dm2,0,0);CHKERRQ(ierr);
945   PetscFunctionReturn(0);
946 }
947 
948 #undef __FUNCT__
949 #define __FUNCT__ "DMCreateInjection"
950 /*@
951     DMCreateInjection - Gets injection matrix between two DM objects
952 
953     Collective on DM
954 
955     Input Parameter:
956 +   dm1 - the DM object
957 -   dm2 - the second, finer DM object
958 
959     Output Parameter:
960 .   mat - the injection
961 
962     Level: developer
963 
964    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
965         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the injection.
966 
967 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMCreateInterpolation()
968 
969 @*/
970 PetscErrorCode  DMCreateInjection(DM dm1,DM dm2,Mat *mat)
971 {
972   PetscErrorCode ierr;
973 
974   PetscFunctionBegin;
975   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
976   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
977   ierr = (*dm1->ops->getinjection)(dm1,dm2,mat);CHKERRQ(ierr);
978   PetscFunctionReturn(0);
979 }
980 
981 #undef __FUNCT__
982 #define __FUNCT__ "DMCreateColoring"
983 /*@
984     DMCreateColoring - Gets coloring for a DM
985 
986     Collective on DM
987 
988     Input Parameter:
989 +   dm - the DM object
990 -   ctype - IS_COLORING_GHOSTED or IS_COLORING_GLOBAL
991 
992     Output Parameter:
993 .   coloring - the coloring
994 
995     Level: developer
996 
997 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateMatrix(), DMSetMatType()
998 
999 @*/
1000 PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1001 {
1002   PetscErrorCode ierr;
1003 
1004   PetscFunctionBegin;
1005   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1006   if (!dm->ops->getcoloring) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No coloring for this type of DM yet");
1007   ierr = (*dm->ops->getcoloring)(dm,ctype,coloring);CHKERRQ(ierr);
1008   PetscFunctionReturn(0);
1009 }
1010 
1011 #undef __FUNCT__
1012 #define __FUNCT__ "DMCreateMatrix"
1013 /*@
1014     DMCreateMatrix - Gets empty Jacobian for a DM
1015 
1016     Collective on DM
1017 
1018     Input Parameter:
1019 .   dm - the DM object
1020 
1021     Output Parameter:
1022 .   mat - the empty Jacobian
1023 
1024     Level: beginner
1025 
1026     Notes: This properly preallocates the number of nonzeros in the sparse matrix so you
1027        do not need to do it yourself.
1028 
1029        By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1030        the nonzero pattern call DMDASetMatPreallocateOnly()
1031 
1032        For structured grid problems, when you call MatView() on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1033        internally by PETSc.
1034 
1035        For structured grid problems, in general it is easiest to use MatSetValuesStencil() or MatSetValuesLocal() to put values into the matrix because MatSetValues() requires
1036        the indices for the global numbering for DMDAs which is complicated.
1037 
1038 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMSetMatType()
1039 
1040 @*/
1041 PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1042 {
1043   PetscErrorCode ierr;
1044 
1045   PetscFunctionBegin;
1046   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1047   ierr = MatInitializePackage();CHKERRQ(ierr);
1048   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1049   PetscValidPointer(mat,3);
1050   ierr = (*dm->ops->creatematrix)(dm,mat);CHKERRQ(ierr);
1051   PetscFunctionReturn(0);
1052 }
1053 
1054 #undef __FUNCT__
1055 #define __FUNCT__ "DMSetMatrixPreallocateOnly"
1056 /*@
1057   DMSetMatrixPreallocateOnly - When DMCreateMatrix() is called the matrix will be properly
1058     preallocated but the nonzero structure and zero values will not be set.
1059 
1060   Logically Collective on DM
1061 
1062   Input Parameter:
1063 + dm - the DM
1064 - only - PETSC_TRUE if only want preallocation
1065 
1066   Level: developer
1067 .seealso DMCreateMatrix()
1068 @*/
1069 PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1070 {
1071   PetscFunctionBegin;
1072   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1073   dm->prealloc_only = only;
1074   PetscFunctionReturn(0);
1075 }
1076 
1077 #undef __FUNCT__
1078 #define __FUNCT__ "DMGetWorkArray"
1079 /*@C
1080   DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1081 
1082   Not Collective
1083 
1084   Input Parameters:
1085 + dm - the DM object
1086 . count - The minium size
1087 - dtype - data type (PETSC_REAL, PETSC_SCALAR, PETSC_INT)
1088 
1089   Output Parameter:
1090 . array - the work array
1091 
1092   Level: developer
1093 
1094 .seealso DMDestroy(), DMCreate()
1095 @*/
1096 PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,PetscDataType dtype,void *mem)
1097 {
1098   PetscErrorCode ierr;
1099   DMWorkLink     link;
1100   size_t         dsize;
1101 
1102   PetscFunctionBegin;
1103   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1104   PetscValidPointer(mem,4);
1105   if (dm->workin) {
1106     link       = dm->workin;
1107     dm->workin = dm->workin->next;
1108   } else {
1109     ierr = PetscNewLog(dm,&link);CHKERRQ(ierr);
1110   }
1111   ierr = PetscDataTypeGetSize(dtype,&dsize);CHKERRQ(ierr);
1112   if (dsize*count > link->bytes) {
1113     ierr        = PetscFree(link->mem);CHKERRQ(ierr);
1114     ierr        = PetscMalloc(dsize*count,&link->mem);CHKERRQ(ierr);
1115     link->bytes = dsize*count;
1116   }
1117   link->next   = dm->workout;
1118   dm->workout  = link;
1119   *(void**)mem = link->mem;
1120   PetscFunctionReturn(0);
1121 }
1122 
1123 #undef __FUNCT__
1124 #define __FUNCT__ "DMRestoreWorkArray"
1125 /*@C
1126   DMRestoreWorkArray - Restores a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1127 
1128   Not Collective
1129 
1130   Input Parameters:
1131 + dm - the DM object
1132 . count - The minium size
1133 - dtype - data type (PETSC_REAL, PETSC_SCALAR, PETSC_INT)
1134 
1135   Output Parameter:
1136 . array - the work array
1137 
1138   Level: developer
1139 
1140 .seealso DMDestroy(), DMCreate()
1141 @*/
1142 PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,PetscDataType dtype,void *mem)
1143 {
1144   DMWorkLink *p,link;
1145 
1146   PetscFunctionBegin;
1147   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1148   PetscValidPointer(mem,4);
1149   for (p=&dm->workout; (link=*p); p=&link->next) {
1150     if (link->mem == *(void**)mem) {
1151       *p           = link->next;
1152       link->next   = dm->workin;
1153       dm->workin   = link;
1154       *(void**)mem = NULL;
1155       PetscFunctionReturn(0);
1156     }
1157   }
1158   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1159 }
1160 
1161 #undef __FUNCT__
1162 #define __FUNCT__ "DMSetNullSpaceConstructor"
1163 PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1164 {
1165   PetscFunctionBegin;
1166   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1167   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1168   dm->nullspaceConstructors[field] = nullsp;
1169   PetscFunctionReturn(0);
1170 }
1171 
1172 #undef __FUNCT__
1173 #define __FUNCT__ "DMCreateFieldIS"
1174 /*@C
1175   DMCreateFieldIS - Creates a set of IS objects with the global indices of dofs for each field
1176 
1177   Not collective
1178 
1179   Input Parameter:
1180 . dm - the DM object
1181 
1182   Output Parameters:
1183 + numFields  - The number of fields (or NULL if not requested)
1184 . fieldNames - The name for each field (or NULL if not requested)
1185 - fields     - The global indices for each field (or NULL if not requested)
1186 
1187   Level: intermediate
1188 
1189   Notes:
1190   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1191   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1192   PetscFree().
1193 
1194 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1195 @*/
1196 PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1197 {
1198   PetscSection   section, sectionGlobal;
1199   PetscErrorCode ierr;
1200 
1201   PetscFunctionBegin;
1202   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1203   if (numFields) {
1204     PetscValidPointer(numFields,2);
1205     *numFields = 0;
1206   }
1207   if (fieldNames) {
1208     PetscValidPointer(fieldNames,3);
1209     *fieldNames = NULL;
1210   }
1211   if (fields) {
1212     PetscValidPointer(fields,4);
1213     *fields = NULL;
1214   }
1215   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1216   if (section) {
1217     PetscInt *fieldSizes, **fieldIndices;
1218     PetscInt nF, f, pStart, pEnd, p;
1219 
1220     ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1221     ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1222     ierr = PetscMalloc2(nF,&fieldSizes,nF,&fieldIndices);CHKERRQ(ierr);
1223     ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1224     for (f = 0; f < nF; ++f) {
1225       fieldSizes[f] = 0;
1226     }
1227     for (p = pStart; p < pEnd; ++p) {
1228       PetscInt gdof;
1229 
1230       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1231       if (gdof > 0) {
1232         for (f = 0; f < nF; ++f) {
1233           PetscInt fdof, fcdof;
1234 
1235           ierr           = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
1236           ierr           = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
1237           fieldSizes[f] += fdof-fcdof;
1238         }
1239       }
1240     }
1241     for (f = 0; f < nF; ++f) {
1242       ierr          = PetscMalloc1(fieldSizes[f], &fieldIndices[f]);CHKERRQ(ierr);
1243       fieldSizes[f] = 0;
1244     }
1245     for (p = pStart; p < pEnd; ++p) {
1246       PetscInt gdof, goff;
1247 
1248       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1249       if (gdof > 0) {
1250         ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1251         for (f = 0; f < nF; ++f) {
1252           PetscInt fdof, fcdof, fc;
1253 
1254           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
1255           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
1256           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1257             fieldIndices[f][fieldSizes[f]] = goff++;
1258           }
1259         }
1260       }
1261     }
1262     if (numFields) *numFields = nF;
1263     if (fieldNames) {
1264       ierr = PetscMalloc1(nF, fieldNames);CHKERRQ(ierr);
1265       for (f = 0; f < nF; ++f) {
1266         const char *fieldName;
1267 
1268         ierr = PetscSectionGetFieldName(section, f, &fieldName);CHKERRQ(ierr);
1269         ierr = PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);CHKERRQ(ierr);
1270       }
1271     }
1272     if (fields) {
1273       ierr = PetscMalloc1(nF, fields);CHKERRQ(ierr);
1274       for (f = 0; f < nF; ++f) {
1275         ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);CHKERRQ(ierr);
1276       }
1277     }
1278     ierr = PetscFree2(fieldSizes,fieldIndices);CHKERRQ(ierr);
1279   } else if (dm->ops->createfieldis) {
1280     ierr = (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);CHKERRQ(ierr);
1281   }
1282   PetscFunctionReturn(0);
1283 }
1284 
1285 
1286 #undef __FUNCT__
1287 #define __FUNCT__ "DMCreateFieldDecomposition"
1288 /*@C
1289   DMCreateFieldDecomposition - Returns a list of IS objects defining a decomposition of a problem into subproblems
1290                           corresponding to different fields: each IS contains the global indices of the dofs of the
1291                           corresponding field. The optional list of DMs define the DM for each subproblem.
1292                           Generalizes DMCreateFieldIS().
1293 
1294   Not collective
1295 
1296   Input Parameter:
1297 . dm - the DM object
1298 
1299   Output Parameters:
1300 + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1301 . namelist  - The name for each field (or NULL if not requested)
1302 . islist    - The global indices for each field (or NULL if not requested)
1303 - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1304 
1305   Level: intermediate
1306 
1307   Notes:
1308   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1309   PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1310   and all of the arrays should be freed with PetscFree().
1311 
1312 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1313 @*/
1314 PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1315 {
1316   PetscErrorCode ierr;
1317 
1318   PetscFunctionBegin;
1319   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1320   if (len) {
1321     PetscValidPointer(len,2);
1322     *len = 0;
1323   }
1324   if (namelist) {
1325     PetscValidPointer(namelist,3);
1326     *namelist = 0;
1327   }
1328   if (islist) {
1329     PetscValidPointer(islist,4);
1330     *islist = 0;
1331   }
1332   if (dmlist) {
1333     PetscValidPointer(dmlist,5);
1334     *dmlist = 0;
1335   }
1336   /*
1337    Is it a good idea to apply the following check across all impls?
1338    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1339    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1340    */
1341   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1342   if (!dm->ops->createfielddecomposition) {
1343     PetscSection section;
1344     PetscInt     numFields, f;
1345 
1346     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1347     if (section) {ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);}
1348     if (section && numFields && dm->ops->createsubdm) {
1349       *len = numFields;
1350       if (namelist) {ierr = PetscMalloc1(numFields,namelist);CHKERRQ(ierr);}
1351       if (islist)   {ierr = PetscMalloc1(numFields,islist);CHKERRQ(ierr);}
1352       if (dmlist)   {ierr = PetscMalloc1(numFields,dmlist);CHKERRQ(ierr);}
1353       for (f = 0; f < numFields; ++f) {
1354         const char *fieldName;
1355 
1356         ierr = DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);CHKERRQ(ierr);
1357         if (namelist) {
1358           ierr = PetscSectionGetFieldName(section, f, &fieldName);CHKERRQ(ierr);
1359           ierr = PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);CHKERRQ(ierr);
1360         }
1361       }
1362     } else {
1363       ierr = DMCreateFieldIS(dm, len, namelist, islist);CHKERRQ(ierr);
1364       /* By default there are no DMs associated with subproblems. */
1365       if (dmlist) *dmlist = NULL;
1366     }
1367   } else {
1368     ierr = (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);CHKERRQ(ierr);
1369   }
1370   PetscFunctionReturn(0);
1371 }
1372 
1373 #undef __FUNCT__
1374 #define __FUNCT__ "DMCreateSubDM"
1375 /*@
1376   DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1377                   The fields are defined by DMCreateFieldIS().
1378 
1379   Not collective
1380 
1381   Input Parameters:
1382 + dm - the DM object
1383 . numFields - number of fields in this subproblem
1384 - len       - The number of subproblems in the decomposition (or NULL if not requested)
1385 
1386   Output Parameters:
1387 . is - The global indices for the subproblem
1388 - dm - The DM for the subproblem
1389 
1390   Level: intermediate
1391 
1392 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1393 @*/
1394 PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1395 {
1396   PetscErrorCode ierr;
1397 
1398   PetscFunctionBegin;
1399   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1400   PetscValidPointer(fields,3);
1401   if (is) PetscValidPointer(is,4);
1402   if (subdm) PetscValidPointer(subdm,5);
1403   if (dm->ops->createsubdm) {
1404     ierr = (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
1405   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateSubDM implementation defined");
1406   PetscFunctionReturn(0);
1407 }
1408 
1409 
1410 #undef __FUNCT__
1411 #define __FUNCT__ "DMCreateDomainDecomposition"
1412 /*@C
1413   DMCreateDomainDecomposition - Returns lists of IS objects defining a decomposition of a problem into subproblems
1414                           corresponding to restrictions to pairs nested subdomains: each IS contains the global
1415                           indices of the dofs of the corresponding subdomains.  The inner subdomains conceptually
1416                           define a nonoverlapping covering, while outer subdomains can overlap.
1417                           The optional list of DMs define the DM for each subproblem.
1418 
1419   Not collective
1420 
1421   Input Parameter:
1422 . dm - the DM object
1423 
1424   Output Parameters:
1425 + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
1426 . namelist    - The name for each subdomain (or NULL if not requested)
1427 . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1428 . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1429 - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1430 
1431   Level: intermediate
1432 
1433   Notes:
1434   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1435   PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1436   and all of the arrays should be freed with PetscFree().
1437 
1438 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateDomainDecompositionDM(), DMCreateFieldDecomposition()
1439 @*/
1440 PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1441 {
1442   PetscErrorCode      ierr;
1443   DMSubDomainHookLink link;
1444   PetscInt            i,l;
1445 
1446   PetscFunctionBegin;
1447   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1448   if (len)           {PetscValidPointer(len,2);            *len         = 0;}
1449   if (namelist)      {PetscValidPointer(namelist,3);       *namelist    = NULL;}
1450   if (innerislist)   {PetscValidPointer(innerislist,4);    *innerislist = NULL;}
1451   if (outerislist)   {PetscValidPointer(outerislist,5);    *outerislist = NULL;}
1452   if (dmlist)        {PetscValidPointer(dmlist,6);         *dmlist      = NULL;}
1453   /*
1454    Is it a good idea to apply the following check across all impls?
1455    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1456    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1457    */
1458   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1459   if (dm->ops->createdomaindecomposition) {
1460     ierr = (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);CHKERRQ(ierr);
1461     /* copy subdomain hooks and context over to the subdomain DMs */
1462     if (dmlist) {
1463       for (i = 0; i < l; i++) {
1464         for (link=dm->subdomainhook; link; link=link->next) {
1465           if (link->ddhook) {ierr = (*link->ddhook)(dm,(*dmlist)[i],link->ctx);CHKERRQ(ierr);}
1466         }
1467         (*dmlist)[i]->ctx = dm->ctx;
1468       }
1469     }
1470     if (len) *len = l;
1471   }
1472   PetscFunctionReturn(0);
1473 }
1474 
1475 
1476 #undef __FUNCT__
1477 #define __FUNCT__ "DMCreateDomainDecompositionScatters"
1478 /*@C
1479   DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector
1480 
1481   Not collective
1482 
1483   Input Parameters:
1484 + dm - the DM object
1485 . n  - the number of subdomain scatters
1486 - subdms - the local subdomains
1487 
1488   Output Parameters:
1489 + n     - the number of scatters returned
1490 . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
1491 . oscat - scatter from global vector to overlapping global vector entries on subdomain
1492 - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
1493 
1494   Notes: This is an alternative to the iis and ois arguments in DMCreateDomainDecomposition that allow for the solution
1495   of general nonlinear problems with overlapping subdomain methods.  While merely having index sets that enable subsets
1496   of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
1497   solution and residual data.
1498 
1499   Level: developer
1500 
1501 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1502 @*/
1503 PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
1504 {
1505   PetscErrorCode ierr;
1506 
1507   PetscFunctionBegin;
1508   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1509   PetscValidPointer(subdms,3);
1510   if (dm->ops->createddscatters) {
1511     ierr = (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);CHKERRQ(ierr);
1512   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateDomainDecompositionLocalScatter implementation defined");
1513   PetscFunctionReturn(0);
1514 }
1515 
1516 #undef __FUNCT__
1517 #define __FUNCT__ "DMRefine"
1518 /*@
1519   DMRefine - Refines a DM object
1520 
1521   Collective on DM
1522 
1523   Input Parameter:
1524 + dm   - the DM object
1525 - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
1526 
1527   Output Parameter:
1528 . dmf - the refined DM, or NULL
1529 
1530   Note: If no refinement was done, the return value is NULL
1531 
1532   Level: developer
1533 
1534 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1535 @*/
1536 PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
1537 {
1538   PetscErrorCode   ierr;
1539   DMRefineHookLink link;
1540 
1541   PetscFunctionBegin;
1542   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1543   ierr = (*dm->ops->refine)(dm,comm,dmf);CHKERRQ(ierr);
1544   if (*dmf) {
1545     (*dmf)->ops->creatematrix = dm->ops->creatematrix;
1546 
1547     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmf);CHKERRQ(ierr);
1548 
1549     (*dmf)->ctx       = dm->ctx;
1550     (*dmf)->leveldown = dm->leveldown;
1551     (*dmf)->levelup   = dm->levelup + 1;
1552 
1553     ierr = DMSetMatType(*dmf,dm->mattype);CHKERRQ(ierr);
1554     for (link=dm->refinehook; link; link=link->next) {
1555       if (link->refinehook) {
1556         ierr = (*link->refinehook)(dm,*dmf,link->ctx);CHKERRQ(ierr);
1557       }
1558     }
1559   }
1560   PetscFunctionReturn(0);
1561 }
1562 
1563 #undef __FUNCT__
1564 #define __FUNCT__ "DMRefineHookAdd"
1565 /*@C
1566    DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
1567 
1568    Logically Collective
1569 
1570    Input Arguments:
1571 +  coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
1572 .  refinehook - function to run when setting up a coarser level
1573 .  interphook - function to run to update data on finer levels (once per SNESSolve())
1574 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1575 
1576    Calling sequence of refinehook:
1577 $    refinehook(DM coarse,DM fine,void *ctx);
1578 
1579 +  coarse - coarse level DM
1580 .  fine - fine level DM to interpolate problem to
1581 -  ctx - optional user-defined function context
1582 
1583    Calling sequence for interphook:
1584 $    interphook(DM coarse,Mat interp,DM fine,void *ctx)
1585 
1586 +  coarse - coarse level DM
1587 .  interp - matrix interpolating a coarse-level solution to the finer grid
1588 .  fine - fine level DM to update
1589 -  ctx - optional user-defined function context
1590 
1591    Level: advanced
1592 
1593    Notes:
1594    This function is only needed if auxiliary data needs to be passed to fine grids while grid sequencing
1595 
1596    If this function is called multiple times, the hooks will be run in the order they are added.
1597 
1598    This function is currently not available from Fortran.
1599 
1600 .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1601 @*/
1602 PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
1603 {
1604   PetscErrorCode   ierr;
1605   DMRefineHookLink link,*p;
1606 
1607   PetscFunctionBegin;
1608   PetscValidHeaderSpecific(coarse,DM_CLASSID,1);
1609   for (p=&coarse->refinehook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
1610   ierr             = PetscMalloc(sizeof(struct _DMRefineHookLink),&link);CHKERRQ(ierr);
1611   link->refinehook = refinehook;
1612   link->interphook = interphook;
1613   link->ctx        = ctx;
1614   link->next       = NULL;
1615   *p               = link;
1616   PetscFunctionReturn(0);
1617 }
1618 
1619 #undef __FUNCT__
1620 #define __FUNCT__ "DMInterpolate"
1621 /*@
1622    DMInterpolate - interpolates user-defined problem data to a finer DM by running hooks registered by DMRefineHookAdd()
1623 
1624    Collective if any hooks are
1625 
1626    Input Arguments:
1627 +  coarse - coarser DM to use as a base
1628 .  restrct - interpolation matrix, apply using MatInterpolate()
1629 -  fine - finer DM to update
1630 
1631    Level: developer
1632 
1633 .seealso: DMRefineHookAdd(), MatInterpolate()
1634 @*/
1635 PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
1636 {
1637   PetscErrorCode   ierr;
1638   DMRefineHookLink link;
1639 
1640   PetscFunctionBegin;
1641   for (link=fine->refinehook; link; link=link->next) {
1642     if (link->interphook) {
1643       ierr = (*link->interphook)(coarse,interp,fine,link->ctx);CHKERRQ(ierr);
1644     }
1645   }
1646   PetscFunctionReturn(0);
1647 }
1648 
1649 #undef __FUNCT__
1650 #define __FUNCT__ "DMGetRefineLevel"
1651 /*@
1652     DMGetRefineLevel - Get's the number of refinements that have generated this DM.
1653 
1654     Not Collective
1655 
1656     Input Parameter:
1657 .   dm - the DM object
1658 
1659     Output Parameter:
1660 .   level - number of refinements
1661 
1662     Level: developer
1663 
1664 .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1665 
1666 @*/
1667 PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
1668 {
1669   PetscFunctionBegin;
1670   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1671   *level = dm->levelup;
1672   PetscFunctionReturn(0);
1673 }
1674 
1675 #undef __FUNCT__
1676 #define __FUNCT__ "DMGlobalToLocalHookAdd"
1677 /*@C
1678    DMGlobalToLocalHookAdd - adds a callback to be run when global to local is called
1679 
1680    Logically Collective
1681 
1682    Input Arguments:
1683 +  dm - the DM
1684 .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
1685 .  endhook - function to run after DMGlobalToLocalEnd() has completed
1686 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1687 
1688    Calling sequence for beginhook:
1689 $    beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
1690 
1691 +  dm - global DM
1692 .  g - global vector
1693 .  mode - mode
1694 .  l - local vector
1695 -  ctx - optional user-defined function context
1696 
1697 
1698    Calling sequence for endhook:
1699 $    endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
1700 
1701 +  global - global DM
1702 -  ctx - optional user-defined function context
1703 
1704    Level: advanced
1705 
1706 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1707 @*/
1708 PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
1709 {
1710   PetscErrorCode          ierr;
1711   DMGlobalToLocalHookLink link,*p;
1712 
1713   PetscFunctionBegin;
1714   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1715   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
1716   ierr            = PetscMalloc(sizeof(struct _DMGlobalToLocalHookLink),&link);CHKERRQ(ierr);
1717   link->beginhook = beginhook;
1718   link->endhook   = endhook;
1719   link->ctx       = ctx;
1720   link->next      = NULL;
1721   *p              = link;
1722   PetscFunctionReturn(0);
1723 }
1724 
1725 #undef __FUNCT__
1726 #define __FUNCT__ "DMGlobalToLocalHook_Constraints"
1727 static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
1728 {
1729   Mat cMat;
1730   Vec cVec;
1731   PetscSection section, cSec;
1732   PetscInt pStart, pEnd, p, dof;
1733   PetscErrorCode ierr;
1734 
1735   PetscFunctionBegin;
1736   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1737   ierr = DMGetDefaultConstraints(dm,&cSec,&cMat);CHKERRQ(ierr);
1738   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
1739     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
1740     ierr = MatCreateVecs(cMat,NULL,&cVec);CHKERRQ(ierr);
1741     ierr = MatMult(cMat,l,cVec);CHKERRQ(ierr);
1742     ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
1743     for (p = pStart; p < pEnd; p++) {
1744       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
1745       if (dof) {
1746         PetscScalar *vals;
1747         ierr = VecGetValuesSection(cVec,cSec,p,&vals);CHKERRQ(ierr);
1748         ierr = VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);CHKERRQ(ierr);
1749       }
1750     }
1751     ierr = VecDestroy(&cVec);CHKERRQ(ierr);
1752   }
1753   PetscFunctionReturn(0);
1754 }
1755 
1756 #undef __FUNCT__
1757 #define __FUNCT__ "DMGlobalToLocalBegin"
1758 /*@
1759     DMGlobalToLocalBegin - Begins updating local vectors from global vector
1760 
1761     Neighbor-wise Collective on DM
1762 
1763     Input Parameters:
1764 +   dm - the DM object
1765 .   g - the global vector
1766 .   mode - INSERT_VALUES or ADD_VALUES
1767 -   l - the local vector
1768 
1769 
1770     Level: beginner
1771 
1772 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1773 
1774 @*/
1775 PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
1776 {
1777   PetscSF                 sf;
1778   PetscErrorCode          ierr;
1779   DMGlobalToLocalHookLink link;
1780 
1781   PetscFunctionBegin;
1782   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1783   for (link=dm->gtolhook; link; link=link->next) {
1784     if (link->beginhook) {
1785       ierr = (*link->beginhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);
1786     }
1787   }
1788   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1789   if (sf) {
1790     const PetscScalar *gArray;
1791     PetscScalar       *lArray;
1792 
1793     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1794     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1795     ierr = VecGetArrayRead(g, &gArray);CHKERRQ(ierr);
1796     ierr = PetscSFBcastBegin(sf, MPIU_SCALAR, gArray, lArray);CHKERRQ(ierr);
1797     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1798     ierr = VecRestoreArrayRead(g, &gArray);CHKERRQ(ierr);
1799   } else {
1800     ierr = (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1801   }
1802   PetscFunctionReturn(0);
1803 }
1804 
1805 #undef __FUNCT__
1806 #define __FUNCT__ "DMGlobalToLocalEnd"
1807 /*@
1808     DMGlobalToLocalEnd - Ends updating local vectors from global vector
1809 
1810     Neighbor-wise Collective on DM
1811 
1812     Input Parameters:
1813 +   dm - the DM object
1814 .   g - the global vector
1815 .   mode - INSERT_VALUES or ADD_VALUES
1816 -   l - the local vector
1817 
1818 
1819     Level: beginner
1820 
1821 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1822 
1823 @*/
1824 PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
1825 {
1826   PetscSF                 sf;
1827   PetscErrorCode          ierr;
1828   const PetscScalar      *gArray;
1829   PetscScalar            *lArray;
1830   DMGlobalToLocalHookLink link;
1831 
1832   PetscFunctionBegin;
1833   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1834   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1835   if (sf) {
1836     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1837 
1838     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1839     ierr = VecGetArrayRead(g, &gArray);CHKERRQ(ierr);
1840     ierr = PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);CHKERRQ(ierr);
1841     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1842     ierr = VecRestoreArrayRead(g, &gArray);CHKERRQ(ierr);
1843   } else {
1844     ierr = (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1845   }
1846   ierr = DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);CHKERRQ(ierr);
1847   for (link=dm->gtolhook; link; link=link->next) {
1848     if (link->endhook) {ierr = (*link->endhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);}
1849   }
1850   PetscFunctionReturn(0);
1851 }
1852 
1853 #undef __FUNCT__
1854 #define __FUNCT__ "DMLocalToGlobalHookAdd"
1855 /*@C
1856    DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
1857 
1858    Logically Collective
1859 
1860    Input Arguments:
1861 +  dm - the DM
1862 .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
1863 .  endhook - function to run after DMLocalToGlobalEnd() has completed
1864 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1865 
1866    Calling sequence for beginhook:
1867 $    beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
1868 
1869 +  dm - global DM
1870 .  l - local vector
1871 .  mode - mode
1872 .  g - global vector
1873 -  ctx - optional user-defined function context
1874 
1875 
1876    Calling sequence for endhook:
1877 $    endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
1878 
1879 +  global - global DM
1880 .  l - local vector
1881 .  mode - mode
1882 .  g - global vector
1883 -  ctx - optional user-defined function context
1884 
1885    Level: advanced
1886 
1887 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1888 @*/
1889 PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
1890 {
1891   PetscErrorCode          ierr;
1892   DMLocalToGlobalHookLink link,*p;
1893 
1894   PetscFunctionBegin;
1895   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1896   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
1897   ierr            = PetscMalloc(sizeof(struct _DMLocalToGlobalHookLink),&link);CHKERRQ(ierr);
1898   link->beginhook = beginhook;
1899   link->endhook   = endhook;
1900   link->ctx       = ctx;
1901   link->next      = NULL;
1902   *p              = link;
1903   PetscFunctionReturn(0);
1904 }
1905 
1906 #undef __FUNCT__
1907 #define __FUNCT__ "DMLocalToGlobalHook_Constraints"
1908 static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
1909 {
1910   Mat cMat;
1911   Vec cVec;
1912   PetscSection section, cSec;
1913   PetscInt pStart, pEnd, p, dof;
1914   PetscErrorCode ierr;
1915 
1916   PetscFunctionBegin;
1917   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1918   ierr = DMGetDefaultConstraints(dm,&cSec,&cMat);CHKERRQ(ierr);
1919   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
1920     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
1921     ierr = MatCreateVecs(cMat,NULL,&cVec);CHKERRQ(ierr);
1922     ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
1923     for (p = pStart; p < pEnd; p++) {
1924       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
1925       if (dof) {
1926         PetscInt d;
1927         PetscScalar *vals;
1928         ierr = VecGetValuesSection(l,section,p,&vals);CHKERRQ(ierr);
1929         ierr = VecSetValuesSection(cVec,cSec,p,vals,mode);CHKERRQ(ierr);
1930         /* for this to be the true transpose, we have to zero the values that
1931          * we just extracted */
1932         for (d = 0; d < dof; d++) {
1933           vals[d] = 0.;
1934         }
1935       }
1936     }
1937     ierr = MatMultTransposeAdd(cMat,cVec,l,l);CHKERRQ(ierr);
1938     ierr = VecDestroy(&cVec);CHKERRQ(ierr);
1939   }
1940   PetscFunctionReturn(0);
1941 }
1942 
1943 #undef __FUNCT__
1944 #define __FUNCT__ "DMLocalToGlobalBegin"
1945 /*@
1946     DMLocalToGlobalBegin - updates global vectors from local vectors
1947 
1948     Neighbor-wise Collective on DM
1949 
1950     Input Parameters:
1951 +   dm - the DM object
1952 .   l - the local vector
1953 .   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.
1954 -   g - the global vector
1955 
1956     Notes: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
1957            INSERT_VALUES is not supported for DMDA, in that case simply compute the values directly into a global vector instead of a local one.
1958 
1959     Level: beginner
1960 
1961 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
1962 
1963 @*/
1964 PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
1965 {
1966   PetscSF                 sf;
1967   PetscSection            s, gs;
1968   DMLocalToGlobalHookLink link;
1969   const PetscScalar      *lArray;
1970   PetscScalar            *gArray;
1971   PetscBool               isInsert;
1972   PetscErrorCode          ierr;
1973 
1974   PetscFunctionBegin;
1975   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1976   for (link=dm->ltoghook; link; link=link->next) {
1977     if (link->beginhook) {
1978       ierr = (*link->beginhook)(dm,l,mode,g,link->ctx);CHKERRQ(ierr);
1979     }
1980   }
1981   ierr = DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);CHKERRQ(ierr);
1982   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1983   ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
1984   switch (mode) {
1985   case INSERT_VALUES:
1986   case INSERT_ALL_VALUES:
1987     isInsert = PETSC_TRUE; break;
1988   case ADD_VALUES:
1989   case ADD_ALL_VALUES:
1990     isInsert = PETSC_FALSE; break;
1991   default:
1992     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1993   }
1994   if (sf && !isInsert) {
1995     ierr = VecGetArrayRead(l, &lArray);CHKERRQ(ierr);
1996     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1997     ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);CHKERRQ(ierr);
1998     ierr = VecRestoreArrayRead(l, &lArray);CHKERRQ(ierr);
1999     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
2000   } else if (s && isInsert) {
2001     PetscInt gStart, pStart, pEnd, p;
2002 
2003     ierr = DMGetDefaultGlobalSection(dm, &gs);CHKERRQ(ierr);
2004     ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
2005     ierr = VecGetOwnershipRange(g, &gStart, NULL);CHKERRQ(ierr);
2006     ierr = VecGetArrayRead(l, &lArray);CHKERRQ(ierr);
2007     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
2008     for (p = pStart; p < pEnd; ++p) {
2009       PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
2010 
2011       ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
2012       ierr = PetscSectionGetDof(gs, p, &gdof);CHKERRQ(ierr);
2013       ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
2014       ierr = PetscSectionGetConstraintDof(gs, p, &gcdof);CHKERRQ(ierr);
2015       ierr = PetscSectionGetOffset(s, p, &off);CHKERRQ(ierr);
2016       ierr = PetscSectionGetOffset(gs, p, &goff);CHKERRQ(ierr);
2017       /* Ignore off-process data and points with no global data */
2018       if (!gdof || goff < 0) continue;
2019       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);
2020       /* If no constraints are enforced in the global vector */
2021       if (!gcdof) {
2022         for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2023       /* If constraints are enforced in the global vector */
2024       } else if (cdof == gcdof) {
2025         const PetscInt *cdofs;
2026         PetscInt        cind = 0;
2027 
2028         ierr = PetscSectionGetConstraintIndices(s, p, &cdofs);CHKERRQ(ierr);
2029         for (d = 0, e = 0; d < dof; ++d) {
2030           if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2031           gArray[goff-gStart+e++] = lArray[off+d];
2032         }
2033       } 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);
2034     }
2035     ierr = VecRestoreArrayRead(l, &lArray);CHKERRQ(ierr);
2036     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
2037   } else {
2038     ierr = (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);CHKERRQ(ierr);
2039   }
2040   PetscFunctionReturn(0);
2041 }
2042 
2043 #undef __FUNCT__
2044 #define __FUNCT__ "DMLocalToGlobalEnd"
2045 /*@
2046     DMLocalToGlobalEnd - updates global vectors from local vectors
2047 
2048     Neighbor-wise Collective on DM
2049 
2050     Input Parameters:
2051 +   dm - the DM object
2052 .   l - the local vector
2053 .   mode - INSERT_VALUES or ADD_VALUES
2054 -   g - the global vector
2055 
2056 
2057     Level: beginner
2058 
2059 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalEnd()
2060 
2061 @*/
2062 PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2063 {
2064   PetscSF                 sf;
2065   PetscSection            s;
2066   DMLocalToGlobalHookLink link;
2067   PetscBool               isInsert;
2068   PetscErrorCode          ierr;
2069 
2070   PetscFunctionBegin;
2071   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2072   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
2073   ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
2074   switch (mode) {
2075   case INSERT_VALUES:
2076   case INSERT_ALL_VALUES:
2077     isInsert = PETSC_TRUE; break;
2078   case ADD_VALUES:
2079   case ADD_ALL_VALUES:
2080     isInsert = PETSC_FALSE; break;
2081   default:
2082     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2083   }
2084   if (sf && !isInsert) {
2085     const PetscScalar *lArray;
2086     PetscScalar       *gArray;
2087 
2088     ierr = VecGetArrayRead(l, &lArray);CHKERRQ(ierr);
2089     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
2090     ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);CHKERRQ(ierr);
2091     ierr = VecRestoreArrayRead(l, &lArray);CHKERRQ(ierr);
2092     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
2093   } else if (s && isInsert) {
2094   } else {
2095     ierr = (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);CHKERRQ(ierr);
2096   }
2097   for (link=dm->ltoghook; link; link=link->next) {
2098     if (link->endhook) {ierr = (*link->endhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);}
2099   }
2100   PetscFunctionReturn(0);
2101 }
2102 
2103 #undef __FUNCT__
2104 #define __FUNCT__ "DMLocalToLocalBegin"
2105 /*@
2106    DMLocalToLocalBegin - Maps from a local vector (including ghost points
2107    that contain irrelevant values) to another local vector where the ghost
2108    points in the second are set correctly. Must be followed by DMLocalToLocalEnd().
2109 
2110    Neighbor-wise Collective on DM and Vec
2111 
2112    Input Parameters:
2113 +  dm - the DM object
2114 .  g - the original local vector
2115 -  mode - one of INSERT_VALUES or ADD_VALUES
2116 
2117    Output Parameter:
2118 .  l  - the local vector with correct ghost values
2119 
2120    Level: intermediate
2121 
2122    Notes:
2123    The local vectors used here need not be the same as those
2124    obtained from DMCreateLocalVector(), BUT they
2125    must have the same parallel data layout; they could, for example, be
2126    obtained with VecDuplicate() from the DM originating vectors.
2127 
2128 .keywords: DM, local-to-local, begin
2129 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2130 
2131 @*/
2132 PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2133 {
2134   PetscErrorCode          ierr;
2135 
2136   PetscFunctionBegin;
2137   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2138   ierr = (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
2139   PetscFunctionReturn(0);
2140 }
2141 
2142 #undef __FUNCT__
2143 #define __FUNCT__ "DMLocalToLocalEnd"
2144 /*@
2145    DMLocalToLocalEnd - Maps from a local vector (including ghost points
2146    that contain irrelevant values) to another local vector where the ghost
2147    points in the second are set correctly. Must be preceded by DMLocalToLocalBegin().
2148 
2149    Neighbor-wise Collective on DM and Vec
2150 
2151    Input Parameters:
2152 +  da - the DM object
2153 .  g - the original local vector
2154 -  mode - one of INSERT_VALUES or ADD_VALUES
2155 
2156    Output Parameter:
2157 .  l  - the local vector with correct ghost values
2158 
2159    Level: intermediate
2160 
2161    Notes:
2162    The local vectors used here need not be the same as those
2163    obtained from DMCreateLocalVector(), BUT they
2164    must have the same parallel data layout; they could, for example, be
2165    obtained with VecDuplicate() from the DM originating vectors.
2166 
2167 .keywords: DM, local-to-local, end
2168 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
2169 
2170 @*/
2171 PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2172 {
2173   PetscErrorCode          ierr;
2174 
2175   PetscFunctionBegin;
2176   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2177   ierr = (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
2178   PetscFunctionReturn(0);
2179 }
2180 
2181 
2182 #undef __FUNCT__
2183 #define __FUNCT__ "DMCoarsen"
2184 /*@
2185     DMCoarsen - Coarsens a DM object
2186 
2187     Collective on DM
2188 
2189     Input Parameter:
2190 +   dm - the DM object
2191 -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
2192 
2193     Output Parameter:
2194 .   dmc - the coarsened DM
2195 
2196     Level: developer
2197 
2198 .seealso DMRefine(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2199 
2200 @*/
2201 PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
2202 {
2203   PetscErrorCode    ierr;
2204   DMCoarsenHookLink link;
2205 
2206   PetscFunctionBegin;
2207   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2208   ierr = PetscLogEventBegin(DM_Coarsen,dm,0,0,0);CHKERRQ(ierr);
2209   ierr                      = (*dm->ops->coarsen)(dm, comm, dmc);CHKERRQ(ierr);
2210   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
2211   ierr = DMSetCoarseDM(dm,*dmc);CHKERRQ(ierr);
2212   (*dmc)->ops->creatematrix = dm->ops->creatematrix;
2213   ierr                      = PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);CHKERRQ(ierr);
2214   (*dmc)->ctx               = dm->ctx;
2215   (*dmc)->levelup           = dm->levelup;
2216   (*dmc)->leveldown         = dm->leveldown + 1;
2217   ierr                      = DMSetMatType(*dmc,dm->mattype);CHKERRQ(ierr);
2218   for (link=dm->coarsenhook; link; link=link->next) {
2219     if (link->coarsenhook) {ierr = (*link->coarsenhook)(dm,*dmc,link->ctx);CHKERRQ(ierr);}
2220   }
2221   ierr = PetscLogEventEnd(DM_Coarsen,dm,0,0,0);CHKERRQ(ierr);
2222   PetscFunctionReturn(0);
2223 }
2224 
2225 #undef __FUNCT__
2226 #define __FUNCT__ "DMCoarsenHookAdd"
2227 /*@C
2228    DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
2229 
2230    Logically Collective
2231 
2232    Input Arguments:
2233 +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
2234 .  coarsenhook - function to run when setting up a coarser level
2235 .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
2236 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2237 
2238    Calling sequence of coarsenhook:
2239 $    coarsenhook(DM fine,DM coarse,void *ctx);
2240 
2241 +  fine - fine level DM
2242 .  coarse - coarse level DM to restrict problem to
2243 -  ctx - optional user-defined function context
2244 
2245    Calling sequence for restricthook:
2246 $    restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
2247 
2248 +  fine - fine level DM
2249 .  mrestrict - matrix restricting a fine-level solution to the coarse grid
2250 .  rscale - scaling vector for restriction
2251 .  inject - matrix restricting by injection
2252 .  coarse - coarse level DM to update
2253 -  ctx - optional user-defined function context
2254 
2255    Level: advanced
2256 
2257    Notes:
2258    This function is only needed if auxiliary data needs to be set up on coarse grids.
2259 
2260    If this function is called multiple times, the hooks will be run in the order they are added.
2261 
2262    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2263    extract the finest level information from its context (instead of from the SNES).
2264 
2265    This function is currently not available from Fortran.
2266 
2267 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2268 @*/
2269 PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2270 {
2271   PetscErrorCode    ierr;
2272   DMCoarsenHookLink link,*p;
2273 
2274   PetscFunctionBegin;
2275   PetscValidHeaderSpecific(fine,DM_CLASSID,1);
2276   for (p=&fine->coarsenhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2277   ierr               = PetscMalloc(sizeof(struct _DMCoarsenHookLink),&link);CHKERRQ(ierr);
2278   link->coarsenhook  = coarsenhook;
2279   link->restricthook = restricthook;
2280   link->ctx          = ctx;
2281   link->next         = NULL;
2282   *p                 = link;
2283   PetscFunctionReturn(0);
2284 }
2285 
2286 #undef __FUNCT__
2287 #define __FUNCT__ "DMRestrict"
2288 /*@
2289    DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()
2290 
2291    Collective if any hooks are
2292 
2293    Input Arguments:
2294 +  fine - finer DM to use as a base
2295 .  restrct - restriction matrix, apply using MatRestrict()
2296 .  inject - injection matrix, also use MatRestrict()
2297 -  coarse - coarer DM to update
2298 
2299    Level: developer
2300 
2301 .seealso: DMCoarsenHookAdd(), MatRestrict()
2302 @*/
2303 PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
2304 {
2305   PetscErrorCode    ierr;
2306   DMCoarsenHookLink link;
2307 
2308   PetscFunctionBegin;
2309   for (link=fine->coarsenhook; link; link=link->next) {
2310     if (link->restricthook) {
2311       ierr = (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);CHKERRQ(ierr);
2312     }
2313   }
2314   PetscFunctionReturn(0);
2315 }
2316 
2317 #undef __FUNCT__
2318 #define __FUNCT__ "DMSubDomainHookAdd"
2319 /*@C
2320    DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
2321 
2322    Logically Collective
2323 
2324    Input Arguments:
2325 +  global - global DM
2326 .  ddhook - function to run to pass data to the decomposition DM upon its creation
2327 .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
2328 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2329 
2330 
2331    Calling sequence for ddhook:
2332 $    ddhook(DM global,DM block,void *ctx)
2333 
2334 +  global - global DM
2335 .  block  - block DM
2336 -  ctx - optional user-defined function context
2337 
2338    Calling sequence for restricthook:
2339 $    restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
2340 
2341 +  global - global DM
2342 .  out    - scatter to the outer (with ghost and overlap points) block vector
2343 .  in     - scatter to block vector values only owned locally
2344 .  block  - block DM
2345 -  ctx - optional user-defined function context
2346 
2347    Level: advanced
2348 
2349    Notes:
2350    This function is only needed if auxiliary data needs to be set up on subdomain DMs.
2351 
2352    If this function is called multiple times, the hooks will be run in the order they are added.
2353 
2354    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2355    extract the global information from its context (instead of from the SNES).
2356 
2357    This function is currently not available from Fortran.
2358 
2359 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2360 @*/
2361 PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
2362 {
2363   PetscErrorCode      ierr;
2364   DMSubDomainHookLink link,*p;
2365 
2366   PetscFunctionBegin;
2367   PetscValidHeaderSpecific(global,DM_CLASSID,1);
2368   for (p=&global->subdomainhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2369   ierr               = PetscMalloc(sizeof(struct _DMSubDomainHookLink),&link);CHKERRQ(ierr);
2370   link->restricthook = restricthook;
2371   link->ddhook       = ddhook;
2372   link->ctx          = ctx;
2373   link->next         = NULL;
2374   *p                 = link;
2375   PetscFunctionReturn(0);
2376 }
2377 
2378 #undef __FUNCT__
2379 #define __FUNCT__ "DMSubDomainRestrict"
2380 /*@
2381    DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()
2382 
2383    Collective if any hooks are
2384 
2385    Input Arguments:
2386 +  fine - finer DM to use as a base
2387 .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
2388 .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
2389 -  coarse - coarer DM to update
2390 
2391    Level: developer
2392 
2393 .seealso: DMCoarsenHookAdd(), MatRestrict()
2394 @*/
2395 PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
2396 {
2397   PetscErrorCode      ierr;
2398   DMSubDomainHookLink link;
2399 
2400   PetscFunctionBegin;
2401   for (link=global->subdomainhook; link; link=link->next) {
2402     if (link->restricthook) {
2403       ierr = (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);CHKERRQ(ierr);
2404     }
2405   }
2406   PetscFunctionReturn(0);
2407 }
2408 
2409 #undef __FUNCT__
2410 #define __FUNCT__ "DMGetCoarsenLevel"
2411 /*@
2412     DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.
2413 
2414     Not Collective
2415 
2416     Input Parameter:
2417 .   dm - the DM object
2418 
2419     Output Parameter:
2420 .   level - number of coarsenings
2421 
2422     Level: developer
2423 
2424 .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2425 
2426 @*/
2427 PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
2428 {
2429   PetscFunctionBegin;
2430   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2431   *level = dm->leveldown;
2432   PetscFunctionReturn(0);
2433 }
2434 
2435 
2436 
2437 #undef __FUNCT__
2438 #define __FUNCT__ "DMRefineHierarchy"
2439 /*@C
2440     DMRefineHierarchy - Refines a DM object, all levels at once
2441 
2442     Collective on DM
2443 
2444     Input Parameter:
2445 +   dm - the DM object
2446 -   nlevels - the number of levels of refinement
2447 
2448     Output Parameter:
2449 .   dmf - the refined DM hierarchy
2450 
2451     Level: developer
2452 
2453 .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2454 
2455 @*/
2456 PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
2457 {
2458   PetscErrorCode ierr;
2459 
2460   PetscFunctionBegin;
2461   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2462   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2463   if (nlevels == 0) PetscFunctionReturn(0);
2464   if (dm->ops->refinehierarchy) {
2465     ierr = (*dm->ops->refinehierarchy)(dm,nlevels,dmf);CHKERRQ(ierr);
2466   } else if (dm->ops->refine) {
2467     PetscInt i;
2468 
2469     ierr = DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);CHKERRQ(ierr);
2470     for (i=1; i<nlevels; i++) {
2471       ierr = DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);CHKERRQ(ierr);
2472     }
2473   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
2474   PetscFunctionReturn(0);
2475 }
2476 
2477 #undef __FUNCT__
2478 #define __FUNCT__ "DMCoarsenHierarchy"
2479 /*@C
2480     DMCoarsenHierarchy - Coarsens a DM object, all levels at once
2481 
2482     Collective on DM
2483 
2484     Input Parameter:
2485 +   dm - the DM object
2486 -   nlevels - the number of levels of coarsening
2487 
2488     Output Parameter:
2489 .   dmc - the coarsened DM hierarchy
2490 
2491     Level: developer
2492 
2493 .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2494 
2495 @*/
2496 PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
2497 {
2498   PetscErrorCode ierr;
2499 
2500   PetscFunctionBegin;
2501   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2502   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2503   if (nlevels == 0) PetscFunctionReturn(0);
2504   PetscValidPointer(dmc,3);
2505   if (dm->ops->coarsenhierarchy) {
2506     ierr = (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);CHKERRQ(ierr);
2507   } else if (dm->ops->coarsen) {
2508     PetscInt i;
2509 
2510     ierr = DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);CHKERRQ(ierr);
2511     for (i=1; i<nlevels; i++) {
2512       ierr = DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);CHKERRQ(ierr);
2513     }
2514   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
2515   PetscFunctionReturn(0);
2516 }
2517 
2518 #undef __FUNCT__
2519 #define __FUNCT__ "DMCreateAggregates"
2520 /*@
2521    DMCreateAggregates - Gets the aggregates that map between
2522    grids associated with two DMs.
2523 
2524    Collective on DM
2525 
2526    Input Parameters:
2527 +  dmc - the coarse grid DM
2528 -  dmf - the fine grid DM
2529 
2530    Output Parameters:
2531 .  rest - the restriction matrix (transpose of the projection matrix)
2532 
2533    Level: intermediate
2534 
2535 .keywords: interpolation, restriction, multigrid
2536 
2537 .seealso: DMRefine(), DMCreateInjection(), DMCreateInterpolation()
2538 @*/
2539 PetscErrorCode  DMCreateAggregates(DM dmc, DM dmf, Mat *rest)
2540 {
2541   PetscErrorCode ierr;
2542 
2543   PetscFunctionBegin;
2544   PetscValidHeaderSpecific(dmc,DM_CLASSID,1);
2545   PetscValidHeaderSpecific(dmf,DM_CLASSID,2);
2546   ierr = (*dmc->ops->getaggregates)(dmc, dmf, rest);CHKERRQ(ierr);
2547   PetscFunctionReturn(0);
2548 }
2549 
2550 #undef __FUNCT__
2551 #define __FUNCT__ "DMSetApplicationContextDestroy"
2552 /*@C
2553     DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
2554 
2555     Not Collective
2556 
2557     Input Parameters:
2558 +   dm - the DM object
2559 -   destroy - the destroy function
2560 
2561     Level: intermediate
2562 
2563 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2564 
2565 @*/
2566 PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
2567 {
2568   PetscFunctionBegin;
2569   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2570   dm->ctxdestroy = destroy;
2571   PetscFunctionReturn(0);
2572 }
2573 
2574 #undef __FUNCT__
2575 #define __FUNCT__ "DMSetApplicationContext"
2576 /*@
2577     DMSetApplicationContext - Set a user context into a DM object
2578 
2579     Not Collective
2580 
2581     Input Parameters:
2582 +   dm - the DM object
2583 -   ctx - the user context
2584 
2585     Level: intermediate
2586 
2587 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2588 
2589 @*/
2590 PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
2591 {
2592   PetscFunctionBegin;
2593   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2594   dm->ctx = ctx;
2595   PetscFunctionReturn(0);
2596 }
2597 
2598 #undef __FUNCT__
2599 #define __FUNCT__ "DMGetApplicationContext"
2600 /*@
2601     DMGetApplicationContext - Gets a user context from a DM object
2602 
2603     Not Collective
2604 
2605     Input Parameter:
2606 .   dm - the DM object
2607 
2608     Output Parameter:
2609 .   ctx - the user context
2610 
2611     Level: intermediate
2612 
2613 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2614 
2615 @*/
2616 PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
2617 {
2618   PetscFunctionBegin;
2619   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2620   *(void**)ctx = dm->ctx;
2621   PetscFunctionReturn(0);
2622 }
2623 
2624 #undef __FUNCT__
2625 #define __FUNCT__ "DMSetVariableBounds"
2626 /*@C
2627     DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
2628 
2629     Logically Collective on DM
2630 
2631     Input Parameter:
2632 +   dm - the DM object
2633 -   f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
2634 
2635     Level: intermediate
2636 
2637 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
2638          DMSetJacobian()
2639 
2640 @*/
2641 PetscErrorCode  DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
2642 {
2643   PetscFunctionBegin;
2644   dm->ops->computevariablebounds = f;
2645   PetscFunctionReturn(0);
2646 }
2647 
2648 #undef __FUNCT__
2649 #define __FUNCT__ "DMHasVariableBounds"
2650 /*@
2651     DMHasVariableBounds - does the DM object have a variable bounds function?
2652 
2653     Not Collective
2654 
2655     Input Parameter:
2656 .   dm - the DM object to destroy
2657 
2658     Output Parameter:
2659 .   flg - PETSC_TRUE if the variable bounds function exists
2660 
2661     Level: developer
2662 
2663 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2664 
2665 @*/
2666 PetscErrorCode  DMHasVariableBounds(DM dm,PetscBool  *flg)
2667 {
2668   PetscFunctionBegin;
2669   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
2670   PetscFunctionReturn(0);
2671 }
2672 
2673 #undef __FUNCT__
2674 #define __FUNCT__ "DMComputeVariableBounds"
2675 /*@C
2676     DMComputeVariableBounds - compute variable bounds used by SNESVI.
2677 
2678     Logically Collective on DM
2679 
2680     Input Parameters:
2681 .   dm - the DM object
2682 
2683     Output parameters:
2684 +   xl - lower bound
2685 -   xu - upper bound
2686 
2687     Level: advanced
2688 
2689     Notes: This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
2690 
2691 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2692 
2693 @*/
2694 PetscErrorCode  DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
2695 {
2696   PetscErrorCode ierr;
2697 
2698   PetscFunctionBegin;
2699   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
2700   PetscValidHeaderSpecific(xu,VEC_CLASSID,2);
2701   if (dm->ops->computevariablebounds) {
2702     ierr = (*dm->ops->computevariablebounds)(dm, xl,xu);CHKERRQ(ierr);
2703   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "This DM is incapable of computing variable bounds.");
2704   PetscFunctionReturn(0);
2705 }
2706 
2707 #undef __FUNCT__
2708 #define __FUNCT__ "DMHasColoring"
2709 /*@
2710     DMHasColoring - does the DM object have a method of providing a coloring?
2711 
2712     Not Collective
2713 
2714     Input Parameter:
2715 .   dm - the DM object
2716 
2717     Output Parameter:
2718 .   flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
2719 
2720     Level: developer
2721 
2722 .seealso DMHasFunction(), DMCreateColoring()
2723 
2724 @*/
2725 PetscErrorCode  DMHasColoring(DM dm,PetscBool  *flg)
2726 {
2727   PetscFunctionBegin;
2728   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
2729   PetscFunctionReturn(0);
2730 }
2731 
2732 #undef  __FUNCT__
2733 #define __FUNCT__ "DMSetVec"
2734 /*@C
2735     DMSetVec - set the vector at which to compute residual, Jacobian and VI bounds, if the problem is nonlinear.
2736 
2737     Collective on DM
2738 
2739     Input Parameter:
2740 +   dm - the DM object
2741 -   x - location to compute residual and Jacobian, if NULL is passed to those routines; will be NULL for linear problems.
2742 
2743     Level: developer
2744 
2745 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2746 
2747 @*/
2748 PetscErrorCode  DMSetVec(DM dm,Vec x)
2749 {
2750   PetscErrorCode ierr;
2751 
2752   PetscFunctionBegin;
2753   if (x) {
2754     if (!dm->x) {
2755       ierr = DMCreateGlobalVector(dm,&dm->x);CHKERRQ(ierr);
2756     }
2757     ierr = VecCopy(x,dm->x);CHKERRQ(ierr);
2758   } else if (dm->x) {
2759     ierr = VecDestroy(&dm->x);CHKERRQ(ierr);
2760   }
2761   PetscFunctionReturn(0);
2762 }
2763 
2764 PetscFunctionList DMList              = NULL;
2765 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
2766 
2767 #undef __FUNCT__
2768 #define __FUNCT__ "DMSetType"
2769 /*@C
2770   DMSetType - Builds a DM, for a particular DM implementation.
2771 
2772   Collective on DM
2773 
2774   Input Parameters:
2775 + dm     - The DM object
2776 - method - The name of the DM type
2777 
2778   Options Database Key:
2779 . -dm_type <type> - Sets the DM type; use -help for a list of available types
2780 
2781   Notes:
2782   See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
2783 
2784   Level: intermediate
2785 
2786 .keywords: DM, set, type
2787 .seealso: DMGetType(), DMCreate()
2788 @*/
2789 PetscErrorCode  DMSetType(DM dm, DMType method)
2790 {
2791   PetscErrorCode (*r)(DM);
2792   PetscBool      match;
2793   PetscErrorCode ierr;
2794 
2795   PetscFunctionBegin;
2796   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
2797   ierr = PetscObjectTypeCompare((PetscObject) dm, method, &match);CHKERRQ(ierr);
2798   if (match) PetscFunctionReturn(0);
2799 
2800   ierr = DMRegisterAll();CHKERRQ(ierr);
2801   ierr = PetscFunctionListFind(DMList,method,&r);CHKERRQ(ierr);
2802   if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
2803 
2804   if (dm->ops->destroy) {
2805     ierr             = (*dm->ops->destroy)(dm);CHKERRQ(ierr);
2806     dm->ops->destroy = NULL;
2807   }
2808   ierr = (*r)(dm);CHKERRQ(ierr);
2809   ierr = PetscObjectChangeTypeName((PetscObject)dm,method);CHKERRQ(ierr);
2810   PetscFunctionReturn(0);
2811 }
2812 
2813 #undef __FUNCT__
2814 #define __FUNCT__ "DMGetType"
2815 /*@C
2816   DMGetType - Gets the DM type name (as a string) from the DM.
2817 
2818   Not Collective
2819 
2820   Input Parameter:
2821 . dm  - The DM
2822 
2823   Output Parameter:
2824 . type - The DM type name
2825 
2826   Level: intermediate
2827 
2828 .keywords: DM, get, type, name
2829 .seealso: DMSetType(), DMCreate()
2830 @*/
2831 PetscErrorCode  DMGetType(DM dm, DMType *type)
2832 {
2833   PetscErrorCode ierr;
2834 
2835   PetscFunctionBegin;
2836   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
2837   PetscValidPointer(type,2);
2838   ierr = DMRegisterAll();CHKERRQ(ierr);
2839   *type = ((PetscObject)dm)->type_name;
2840   PetscFunctionReturn(0);
2841 }
2842 
2843 #undef __FUNCT__
2844 #define __FUNCT__ "DMConvert"
2845 /*@C
2846   DMConvert - Converts a DM to another DM, either of the same or different type.
2847 
2848   Collective on DM
2849 
2850   Input Parameters:
2851 + dm - the DM
2852 - newtype - new DM type (use "same" for the same type)
2853 
2854   Output Parameter:
2855 . M - pointer to new DM
2856 
2857   Notes:
2858   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
2859   the MPI communicator of the generated DM is always the same as the communicator
2860   of the input DM.
2861 
2862   Level: intermediate
2863 
2864 .seealso: DMCreate()
2865 @*/
2866 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
2867 {
2868   DM             B;
2869   char           convname[256];
2870   PetscBool      sametype, issame;
2871   PetscErrorCode ierr;
2872 
2873   PetscFunctionBegin;
2874   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2875   PetscValidType(dm,1);
2876   PetscValidPointer(M,3);
2877   ierr = PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);CHKERRQ(ierr);
2878   ierr = PetscStrcmp(newtype, "same", &issame);CHKERRQ(ierr);
2879   {
2880     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
2881 
2882     /*
2883        Order of precedence:
2884        1) See if a specialized converter is known to the current DM.
2885        2) See if a specialized converter is known to the desired DM class.
2886        3) See if a good general converter is registered for the desired class
2887        4) See if a good general converter is known for the current matrix.
2888        5) Use a really basic converter.
2889     */
2890 
2891     /* 1) See if a specialized converter is known to the current DM and the desired class */
2892     ierr = PetscStrcpy(convname,"DMConvert_");CHKERRQ(ierr);
2893     ierr = PetscStrcat(convname,((PetscObject) dm)->type_name);CHKERRQ(ierr);
2894     ierr = PetscStrcat(convname,"_");CHKERRQ(ierr);
2895     ierr = PetscStrcat(convname,newtype);CHKERRQ(ierr);
2896     ierr = PetscStrcat(convname,"_C");CHKERRQ(ierr);
2897     ierr = PetscObjectQueryFunction((PetscObject)dm,convname,&conv);CHKERRQ(ierr);
2898     if (conv) goto foundconv;
2899 
2900     /* 2)  See if a specialized converter is known to the desired DM class. */
2901     ierr = DMCreate(PetscObjectComm((PetscObject)dm), &B);CHKERRQ(ierr);
2902     ierr = DMSetType(B, newtype);CHKERRQ(ierr);
2903     ierr = PetscStrcpy(convname,"DMConvert_");CHKERRQ(ierr);
2904     ierr = PetscStrcat(convname,((PetscObject) dm)->type_name);CHKERRQ(ierr);
2905     ierr = PetscStrcat(convname,"_");CHKERRQ(ierr);
2906     ierr = PetscStrcat(convname,newtype);CHKERRQ(ierr);
2907     ierr = PetscStrcat(convname,"_C");CHKERRQ(ierr);
2908     ierr = PetscObjectQueryFunction((PetscObject)B,convname,&conv);CHKERRQ(ierr);
2909     if (conv) {
2910       ierr = DMDestroy(&B);CHKERRQ(ierr);
2911       goto foundconv;
2912     }
2913 
2914 #if 0
2915     /* 3) See if a good general converter is registered for the desired class */
2916     conv = B->ops->convertfrom;
2917     ierr = DMDestroy(&B);CHKERRQ(ierr);
2918     if (conv) goto foundconv;
2919 
2920     /* 4) See if a good general converter is known for the current matrix */
2921     if (dm->ops->convert) {
2922       conv = dm->ops->convert;
2923     }
2924     if (conv) goto foundconv;
2925 #endif
2926 
2927     /* 5) Use a really basic converter. */
2928     SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
2929 
2930 foundconv:
2931     ierr = PetscLogEventBegin(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
2932     ierr = (*conv)(dm,newtype,M);CHKERRQ(ierr);
2933     ierr = PetscLogEventEnd(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
2934   }
2935   ierr = PetscObjectStateIncrease((PetscObject) *M);CHKERRQ(ierr);
2936   PetscFunctionReturn(0);
2937 }
2938 
2939 /*--------------------------------------------------------------------------------------------------------------------*/
2940 
2941 #undef __FUNCT__
2942 #define __FUNCT__ "DMRegister"
2943 /*@C
2944   DMRegister -  Adds a new DM component implementation
2945 
2946   Not Collective
2947 
2948   Input Parameters:
2949 + name        - The name of a new user-defined creation routine
2950 - create_func - The creation routine itself
2951 
2952   Notes:
2953   DMRegister() may be called multiple times to add several user-defined DMs
2954 
2955 
2956   Sample usage:
2957 .vb
2958     DMRegister("my_da", MyDMCreate);
2959 .ve
2960 
2961   Then, your DM type can be chosen with the procedural interface via
2962 .vb
2963     DMCreate(MPI_Comm, DM *);
2964     DMSetType(DM,"my_da");
2965 .ve
2966    or at runtime via the option
2967 .vb
2968     -da_type my_da
2969 .ve
2970 
2971   Level: advanced
2972 
2973 .keywords: DM, register
2974 .seealso: DMRegisterAll(), DMRegisterDestroy()
2975 
2976 @*/
2977 PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
2978 {
2979   PetscErrorCode ierr;
2980 
2981   PetscFunctionBegin;
2982   ierr = PetscFunctionListAdd(&DMList,sname,function);CHKERRQ(ierr);
2983   PetscFunctionReturn(0);
2984 }
2985 
2986 #undef __FUNCT__
2987 #define __FUNCT__ "DMLoad"
2988 /*@C
2989   DMLoad - Loads a DM that has been stored in binary  with DMView().
2990 
2991   Collective on PetscViewer
2992 
2993   Input Parameters:
2994 + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
2995            some related function before a call to DMLoad().
2996 - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
2997            HDF5 file viewer, obtained from PetscViewerHDF5Open()
2998 
2999    Level: intermediate
3000 
3001   Notes:
3002    The type is determined by the data in the file, any type set into the DM before this call is ignored.
3003 
3004   Notes for advanced users:
3005   Most users should not need to know the details of the binary storage
3006   format, since DMLoad() and DMView() completely hide these details.
3007   But for anyone who's interested, the standard binary matrix storage
3008   format is
3009 .vb
3010      has not yet been determined
3011 .ve
3012 
3013 .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3014 @*/
3015 PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3016 {
3017   PetscBool      isbinary, ishdf5;
3018   PetscErrorCode ierr;
3019 
3020   PetscFunctionBegin;
3021   PetscValidHeaderSpecific(newdm,DM_CLASSID,1);
3022   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
3023   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
3024   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
3025   if (isbinary) {
3026     PetscInt classid;
3027     char     type[256];
3028 
3029     ierr = PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);CHKERRQ(ierr);
3030     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3031     ierr = PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);CHKERRQ(ierr);
3032     ierr = DMSetType(newdm, type);CHKERRQ(ierr);
3033     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
3034   } else if (ishdf5) {
3035     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
3036   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3037   PetscFunctionReturn(0);
3038 }
3039 
3040 /******************************** FEM Support **********************************/
3041 
3042 #undef __FUNCT__
3043 #define __FUNCT__ "DMPrintCellVector"
3044 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3045 {
3046   PetscInt       f;
3047   PetscErrorCode ierr;
3048 
3049   PetscFunctionBegin;
3050   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3051   for (f = 0; f < len; ++f) {
3052     ierr = PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));CHKERRQ(ierr);
3053   }
3054   PetscFunctionReturn(0);
3055 }
3056 
3057 #undef __FUNCT__
3058 #define __FUNCT__ "DMPrintCellMatrix"
3059 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
3060 {
3061   PetscInt       f, g;
3062   PetscErrorCode ierr;
3063 
3064   PetscFunctionBegin;
3065   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3066   for (f = 0; f < rows; ++f) {
3067     ierr = PetscPrintf(PETSC_COMM_SELF, "  |");CHKERRQ(ierr);
3068     for (g = 0; g < cols; ++g) {
3069       ierr = PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));CHKERRQ(ierr);
3070     }
3071     ierr = PetscPrintf(PETSC_COMM_SELF, " |\n");CHKERRQ(ierr);
3072   }
3073   PetscFunctionReturn(0);
3074 }
3075 
3076 #undef __FUNCT__
3077 #define __FUNCT__ "DMPrintLocalVec"
3078 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
3079 {
3080   PetscMPIInt    rank, numProcs;
3081   PetscInt       p;
3082   PetscErrorCode ierr;
3083 
3084   PetscFunctionBegin;
3085   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
3086   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);CHKERRQ(ierr);
3087   ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "%s:\n", name);CHKERRQ(ierr);
3088   for (p = 0; p < numProcs; ++p) {
3089     if (p == rank) {
3090       Vec x;
3091 
3092       ierr = VecDuplicate(X, &x);CHKERRQ(ierr);
3093       ierr = VecCopy(X, x);CHKERRQ(ierr);
3094       ierr = VecChop(x, tol);CHKERRQ(ierr);
3095       ierr = VecView(x, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
3096       ierr = VecDestroy(&x);CHKERRQ(ierr);
3097       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
3098     }
3099     ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
3100   }
3101   PetscFunctionReturn(0);
3102 }
3103 
3104 #undef __FUNCT__
3105 #define __FUNCT__ "DMGetDefaultSection"
3106 /*@
3107   DMGetDefaultSection - Get the PetscSection encoding the local data layout for the DM.
3108 
3109   Input Parameter:
3110 . dm - The DM
3111 
3112   Output Parameter:
3113 . section - The PetscSection
3114 
3115   Level: intermediate
3116 
3117   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3118 
3119 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3120 @*/
3121 PetscErrorCode DMGetDefaultSection(DM dm, PetscSection *section)
3122 {
3123   PetscErrorCode ierr;
3124 
3125   PetscFunctionBegin;
3126   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3127   PetscValidPointer(section, 2);
3128   if (!dm->defaultSection && dm->ops->createdefaultsection) {
3129     ierr = (*dm->ops->createdefaultsection)(dm);CHKERRQ(ierr);
3130     ierr = PetscObjectViewFromOptions((PetscObject) dm->defaultSection, NULL, "-dm_petscsection_view");CHKERRQ(ierr);
3131   }
3132   *section = dm->defaultSection;
3133   PetscFunctionReturn(0);
3134 }
3135 
3136 #undef __FUNCT__
3137 #define __FUNCT__ "DMSetDefaultSection"
3138 /*@
3139   DMSetDefaultSection - Set the PetscSection encoding the local data layout for the DM.
3140 
3141   Input Parameters:
3142 + dm - The DM
3143 - section - The PetscSection
3144 
3145   Level: intermediate
3146 
3147   Note: Any existing Section will be destroyed
3148 
3149 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3150 @*/
3151 PetscErrorCode DMSetDefaultSection(DM dm, PetscSection section)
3152 {
3153   PetscInt       numFields = 0;
3154   PetscInt       f;
3155   PetscErrorCode ierr;
3156 
3157   PetscFunctionBegin;
3158   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3159   if (section) {
3160     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3161     ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3162   }
3163   ierr = PetscSectionDestroy(&dm->defaultSection);CHKERRQ(ierr);
3164   dm->defaultSection = section;
3165   if (section) {ierr = PetscSectionGetNumFields(dm->defaultSection, &numFields);CHKERRQ(ierr);}
3166   if (numFields) {
3167     ierr = DMSetNumFields(dm, numFields);CHKERRQ(ierr);
3168     for (f = 0; f < numFields; ++f) {
3169       PetscObject disc;
3170       const char *name;
3171 
3172       ierr = PetscSectionGetFieldName(dm->defaultSection, f, &name);CHKERRQ(ierr);
3173       ierr = DMGetField(dm, f, &disc);CHKERRQ(ierr);
3174       ierr = PetscObjectSetName(disc, name);CHKERRQ(ierr);
3175     }
3176   }
3177   /* The global section will be rebuilt in the next call to DMGetDefaultGlobalSection(). */
3178   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3179   PetscFunctionReturn(0);
3180 }
3181 
3182 #undef __FUNCT__
3183 #define __FUNCT__ "DMGetDefaultConstraints"
3184 /*@
3185   DMGetDefaultConstraints - Get the PetscSection and Mat the specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
3186 
3187   not collective
3188 
3189   Input Parameter:
3190 . dm - The DM
3191 
3192   Output Parameter:
3193 + 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.
3194 - 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.
3195 
3196   Level: advanced
3197 
3198   Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
3199 
3200 .seealso: DMSetDefaultConstraints()
3201 @*/
3202 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
3203 {
3204   PetscErrorCode ierr;
3205 
3206   PetscFunctionBegin;
3207   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3208   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {ierr = (*dm->ops->createdefaultconstraints)(dm);CHKERRQ(ierr);}
3209   if (section) {*section = dm->defaultConstraintSection;}
3210   if (mat) {*mat = dm->defaultConstraintMat;}
3211   PetscFunctionReturn(0);
3212 }
3213 
3214 #undef __FUNCT__
3215 #define __FUNCT__ "DMSetDefaultConstraints"
3216 /*@
3217   DMSetDefaultConstraints - Set the PetscSection and Mat the specify the local constraint interpolation.
3218 
3219   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().
3220 
3221   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.
3222 
3223   collective on dm
3224 
3225   Input Parameters:
3226 + dm - The DM
3227 + 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).
3228 - 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).
3229 
3230   Level: advanced
3231 
3232   Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
3233 
3234 .seealso: DMGetDefaultConstraints()
3235 @*/
3236 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
3237 {
3238   PetscMPIInt result;
3239   PetscErrorCode ierr;
3240 
3241   PetscFunctionBegin;
3242   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3243   if (section) {
3244     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3245     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);CHKERRQ(ierr);
3246     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
3247   }
3248   if (mat) {
3249     PetscValidHeaderSpecific(mat,MAT_CLASSID,3);
3250     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);CHKERRQ(ierr);
3251     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
3252   }
3253   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3254   ierr = PetscSectionDestroy(&dm->defaultConstraintSection);CHKERRQ(ierr);
3255   dm->defaultConstraintSection = section;
3256   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
3257   ierr = MatDestroy(&dm->defaultConstraintMat);CHKERRQ(ierr);
3258   dm->defaultConstraintMat = mat;
3259   PetscFunctionReturn(0);
3260 }
3261 
3262 #ifdef PETSC_USE_DEBUG
3263 #undef __FUNCT__
3264 #define __FUNCT__ "DMDefaultSectionCheckConsistency_Internal"
3265 /*
3266   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
3267 
3268   Input Parameters:
3269 + dm - The DM
3270 . localSection - PetscSection describing the local data layout
3271 - globalSection - PetscSection describing the global data layout
3272 
3273   Level: intermediate
3274 
3275 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3276 */
3277 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
3278 {
3279   MPI_Comm        comm;
3280   PetscLayout     layout;
3281   const PetscInt *ranges;
3282   PetscInt        pStart, pEnd, p, nroots;
3283   PetscMPIInt     size, rank;
3284   PetscBool       valid = PETSC_TRUE, gvalid;
3285   PetscErrorCode  ierr;
3286 
3287   PetscFunctionBegin;
3288   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3289   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3290   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3291   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3292   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3293   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3294   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3295   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3296   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3297   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3298   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3299   for (p = pStart; p < pEnd; ++p) {
3300     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;
3301 
3302     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3303     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3304     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3305     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3306     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3307     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3308     if (!gdof) continue; /* Censored point */
3309     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;}
3310     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;}
3311     if (gdof < 0) {
3312       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3313       for (d = 0; d < gsize; ++d) {
3314         PetscInt offset = -(goff+1) + d, r;
3315 
3316         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3317         if (r < 0) r = -(r+2);
3318         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;}
3319       }
3320     }
3321   }
3322   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3323   ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
3324   ierr = MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);CHKERRQ(ierr);
3325   if (!gvalid) {
3326     ierr = DMView(dm, NULL);CHKERRQ(ierr);
3327     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
3328   }
3329   PetscFunctionReturn(0);
3330 }
3331 #endif
3332 
3333 #undef __FUNCT__
3334 #define __FUNCT__ "DMGetDefaultGlobalSection"
3335 /*@
3336   DMGetDefaultGlobalSection - Get the PetscSection encoding the global data layout for the DM.
3337 
3338   Collective on DM
3339 
3340   Input Parameter:
3341 . dm - The DM
3342 
3343   Output Parameter:
3344 . section - The PetscSection
3345 
3346   Level: intermediate
3347 
3348   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3349 
3350 .seealso: DMSetDefaultSection(), DMGetDefaultSection()
3351 @*/
3352 PetscErrorCode DMGetDefaultGlobalSection(DM dm, PetscSection *section)
3353 {
3354   PetscErrorCode ierr;
3355 
3356   PetscFunctionBegin;
3357   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3358   PetscValidPointer(section, 2);
3359   if (!dm->defaultGlobalSection) {
3360     PetscSection s;
3361 
3362     ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
3363     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
3364     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSF in order to create a global PetscSection");
3365     ierr = PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->defaultGlobalSection);CHKERRQ(ierr);
3366     ierr = PetscLayoutDestroy(&dm->map);CHKERRQ(ierr);
3367     ierr = PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->defaultGlobalSection, &dm->map);CHKERRQ(ierr);
3368     ierr = PetscSectionViewFromOptions(dm->defaultGlobalSection, NULL, "-global_section_view");CHKERRQ(ierr);
3369   }
3370   *section = dm->defaultGlobalSection;
3371   PetscFunctionReturn(0);
3372 }
3373 
3374 #undef __FUNCT__
3375 #define __FUNCT__ "DMSetDefaultGlobalSection"
3376 /*@
3377   DMSetDefaultGlobalSection - Set the PetscSection encoding the global data layout for the DM.
3378 
3379   Input Parameters:
3380 + dm - The DM
3381 - section - The PetscSection, or NULL
3382 
3383   Level: intermediate
3384 
3385   Note: Any existing Section will be destroyed
3386 
3387 .seealso: DMGetDefaultGlobalSection(), DMSetDefaultSection()
3388 @*/
3389 PetscErrorCode DMSetDefaultGlobalSection(DM dm, PetscSection section)
3390 {
3391   PetscErrorCode ierr;
3392 
3393   PetscFunctionBegin;
3394   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3395   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3396   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3397   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3398   dm->defaultGlobalSection = section;
3399 #ifdef PETSC_USE_DEBUG
3400   if (section) {ierr = DMDefaultSectionCheckConsistency_Internal(dm, dm->defaultSection, section);CHKERRQ(ierr);}
3401 #endif
3402   PetscFunctionReturn(0);
3403 }
3404 
3405 #undef __FUNCT__
3406 #define __FUNCT__ "DMGetDefaultSF"
3407 /*@
3408   DMGetDefaultSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
3409   it is created from the default PetscSection layouts in the DM.
3410 
3411   Input Parameter:
3412 . dm - The DM
3413 
3414   Output Parameter:
3415 . sf - The PetscSF
3416 
3417   Level: intermediate
3418 
3419   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3420 
3421 .seealso: DMSetDefaultSF(), DMCreateDefaultSF()
3422 @*/
3423 PetscErrorCode DMGetDefaultSF(DM dm, PetscSF *sf)
3424 {
3425   PetscInt       nroots;
3426   PetscErrorCode ierr;
3427 
3428   PetscFunctionBegin;
3429   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3430   PetscValidPointer(sf, 2);
3431   ierr = PetscSFGetGraph(dm->defaultSF, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
3432   if (nroots < 0) {
3433     PetscSection section, gSection;
3434 
3435     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
3436     if (section) {
3437       ierr = DMGetDefaultGlobalSection(dm, &gSection);CHKERRQ(ierr);
3438       ierr = DMCreateDefaultSF(dm, section, gSection);CHKERRQ(ierr);
3439     } else {
3440       *sf = NULL;
3441       PetscFunctionReturn(0);
3442     }
3443   }
3444   *sf = dm->defaultSF;
3445   PetscFunctionReturn(0);
3446 }
3447 
3448 #undef __FUNCT__
3449 #define __FUNCT__ "DMSetDefaultSF"
3450 /*@
3451   DMSetDefaultSF - Set the PetscSF encoding the parallel dof overlap for the DM
3452 
3453   Input Parameters:
3454 + dm - The DM
3455 - sf - The PetscSF
3456 
3457   Level: intermediate
3458 
3459   Note: Any previous SF is destroyed
3460 
3461 .seealso: DMGetDefaultSF(), DMCreateDefaultSF()
3462 @*/
3463 PetscErrorCode DMSetDefaultSF(DM dm, PetscSF sf)
3464 {
3465   PetscErrorCode ierr;
3466 
3467   PetscFunctionBegin;
3468   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3469   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
3470   ierr          = PetscSFDestroy(&dm->defaultSF);CHKERRQ(ierr);
3471   dm->defaultSF = sf;
3472   PetscFunctionReturn(0);
3473 }
3474 
3475 #undef __FUNCT__
3476 #define __FUNCT__ "DMCreateDefaultSF"
3477 /*@C
3478   DMCreateDefaultSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
3479   describing the data layout.
3480 
3481   Input Parameters:
3482 + dm - The DM
3483 . localSection - PetscSection describing the local data layout
3484 - globalSection - PetscSection describing the global data layout
3485 
3486   Level: intermediate
3487 
3488 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3489 @*/
3490 PetscErrorCode DMCreateDefaultSF(DM dm, PetscSection localSection, PetscSection globalSection)
3491 {
3492   MPI_Comm       comm;
3493   PetscLayout    layout;
3494   const PetscInt *ranges;
3495   PetscInt       *local;
3496   PetscSFNode    *remote;
3497   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
3498   PetscMPIInt    size, rank;
3499   PetscErrorCode ierr;
3500 
3501   PetscFunctionBegin;
3502   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3503   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3504   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3505   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3506   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3507   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3508   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3509   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3510   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3511   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3512   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3513   for (p = pStart; p < pEnd; ++p) {
3514     PetscInt gdof, gcdof;
3515 
3516     ierr     = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3517     ierr     = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3518     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));
3519     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3520   }
3521   ierr = PetscMalloc1(nleaves, &local);CHKERRQ(ierr);
3522   ierr = PetscMalloc1(nleaves, &remote);CHKERRQ(ierr);
3523   for (p = pStart, l = 0; p < pEnd; ++p) {
3524     const PetscInt *cind;
3525     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
3526 
3527     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3528     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3529     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3530     ierr = PetscSectionGetConstraintIndices(localSection, p, &cind);CHKERRQ(ierr);
3531     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3532     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3533     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3534     if (!gdof) continue; /* Censored point */
3535     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3536     if (gsize != dof-cdof) {
3537       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);
3538       cdof = 0; /* Ignore constraints */
3539     }
3540     for (d = 0, c = 0; d < dof; ++d) {
3541       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
3542       local[l+d-c] = off+d;
3543     }
3544     if (gdof < 0) {
3545       for (d = 0; d < gsize; ++d, ++l) {
3546         PetscInt offset = -(goff+1) + d, r;
3547 
3548         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3549         if (r < 0) r = -(r+2);
3550         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);
3551         remote[l].rank  = r;
3552         remote[l].index = offset - ranges[r];
3553       }
3554     } else {
3555       for (d = 0; d < gsize; ++d, ++l) {
3556         remote[l].rank  = rank;
3557         remote[l].index = goff+d - ranges[rank];
3558       }
3559     }
3560   }
3561   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
3562   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3563   ierr = PetscSFSetGraph(dm->defaultSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
3564   PetscFunctionReturn(0);
3565 }
3566 
3567 #undef __FUNCT__
3568 #define __FUNCT__ "DMGetPointSF"
3569 /*@
3570   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
3571 
3572   Input Parameter:
3573 . dm - The DM
3574 
3575   Output Parameter:
3576 . sf - The PetscSF
3577 
3578   Level: intermediate
3579 
3580   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3581 
3582 .seealso: DMSetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3583 @*/
3584 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
3585 {
3586   PetscFunctionBegin;
3587   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3588   PetscValidPointer(sf, 2);
3589   *sf = dm->sf;
3590   PetscFunctionReturn(0);
3591 }
3592 
3593 #undef __FUNCT__
3594 #define __FUNCT__ "DMSetPointSF"
3595 /*@
3596   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
3597 
3598   Input Parameters:
3599 + dm - The DM
3600 - sf - The PetscSF
3601 
3602   Level: intermediate
3603 
3604 .seealso: DMGetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3605 @*/
3606 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
3607 {
3608   PetscErrorCode ierr;
3609 
3610   PetscFunctionBegin;
3611   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3612   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
3613   ierr   = PetscSFDestroy(&dm->sf);CHKERRQ(ierr);
3614   ierr   = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
3615   dm->sf = sf;
3616   PetscFunctionReturn(0);
3617 }
3618 
3619 #undef __FUNCT__
3620 #define __FUNCT__ "DMGetDS"
3621 /*@
3622   DMGetDS - Get the PetscDS
3623 
3624   Input Parameter:
3625 . dm - The DM
3626 
3627   Output Parameter:
3628 . prob - The PetscDS
3629 
3630   Level: developer
3631 
3632 .seealso: DMSetDS()
3633 @*/
3634 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
3635 {
3636   PetscFunctionBegin;
3637   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3638   PetscValidPointer(prob, 2);
3639   *prob = dm->prob;
3640   PetscFunctionReturn(0);
3641 }
3642 
3643 #undef __FUNCT__
3644 #define __FUNCT__ "DMSetDS"
3645 /*@
3646   DMSetDS - Set the PetscDS
3647 
3648   Input Parameters:
3649 + dm - The DM
3650 - prob - The PetscDS
3651 
3652   Level: developer
3653 
3654 .seealso: DMGetDS()
3655 @*/
3656 PetscErrorCode DMSetDS(DM dm, PetscDS prob)
3657 {
3658   PetscErrorCode ierr;
3659 
3660   PetscFunctionBegin;
3661   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3662   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 2);
3663   ierr = PetscDSDestroy(&dm->prob);CHKERRQ(ierr);
3664   dm->prob = prob;
3665   ierr = PetscObjectReference((PetscObject) dm->prob);CHKERRQ(ierr);
3666   PetscFunctionReturn(0);
3667 }
3668 
3669 #undef __FUNCT__
3670 #define __FUNCT__ "DMGetNumFields"
3671 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
3672 {
3673   PetscErrorCode ierr;
3674 
3675   PetscFunctionBegin;
3676   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3677   ierr = PetscDSGetNumFields(dm->prob, numFields);CHKERRQ(ierr);
3678   PetscFunctionReturn(0);
3679 }
3680 
3681 #undef __FUNCT__
3682 #define __FUNCT__ "DMSetNumFields"
3683 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
3684 {
3685   PetscInt       Nf, f;
3686   PetscErrorCode ierr;
3687 
3688   PetscFunctionBegin;
3689   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3690   ierr = PetscDSGetNumFields(dm->prob, &Nf);CHKERRQ(ierr);
3691   for (f = Nf; f < numFields; ++f) {
3692     PetscContainer obj;
3693 
3694     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
3695     ierr = PetscDSSetDiscretization(dm->prob, f, (PetscObject) obj);CHKERRQ(ierr);
3696     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
3697   }
3698   PetscFunctionReturn(0);
3699 }
3700 
3701 #undef __FUNCT__
3702 #define __FUNCT__ "DMGetField"
3703 /*@
3704   DMGetField - Return the discretization object for a given DM field
3705 
3706   Not collective
3707 
3708   Input Parameters:
3709 + dm - The DM
3710 - f  - The field number
3711 
3712   Output Parameter:
3713 . field - The discretization object
3714 
3715   Level: developer
3716 
3717 .seealso: DMSetField()
3718 @*/
3719 PetscErrorCode DMGetField(DM dm, PetscInt f, PetscObject *field)
3720 {
3721   PetscErrorCode ierr;
3722 
3723   PetscFunctionBegin;
3724   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3725   ierr = PetscDSGetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3726   PetscFunctionReturn(0);
3727 }
3728 
3729 #undef __FUNCT__
3730 #define __FUNCT__ "DMSetField"
3731 /*@
3732   DMSetField - Set the discretization object for a given DM field
3733 
3734   Logically collective on DM
3735 
3736   Input Parameters:
3737 + dm - The DM
3738 . f  - The field number
3739 - field - The discretization object
3740 
3741   Level: developer
3742 
3743 .seealso: DMGetField()
3744 @*/
3745 PetscErrorCode DMSetField(DM dm, PetscInt f, PetscObject field)
3746 {
3747   PetscErrorCode ierr;
3748 
3749   PetscFunctionBegin;
3750   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3751   ierr = PetscDSSetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3752   PetscFunctionReturn(0);
3753 }
3754 
3755 #undef __FUNCT__
3756 #define __FUNCT__ "DMRestrictHook_Coordinates"
3757 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
3758 {
3759   DM dm_coord,dmc_coord;
3760   PetscErrorCode ierr;
3761   Vec coords,ccoords;
3762   Mat inject;
3763   PetscFunctionBegin;
3764   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3765   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
3766   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3767   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
3768   if (coords && !ccoords) {
3769     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
3770     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
3771     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
3772     ierr = MatDestroy(&inject);CHKERRQ(ierr);
3773     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
3774     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3775   }
3776   PetscFunctionReturn(0);
3777 }
3778 
3779 #undef __FUNCT__
3780 #define __FUNCT__ "DMSubDomainHook_Coordinates"
3781 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
3782 {
3783   DM dm_coord,subdm_coord;
3784   PetscErrorCode ierr;
3785   Vec coords,ccoords,clcoords;
3786   VecScatter *scat_i,*scat_g;
3787   PetscFunctionBegin;
3788   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3789   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
3790   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3791   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
3792   if (coords && !ccoords) {
3793     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
3794     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
3795     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
3796     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
3797     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3798     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3799     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3800     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3801     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
3802     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
3803     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
3804     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
3805     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3806     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
3807     ierr = PetscFree(scat_i);CHKERRQ(ierr);
3808     ierr = PetscFree(scat_g);CHKERRQ(ierr);
3809   }
3810   PetscFunctionReturn(0);
3811 }
3812 
3813 #undef __FUNCT__
3814 #define __FUNCT__ "DMGetDimension"
3815 /*@
3816   DMGetDimension - Return the topological dimension of the DM
3817 
3818   Not collective
3819 
3820   Input Parameter:
3821 . dm - The DM
3822 
3823   Output Parameter:
3824 . dim - The topological dimension
3825 
3826   Level: beginner
3827 
3828 .seealso: DMSetDimension(), DMCreate()
3829 @*/
3830 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
3831 {
3832   PetscFunctionBegin;
3833   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3834   PetscValidPointer(dim, 2);
3835   *dim = dm->dim;
3836   PetscFunctionReturn(0);
3837 }
3838 
3839 #undef __FUNCT__
3840 #define __FUNCT__ "DMSetDimension"
3841 /*@
3842   DMSetDimension - Set the topological dimension of the DM
3843 
3844   Collective on dm
3845 
3846   Input Parameters:
3847 + dm - The DM
3848 - dim - The topological dimension
3849 
3850   Level: beginner
3851 
3852 .seealso: DMGetDimension(), DMCreate()
3853 @*/
3854 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
3855 {
3856   PetscFunctionBegin;
3857   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3858   PetscValidLogicalCollectiveInt(dm, dim, 2);
3859   dm->dim = dim;
3860   PetscFunctionReturn(0);
3861 }
3862 
3863 #undef __FUNCT__
3864 #define __FUNCT__ "DMGetDimPoints"
3865 /*@
3866   DMGetDimPoints - Get the half-open interval for all points of a given dimension
3867 
3868   Collective on DM
3869 
3870   Input Parameters:
3871 + dm - the DM
3872 - dim - the dimension
3873 
3874   Output Parameters:
3875 + pStart - The first point of the given dimension
3876 . pEnd - The first point following points of the given dimension
3877 
3878   Note:
3879   The points are vertices in the Hasse diagram encoding the topology. This is explained in
3880   http://arxiv.org/abs/0908.4427. If not points exist of this dimension in the storage scheme,
3881   then the interval is empty.
3882 
3883   Level: intermediate
3884 
3885 .keywords: point, Hasse Diagram, dimension
3886 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
3887 @*/
3888 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
3889 {
3890   PetscInt       d;
3891   PetscErrorCode ierr;
3892 
3893   PetscFunctionBegin;
3894   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3895   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
3896   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
3897   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
3898   PetscFunctionReturn(0);
3899 }
3900 
3901 #undef __FUNCT__
3902 #define __FUNCT__ "DMSetCoordinates"
3903 /*@
3904   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
3905 
3906   Collective on DM
3907 
3908   Input Parameters:
3909 + dm - the DM
3910 - c - coordinate vector
3911 
3912   Note:
3913   The coordinates do include those for ghost points, which are in the local vector
3914 
3915   Level: intermediate
3916 
3917 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3918 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLoca(), DMGetCoordinateDM()
3919 @*/
3920 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
3921 {
3922   PetscErrorCode ierr;
3923 
3924   PetscFunctionBegin;
3925   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3926   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3927   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3928   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3929   dm->coordinates = c;
3930   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3931   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3932   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3933   PetscFunctionReturn(0);
3934 }
3935 
3936 #undef __FUNCT__
3937 #define __FUNCT__ "DMSetCoordinatesLocal"
3938 /*@
3939   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
3940 
3941   Collective on DM
3942 
3943    Input Parameters:
3944 +  dm - the DM
3945 -  c - coordinate vector
3946 
3947   Note:
3948   The coordinates of ghost points can be set using DMSetCoordinates()
3949   followed by DMGetCoordinatesLocal(). This is intended to enable the
3950   setting of ghost coordinates outside of the domain.
3951 
3952   Level: intermediate
3953 
3954 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3955 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
3956 @*/
3957 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
3958 {
3959   PetscErrorCode ierr;
3960 
3961   PetscFunctionBegin;
3962   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3963   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3964   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3965   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3966 
3967   dm->coordinatesLocal = c;
3968 
3969   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3970   PetscFunctionReturn(0);
3971 }
3972 
3973 #undef __FUNCT__
3974 #define __FUNCT__ "DMGetCoordinates"
3975 /*@
3976   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
3977 
3978   Not Collective
3979 
3980   Input Parameter:
3981 . dm - the DM
3982 
3983   Output Parameter:
3984 . c - global coordinate vector
3985 
3986   Note:
3987   This is a borrowed reference, so the user should NOT destroy this vector
3988 
3989   Each process has only the local coordinates (does NOT have the ghost coordinates).
3990 
3991   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
3992   and (x_0,y_0,z_0,x_1,y_1,z_1...)
3993 
3994   Level: intermediate
3995 
3996 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3997 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
3998 @*/
3999 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
4000 {
4001   PetscErrorCode ierr;
4002 
4003   PetscFunctionBegin;
4004   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4005   PetscValidPointer(c,2);
4006   if (!dm->coordinates && dm->coordinatesLocal) {
4007     DM cdm = NULL;
4008 
4009     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4010     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
4011     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
4012     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4013     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4014   }
4015   *c = dm->coordinates;
4016   PetscFunctionReturn(0);
4017 }
4018 
4019 #undef __FUNCT__
4020 #define __FUNCT__ "DMGetCoordinatesLocal"
4021 /*@
4022   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
4023 
4024   Collective on DM
4025 
4026   Input Parameter:
4027 . dm - the DM
4028 
4029   Output Parameter:
4030 . c - coordinate vector
4031 
4032   Note:
4033   This is a borrowed reference, so the user should NOT destroy this vector
4034 
4035   Each process has the local and ghost coordinates
4036 
4037   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4038   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4039 
4040   Level: intermediate
4041 
4042 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4043 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
4044 @*/
4045 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
4046 {
4047   PetscErrorCode ierr;
4048 
4049   PetscFunctionBegin;
4050   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4051   PetscValidPointer(c,2);
4052   if (!dm->coordinatesLocal && dm->coordinates) {
4053     DM cdm = NULL;
4054 
4055     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4056     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
4057     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
4058     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4059     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4060   }
4061   *c = dm->coordinatesLocal;
4062   PetscFunctionReturn(0);
4063 }
4064 
4065 #undef __FUNCT__
4066 #define __FUNCT__ "DMGetCoordinateDM"
4067 /*@
4068   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
4069 
4070   Collective on DM
4071 
4072   Input Parameter:
4073 . dm - the DM
4074 
4075   Output Parameter:
4076 . cdm - coordinate DM
4077 
4078   Level: intermediate
4079 
4080 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4081 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4082 @*/
4083 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
4084 {
4085   PetscErrorCode ierr;
4086 
4087   PetscFunctionBegin;
4088   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4089   PetscValidPointer(cdm,2);
4090   if (!dm->coordinateDM) {
4091     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
4092     ierr = (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);CHKERRQ(ierr);
4093   }
4094   *cdm = dm->coordinateDM;
4095   PetscFunctionReturn(0);
4096 }
4097 
4098 #undef __FUNCT__
4099 #define __FUNCT__ "DMSetCoordinateDM"
4100 /*@
4101   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
4102 
4103   Logically Collective on DM
4104 
4105   Input Parameters:
4106 + dm - the DM
4107 - cdm - coordinate DM
4108 
4109   Level: intermediate
4110 
4111 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4112 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4113 @*/
4114 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
4115 {
4116   PetscErrorCode ierr;
4117 
4118   PetscFunctionBegin;
4119   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4120   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
4121   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
4122   dm->coordinateDM = cdm;
4123   ierr = PetscObjectReference((PetscObject) dm->coordinateDM);CHKERRQ(ierr);
4124   PetscFunctionReturn(0);
4125 }
4126 
4127 #undef __FUNCT__
4128 #define __FUNCT__ "DMGetCoordinateDim"
4129 /*@
4130   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
4131 
4132   Not Collective
4133 
4134   Input Parameter:
4135 . dm - The DM object
4136 
4137   Output Parameter:
4138 . dim - The embedding dimension
4139 
4140   Level: intermediate
4141 
4142 .keywords: mesh, coordinates
4143 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4144 @*/
4145 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
4146 {
4147   PetscFunctionBegin;
4148   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4149   PetscValidPointer(dim, 2);
4150   if (dm->dimEmbed == PETSC_DEFAULT) {
4151     dm->dimEmbed = dm->dim;
4152   }
4153   *dim = dm->dimEmbed;
4154   PetscFunctionReturn(0);
4155 }
4156 
4157 #undef __FUNCT__
4158 #define __FUNCT__ "DMSetCoordinateDim"
4159 /*@
4160   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
4161 
4162   Not Collective
4163 
4164   Input Parameters:
4165 + dm  - The DM object
4166 - dim - The embedding dimension
4167 
4168   Level: intermediate
4169 
4170 .keywords: mesh, coordinates
4171 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4172 @*/
4173 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
4174 {
4175   PetscFunctionBegin;
4176   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4177   dm->dimEmbed = dim;
4178   PetscFunctionReturn(0);
4179 }
4180 
4181 #undef __FUNCT__
4182 #define __FUNCT__ "DMGetCoordinateSection"
4183 /*@
4184   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
4185 
4186   Not Collective
4187 
4188   Input Parameter:
4189 . dm - The DM object
4190 
4191   Output Parameter:
4192 . section - The PetscSection object
4193 
4194   Level: intermediate
4195 
4196 .keywords: mesh, coordinates
4197 .seealso: DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4198 @*/
4199 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
4200 {
4201   DM             cdm;
4202   PetscErrorCode ierr;
4203 
4204   PetscFunctionBegin;
4205   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4206   PetscValidPointer(section, 2);
4207   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4208   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
4209   PetscFunctionReturn(0);
4210 }
4211 
4212 #undef __FUNCT__
4213 #define __FUNCT__ "DMSetCoordinateSection"
4214 /*@
4215   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
4216 
4217   Not Collective
4218 
4219   Input Parameters:
4220 + dm      - The DM object
4221 . dim     - The embedding dimension, or PETSC_DETERMINE
4222 - section - The PetscSection object
4223 
4224   Level: intermediate
4225 
4226 .keywords: mesh, coordinates
4227 .seealso: DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4228 @*/
4229 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
4230 {
4231   DM             cdm;
4232   PetscErrorCode ierr;
4233 
4234   PetscFunctionBegin;
4235   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4236   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
4237   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4238   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
4239   if (dim == PETSC_DETERMINE) {
4240     PetscInt d = dim;
4241     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
4242 
4243     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4244     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4245     pStart = PetscMax(vStart, pStart);
4246     pEnd   = PetscMin(vEnd, pEnd);
4247     for (v = pStart; v < pEnd; ++v) {
4248       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
4249       if (dd) {d = dd; break;}
4250     }
4251     ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);
4252   }
4253   PetscFunctionReturn(0);
4254 }
4255 
4256 #undef __FUNCT__
4257 #define __FUNCT__ "DMGetPeriodicity"
4258 /*@C
4259   DMSetPeriodicity - Set the description of mesh periodicity
4260 
4261   Input Parameters:
4262 + dm      - The DM object
4263 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4264 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4265 - bd      - This describes the type of periodicity in each topological dimension
4266 
4267   Level: developer
4268 
4269 .seealso: DMGetPeriodicity()
4270 @*/
4271 PetscErrorCode DMGetPeriodicity(DM dm, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
4272 {
4273   PetscFunctionBegin;
4274   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4275   if (L)       *L       = dm->L;
4276   if (maxCell) *maxCell = dm->maxCell;
4277   if (bd)      *bd      = dm->bdtype;
4278   PetscFunctionReturn(0);
4279 }
4280 
4281 #undef __FUNCT__
4282 #define __FUNCT__ "DMSetPeriodicity"
4283 /*@C
4284   DMSetPeriodicity - Set the description of mesh periodicity
4285 
4286   Input Parameters:
4287 + dm      - The DM object
4288 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4289 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4290 - bd      - This describes the type of periodicity in each topological dimension
4291 
4292   Level: developer
4293 
4294 .seealso: DMGetPeriodicity()
4295 @*/
4296 PetscErrorCode DMSetPeriodicity(DM dm, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
4297 {
4298   PetscInt       dim, d;
4299   PetscErrorCode ierr;
4300 
4301   PetscFunctionBegin;
4302   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4303   PetscValidPointer(L,3);PetscValidPointer(maxCell,2);PetscValidPointer(bd,4);
4304   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
4305   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4306   ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
4307   for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
4308   PetscFunctionReturn(0);
4309 }
4310 
4311 #undef __FUNCT__
4312 #define __FUNCT__ "DMLocatePoints"
4313 /*@
4314   DMLocatePoints - Locate the points in v in the mesh and return an IS of the containing cells
4315 
4316   Not collective
4317 
4318   Input Parameters:
4319 + dm - The DM
4320 - v - The Vec of points
4321 
4322   Output Parameter:
4323 . cells - The local cell numbers for cells which contain the points
4324 
4325   Level: developer
4326 
4327 .keywords: point location, mesh
4328 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4329 @*/
4330 PetscErrorCode DMLocatePoints(DM dm, Vec v, IS *cells)
4331 {
4332   PetscErrorCode ierr;
4333 
4334   PetscFunctionBegin;
4335   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4336   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
4337   PetscValidPointer(cells,3);
4338   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
4339   if (dm->ops->locatepoints) {
4340     ierr = (*dm->ops->locatepoints)(dm,v,cells);CHKERRQ(ierr);
4341   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
4342   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
4343   PetscFunctionReturn(0);
4344 }
4345 
4346 #undef __FUNCT__
4347 #define __FUNCT__ "DMGetOutputDM"
4348 /*@
4349   DMGetOutputDM - Retrieve the DM associated with the layout for output
4350 
4351   Input Parameter:
4352 . dm - The original DM
4353 
4354   Output Parameter:
4355 . odm - The DM which provides the layout for output
4356 
4357   Level: intermediate
4358 
4359 .seealso: VecView(), DMGetDefaultGlobalSection()
4360 @*/
4361 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
4362 {
4363   PetscSection   section;
4364   PetscBool      hasConstraints;
4365   PetscErrorCode ierr;
4366 
4367   PetscFunctionBegin;
4368   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4369   PetscValidPointer(odm,2);
4370   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
4371   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
4372   if (!hasConstraints) {
4373     *odm = dm;
4374     PetscFunctionReturn(0);
4375   }
4376   if (!dm->dmBC) {
4377     PetscSection newSection, gsection;
4378     PetscSF      sf;
4379 
4380     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
4381     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
4382     ierr = DMSetDefaultSection(dm->dmBC, newSection);CHKERRQ(ierr);
4383     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
4384     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
4385     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
4386     ierr = DMSetDefaultGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
4387     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
4388   }
4389   *odm = dm->dmBC;
4390   PetscFunctionReturn(0);
4391 }
4392 
4393 #undef __FUNCT__
4394 #define __FUNCT__ "DMGetOutputSequenceNumber"
4395 /*@
4396   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
4397 
4398   Input Parameter:
4399 . dm - The original DM
4400 
4401   Output Parameters:
4402 + num - The output sequence number
4403 - val - The output sequence value
4404 
4405   Level: intermediate
4406 
4407   Note: This is intended for output that should appear in sequence, for instance
4408   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4409 
4410 .seealso: VecView()
4411 @*/
4412 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
4413 {
4414   PetscFunctionBegin;
4415   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4416   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
4417   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
4418   PetscFunctionReturn(0);
4419 }
4420 
4421 #undef __FUNCT__
4422 #define __FUNCT__ "DMSetOutputSequenceNumber"
4423 /*@
4424   DMSetOutputSequenceNumber - Set the sequence number/value for output
4425 
4426   Input Parameters:
4427 + dm - The original DM
4428 . num - The output sequence number
4429 - val - The output sequence value
4430 
4431   Level: intermediate
4432 
4433   Note: This is intended for output that should appear in sequence, for instance
4434   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4435 
4436 .seealso: VecView()
4437 @*/
4438 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
4439 {
4440   PetscFunctionBegin;
4441   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4442   dm->outputSequenceNum = num;
4443   dm->outputSequenceVal = val;
4444   PetscFunctionReturn(0);
4445 }
4446 
4447 #undef __FUNCT__
4448 #define __FUNCT__ "DMOutputSequenceLoad"
4449 /*@C
4450   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
4451 
4452   Input Parameters:
4453 + dm   - The original DM
4454 . name - The sequence name
4455 - num  - The output sequence number
4456 
4457   Output Parameter:
4458 . val  - The output sequence value
4459 
4460   Level: intermediate
4461 
4462   Note: This is intended for output that should appear in sequence, for instance
4463   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4464 
4465 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
4466 @*/
4467 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
4468 {
4469   PetscBool      ishdf5;
4470   PetscErrorCode ierr;
4471 
4472   PetscFunctionBegin;
4473   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4474   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
4475   PetscValidPointer(val,4);
4476   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
4477   if (ishdf5) {
4478 #if defined(PETSC_HAVE_HDF5)
4479     PetscScalar value;
4480 
4481     ierr = DMSequenceLoad_HDF5(dm, name, num, &value, viewer);CHKERRQ(ierr);
4482     *val = PetscRealPart(value);
4483 #endif
4484   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
4485   PetscFunctionReturn(0);
4486 }
4487 
4488 #undef __FUNCT__
4489 #define __FUNCT__ "DMGetUseNatural"
4490 /*@
4491   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
4492 
4493   Not collective
4494 
4495   Input Parameter:
4496 . dm - The DM
4497 
4498   Output Parameter:
4499 . useNatural - The flag to build the mapping to a natural order during distribution
4500 
4501   Level: beginner
4502 
4503 .seealso: DMSetUseNatural(), DMCreate()
4504 @*/
4505 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
4506 {
4507   PetscFunctionBegin;
4508   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4509   PetscValidPointer(useNatural, 2);
4510   *useNatural = dm->useNatural;
4511   PetscFunctionReturn(0);
4512 }
4513 
4514 #undef __FUNCT__
4515 #define __FUNCT__ "DMSetUseNatural"
4516 /*@
4517   DMSetUseNatural - Set the flag for creating a mapping to the natural order on distribution
4518 
4519   Collective on dm
4520 
4521   Input Parameters:
4522 + dm - The DM
4523 - useNatural - The flag to build the mapping to a natural order during distribution
4524 
4525   Level: beginner
4526 
4527 .seealso: DMGetUseNatural(), DMCreate()
4528 @*/
4529 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
4530 {
4531   PetscFunctionBegin;
4532   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4533   PetscValidLogicalCollectiveInt(dm, useNatural, 2);
4534   dm->useNatural = useNatural;
4535   PetscFunctionReturn(0);
4536 }
4537 
4538 #undef __FUNCT__
4539 #define __FUNCT__
4540 
4541 #undef __FUNCT__
4542 #define __FUNCT__ "DMCreateLabel"
4543 /*@C
4544   DMCreateLabel - Create a label of the given name if it does not already exist
4545 
4546   Not Collective
4547 
4548   Input Parameters:
4549 + dm   - The DM object
4550 - name - The label name
4551 
4552   Level: intermediate
4553 
4554 .keywords: mesh
4555 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4556 @*/
4557 PetscErrorCode DMCreateLabel(DM dm, const char name[])
4558 {
4559   DMLabelLink    next  = dm->labels->next;
4560   PetscBool      flg   = PETSC_FALSE;
4561   PetscErrorCode ierr;
4562 
4563   PetscFunctionBegin;
4564   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4565   PetscValidCharPointer(name, 2);
4566   while (next) {
4567     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
4568     if (flg) break;
4569     next = next->next;
4570   }
4571   if (!flg) {
4572     DMLabelLink tmpLabel;
4573 
4574     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
4575     ierr = DMLabelCreate(name, &tmpLabel->label);CHKERRQ(ierr);
4576     tmpLabel->output = PETSC_TRUE;
4577     tmpLabel->next   = dm->labels->next;
4578     dm->labels->next = tmpLabel;
4579   }
4580   PetscFunctionReturn(0);
4581 }
4582 
4583 #undef __FUNCT__
4584 #define __FUNCT__ "DMGetLabelValue"
4585 /*@C
4586   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
4587 
4588   Not Collective
4589 
4590   Input Parameters:
4591 + dm   - The DM object
4592 . name - The label name
4593 - point - The mesh point
4594 
4595   Output Parameter:
4596 . value - The label value for this point, or -1 if the point is not in the label
4597 
4598   Level: beginner
4599 
4600 .keywords: mesh
4601 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
4602 @*/
4603 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
4604 {
4605   DMLabel        label;
4606   PetscErrorCode ierr;
4607 
4608   PetscFunctionBegin;
4609   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4610   PetscValidCharPointer(name, 2);
4611   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4612   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);CHKERRQ(ierr);
4613   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
4614   PetscFunctionReturn(0);
4615 }
4616 
4617 #undef __FUNCT__
4618 #define __FUNCT__ "DMSetLabelValue"
4619 /*@C
4620   DMSetLabelValue - Add a point to a Sieve Label with given value
4621 
4622   Not Collective
4623 
4624   Input Parameters:
4625 + dm   - The DM object
4626 . name - The label name
4627 . point - The mesh point
4628 - value - The label value for this point
4629 
4630   Output Parameter:
4631 
4632   Level: beginner
4633 
4634 .keywords: mesh
4635 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
4636 @*/
4637 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
4638 {
4639   DMLabel        label;
4640   PetscErrorCode ierr;
4641 
4642   PetscFunctionBegin;
4643   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4644   PetscValidCharPointer(name, 2);
4645   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4646   if (!label) {
4647     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
4648     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4649   }
4650   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
4651   PetscFunctionReturn(0);
4652 }
4653 
4654 #undef __FUNCT__
4655 #define __FUNCT__ "DMClearLabelValue"
4656 /*@C
4657   DMClearLabelValue - Remove a point from a Sieve Label with given value
4658 
4659   Not Collective
4660 
4661   Input Parameters:
4662 + dm   - The DM object
4663 . name - The label name
4664 . point - The mesh point
4665 - value - The label value for this point
4666 
4667   Output Parameter:
4668 
4669   Level: beginner
4670 
4671 .keywords: mesh
4672 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
4673 @*/
4674 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
4675 {
4676   DMLabel        label;
4677   PetscErrorCode ierr;
4678 
4679   PetscFunctionBegin;
4680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4681   PetscValidCharPointer(name, 2);
4682   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4683   if (!label) PetscFunctionReturn(0);
4684   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
4685   PetscFunctionReturn(0);
4686 }
4687 
4688 #undef __FUNCT__
4689 #define __FUNCT__ "DMGetLabelSize"
4690 /*@C
4691   DMGetLabelSize - Get the number of different integer ids in a Label
4692 
4693   Not Collective
4694 
4695   Input Parameters:
4696 + dm   - The DM object
4697 - name - The label name
4698 
4699   Output Parameter:
4700 . size - The number of different integer ids, or 0 if the label does not exist
4701 
4702   Level: beginner
4703 
4704 .keywords: mesh
4705 .seealso: DMLabeGetNumValues(), DMSetLabelValue()
4706 @*/
4707 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
4708 {
4709   DMLabel        label;
4710   PetscErrorCode ierr;
4711 
4712   PetscFunctionBegin;
4713   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4714   PetscValidCharPointer(name, 2);
4715   PetscValidPointer(size, 3);
4716   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4717   *size = 0;
4718   if (!label) PetscFunctionReturn(0);
4719   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
4720   PetscFunctionReturn(0);
4721 }
4722 
4723 #undef __FUNCT__
4724 #define __FUNCT__ "DMGetLabelIdIS"
4725 /*@C
4726   DMGetLabelIdIS - Get the integer ids in a label
4727 
4728   Not Collective
4729 
4730   Input Parameters:
4731 + mesh - The DM object
4732 - name - The label name
4733 
4734   Output Parameter:
4735 . ids - The integer ids, or NULL if the label does not exist
4736 
4737   Level: beginner
4738 
4739 .keywords: mesh
4740 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
4741 @*/
4742 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
4743 {
4744   DMLabel        label;
4745   PetscErrorCode ierr;
4746 
4747   PetscFunctionBegin;
4748   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4749   PetscValidCharPointer(name, 2);
4750   PetscValidPointer(ids, 3);
4751   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4752   *ids = NULL;
4753   if (!label) PetscFunctionReturn(0);
4754   ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
4755   PetscFunctionReturn(0);
4756 }
4757 
4758 #undef __FUNCT__
4759 #define __FUNCT__ "DMGetStratumSize"
4760 /*@C
4761   DMGetStratumSize - Get the number of points in a label stratum
4762 
4763   Not Collective
4764 
4765   Input Parameters:
4766 + dm - The DM object
4767 . name - The label name
4768 - value - The stratum value
4769 
4770   Output Parameter:
4771 . size - The stratum size
4772 
4773   Level: beginner
4774 
4775 .keywords: mesh
4776 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
4777 @*/
4778 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
4779 {
4780   DMLabel        label;
4781   PetscErrorCode ierr;
4782 
4783   PetscFunctionBegin;
4784   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4785   PetscValidCharPointer(name, 2);
4786   PetscValidPointer(size, 4);
4787   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4788   *size = 0;
4789   if (!label) PetscFunctionReturn(0);
4790   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
4791   PetscFunctionReturn(0);
4792 }
4793 
4794 #undef __FUNCT__
4795 #define __FUNCT__ "DMGetStratumIS"
4796 /*@C
4797   DMGetStratumIS - Get the points in a label stratum
4798 
4799   Not Collective
4800 
4801   Input Parameters:
4802 + dm - The DM object
4803 . name - The label name
4804 - value - The stratum value
4805 
4806   Output Parameter:
4807 . points - The stratum points, or NULL if the label does not exist or does not have that value
4808 
4809   Level: beginner
4810 
4811 .keywords: mesh
4812 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
4813 @*/
4814 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
4815 {
4816   DMLabel        label;
4817   PetscErrorCode ierr;
4818 
4819   PetscFunctionBegin;
4820   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4821   PetscValidCharPointer(name, 2);
4822   PetscValidPointer(points, 4);
4823   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4824   *points = NULL;
4825   if (!label) PetscFunctionReturn(0);
4826   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
4827   PetscFunctionReturn(0);
4828 }
4829 
4830 #undef __FUNCT__
4831 #define __FUNCT__ "DMClearLabelStratum"
4832 /*@C
4833   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
4834 
4835   Not Collective
4836 
4837   Input Parameters:
4838 + dm   - The DM object
4839 . name - The label name
4840 - value - The label value for this point
4841 
4842   Output Parameter:
4843 
4844   Level: beginner
4845 
4846 .keywords: mesh
4847 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
4848 @*/
4849 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
4850 {
4851   DMLabel        label;
4852   PetscErrorCode ierr;
4853 
4854   PetscFunctionBegin;
4855   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4856   PetscValidCharPointer(name, 2);
4857   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4858   if (!label) PetscFunctionReturn(0);
4859   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
4860   PetscFunctionReturn(0);
4861 }
4862 
4863 #undef __FUNCT__
4864 #define __FUNCT__ "DMGetNumLabels"
4865 /*@
4866   DMGetNumLabels - Return the number of labels defined by the mesh
4867 
4868   Not Collective
4869 
4870   Input Parameter:
4871 . dm   - The DM object
4872 
4873   Output Parameter:
4874 . numLabels - the number of Labels
4875 
4876   Level: intermediate
4877 
4878 .keywords: mesh
4879 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4880 @*/
4881 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
4882 {
4883   DMLabelLink next = dm->labels->next;
4884   PetscInt  n    = 0;
4885 
4886   PetscFunctionBegin;
4887   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4888   PetscValidPointer(numLabels, 2);
4889   while (next) {++n; next = next->next;}
4890   *numLabels = n;
4891   PetscFunctionReturn(0);
4892 }
4893 
4894 #undef __FUNCT__
4895 #define __FUNCT__ "DMGetLabelName"
4896 /*@C
4897   DMGetLabelName - Return the name of nth label
4898 
4899   Not Collective
4900 
4901   Input Parameters:
4902 + dm - The DM object
4903 - n  - the label number
4904 
4905   Output Parameter:
4906 . name - the label name
4907 
4908   Level: intermediate
4909 
4910 .keywords: mesh
4911 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4912 @*/
4913 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
4914 {
4915   DMLabelLink next = dm->labels->next;
4916   PetscInt  l    = 0;
4917 
4918   PetscFunctionBegin;
4919   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4920   PetscValidPointer(name, 3);
4921   while (next) {
4922     if (l == n) {
4923       *name = next->label->name;
4924       PetscFunctionReturn(0);
4925     }
4926     ++l;
4927     next = next->next;
4928   }
4929   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
4930 }
4931 
4932 #undef __FUNCT__
4933 #define __FUNCT__ "DMHasLabel"
4934 /*@C
4935   DMHasLabel - Determine whether the mesh has a label of a given name
4936 
4937   Not Collective
4938 
4939   Input Parameters:
4940 + dm   - The DM object
4941 - name - The label name
4942 
4943   Output Parameter:
4944 . hasLabel - PETSC_TRUE if the label is present
4945 
4946   Level: intermediate
4947 
4948 .keywords: mesh
4949 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4950 @*/
4951 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
4952 {
4953   DMLabelLink    next = dm->labels->next;
4954   PetscErrorCode ierr;
4955 
4956   PetscFunctionBegin;
4957   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4958   PetscValidCharPointer(name, 2);
4959   PetscValidPointer(hasLabel, 3);
4960   *hasLabel = PETSC_FALSE;
4961   while (next) {
4962     ierr = PetscStrcmp(name, next->label->name, hasLabel);CHKERRQ(ierr);
4963     if (*hasLabel) break;
4964     next = next->next;
4965   }
4966   PetscFunctionReturn(0);
4967 }
4968 
4969 #undef __FUNCT__
4970 #define __FUNCT__ "DMGetLabel"
4971 /*@C
4972   DMGetLabel - Return the label of a given name, or NULL
4973 
4974   Not Collective
4975 
4976   Input Parameters:
4977 + dm   - The DM object
4978 - name - The label name
4979 
4980   Output Parameter:
4981 . label - The DMLabel, or NULL if the label is absent
4982 
4983   Level: intermediate
4984 
4985 .keywords: mesh
4986 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4987 @*/
4988 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
4989 {
4990   DMLabelLink    next = dm->labels->next;
4991   PetscBool      hasLabel;
4992   PetscErrorCode ierr;
4993 
4994   PetscFunctionBegin;
4995   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4996   PetscValidCharPointer(name, 2);
4997   PetscValidPointer(label, 3);
4998   *label = NULL;
4999   while (next) {
5000     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5001     if (hasLabel) {
5002       *label = next->label;
5003       break;
5004     }
5005     next = next->next;
5006   }
5007   PetscFunctionReturn(0);
5008 }
5009 
5010 #undef __FUNCT__
5011 #define __FUNCT__ "DMGetLabelByNum"
5012 /*@C
5013   DMGetLabelByNum - Return the nth label
5014 
5015   Not Collective
5016 
5017   Input Parameters:
5018 + dm - The DM object
5019 - n  - the label number
5020 
5021   Output Parameter:
5022 . label - the label
5023 
5024   Level: intermediate
5025 
5026 .keywords: mesh
5027 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5028 @*/
5029 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
5030 {
5031   DMLabelLink next = dm->labels->next;
5032   PetscInt    l    = 0;
5033 
5034   PetscFunctionBegin;
5035   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5036   PetscValidPointer(label, 3);
5037   while (next) {
5038     if (l == n) {
5039       *label = next->label;
5040       PetscFunctionReturn(0);
5041     }
5042     ++l;
5043     next = next->next;
5044   }
5045   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5046 }
5047 
5048 #undef __FUNCT__
5049 #define __FUNCT__ "DMAddLabel"
5050 /*@C
5051   DMAddLabel - Add the label to this mesh
5052 
5053   Not Collective
5054 
5055   Input Parameters:
5056 + dm   - The DM object
5057 - label - The DMLabel
5058 
5059   Level: developer
5060 
5061 .keywords: mesh
5062 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5063 @*/
5064 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
5065 {
5066   DMLabelLink    tmpLabel;
5067   PetscBool      hasLabel;
5068   PetscErrorCode ierr;
5069 
5070   PetscFunctionBegin;
5071   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5072   ierr = DMHasLabel(dm, label->name, &hasLabel);CHKERRQ(ierr);
5073   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", label->name);
5074   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5075   tmpLabel->label  = label;
5076   tmpLabel->output = PETSC_TRUE;
5077   tmpLabel->next   = dm->labels->next;
5078   dm->labels->next = tmpLabel;
5079   PetscFunctionReturn(0);
5080 }
5081 
5082 #undef __FUNCT__
5083 #define __FUNCT__ "DMRemoveLabel"
5084 /*@C
5085   DMRemoveLabel - Remove the label from this mesh
5086 
5087   Not Collective
5088 
5089   Input Parameters:
5090 + dm   - The DM object
5091 - name - The label name
5092 
5093   Output Parameter:
5094 . label - The DMLabel, or NULL if the label is absent
5095 
5096   Level: developer
5097 
5098 .keywords: mesh
5099 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5100 @*/
5101 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
5102 {
5103   DMLabelLink    next = dm->labels->next;
5104   DMLabelLink    last = NULL;
5105   PetscBool      hasLabel;
5106   PetscErrorCode ierr;
5107 
5108   PetscFunctionBegin;
5109   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5110   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
5111   *label = NULL;
5112   if (!hasLabel) PetscFunctionReturn(0);
5113   while (next) {
5114     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5115     if (hasLabel) {
5116       if (last) last->next       = next->next;
5117       else      dm->labels->next = next->next;
5118       next->next = NULL;
5119       *label     = next->label;
5120       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
5121       if (hasLabel) {
5122         dm->depthLabel = NULL;
5123       }
5124       ierr = PetscFree(next);CHKERRQ(ierr);
5125       break;
5126     }
5127     last = next;
5128     next = next->next;
5129   }
5130   PetscFunctionReturn(0);
5131 }
5132 
5133 #undef __FUNCT__
5134 #define __FUNCT__ "DMGetLabelOutput"
5135 /*@C
5136   DMGetLabelOutput - Get the output flag for a given label
5137 
5138   Not Collective
5139 
5140   Input Parameters:
5141 + dm   - The DM object
5142 - name - The label name
5143 
5144   Output Parameter:
5145 . output - The flag for output
5146 
5147   Level: developer
5148 
5149 .keywords: mesh
5150 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5151 @*/
5152 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
5153 {
5154   DMLabelLink    next = dm->labels->next;
5155   PetscErrorCode ierr;
5156 
5157   PetscFunctionBegin;
5158   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5159   PetscValidPointer(name, 2);
5160   PetscValidPointer(output, 3);
5161   while (next) {
5162     PetscBool flg;
5163 
5164     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5165     if (flg) {*output = next->output; PetscFunctionReturn(0);}
5166     next = next->next;
5167   }
5168   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5169 }
5170 
5171 #undef __FUNCT__
5172 #define __FUNCT__ "DMSetLabelOutput"
5173 /*@C
5174   DMSetLabelOutput - Set the output flag for a given label
5175 
5176   Not Collective
5177 
5178   Input Parameters:
5179 + dm     - The DM object
5180 . name   - The label name
5181 - output - The flag for output
5182 
5183   Level: developer
5184 
5185 .keywords: mesh
5186 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5187 @*/
5188 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
5189 {
5190   DMLabelLink    next = dm->labels->next;
5191   PetscErrorCode ierr;
5192 
5193   PetscFunctionBegin;
5194   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5195   PetscValidPointer(name, 2);
5196   while (next) {
5197     PetscBool flg;
5198 
5199     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5200     if (flg) {next->output = output; PetscFunctionReturn(0);}
5201     next = next->next;
5202   }
5203   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5204 }
5205 
5206 
5207 #undef __FUNCT__
5208 #define __FUNCT__ "DMCopyLabels"
5209 /*@
5210   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
5211 
5212   Collective on DM
5213 
5214   Input Parameter:
5215 . dmA - The DMPlex object with initial labels
5216 
5217   Output Parameter:
5218 . dmB - The DMPlex object with copied labels
5219 
5220   Level: intermediate
5221 
5222   Note: This is typically used when interpolating or otherwise adding to a mesh
5223 
5224 .keywords: mesh
5225 .seealso: DMCopyCoordinates(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
5226 @*/
5227 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
5228 {
5229   PetscInt       numLabels, l;
5230   PetscErrorCode ierr;
5231 
5232   PetscFunctionBegin;
5233   if (dmA == dmB) PetscFunctionReturn(0);
5234   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
5235   for (l = 0; l < numLabels; ++l) {
5236     DMLabel     label, labelNew;
5237     const char *name;
5238     PetscBool   flg;
5239 
5240     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
5241     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
5242     if (flg) continue;
5243     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
5244     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
5245     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
5246   }
5247   PetscFunctionReturn(0);
5248 }
5249 
5250 #undef __FUNCT__
5251 #define __FUNCT__ "DMGetCoarseDM"
5252 /*@
5253   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
5254 
5255   Input Parameter:
5256 . dm - The DM object
5257 
5258   Output Parameter:
5259 . cdm - The coarse DM
5260 
5261   Level: intermediate
5262 
5263 .seealso: DMSetCoarseDM()
5264 @*/
5265 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
5266 {
5267   PetscFunctionBegin;
5268   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5269   PetscValidPointer(cdm, 2);
5270   *cdm = dm->coarseMesh;
5271   PetscFunctionReturn(0);
5272 }
5273 
5274 #undef __FUNCT__
5275 #define __FUNCT__ "DMSetCoarseDM"
5276 /*@
5277   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
5278 
5279   Input Parameters:
5280 + dm - The DM object
5281 - cdm - The coarse DM
5282 
5283   Level: intermediate
5284 
5285 .seealso: DMGetCoarseDM()
5286 @*/
5287 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
5288 {
5289   PetscErrorCode ierr;
5290 
5291   PetscFunctionBegin;
5292   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5293   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
5294   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
5295   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
5296   dm->coarseMesh = cdm;
5297   PetscFunctionReturn(0);
5298 }
5299 
5300