xref: /petsc/src/dm/interface/dm.c (revision a8fb8f2974ee66bb003afa65900fab794a3643ec)
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   dm->coarseMesh            = *dmc;
2213   (*dmc)->ops->creatematrix = dm->ops->creatematrix;
2214   ierr                      = PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);CHKERRQ(ierr);
2215   (*dmc)->ctx               = dm->ctx;
2216   (*dmc)->levelup           = dm->levelup;
2217   (*dmc)->leveldown         = dm->leveldown + 1;
2218   ierr                      = DMSetMatType(*dmc,dm->mattype);CHKERRQ(ierr);
2219   for (link=dm->coarsenhook; link; link=link->next) {
2220     if (link->coarsenhook) {ierr = (*link->coarsenhook)(dm,*dmc,link->ctx);CHKERRQ(ierr);}
2221   }
2222   ierr = PetscLogEventEnd(DM_Coarsen,dm,0,0,0);CHKERRQ(ierr);
2223   PetscFunctionReturn(0);
2224 }
2225 
2226 #undef __FUNCT__
2227 #define __FUNCT__ "DMCoarsenHookAdd"
2228 /*@C
2229    DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
2230 
2231    Logically Collective
2232 
2233    Input Arguments:
2234 +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
2235 .  coarsenhook - function to run when setting up a coarser level
2236 .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
2237 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2238 
2239    Calling sequence of coarsenhook:
2240 $    coarsenhook(DM fine,DM coarse,void *ctx);
2241 
2242 +  fine - fine level DM
2243 .  coarse - coarse level DM to restrict problem to
2244 -  ctx - optional user-defined function context
2245 
2246    Calling sequence for restricthook:
2247 $    restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
2248 
2249 +  fine - fine level DM
2250 .  mrestrict - matrix restricting a fine-level solution to the coarse grid
2251 .  rscale - scaling vector for restriction
2252 .  inject - matrix restricting by injection
2253 .  coarse - coarse level DM to update
2254 -  ctx - optional user-defined function context
2255 
2256    Level: advanced
2257 
2258    Notes:
2259    This function is only needed if auxiliary data needs to be set up on coarse grids.
2260 
2261    If this function is called multiple times, the hooks will be run in the order they are added.
2262 
2263    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2264    extract the finest level information from its context (instead of from the SNES).
2265 
2266    This function is currently not available from Fortran.
2267 
2268 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2269 @*/
2270 PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2271 {
2272   PetscErrorCode    ierr;
2273   DMCoarsenHookLink link,*p;
2274 
2275   PetscFunctionBegin;
2276   PetscValidHeaderSpecific(fine,DM_CLASSID,1);
2277   for (p=&fine->coarsenhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2278   ierr               = PetscMalloc(sizeof(struct _DMCoarsenHookLink),&link);CHKERRQ(ierr);
2279   link->coarsenhook  = coarsenhook;
2280   link->restricthook = restricthook;
2281   link->ctx          = ctx;
2282   link->next         = NULL;
2283   *p                 = link;
2284   PetscFunctionReturn(0);
2285 }
2286 
2287 #undef __FUNCT__
2288 #define __FUNCT__ "DMRestrict"
2289 /*@
2290    DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()
2291 
2292    Collective if any hooks are
2293 
2294    Input Arguments:
2295 +  fine - finer DM to use as a base
2296 .  restrct - restriction matrix, apply using MatRestrict()
2297 .  inject - injection matrix, also use MatRestrict()
2298 -  coarse - coarer DM to update
2299 
2300    Level: developer
2301 
2302 .seealso: DMCoarsenHookAdd(), MatRestrict()
2303 @*/
2304 PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
2305 {
2306   PetscErrorCode    ierr;
2307   DMCoarsenHookLink link;
2308 
2309   PetscFunctionBegin;
2310   for (link=fine->coarsenhook; link; link=link->next) {
2311     if (link->restricthook) {
2312       ierr = (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);CHKERRQ(ierr);
2313     }
2314   }
2315   PetscFunctionReturn(0);
2316 }
2317 
2318 #undef __FUNCT__
2319 #define __FUNCT__ "DMSubDomainHookAdd"
2320 /*@C
2321    DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
2322 
2323    Logically Collective
2324 
2325    Input Arguments:
2326 +  global - global DM
2327 .  ddhook - function to run to pass data to the decomposition DM upon its creation
2328 .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
2329 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2330 
2331 
2332    Calling sequence for ddhook:
2333 $    ddhook(DM global,DM block,void *ctx)
2334 
2335 +  global - global DM
2336 .  block  - block DM
2337 -  ctx - optional user-defined function context
2338 
2339    Calling sequence for restricthook:
2340 $    restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
2341 
2342 +  global - global DM
2343 .  out    - scatter to the outer (with ghost and overlap points) block vector
2344 .  in     - scatter to block vector values only owned locally
2345 .  block  - block DM
2346 -  ctx - optional user-defined function context
2347 
2348    Level: advanced
2349 
2350    Notes:
2351    This function is only needed if auxiliary data needs to be set up on subdomain DMs.
2352 
2353    If this function is called multiple times, the hooks will be run in the order they are added.
2354 
2355    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2356    extract the global information from its context (instead of from the SNES).
2357 
2358    This function is currently not available from Fortran.
2359 
2360 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2361 @*/
2362 PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
2363 {
2364   PetscErrorCode      ierr;
2365   DMSubDomainHookLink link,*p;
2366 
2367   PetscFunctionBegin;
2368   PetscValidHeaderSpecific(global,DM_CLASSID,1);
2369   for (p=&global->subdomainhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2370   ierr               = PetscMalloc(sizeof(struct _DMSubDomainHookLink),&link);CHKERRQ(ierr);
2371   link->restricthook = restricthook;
2372   link->ddhook       = ddhook;
2373   link->ctx          = ctx;
2374   link->next         = NULL;
2375   *p                 = link;
2376   PetscFunctionReturn(0);
2377 }
2378 
2379 #undef __FUNCT__
2380 #define __FUNCT__ "DMSubDomainRestrict"
2381 /*@
2382    DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()
2383 
2384    Collective if any hooks are
2385 
2386    Input Arguments:
2387 +  fine - finer DM to use as a base
2388 .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
2389 .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
2390 -  coarse - coarer DM to update
2391 
2392    Level: developer
2393 
2394 .seealso: DMCoarsenHookAdd(), MatRestrict()
2395 @*/
2396 PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
2397 {
2398   PetscErrorCode      ierr;
2399   DMSubDomainHookLink link;
2400 
2401   PetscFunctionBegin;
2402   for (link=global->subdomainhook; link; link=link->next) {
2403     if (link->restricthook) {
2404       ierr = (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);CHKERRQ(ierr);
2405     }
2406   }
2407   PetscFunctionReturn(0);
2408 }
2409 
2410 #undef __FUNCT__
2411 #define __FUNCT__ "DMGetCoarsenLevel"
2412 /*@
2413     DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.
2414 
2415     Not Collective
2416 
2417     Input Parameter:
2418 .   dm - the DM object
2419 
2420     Output Parameter:
2421 .   level - number of coarsenings
2422 
2423     Level: developer
2424 
2425 .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2426 
2427 @*/
2428 PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
2429 {
2430   PetscFunctionBegin;
2431   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2432   *level = dm->leveldown;
2433   PetscFunctionReturn(0);
2434 }
2435 
2436 
2437 
2438 #undef __FUNCT__
2439 #define __FUNCT__ "DMRefineHierarchy"
2440 /*@C
2441     DMRefineHierarchy - Refines a DM object, all levels at once
2442 
2443     Collective on DM
2444 
2445     Input Parameter:
2446 +   dm - the DM object
2447 -   nlevels - the number of levels of refinement
2448 
2449     Output Parameter:
2450 .   dmf - the refined DM hierarchy
2451 
2452     Level: developer
2453 
2454 .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2455 
2456 @*/
2457 PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
2458 {
2459   PetscErrorCode ierr;
2460 
2461   PetscFunctionBegin;
2462   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2463   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2464   if (nlevels == 0) PetscFunctionReturn(0);
2465   if (dm->ops->refinehierarchy) {
2466     ierr = (*dm->ops->refinehierarchy)(dm,nlevels,dmf);CHKERRQ(ierr);
2467   } else if (dm->ops->refine) {
2468     PetscInt i;
2469 
2470     ierr = DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);CHKERRQ(ierr);
2471     for (i=1; i<nlevels; i++) {
2472       ierr = DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);CHKERRQ(ierr);
2473     }
2474   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
2475   PetscFunctionReturn(0);
2476 }
2477 
2478 #undef __FUNCT__
2479 #define __FUNCT__ "DMCoarsenHierarchy"
2480 /*@C
2481     DMCoarsenHierarchy - Coarsens a DM object, all levels at once
2482 
2483     Collective on DM
2484 
2485     Input Parameter:
2486 +   dm - the DM object
2487 -   nlevels - the number of levels of coarsening
2488 
2489     Output Parameter:
2490 .   dmc - the coarsened DM hierarchy
2491 
2492     Level: developer
2493 
2494 .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2495 
2496 @*/
2497 PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
2498 {
2499   PetscErrorCode ierr;
2500 
2501   PetscFunctionBegin;
2502   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2503   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2504   if (nlevels == 0) PetscFunctionReturn(0);
2505   PetscValidPointer(dmc,3);
2506   if (dm->ops->coarsenhierarchy) {
2507     ierr = (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);CHKERRQ(ierr);
2508   } else if (dm->ops->coarsen) {
2509     PetscInt i;
2510 
2511     ierr = DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);CHKERRQ(ierr);
2512     for (i=1; i<nlevels; i++) {
2513       ierr = DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);CHKERRQ(ierr);
2514     }
2515   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
2516   PetscFunctionReturn(0);
2517 }
2518 
2519 #undef __FUNCT__
2520 #define __FUNCT__ "DMCreateAggregates"
2521 /*@
2522    DMCreateAggregates - Gets the aggregates that map between
2523    grids associated with two DMs.
2524 
2525    Collective on DM
2526 
2527    Input Parameters:
2528 +  dmc - the coarse grid DM
2529 -  dmf - the fine grid DM
2530 
2531    Output Parameters:
2532 .  rest - the restriction matrix (transpose of the projection matrix)
2533 
2534    Level: intermediate
2535 
2536 .keywords: interpolation, restriction, multigrid
2537 
2538 .seealso: DMRefine(), DMCreateInjection(), DMCreateInterpolation()
2539 @*/
2540 PetscErrorCode  DMCreateAggregates(DM dmc, DM dmf, Mat *rest)
2541 {
2542   PetscErrorCode ierr;
2543 
2544   PetscFunctionBegin;
2545   PetscValidHeaderSpecific(dmc,DM_CLASSID,1);
2546   PetscValidHeaderSpecific(dmf,DM_CLASSID,2);
2547   ierr = (*dmc->ops->getaggregates)(dmc, dmf, rest);CHKERRQ(ierr);
2548   PetscFunctionReturn(0);
2549 }
2550 
2551 #undef __FUNCT__
2552 #define __FUNCT__ "DMSetApplicationContextDestroy"
2553 /*@C
2554     DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
2555 
2556     Not Collective
2557 
2558     Input Parameters:
2559 +   dm - the DM object
2560 -   destroy - the destroy function
2561 
2562     Level: intermediate
2563 
2564 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2565 
2566 @*/
2567 PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
2568 {
2569   PetscFunctionBegin;
2570   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2571   dm->ctxdestroy = destroy;
2572   PetscFunctionReturn(0);
2573 }
2574 
2575 #undef __FUNCT__
2576 #define __FUNCT__ "DMSetApplicationContext"
2577 /*@
2578     DMSetApplicationContext - Set a user context into a DM object
2579 
2580     Not Collective
2581 
2582     Input Parameters:
2583 +   dm - the DM object
2584 -   ctx - the user context
2585 
2586     Level: intermediate
2587 
2588 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2589 
2590 @*/
2591 PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
2592 {
2593   PetscFunctionBegin;
2594   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2595   dm->ctx = ctx;
2596   PetscFunctionReturn(0);
2597 }
2598 
2599 #undef __FUNCT__
2600 #define __FUNCT__ "DMGetApplicationContext"
2601 /*@
2602     DMGetApplicationContext - Gets a user context from a DM object
2603 
2604     Not Collective
2605 
2606     Input Parameter:
2607 .   dm - the DM object
2608 
2609     Output Parameter:
2610 .   ctx - the user context
2611 
2612     Level: intermediate
2613 
2614 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2615 
2616 @*/
2617 PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
2618 {
2619   PetscFunctionBegin;
2620   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2621   *(void**)ctx = dm->ctx;
2622   PetscFunctionReturn(0);
2623 }
2624 
2625 #undef __FUNCT__
2626 #define __FUNCT__ "DMSetVariableBounds"
2627 /*@C
2628     DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
2629 
2630     Logically Collective on DM
2631 
2632     Input Parameter:
2633 +   dm - the DM object
2634 -   f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
2635 
2636     Level: intermediate
2637 
2638 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
2639          DMSetJacobian()
2640 
2641 @*/
2642 PetscErrorCode  DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
2643 {
2644   PetscFunctionBegin;
2645   dm->ops->computevariablebounds = f;
2646   PetscFunctionReturn(0);
2647 }
2648 
2649 #undef __FUNCT__
2650 #define __FUNCT__ "DMHasVariableBounds"
2651 /*@
2652     DMHasVariableBounds - does the DM object have a variable bounds function?
2653 
2654     Not Collective
2655 
2656     Input Parameter:
2657 .   dm - the DM object to destroy
2658 
2659     Output Parameter:
2660 .   flg - PETSC_TRUE if the variable bounds function exists
2661 
2662     Level: developer
2663 
2664 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2665 
2666 @*/
2667 PetscErrorCode  DMHasVariableBounds(DM dm,PetscBool  *flg)
2668 {
2669   PetscFunctionBegin;
2670   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
2671   PetscFunctionReturn(0);
2672 }
2673 
2674 #undef __FUNCT__
2675 #define __FUNCT__ "DMComputeVariableBounds"
2676 /*@C
2677     DMComputeVariableBounds - compute variable bounds used by SNESVI.
2678 
2679     Logically Collective on DM
2680 
2681     Input Parameters:
2682 .   dm - the DM object
2683 
2684     Output parameters:
2685 +   xl - lower bound
2686 -   xu - upper bound
2687 
2688     Level: advanced
2689 
2690     Notes: This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
2691 
2692 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2693 
2694 @*/
2695 PetscErrorCode  DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
2696 {
2697   PetscErrorCode ierr;
2698 
2699   PetscFunctionBegin;
2700   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
2701   PetscValidHeaderSpecific(xu,VEC_CLASSID,2);
2702   if (dm->ops->computevariablebounds) {
2703     ierr = (*dm->ops->computevariablebounds)(dm, xl,xu);CHKERRQ(ierr);
2704   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "This DM is incapable of computing variable bounds.");
2705   PetscFunctionReturn(0);
2706 }
2707 
2708 #undef __FUNCT__
2709 #define __FUNCT__ "DMHasColoring"
2710 /*@
2711     DMHasColoring - does the DM object have a method of providing a coloring?
2712 
2713     Not Collective
2714 
2715     Input Parameter:
2716 .   dm - the DM object
2717 
2718     Output Parameter:
2719 .   flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
2720 
2721     Level: developer
2722 
2723 .seealso DMHasFunction(), DMCreateColoring()
2724 
2725 @*/
2726 PetscErrorCode  DMHasColoring(DM dm,PetscBool  *flg)
2727 {
2728   PetscFunctionBegin;
2729   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
2730   PetscFunctionReturn(0);
2731 }
2732 
2733 #undef  __FUNCT__
2734 #define __FUNCT__ "DMSetVec"
2735 /*@C
2736     DMSetVec - set the vector at which to compute residual, Jacobian and VI bounds, if the problem is nonlinear.
2737 
2738     Collective on DM
2739 
2740     Input Parameter:
2741 +   dm - the DM object
2742 -   x - location to compute residual and Jacobian, if NULL is passed to those routines; will be NULL for linear problems.
2743 
2744     Level: developer
2745 
2746 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2747 
2748 @*/
2749 PetscErrorCode  DMSetVec(DM dm,Vec x)
2750 {
2751   PetscErrorCode ierr;
2752 
2753   PetscFunctionBegin;
2754   if (x) {
2755     if (!dm->x) {
2756       ierr = DMCreateGlobalVector(dm,&dm->x);CHKERRQ(ierr);
2757     }
2758     ierr = VecCopy(x,dm->x);CHKERRQ(ierr);
2759   } else if (dm->x) {
2760     ierr = VecDestroy(&dm->x);CHKERRQ(ierr);
2761   }
2762   PetscFunctionReturn(0);
2763 }
2764 
2765 PetscFunctionList DMList              = NULL;
2766 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
2767 
2768 #undef __FUNCT__
2769 #define __FUNCT__ "DMSetType"
2770 /*@C
2771   DMSetType - Builds a DM, for a particular DM implementation.
2772 
2773   Collective on DM
2774 
2775   Input Parameters:
2776 + dm     - The DM object
2777 - method - The name of the DM type
2778 
2779   Options Database Key:
2780 . -dm_type <type> - Sets the DM type; use -help for a list of available types
2781 
2782   Notes:
2783   See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
2784 
2785   Level: intermediate
2786 
2787 .keywords: DM, set, type
2788 .seealso: DMGetType(), DMCreate()
2789 @*/
2790 PetscErrorCode  DMSetType(DM dm, DMType method)
2791 {
2792   PetscErrorCode (*r)(DM);
2793   PetscBool      match;
2794   PetscErrorCode ierr;
2795 
2796   PetscFunctionBegin;
2797   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
2798   ierr = PetscObjectTypeCompare((PetscObject) dm, method, &match);CHKERRQ(ierr);
2799   if (match) PetscFunctionReturn(0);
2800 
2801   ierr = DMRegisterAll();CHKERRQ(ierr);
2802   ierr = PetscFunctionListFind(DMList,method,&r);CHKERRQ(ierr);
2803   if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
2804 
2805   if (dm->ops->destroy) {
2806     ierr             = (*dm->ops->destroy)(dm);CHKERRQ(ierr);
2807     dm->ops->destroy = NULL;
2808   }
2809   ierr = (*r)(dm);CHKERRQ(ierr);
2810   ierr = PetscObjectChangeTypeName((PetscObject)dm,method);CHKERRQ(ierr);
2811   PetscFunctionReturn(0);
2812 }
2813 
2814 #undef __FUNCT__
2815 #define __FUNCT__ "DMGetType"
2816 /*@C
2817   DMGetType - Gets the DM type name (as a string) from the DM.
2818 
2819   Not Collective
2820 
2821   Input Parameter:
2822 . dm  - The DM
2823 
2824   Output Parameter:
2825 . type - The DM type name
2826 
2827   Level: intermediate
2828 
2829 .keywords: DM, get, type, name
2830 .seealso: DMSetType(), DMCreate()
2831 @*/
2832 PetscErrorCode  DMGetType(DM dm, DMType *type)
2833 {
2834   PetscErrorCode ierr;
2835 
2836   PetscFunctionBegin;
2837   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
2838   PetscValidPointer(type,2);
2839   ierr = DMRegisterAll();CHKERRQ(ierr);
2840   *type = ((PetscObject)dm)->type_name;
2841   PetscFunctionReturn(0);
2842 }
2843 
2844 #undef __FUNCT__
2845 #define __FUNCT__ "DMConvert"
2846 /*@C
2847   DMConvert - Converts a DM to another DM, either of the same or different type.
2848 
2849   Collective on DM
2850 
2851   Input Parameters:
2852 + dm - the DM
2853 - newtype - new DM type (use "same" for the same type)
2854 
2855   Output Parameter:
2856 . M - pointer to new DM
2857 
2858   Notes:
2859   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
2860   the MPI communicator of the generated DM is always the same as the communicator
2861   of the input DM.
2862 
2863   Level: intermediate
2864 
2865 .seealso: DMCreate()
2866 @*/
2867 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
2868 {
2869   DM             B;
2870   char           convname[256];
2871   PetscBool      sametype, issame;
2872   PetscErrorCode ierr;
2873 
2874   PetscFunctionBegin;
2875   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2876   PetscValidType(dm,1);
2877   PetscValidPointer(M,3);
2878   ierr = PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);CHKERRQ(ierr);
2879   ierr = PetscStrcmp(newtype, "same", &issame);CHKERRQ(ierr);
2880   {
2881     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
2882 
2883     /*
2884        Order of precedence:
2885        1) See if a specialized converter is known to the current DM.
2886        2) See if a specialized converter is known to the desired DM class.
2887        3) See if a good general converter is registered for the desired class
2888        4) See if a good general converter is known for the current matrix.
2889        5) Use a really basic converter.
2890     */
2891 
2892     /* 1) See if a specialized converter is known to the current DM and the desired class */
2893     ierr = PetscStrcpy(convname,"DMConvert_");CHKERRQ(ierr);
2894     ierr = PetscStrcat(convname,((PetscObject) dm)->type_name);CHKERRQ(ierr);
2895     ierr = PetscStrcat(convname,"_");CHKERRQ(ierr);
2896     ierr = PetscStrcat(convname,newtype);CHKERRQ(ierr);
2897     ierr = PetscStrcat(convname,"_C");CHKERRQ(ierr);
2898     ierr = PetscObjectQueryFunction((PetscObject)dm,convname,&conv);CHKERRQ(ierr);
2899     if (conv) goto foundconv;
2900 
2901     /* 2)  See if a specialized converter is known to the desired DM class. */
2902     ierr = DMCreate(PetscObjectComm((PetscObject)dm), &B);CHKERRQ(ierr);
2903     ierr = DMSetType(B, newtype);CHKERRQ(ierr);
2904     ierr = PetscStrcpy(convname,"DMConvert_");CHKERRQ(ierr);
2905     ierr = PetscStrcat(convname,((PetscObject) dm)->type_name);CHKERRQ(ierr);
2906     ierr = PetscStrcat(convname,"_");CHKERRQ(ierr);
2907     ierr = PetscStrcat(convname,newtype);CHKERRQ(ierr);
2908     ierr = PetscStrcat(convname,"_C");CHKERRQ(ierr);
2909     ierr = PetscObjectQueryFunction((PetscObject)B,convname,&conv);CHKERRQ(ierr);
2910     if (conv) {
2911       ierr = DMDestroy(&B);CHKERRQ(ierr);
2912       goto foundconv;
2913     }
2914 
2915 #if 0
2916     /* 3) See if a good general converter is registered for the desired class */
2917     conv = B->ops->convertfrom;
2918     ierr = DMDestroy(&B);CHKERRQ(ierr);
2919     if (conv) goto foundconv;
2920 
2921     /* 4) See if a good general converter is known for the current matrix */
2922     if (dm->ops->convert) {
2923       conv = dm->ops->convert;
2924     }
2925     if (conv) goto foundconv;
2926 #endif
2927 
2928     /* 5) Use a really basic converter. */
2929     SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
2930 
2931 foundconv:
2932     ierr = PetscLogEventBegin(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
2933     ierr = (*conv)(dm,newtype,M);CHKERRQ(ierr);
2934     ierr = PetscLogEventEnd(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
2935   }
2936   ierr = PetscObjectStateIncrease((PetscObject) *M);CHKERRQ(ierr);
2937   PetscFunctionReturn(0);
2938 }
2939 
2940 /*--------------------------------------------------------------------------------------------------------------------*/
2941 
2942 #undef __FUNCT__
2943 #define __FUNCT__ "DMRegister"
2944 /*@C
2945   DMRegister -  Adds a new DM component implementation
2946 
2947   Not Collective
2948 
2949   Input Parameters:
2950 + name        - The name of a new user-defined creation routine
2951 - create_func - The creation routine itself
2952 
2953   Notes:
2954   DMRegister() may be called multiple times to add several user-defined DMs
2955 
2956 
2957   Sample usage:
2958 .vb
2959     DMRegister("my_da", MyDMCreate);
2960 .ve
2961 
2962   Then, your DM type can be chosen with the procedural interface via
2963 .vb
2964     DMCreate(MPI_Comm, DM *);
2965     DMSetType(DM,"my_da");
2966 .ve
2967    or at runtime via the option
2968 .vb
2969     -da_type my_da
2970 .ve
2971 
2972   Level: advanced
2973 
2974 .keywords: DM, register
2975 .seealso: DMRegisterAll(), DMRegisterDestroy()
2976 
2977 @*/
2978 PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
2979 {
2980   PetscErrorCode ierr;
2981 
2982   PetscFunctionBegin;
2983   ierr = PetscFunctionListAdd(&DMList,sname,function);CHKERRQ(ierr);
2984   PetscFunctionReturn(0);
2985 }
2986 
2987 #undef __FUNCT__
2988 #define __FUNCT__ "DMLoad"
2989 /*@C
2990   DMLoad - Loads a DM that has been stored in binary  with DMView().
2991 
2992   Collective on PetscViewer
2993 
2994   Input Parameters:
2995 + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
2996            some related function before a call to DMLoad().
2997 - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
2998            HDF5 file viewer, obtained from PetscViewerHDF5Open()
2999 
3000    Level: intermediate
3001 
3002   Notes:
3003    The type is determined by the data in the file, any type set into the DM before this call is ignored.
3004 
3005   Notes for advanced users:
3006   Most users should not need to know the details of the binary storage
3007   format, since DMLoad() and DMView() completely hide these details.
3008   But for anyone who's interested, the standard binary matrix storage
3009   format is
3010 .vb
3011      has not yet been determined
3012 .ve
3013 
3014 .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3015 @*/
3016 PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3017 {
3018   PetscBool      isbinary, ishdf5;
3019   PetscErrorCode ierr;
3020 
3021   PetscFunctionBegin;
3022   PetscValidHeaderSpecific(newdm,DM_CLASSID,1);
3023   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
3024   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
3025   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
3026   if (isbinary) {
3027     PetscInt classid;
3028     char     type[256];
3029 
3030     ierr = PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);CHKERRQ(ierr);
3031     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3032     ierr = PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);CHKERRQ(ierr);
3033     ierr = DMSetType(newdm, type);CHKERRQ(ierr);
3034     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
3035   } else if (ishdf5) {
3036     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
3037   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3038   PetscFunctionReturn(0);
3039 }
3040 
3041 /******************************** FEM Support **********************************/
3042 
3043 #undef __FUNCT__
3044 #define __FUNCT__ "DMPrintCellVector"
3045 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3046 {
3047   PetscInt       f;
3048   PetscErrorCode ierr;
3049 
3050   PetscFunctionBegin;
3051   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3052   for (f = 0; f < len; ++f) {
3053     ierr = PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));CHKERRQ(ierr);
3054   }
3055   PetscFunctionReturn(0);
3056 }
3057 
3058 #undef __FUNCT__
3059 #define __FUNCT__ "DMPrintCellMatrix"
3060 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
3061 {
3062   PetscInt       f, g;
3063   PetscErrorCode ierr;
3064 
3065   PetscFunctionBegin;
3066   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3067   for (f = 0; f < rows; ++f) {
3068     ierr = PetscPrintf(PETSC_COMM_SELF, "  |");CHKERRQ(ierr);
3069     for (g = 0; g < cols; ++g) {
3070       ierr = PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));CHKERRQ(ierr);
3071     }
3072     ierr = PetscPrintf(PETSC_COMM_SELF, " |\n");CHKERRQ(ierr);
3073   }
3074   PetscFunctionReturn(0);
3075 }
3076 
3077 #undef __FUNCT__
3078 #define __FUNCT__ "DMPrintLocalVec"
3079 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
3080 {
3081   PetscMPIInt    rank, numProcs;
3082   PetscInt       p;
3083   PetscErrorCode ierr;
3084 
3085   PetscFunctionBegin;
3086   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
3087   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);CHKERRQ(ierr);
3088   ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "%s:\n", name);CHKERRQ(ierr);
3089   for (p = 0; p < numProcs; ++p) {
3090     if (p == rank) {
3091       Vec x;
3092 
3093       ierr = VecDuplicate(X, &x);CHKERRQ(ierr);
3094       ierr = VecCopy(X, x);CHKERRQ(ierr);
3095       ierr = VecChop(x, tol);CHKERRQ(ierr);
3096       ierr = VecView(x, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
3097       ierr = VecDestroy(&x);CHKERRQ(ierr);
3098       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
3099     }
3100     ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
3101   }
3102   PetscFunctionReturn(0);
3103 }
3104 
3105 #undef __FUNCT__
3106 #define __FUNCT__ "DMGetDefaultSection"
3107 /*@
3108   DMGetDefaultSection - Get the PetscSection encoding the local data layout for the DM.
3109 
3110   Input Parameter:
3111 . dm - The DM
3112 
3113   Output Parameter:
3114 . section - The PetscSection
3115 
3116   Level: intermediate
3117 
3118   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3119 
3120 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3121 @*/
3122 PetscErrorCode DMGetDefaultSection(DM dm, PetscSection *section)
3123 {
3124   PetscErrorCode ierr;
3125 
3126   PetscFunctionBegin;
3127   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3128   PetscValidPointer(section, 2);
3129   if (!dm->defaultSection && dm->ops->createdefaultsection) {
3130     ierr = (*dm->ops->createdefaultsection)(dm);CHKERRQ(ierr);
3131     ierr = PetscObjectViewFromOptions((PetscObject) dm->defaultSection, NULL, "-dm_petscsection_view");CHKERRQ(ierr);
3132   }
3133   *section = dm->defaultSection;
3134   PetscFunctionReturn(0);
3135 }
3136 
3137 #undef __FUNCT__
3138 #define __FUNCT__ "DMSetDefaultSection"
3139 /*@
3140   DMSetDefaultSection - Set the PetscSection encoding the local data layout for the DM.
3141 
3142   Input Parameters:
3143 + dm - The DM
3144 - section - The PetscSection
3145 
3146   Level: intermediate
3147 
3148   Note: Any existing Section will be destroyed
3149 
3150 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3151 @*/
3152 PetscErrorCode DMSetDefaultSection(DM dm, PetscSection section)
3153 {
3154   PetscInt       numFields = 0;
3155   PetscInt       f;
3156   PetscErrorCode ierr;
3157 
3158   PetscFunctionBegin;
3159   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3160   if (section) {
3161     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3162     ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3163   }
3164   ierr = PetscSectionDestroy(&dm->defaultSection);CHKERRQ(ierr);
3165   dm->defaultSection = section;
3166   if (section) {ierr = PetscSectionGetNumFields(dm->defaultSection, &numFields);CHKERRQ(ierr);}
3167   if (numFields) {
3168     ierr = DMSetNumFields(dm, numFields);CHKERRQ(ierr);
3169     for (f = 0; f < numFields; ++f) {
3170       PetscObject disc;
3171       const char *name;
3172 
3173       ierr = PetscSectionGetFieldName(dm->defaultSection, f, &name);CHKERRQ(ierr);
3174       ierr = DMGetField(dm, f, &disc);CHKERRQ(ierr);
3175       ierr = PetscObjectSetName(disc, name);CHKERRQ(ierr);
3176     }
3177   }
3178   /* The global section will be rebuilt in the next call to DMGetDefaultGlobalSection(). */
3179   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3180   PetscFunctionReturn(0);
3181 }
3182 
3183 #undef __FUNCT__
3184 #define __FUNCT__ "DMGetDefaultConstraints"
3185 /*@
3186   DMGetDefaultConstraints - Get the PetscSection and Mat the specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
3187 
3188   not collective
3189 
3190   Input Parameter:
3191 . dm - The DM
3192 
3193   Output Parameter:
3194 + 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.
3195 - 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.
3196 
3197   Level: advanced
3198 
3199   Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
3200 
3201 .seealso: DMSetDefaultConstraints()
3202 @*/
3203 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
3204 {
3205   PetscErrorCode ierr;
3206 
3207   PetscFunctionBegin;
3208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3209   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {ierr = (*dm->ops->createdefaultconstraints)(dm);CHKERRQ(ierr);}
3210   if (section) {*section = dm->defaultConstraintSection;}
3211   if (mat) {*mat = dm->defaultConstraintMat;}
3212   PetscFunctionReturn(0);
3213 }
3214 
3215 #undef __FUNCT__
3216 #define __FUNCT__ "DMSetDefaultConstraints"
3217 /*@
3218   DMSetDefaultConstraints - Set the PetscSection and Mat the specify the local constraint interpolation.
3219 
3220   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().
3221 
3222   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.
3223 
3224   collective on dm
3225 
3226   Input Parameters:
3227 + dm - The DM
3228 + 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).
3229 - 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).
3230 
3231   Level: advanced
3232 
3233   Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
3234 
3235 .seealso: DMGetDefaultConstraints()
3236 @*/
3237 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
3238 {
3239   PetscMPIInt result;
3240   PetscErrorCode ierr;
3241 
3242   PetscFunctionBegin;
3243   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3244   if (section) {
3245     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3246     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);CHKERRQ(ierr);
3247     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
3248   }
3249   if (mat) {
3250     PetscValidHeaderSpecific(mat,MAT_CLASSID,3);
3251     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);CHKERRQ(ierr);
3252     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
3253   }
3254   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3255   ierr = PetscSectionDestroy(&dm->defaultConstraintSection);CHKERRQ(ierr);
3256   dm->defaultConstraintSection = section;
3257   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
3258   ierr = MatDestroy(&dm->defaultConstraintMat);CHKERRQ(ierr);
3259   dm->defaultConstraintMat = mat;
3260   PetscFunctionReturn(0);
3261 }
3262 
3263 #ifdef PETSC_USE_DEBUG
3264 #undef __FUNCT__
3265 #define __FUNCT__ "DMDefaultSectionCheckConsistency_Internal"
3266 /*
3267   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
3268 
3269   Input Parameters:
3270 + dm - The DM
3271 . localSection - PetscSection describing the local data layout
3272 - globalSection - PetscSection describing the global data layout
3273 
3274   Level: intermediate
3275 
3276 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3277 */
3278 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
3279 {
3280   MPI_Comm        comm;
3281   PetscLayout     layout;
3282   const PetscInt *ranges;
3283   PetscInt        pStart, pEnd, p, nroots;
3284   PetscMPIInt     size, rank;
3285   PetscBool       valid = PETSC_TRUE, gvalid;
3286   PetscErrorCode  ierr;
3287 
3288   PetscFunctionBegin;
3289   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3290   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3291   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3292   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3293   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3294   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3295   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3296   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3297   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3298   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3299   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3300   for (p = pStart; p < pEnd; ++p) {
3301     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;
3302 
3303     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3304     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3305     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3306     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3307     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3308     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3309     if (!gdof) continue; /* Censored point */
3310     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;}
3311     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;}
3312     if (gdof < 0) {
3313       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3314       for (d = 0; d < gsize; ++d) {
3315         PetscInt offset = -(goff+1) + d, r;
3316 
3317         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3318         if (r < 0) r = -(r+2);
3319         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;}
3320       }
3321     }
3322   }
3323   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3324   ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
3325   ierr = MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);CHKERRQ(ierr);
3326   if (!gvalid) {
3327     ierr = DMView(dm, NULL);CHKERRQ(ierr);
3328     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
3329   }
3330   PetscFunctionReturn(0);
3331 }
3332 #endif
3333 
3334 #undef __FUNCT__
3335 #define __FUNCT__ "DMGetDefaultGlobalSection"
3336 /*@
3337   DMGetDefaultGlobalSection - Get the PetscSection encoding the global data layout for the DM.
3338 
3339   Collective on DM
3340 
3341   Input Parameter:
3342 . dm - The DM
3343 
3344   Output Parameter:
3345 . section - The PetscSection
3346 
3347   Level: intermediate
3348 
3349   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3350 
3351 .seealso: DMSetDefaultSection(), DMGetDefaultSection()
3352 @*/
3353 PetscErrorCode DMGetDefaultGlobalSection(DM dm, PetscSection *section)
3354 {
3355   PetscErrorCode ierr;
3356 
3357   PetscFunctionBegin;
3358   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3359   PetscValidPointer(section, 2);
3360   if (!dm->defaultGlobalSection) {
3361     PetscSection s;
3362 
3363     ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
3364     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
3365     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSF in order to create a global PetscSection");
3366     ierr = PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->defaultGlobalSection);CHKERRQ(ierr);
3367     ierr = PetscLayoutDestroy(&dm->map);CHKERRQ(ierr);
3368     ierr = PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->defaultGlobalSection, &dm->map);CHKERRQ(ierr);
3369     ierr = PetscSectionViewFromOptions(dm->defaultGlobalSection, NULL, "-global_section_view");CHKERRQ(ierr);
3370   }
3371   *section = dm->defaultGlobalSection;
3372   PetscFunctionReturn(0);
3373 }
3374 
3375 #undef __FUNCT__
3376 #define __FUNCT__ "DMSetDefaultGlobalSection"
3377 /*@
3378   DMSetDefaultGlobalSection - Set the PetscSection encoding the global data layout for the DM.
3379 
3380   Input Parameters:
3381 + dm - The DM
3382 - section - The PetscSection, or NULL
3383 
3384   Level: intermediate
3385 
3386   Note: Any existing Section will be destroyed
3387 
3388 .seealso: DMGetDefaultGlobalSection(), DMSetDefaultSection()
3389 @*/
3390 PetscErrorCode DMSetDefaultGlobalSection(DM dm, PetscSection section)
3391 {
3392   PetscErrorCode ierr;
3393 
3394   PetscFunctionBegin;
3395   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3396   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3397   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3398   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3399   dm->defaultGlobalSection = section;
3400 #ifdef PETSC_USE_DEBUG
3401   if (section) {ierr = DMDefaultSectionCheckConsistency_Internal(dm, dm->defaultSection, section);CHKERRQ(ierr);}
3402 #endif
3403   PetscFunctionReturn(0);
3404 }
3405 
3406 #undef __FUNCT__
3407 #define __FUNCT__ "DMGetDefaultSF"
3408 /*@
3409   DMGetDefaultSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
3410   it is created from the default PetscSection layouts in the DM.
3411 
3412   Input Parameter:
3413 . dm - The DM
3414 
3415   Output Parameter:
3416 . sf - The PetscSF
3417 
3418   Level: intermediate
3419 
3420   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3421 
3422 .seealso: DMSetDefaultSF(), DMCreateDefaultSF()
3423 @*/
3424 PetscErrorCode DMGetDefaultSF(DM dm, PetscSF *sf)
3425 {
3426   PetscInt       nroots;
3427   PetscErrorCode ierr;
3428 
3429   PetscFunctionBegin;
3430   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3431   PetscValidPointer(sf, 2);
3432   ierr = PetscSFGetGraph(dm->defaultSF, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
3433   if (nroots < 0) {
3434     PetscSection section, gSection;
3435 
3436     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
3437     if (section) {
3438       ierr = DMGetDefaultGlobalSection(dm, &gSection);CHKERRQ(ierr);
3439       ierr = DMCreateDefaultSF(dm, section, gSection);CHKERRQ(ierr);
3440     } else {
3441       *sf = NULL;
3442       PetscFunctionReturn(0);
3443     }
3444   }
3445   *sf = dm->defaultSF;
3446   PetscFunctionReturn(0);
3447 }
3448 
3449 #undef __FUNCT__
3450 #define __FUNCT__ "DMSetDefaultSF"
3451 /*@
3452   DMSetDefaultSF - Set the PetscSF encoding the parallel dof overlap for the DM
3453 
3454   Input Parameters:
3455 + dm - The DM
3456 - sf - The PetscSF
3457 
3458   Level: intermediate
3459 
3460   Note: Any previous SF is destroyed
3461 
3462 .seealso: DMGetDefaultSF(), DMCreateDefaultSF()
3463 @*/
3464 PetscErrorCode DMSetDefaultSF(DM dm, PetscSF sf)
3465 {
3466   PetscErrorCode ierr;
3467 
3468   PetscFunctionBegin;
3469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3470   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
3471   ierr          = PetscSFDestroy(&dm->defaultSF);CHKERRQ(ierr);
3472   dm->defaultSF = sf;
3473   PetscFunctionReturn(0);
3474 }
3475 
3476 #undef __FUNCT__
3477 #define __FUNCT__ "DMCreateDefaultSF"
3478 /*@C
3479   DMCreateDefaultSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
3480   describing the data layout.
3481 
3482   Input Parameters:
3483 + dm - The DM
3484 . localSection - PetscSection describing the local data layout
3485 - globalSection - PetscSection describing the global data layout
3486 
3487   Level: intermediate
3488 
3489 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3490 @*/
3491 PetscErrorCode DMCreateDefaultSF(DM dm, PetscSection localSection, PetscSection globalSection)
3492 {
3493   MPI_Comm       comm;
3494   PetscLayout    layout;
3495   const PetscInt *ranges;
3496   PetscInt       *local;
3497   PetscSFNode    *remote;
3498   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
3499   PetscMPIInt    size, rank;
3500   PetscErrorCode ierr;
3501 
3502   PetscFunctionBegin;
3503   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3504   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3505   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3506   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3507   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3508   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3509   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3510   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3511   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3512   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3513   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3514   for (p = pStart; p < pEnd; ++p) {
3515     PetscInt gdof, gcdof;
3516 
3517     ierr     = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3518     ierr     = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3519     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));
3520     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3521   }
3522   ierr = PetscMalloc1(nleaves, &local);CHKERRQ(ierr);
3523   ierr = PetscMalloc1(nleaves, &remote);CHKERRQ(ierr);
3524   for (p = pStart, l = 0; p < pEnd; ++p) {
3525     const PetscInt *cind;
3526     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
3527 
3528     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3529     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3530     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3531     ierr = PetscSectionGetConstraintIndices(localSection, p, &cind);CHKERRQ(ierr);
3532     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3533     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3534     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3535     if (!gdof) continue; /* Censored point */
3536     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3537     if (gsize != dof-cdof) {
3538       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);
3539       cdof = 0; /* Ignore constraints */
3540     }
3541     for (d = 0, c = 0; d < dof; ++d) {
3542       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
3543       local[l+d-c] = off+d;
3544     }
3545     if (gdof < 0) {
3546       for (d = 0; d < gsize; ++d, ++l) {
3547         PetscInt offset = -(goff+1) + d, r;
3548 
3549         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3550         if (r < 0) r = -(r+2);
3551         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);
3552         remote[l].rank  = r;
3553         remote[l].index = offset - ranges[r];
3554       }
3555     } else {
3556       for (d = 0; d < gsize; ++d, ++l) {
3557         remote[l].rank  = rank;
3558         remote[l].index = goff+d - ranges[rank];
3559       }
3560     }
3561   }
3562   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
3563   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3564   ierr = PetscSFSetGraph(dm->defaultSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
3565   PetscFunctionReturn(0);
3566 }
3567 
3568 #undef __FUNCT__
3569 #define __FUNCT__ "DMGetPointSF"
3570 /*@
3571   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
3572 
3573   Input Parameter:
3574 . dm - The DM
3575 
3576   Output Parameter:
3577 . sf - The PetscSF
3578 
3579   Level: intermediate
3580 
3581   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3582 
3583 .seealso: DMSetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3584 @*/
3585 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
3586 {
3587   PetscFunctionBegin;
3588   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3589   PetscValidPointer(sf, 2);
3590   *sf = dm->sf;
3591   PetscFunctionReturn(0);
3592 }
3593 
3594 #undef __FUNCT__
3595 #define __FUNCT__ "DMSetPointSF"
3596 /*@
3597   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
3598 
3599   Input Parameters:
3600 + dm - The DM
3601 - sf - The PetscSF
3602 
3603   Level: intermediate
3604 
3605 .seealso: DMGetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3606 @*/
3607 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
3608 {
3609   PetscErrorCode ierr;
3610 
3611   PetscFunctionBegin;
3612   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3613   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
3614   ierr   = PetscSFDestroy(&dm->sf);CHKERRQ(ierr);
3615   ierr   = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
3616   dm->sf = sf;
3617   PetscFunctionReturn(0);
3618 }
3619 
3620 #undef __FUNCT__
3621 #define __FUNCT__ "DMGetDS"
3622 /*@
3623   DMGetDS - Get the PetscDS
3624 
3625   Input Parameter:
3626 . dm - The DM
3627 
3628   Output Parameter:
3629 . prob - The PetscDS
3630 
3631   Level: developer
3632 
3633 .seealso: DMSetDS()
3634 @*/
3635 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
3636 {
3637   PetscFunctionBegin;
3638   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3639   PetscValidPointer(prob, 2);
3640   *prob = dm->prob;
3641   PetscFunctionReturn(0);
3642 }
3643 
3644 #undef __FUNCT__
3645 #define __FUNCT__ "DMSetDS"
3646 /*@
3647   DMSetDS - Set the PetscDS
3648 
3649   Input Parameters:
3650 + dm - The DM
3651 - prob - The PetscDS
3652 
3653   Level: developer
3654 
3655 .seealso: DMGetDS()
3656 @*/
3657 PetscErrorCode DMSetDS(DM dm, PetscDS prob)
3658 {
3659   PetscErrorCode ierr;
3660 
3661   PetscFunctionBegin;
3662   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3663   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 2);
3664   ierr = PetscDSDestroy(&dm->prob);CHKERRQ(ierr);
3665   dm->prob = prob;
3666   ierr = PetscObjectReference((PetscObject) dm->prob);CHKERRQ(ierr);
3667   PetscFunctionReturn(0);
3668 }
3669 
3670 #undef __FUNCT__
3671 #define __FUNCT__ "DMGetNumFields"
3672 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
3673 {
3674   PetscErrorCode ierr;
3675 
3676   PetscFunctionBegin;
3677   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3678   ierr = PetscDSGetNumFields(dm->prob, numFields);CHKERRQ(ierr);
3679   PetscFunctionReturn(0);
3680 }
3681 
3682 #undef __FUNCT__
3683 #define __FUNCT__ "DMSetNumFields"
3684 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
3685 {
3686   PetscInt       Nf, f;
3687   PetscErrorCode ierr;
3688 
3689   PetscFunctionBegin;
3690   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3691   ierr = PetscDSGetNumFields(dm->prob, &Nf);CHKERRQ(ierr);
3692   for (f = Nf; f < numFields; ++f) {
3693     PetscContainer obj;
3694 
3695     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
3696     ierr = PetscDSSetDiscretization(dm->prob, f, (PetscObject) obj);CHKERRQ(ierr);
3697     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
3698   }
3699   PetscFunctionReturn(0);
3700 }
3701 
3702 #undef __FUNCT__
3703 #define __FUNCT__ "DMGetField"
3704 /*@
3705   DMGetField - Return the discretization object for a given DM field
3706 
3707   Not collective
3708 
3709   Input Parameters:
3710 + dm - The DM
3711 - f  - The field number
3712 
3713   Output Parameter:
3714 . field - The discretization object
3715 
3716   Level: developer
3717 
3718 .seealso: DMSetField()
3719 @*/
3720 PetscErrorCode DMGetField(DM dm, PetscInt f, PetscObject *field)
3721 {
3722   PetscErrorCode ierr;
3723 
3724   PetscFunctionBegin;
3725   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3726   ierr = PetscDSGetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3727   PetscFunctionReturn(0);
3728 }
3729 
3730 #undef __FUNCT__
3731 #define __FUNCT__ "DMSetField"
3732 /*@
3733   DMSetField - Set the discretization object for a given DM field
3734 
3735   Logically collective on DM
3736 
3737   Input Parameters:
3738 + dm - The DM
3739 . f  - The field number
3740 - field - The discretization object
3741 
3742   Level: developer
3743 
3744 .seealso: DMGetField()
3745 @*/
3746 PetscErrorCode DMSetField(DM dm, PetscInt f, PetscObject field)
3747 {
3748   PetscErrorCode ierr;
3749 
3750   PetscFunctionBegin;
3751   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3752   ierr = PetscDSSetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3753   PetscFunctionReturn(0);
3754 }
3755 
3756 #undef __FUNCT__
3757 #define __FUNCT__ "DMRestrictHook_Coordinates"
3758 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
3759 {
3760   DM dm_coord,dmc_coord;
3761   PetscErrorCode ierr;
3762   Vec coords,ccoords;
3763   Mat inject;
3764   PetscFunctionBegin;
3765   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3766   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
3767   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3768   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
3769   if (coords && !ccoords) {
3770     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
3771     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
3772     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
3773     ierr = MatDestroy(&inject);CHKERRQ(ierr);
3774     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
3775     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3776   }
3777   PetscFunctionReturn(0);
3778 }
3779 
3780 #undef __FUNCT__
3781 #define __FUNCT__ "DMSubDomainHook_Coordinates"
3782 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
3783 {
3784   DM dm_coord,subdm_coord;
3785   PetscErrorCode ierr;
3786   Vec coords,ccoords,clcoords;
3787   VecScatter *scat_i,*scat_g;
3788   PetscFunctionBegin;
3789   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3790   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
3791   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3792   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
3793   if (coords && !ccoords) {
3794     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
3795     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
3796     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
3797     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
3798     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3799     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3800     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3801     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3802     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
3803     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
3804     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
3805     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
3806     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3807     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
3808     ierr = PetscFree(scat_i);CHKERRQ(ierr);
3809     ierr = PetscFree(scat_g);CHKERRQ(ierr);
3810   }
3811   PetscFunctionReturn(0);
3812 }
3813 
3814 #undef __FUNCT__
3815 #define __FUNCT__ "DMGetDimension"
3816 /*@
3817   DMGetDimension - Return the topological dimension of the DM
3818 
3819   Not collective
3820 
3821   Input Parameter:
3822 . dm - The DM
3823 
3824   Output Parameter:
3825 . dim - The topological dimension
3826 
3827   Level: beginner
3828 
3829 .seealso: DMSetDimension(), DMCreate()
3830 @*/
3831 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
3832 {
3833   PetscFunctionBegin;
3834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3835   PetscValidPointer(dim, 2);
3836   *dim = dm->dim;
3837   PetscFunctionReturn(0);
3838 }
3839 
3840 #undef __FUNCT__
3841 #define __FUNCT__ "DMSetDimension"
3842 /*@
3843   DMSetDimension - Set the topological dimension of the DM
3844 
3845   Collective on dm
3846 
3847   Input Parameters:
3848 + dm - The DM
3849 - dim - The topological dimension
3850 
3851   Level: beginner
3852 
3853 .seealso: DMGetDimension(), DMCreate()
3854 @*/
3855 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
3856 {
3857   PetscFunctionBegin;
3858   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3859   PetscValidLogicalCollectiveInt(dm, dim, 2);
3860   dm->dim = dim;
3861   PetscFunctionReturn(0);
3862 }
3863 
3864 #undef __FUNCT__
3865 #define __FUNCT__ "DMGetDimPoints"
3866 /*@
3867   DMGetDimPoints - Get the half-open interval for all points of a given dimension
3868 
3869   Collective on DM
3870 
3871   Input Parameters:
3872 + dm - the DM
3873 - dim - the dimension
3874 
3875   Output Parameters:
3876 + pStart - The first point of the given dimension
3877 . pEnd - The first point following points of the given dimension
3878 
3879   Note:
3880   The points are vertices in the Hasse diagram encoding the topology. This is explained in
3881   http://arxiv.org/abs/0908.4427. If not points exist of this dimension in the storage scheme,
3882   then the interval is empty.
3883 
3884   Level: intermediate
3885 
3886 .keywords: point, Hasse Diagram, dimension
3887 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
3888 @*/
3889 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
3890 {
3891   PetscInt       d;
3892   PetscErrorCode ierr;
3893 
3894   PetscFunctionBegin;
3895   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3896   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
3897   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
3898   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
3899   PetscFunctionReturn(0);
3900 }
3901 
3902 #undef __FUNCT__
3903 #define __FUNCT__ "DMSetCoordinates"
3904 /*@
3905   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
3906 
3907   Collective on DM
3908 
3909   Input Parameters:
3910 + dm - the DM
3911 - c - coordinate vector
3912 
3913   Note:
3914   The coordinates do include those for ghost points, which are in the local vector
3915 
3916   Level: intermediate
3917 
3918 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3919 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLoca(), DMGetCoordinateDM()
3920 @*/
3921 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
3922 {
3923   PetscErrorCode ierr;
3924 
3925   PetscFunctionBegin;
3926   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3927   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3928   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3929   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3930   dm->coordinates = c;
3931   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3932   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3933   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3934   PetscFunctionReturn(0);
3935 }
3936 
3937 #undef __FUNCT__
3938 #define __FUNCT__ "DMSetCoordinatesLocal"
3939 /*@
3940   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
3941 
3942   Collective on DM
3943 
3944    Input Parameters:
3945 +  dm - the DM
3946 -  c - coordinate vector
3947 
3948   Note:
3949   The coordinates of ghost points can be set using DMSetCoordinates()
3950   followed by DMGetCoordinatesLocal(). This is intended to enable the
3951   setting of ghost coordinates outside of the domain.
3952 
3953   Level: intermediate
3954 
3955 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3956 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
3957 @*/
3958 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
3959 {
3960   PetscErrorCode ierr;
3961 
3962   PetscFunctionBegin;
3963   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3964   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3965   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3966   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3967 
3968   dm->coordinatesLocal = c;
3969 
3970   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3971   PetscFunctionReturn(0);
3972 }
3973 
3974 #undef __FUNCT__
3975 #define __FUNCT__ "DMGetCoordinates"
3976 /*@
3977   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
3978 
3979   Not Collective
3980 
3981   Input Parameter:
3982 . dm - the DM
3983 
3984   Output Parameter:
3985 . c - global coordinate vector
3986 
3987   Note:
3988   This is a borrowed reference, so the user should NOT destroy this vector
3989 
3990   Each process has only the local coordinates (does NOT have the ghost coordinates).
3991 
3992   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
3993   and (x_0,y_0,z_0,x_1,y_1,z_1...)
3994 
3995   Level: intermediate
3996 
3997 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3998 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
3999 @*/
4000 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
4001 {
4002   PetscErrorCode ierr;
4003 
4004   PetscFunctionBegin;
4005   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4006   PetscValidPointer(c,2);
4007   if (!dm->coordinates && dm->coordinatesLocal) {
4008     DM cdm = NULL;
4009 
4010     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4011     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
4012     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
4013     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4014     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4015   }
4016   *c = dm->coordinates;
4017   PetscFunctionReturn(0);
4018 }
4019 
4020 #undef __FUNCT__
4021 #define __FUNCT__ "DMGetCoordinatesLocal"
4022 /*@
4023   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
4024 
4025   Collective on DM
4026 
4027   Input Parameter:
4028 . dm - the DM
4029 
4030   Output Parameter:
4031 . c - coordinate vector
4032 
4033   Note:
4034   This is a borrowed reference, so the user should NOT destroy this vector
4035 
4036   Each process has the local and ghost coordinates
4037 
4038   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4039   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4040 
4041   Level: intermediate
4042 
4043 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4044 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
4045 @*/
4046 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
4047 {
4048   PetscErrorCode ierr;
4049 
4050   PetscFunctionBegin;
4051   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4052   PetscValidPointer(c,2);
4053   if (!dm->coordinatesLocal && dm->coordinates) {
4054     DM cdm = NULL;
4055 
4056     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4057     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
4058     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
4059     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4060     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4061   }
4062   *c = dm->coordinatesLocal;
4063   PetscFunctionReturn(0);
4064 }
4065 
4066 #undef __FUNCT__
4067 #define __FUNCT__ "DMGetCoordinateDM"
4068 /*@
4069   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
4070 
4071   Collective on DM
4072 
4073   Input Parameter:
4074 . dm - the DM
4075 
4076   Output Parameter:
4077 . cdm - coordinate DM
4078 
4079   Level: intermediate
4080 
4081 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4082 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4083 @*/
4084 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
4085 {
4086   PetscErrorCode ierr;
4087 
4088   PetscFunctionBegin;
4089   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4090   PetscValidPointer(cdm,2);
4091   if (!dm->coordinateDM) {
4092     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
4093     ierr = (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);CHKERRQ(ierr);
4094   }
4095   *cdm = dm->coordinateDM;
4096   PetscFunctionReturn(0);
4097 }
4098 
4099 #undef __FUNCT__
4100 #define __FUNCT__ "DMSetCoordinateDM"
4101 /*@
4102   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
4103 
4104   Logically Collective on DM
4105 
4106   Input Parameters:
4107 + dm - the DM
4108 - cdm - coordinate DM
4109 
4110   Level: intermediate
4111 
4112 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4113 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4114 @*/
4115 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
4116 {
4117   PetscErrorCode ierr;
4118 
4119   PetscFunctionBegin;
4120   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4121   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
4122   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
4123   dm->coordinateDM = cdm;
4124   ierr = PetscObjectReference((PetscObject) dm->coordinateDM);CHKERRQ(ierr);
4125   PetscFunctionReturn(0);
4126 }
4127 
4128 #undef __FUNCT__
4129 #define __FUNCT__ "DMGetCoordinateDim"
4130 /*@
4131   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
4132 
4133   Not Collective
4134 
4135   Input Parameter:
4136 . dm - The DM object
4137 
4138   Output Parameter:
4139 . dim - The embedding dimension
4140 
4141   Level: intermediate
4142 
4143 .keywords: mesh, coordinates
4144 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4145 @*/
4146 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
4147 {
4148   PetscFunctionBegin;
4149   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4150   PetscValidPointer(dim, 2);
4151   if (dm->dimEmbed == PETSC_DEFAULT) {
4152     dm->dimEmbed = dm->dim;
4153   }
4154   *dim = dm->dimEmbed;
4155   PetscFunctionReturn(0);
4156 }
4157 
4158 #undef __FUNCT__
4159 #define __FUNCT__ "DMSetCoordinateDim"
4160 /*@
4161   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
4162 
4163   Not Collective
4164 
4165   Input Parameters:
4166 + dm  - The DM object
4167 - dim - The embedding dimension
4168 
4169   Level: intermediate
4170 
4171 .keywords: mesh, coordinates
4172 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4173 @*/
4174 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
4175 {
4176   PetscFunctionBegin;
4177   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4178   dm->dimEmbed = dim;
4179   PetscFunctionReturn(0);
4180 }
4181 
4182 #undef __FUNCT__
4183 #define __FUNCT__ "DMGetCoordinateSection"
4184 /*@
4185   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
4186 
4187   Not Collective
4188 
4189   Input Parameter:
4190 . dm - The DM object
4191 
4192   Output Parameter:
4193 . section - The PetscSection object
4194 
4195   Level: intermediate
4196 
4197 .keywords: mesh, coordinates
4198 .seealso: DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4199 @*/
4200 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
4201 {
4202   DM             cdm;
4203   PetscErrorCode ierr;
4204 
4205   PetscFunctionBegin;
4206   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4207   PetscValidPointer(section, 2);
4208   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4209   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
4210   PetscFunctionReturn(0);
4211 }
4212 
4213 #undef __FUNCT__
4214 #define __FUNCT__ "DMSetCoordinateSection"
4215 /*@
4216   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
4217 
4218   Not Collective
4219 
4220   Input Parameters:
4221 + dm      - The DM object
4222 . dim     - The embedding dimension, or PETSC_DETERMINE
4223 - section - The PetscSection object
4224 
4225   Level: intermediate
4226 
4227 .keywords: mesh, coordinates
4228 .seealso: DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4229 @*/
4230 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
4231 {
4232   DM             cdm;
4233   PetscErrorCode ierr;
4234 
4235   PetscFunctionBegin;
4236   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4237   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
4238   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4239   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
4240   if (dim == PETSC_DETERMINE) {
4241     PetscInt d = dim;
4242     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
4243 
4244     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4245     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4246     pStart = PetscMax(vStart, pStart);
4247     pEnd   = PetscMin(vEnd, pEnd);
4248     for (v = pStart; v < pEnd; ++v) {
4249       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
4250       if (dd) {d = dd; break;}
4251     }
4252     ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);
4253   }
4254   PetscFunctionReturn(0);
4255 }
4256 
4257 #undef __FUNCT__
4258 #define __FUNCT__ "DMGetPeriodicity"
4259 /*@C
4260   DMSetPeriodicity - Set the description of mesh periodicity
4261 
4262   Input Parameters:
4263 + dm      - The DM object
4264 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4265 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4266 - bd      - This describes the type of periodicity in each topological dimension
4267 
4268   Level: developer
4269 
4270 .seealso: DMGetPeriodicity()
4271 @*/
4272 PetscErrorCode DMGetPeriodicity(DM dm, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
4273 {
4274   PetscFunctionBegin;
4275   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4276   if (L)       *L       = dm->L;
4277   if (maxCell) *maxCell = dm->maxCell;
4278   if (bd)      *bd      = dm->bdtype;
4279   PetscFunctionReturn(0);
4280 }
4281 
4282 #undef __FUNCT__
4283 #define __FUNCT__ "DMSetPeriodicity"
4284 /*@C
4285   DMSetPeriodicity - Set the description of mesh periodicity
4286 
4287   Input Parameters:
4288 + dm      - The DM object
4289 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4290 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4291 - bd      - This describes the type of periodicity in each topological dimension
4292 
4293   Level: developer
4294 
4295 .seealso: DMGetPeriodicity()
4296 @*/
4297 PetscErrorCode DMSetPeriodicity(DM dm, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
4298 {
4299   PetscInt       dim, d;
4300   PetscErrorCode ierr;
4301 
4302   PetscFunctionBegin;
4303   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4304   PetscValidPointer(L,3);PetscValidPointer(maxCell,2);PetscValidPointer(bd,4);
4305   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
4306   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4307   ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
4308   for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
4309   PetscFunctionReturn(0);
4310 }
4311 
4312 #undef __FUNCT__
4313 #define __FUNCT__ "DMLocatePoints"
4314 /*@
4315   DMLocatePoints - Locate the points in v in the mesh and return an IS of the containing cells
4316 
4317   Not collective
4318 
4319   Input Parameters:
4320 + dm - The DM
4321 - v - The Vec of points
4322 
4323   Output Parameter:
4324 . cells - The local cell numbers for cells which contain the points
4325 
4326   Level: developer
4327 
4328 .keywords: point location, mesh
4329 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4330 @*/
4331 PetscErrorCode DMLocatePoints(DM dm, Vec v, IS *cells)
4332 {
4333   PetscErrorCode ierr;
4334 
4335   PetscFunctionBegin;
4336   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4337   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
4338   PetscValidPointer(cells,3);
4339   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
4340   if (dm->ops->locatepoints) {
4341     ierr = (*dm->ops->locatepoints)(dm,v,cells);CHKERRQ(ierr);
4342   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
4343   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
4344   PetscFunctionReturn(0);
4345 }
4346 
4347 #undef __FUNCT__
4348 #define __FUNCT__ "DMGetOutputDM"
4349 /*@
4350   DMGetOutputDM - Retrieve the DM associated with the layout for output
4351 
4352   Input Parameter:
4353 . dm - The original DM
4354 
4355   Output Parameter:
4356 . odm - The DM which provides the layout for output
4357 
4358   Level: intermediate
4359 
4360 .seealso: VecView(), DMGetDefaultGlobalSection()
4361 @*/
4362 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
4363 {
4364   PetscSection   section;
4365   PetscBool      hasConstraints;
4366   PetscErrorCode ierr;
4367 
4368   PetscFunctionBegin;
4369   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4370   PetscValidPointer(odm,2);
4371   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
4372   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
4373   if (!hasConstraints) {
4374     *odm = dm;
4375     PetscFunctionReturn(0);
4376   }
4377   if (!dm->dmBC) {
4378     PetscSection newSection, gsection;
4379     PetscSF      sf;
4380 
4381     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
4382     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
4383     ierr = DMSetDefaultSection(dm->dmBC, newSection);CHKERRQ(ierr);
4384     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
4385     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
4386     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
4387     ierr = DMSetDefaultGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
4388     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
4389   }
4390   *odm = dm->dmBC;
4391   PetscFunctionReturn(0);
4392 }
4393 
4394 #undef __FUNCT__
4395 #define __FUNCT__ "DMGetOutputSequenceNumber"
4396 /*@
4397   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
4398 
4399   Input Parameter:
4400 . dm - The original DM
4401 
4402   Output Parameters:
4403 + num - The output sequence number
4404 - val - The output sequence value
4405 
4406   Level: intermediate
4407 
4408   Note: This is intended for output that should appear in sequence, for instance
4409   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4410 
4411 .seealso: VecView()
4412 @*/
4413 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
4414 {
4415   PetscFunctionBegin;
4416   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4417   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
4418   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
4419   PetscFunctionReturn(0);
4420 }
4421 
4422 #undef __FUNCT__
4423 #define __FUNCT__ "DMSetOutputSequenceNumber"
4424 /*@
4425   DMSetOutputSequenceNumber - Set the sequence number/value for output
4426 
4427   Input Parameters:
4428 + dm - The original DM
4429 . num - The output sequence number
4430 - val - The output sequence value
4431 
4432   Level: intermediate
4433 
4434   Note: This is intended for output that should appear in sequence, for instance
4435   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4436 
4437 .seealso: VecView()
4438 @*/
4439 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
4440 {
4441   PetscFunctionBegin;
4442   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4443   dm->outputSequenceNum = num;
4444   dm->outputSequenceVal = val;
4445   PetscFunctionReturn(0);
4446 }
4447 
4448 #undef __FUNCT__
4449 #define __FUNCT__ "DMOutputSequenceLoad"
4450 /*@C
4451   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
4452 
4453   Input Parameters:
4454 + dm   - The original DM
4455 . name - The sequence name
4456 - num  - The output sequence number
4457 
4458   Output Parameter:
4459 . val  - The output sequence value
4460 
4461   Level: intermediate
4462 
4463   Note: This is intended for output that should appear in sequence, for instance
4464   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4465 
4466 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
4467 @*/
4468 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
4469 {
4470   PetscBool      ishdf5;
4471   PetscErrorCode ierr;
4472 
4473   PetscFunctionBegin;
4474   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4475   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
4476   PetscValidPointer(val,4);
4477   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
4478   if (ishdf5) {
4479 #if defined(PETSC_HAVE_HDF5)
4480     PetscScalar value;
4481 
4482     ierr = DMSequenceLoad_HDF5(dm, name, num, &value, viewer);CHKERRQ(ierr);
4483     *val = PetscRealPart(value);
4484 #endif
4485   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
4486   PetscFunctionReturn(0);
4487 }
4488 
4489 #undef __FUNCT__
4490 #define __FUNCT__ "DMGetUseNatural"
4491 /*@
4492   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
4493 
4494   Not collective
4495 
4496   Input Parameter:
4497 . dm - The DM
4498 
4499   Output Parameter:
4500 . useNatural - The flag to build the mapping to a natural order during distribution
4501 
4502   Level: beginner
4503 
4504 .seealso: DMSetUseNatural(), DMCreate()
4505 @*/
4506 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
4507 {
4508   PetscFunctionBegin;
4509   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4510   PetscValidPointer(useNatural, 2);
4511   *useNatural = dm->useNatural;
4512   PetscFunctionReturn(0);
4513 }
4514 
4515 #undef __FUNCT__
4516 #define __FUNCT__ "DMSetUseNatural"
4517 /*@
4518   DMSetUseNatural - Set the flag for creating a mapping to the natural order on distribution
4519 
4520   Collective on dm
4521 
4522   Input Parameters:
4523 + dm - The DM
4524 - useNatural - The flag to build the mapping to a natural order during distribution
4525 
4526   Level: beginner
4527 
4528 .seealso: DMGetUseNatural(), DMCreate()
4529 @*/
4530 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
4531 {
4532   PetscFunctionBegin;
4533   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4534   PetscValidLogicalCollectiveInt(dm, useNatural, 2);
4535   dm->useNatural = useNatural;
4536   PetscFunctionReturn(0);
4537 }
4538 
4539 #undef __FUNCT__
4540 #define __FUNCT__
4541 
4542 #undef __FUNCT__
4543 #define __FUNCT__ "DMCreateLabel"
4544 /*@C
4545   DMCreateLabel - Create a label of the given name if it does not already exist
4546 
4547   Not Collective
4548 
4549   Input Parameters:
4550 + dm   - The DM object
4551 - name - The label name
4552 
4553   Level: intermediate
4554 
4555 .keywords: mesh
4556 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4557 @*/
4558 PetscErrorCode DMCreateLabel(DM dm, const char name[])
4559 {
4560   DMLabelLink    next  = dm->labels->next;
4561   PetscBool      flg   = PETSC_FALSE;
4562   PetscErrorCode ierr;
4563 
4564   PetscFunctionBegin;
4565   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4566   PetscValidCharPointer(name, 2);
4567   while (next) {
4568     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
4569     if (flg) break;
4570     next = next->next;
4571   }
4572   if (!flg) {
4573     DMLabelLink tmpLabel;
4574 
4575     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
4576     ierr = DMLabelCreate(name, &tmpLabel->label);CHKERRQ(ierr);
4577     tmpLabel->output = PETSC_TRUE;
4578     tmpLabel->next   = dm->labels->next;
4579     dm->labels->next = tmpLabel;
4580   }
4581   PetscFunctionReturn(0);
4582 }
4583 
4584 #undef __FUNCT__
4585 #define __FUNCT__ "DMGetLabelValue"
4586 /*@C
4587   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
4588 
4589   Not Collective
4590 
4591   Input Parameters:
4592 + dm   - The DM object
4593 . name - The label name
4594 - point - The mesh point
4595 
4596   Output Parameter:
4597 . value - The label value for this point, or -1 if the point is not in the label
4598 
4599   Level: beginner
4600 
4601 .keywords: mesh
4602 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
4603 @*/
4604 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
4605 {
4606   DMLabel        label;
4607   PetscErrorCode ierr;
4608 
4609   PetscFunctionBegin;
4610   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4611   PetscValidCharPointer(name, 2);
4612   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4613   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);CHKERRQ(ierr);
4614   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
4615   PetscFunctionReturn(0);
4616 }
4617 
4618 #undef __FUNCT__
4619 #define __FUNCT__ "DMSetLabelValue"
4620 /*@C
4621   DMSetLabelValue - Add a point to a Sieve Label with given value
4622 
4623   Not Collective
4624 
4625   Input Parameters:
4626 + dm   - The DM object
4627 . name - The label name
4628 . point - The mesh point
4629 - value - The label value for this point
4630 
4631   Output Parameter:
4632 
4633   Level: beginner
4634 
4635 .keywords: mesh
4636 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
4637 @*/
4638 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
4639 {
4640   DMLabel        label;
4641   PetscErrorCode ierr;
4642 
4643   PetscFunctionBegin;
4644   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4645   PetscValidCharPointer(name, 2);
4646   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4647   if (!label) {
4648     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
4649     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4650   }
4651   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
4652   PetscFunctionReturn(0);
4653 }
4654 
4655 #undef __FUNCT__
4656 #define __FUNCT__ "DMClearLabelValue"
4657 /*@C
4658   DMClearLabelValue - Remove a point from a Sieve Label with given value
4659 
4660   Not Collective
4661 
4662   Input Parameters:
4663 + dm   - The DM object
4664 . name - The label name
4665 . point - The mesh point
4666 - value - The label value for this point
4667 
4668   Output Parameter:
4669 
4670   Level: beginner
4671 
4672 .keywords: mesh
4673 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
4674 @*/
4675 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
4676 {
4677   DMLabel        label;
4678   PetscErrorCode ierr;
4679 
4680   PetscFunctionBegin;
4681   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4682   PetscValidCharPointer(name, 2);
4683   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4684   if (!label) PetscFunctionReturn(0);
4685   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
4686   PetscFunctionReturn(0);
4687 }
4688 
4689 #undef __FUNCT__
4690 #define __FUNCT__ "DMGetLabelSize"
4691 /*@C
4692   DMGetLabelSize - Get the number of different integer ids in a Label
4693 
4694   Not Collective
4695 
4696   Input Parameters:
4697 + dm   - The DM object
4698 - name - The label name
4699 
4700   Output Parameter:
4701 . size - The number of different integer ids, or 0 if the label does not exist
4702 
4703   Level: beginner
4704 
4705 .keywords: mesh
4706 .seealso: DMLabeGetNumValues(), DMSetLabelValue()
4707 @*/
4708 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
4709 {
4710   DMLabel        label;
4711   PetscErrorCode ierr;
4712 
4713   PetscFunctionBegin;
4714   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4715   PetscValidCharPointer(name, 2);
4716   PetscValidPointer(size, 3);
4717   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4718   *size = 0;
4719   if (!label) PetscFunctionReturn(0);
4720   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
4721   PetscFunctionReturn(0);
4722 }
4723 
4724 #undef __FUNCT__
4725 #define __FUNCT__ "DMGetLabelIdIS"
4726 /*@C
4727   DMGetLabelIdIS - Get the integer ids in a label
4728 
4729   Not Collective
4730 
4731   Input Parameters:
4732 + mesh - The DM object
4733 - name - The label name
4734 
4735   Output Parameter:
4736 . ids - The integer ids, or NULL if the label does not exist
4737 
4738   Level: beginner
4739 
4740 .keywords: mesh
4741 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
4742 @*/
4743 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
4744 {
4745   DMLabel        label;
4746   PetscErrorCode ierr;
4747 
4748   PetscFunctionBegin;
4749   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4750   PetscValidCharPointer(name, 2);
4751   PetscValidPointer(ids, 3);
4752   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4753   *ids = NULL;
4754   if (!label) PetscFunctionReturn(0);
4755   ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
4756   PetscFunctionReturn(0);
4757 }
4758 
4759 #undef __FUNCT__
4760 #define __FUNCT__ "DMGetStratumSize"
4761 /*@C
4762   DMGetStratumSize - Get the number of points in a label stratum
4763 
4764   Not Collective
4765 
4766   Input Parameters:
4767 + dm - The DM object
4768 . name - The label name
4769 - value - The stratum value
4770 
4771   Output Parameter:
4772 . size - The stratum size
4773 
4774   Level: beginner
4775 
4776 .keywords: mesh
4777 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
4778 @*/
4779 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
4780 {
4781   DMLabel        label;
4782   PetscErrorCode ierr;
4783 
4784   PetscFunctionBegin;
4785   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4786   PetscValidCharPointer(name, 2);
4787   PetscValidPointer(size, 4);
4788   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4789   *size = 0;
4790   if (!label) PetscFunctionReturn(0);
4791   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
4792   PetscFunctionReturn(0);
4793 }
4794 
4795 #undef __FUNCT__
4796 #define __FUNCT__ "DMGetStratumIS"
4797 /*@C
4798   DMGetStratumIS - Get the points in a label stratum
4799 
4800   Not Collective
4801 
4802   Input Parameters:
4803 + dm - The DM object
4804 . name - The label name
4805 - value - The stratum value
4806 
4807   Output Parameter:
4808 . points - The stratum points, or NULL if the label does not exist or does not have that value
4809 
4810   Level: beginner
4811 
4812 .keywords: mesh
4813 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
4814 @*/
4815 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
4816 {
4817   DMLabel        label;
4818   PetscErrorCode ierr;
4819 
4820   PetscFunctionBegin;
4821   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4822   PetscValidCharPointer(name, 2);
4823   PetscValidPointer(points, 4);
4824   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4825   *points = NULL;
4826   if (!label) PetscFunctionReturn(0);
4827   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
4828   PetscFunctionReturn(0);
4829 }
4830 
4831 #undef __FUNCT__
4832 #define __FUNCT__ "DMClearLabelStratum"
4833 /*@C
4834   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
4835 
4836   Not Collective
4837 
4838   Input Parameters:
4839 + dm   - The DM object
4840 . name - The label name
4841 - value - The label value for this point
4842 
4843   Output Parameter:
4844 
4845   Level: beginner
4846 
4847 .keywords: mesh
4848 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
4849 @*/
4850 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
4851 {
4852   DMLabel        label;
4853   PetscErrorCode ierr;
4854 
4855   PetscFunctionBegin;
4856   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4857   PetscValidCharPointer(name, 2);
4858   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4859   if (!label) PetscFunctionReturn(0);
4860   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
4861   PetscFunctionReturn(0);
4862 }
4863 
4864 #undef __FUNCT__
4865 #define __FUNCT__ "DMGetNumLabels"
4866 /*@
4867   DMGetNumLabels - Return the number of labels defined by the mesh
4868 
4869   Not Collective
4870 
4871   Input Parameter:
4872 . dm   - The DM object
4873 
4874   Output Parameter:
4875 . numLabels - the number of Labels
4876 
4877   Level: intermediate
4878 
4879 .keywords: mesh
4880 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4881 @*/
4882 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
4883 {
4884   DMLabelLink next = dm->labels->next;
4885   PetscInt  n    = 0;
4886 
4887   PetscFunctionBegin;
4888   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4889   PetscValidPointer(numLabels, 2);
4890   while (next) {++n; next = next->next;}
4891   *numLabels = n;
4892   PetscFunctionReturn(0);
4893 }
4894 
4895 #undef __FUNCT__
4896 #define __FUNCT__ "DMGetLabelName"
4897 /*@C
4898   DMGetLabelName - Return the name of nth label
4899 
4900   Not Collective
4901 
4902   Input Parameters:
4903 + dm - The DM object
4904 - n  - the label number
4905 
4906   Output Parameter:
4907 . name - the label name
4908 
4909   Level: intermediate
4910 
4911 .keywords: mesh
4912 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4913 @*/
4914 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
4915 {
4916   DMLabelLink next = dm->labels->next;
4917   PetscInt  l    = 0;
4918 
4919   PetscFunctionBegin;
4920   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4921   PetscValidPointer(name, 3);
4922   while (next) {
4923     if (l == n) {
4924       *name = next->label->name;
4925       PetscFunctionReturn(0);
4926     }
4927     ++l;
4928     next = next->next;
4929   }
4930   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
4931 }
4932 
4933 #undef __FUNCT__
4934 #define __FUNCT__ "DMHasLabel"
4935 /*@C
4936   DMHasLabel - Determine whether the mesh has a label of a given name
4937 
4938   Not Collective
4939 
4940   Input Parameters:
4941 + dm   - The DM object
4942 - name - The label name
4943 
4944   Output Parameter:
4945 . hasLabel - PETSC_TRUE if the label is present
4946 
4947   Level: intermediate
4948 
4949 .keywords: mesh
4950 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4951 @*/
4952 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
4953 {
4954   DMLabelLink    next = dm->labels->next;
4955   PetscErrorCode ierr;
4956 
4957   PetscFunctionBegin;
4958   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4959   PetscValidCharPointer(name, 2);
4960   PetscValidPointer(hasLabel, 3);
4961   *hasLabel = PETSC_FALSE;
4962   while (next) {
4963     ierr = PetscStrcmp(name, next->label->name, hasLabel);CHKERRQ(ierr);
4964     if (*hasLabel) break;
4965     next = next->next;
4966   }
4967   PetscFunctionReturn(0);
4968 }
4969 
4970 #undef __FUNCT__
4971 #define __FUNCT__ "DMGetLabel"
4972 /*@C
4973   DMGetLabel - Return the label of a given name, or NULL
4974 
4975   Not Collective
4976 
4977   Input Parameters:
4978 + dm   - The DM object
4979 - name - The label name
4980 
4981   Output Parameter:
4982 . label - The DMLabel, or NULL if the label is absent
4983 
4984   Level: intermediate
4985 
4986 .keywords: mesh
4987 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4988 @*/
4989 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
4990 {
4991   DMLabelLink    next = dm->labels->next;
4992   PetscBool      hasLabel;
4993   PetscErrorCode ierr;
4994 
4995   PetscFunctionBegin;
4996   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4997   PetscValidCharPointer(name, 2);
4998   PetscValidPointer(label, 3);
4999   *label = NULL;
5000   while (next) {
5001     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5002     if (hasLabel) {
5003       *label = next->label;
5004       break;
5005     }
5006     next = next->next;
5007   }
5008   PetscFunctionReturn(0);
5009 }
5010 
5011 #undef __FUNCT__
5012 #define __FUNCT__ "DMGetLabelByNum"
5013 /*@C
5014   DMGetLabelByNum - Return the nth label
5015 
5016   Not Collective
5017 
5018   Input Parameters:
5019 + dm - The DM object
5020 - n  - the label number
5021 
5022   Output Parameter:
5023 . label - the label
5024 
5025   Level: intermediate
5026 
5027 .keywords: mesh
5028 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5029 @*/
5030 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
5031 {
5032   DMLabelLink next = dm->labels->next;
5033   PetscInt    l    = 0;
5034 
5035   PetscFunctionBegin;
5036   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5037   PetscValidPointer(label, 3);
5038   while (next) {
5039     if (l == n) {
5040       *label = next->label;
5041       PetscFunctionReturn(0);
5042     }
5043     ++l;
5044     next = next->next;
5045   }
5046   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5047 }
5048 
5049 #undef __FUNCT__
5050 #define __FUNCT__ "DMAddLabel"
5051 /*@C
5052   DMAddLabel - Add the label to this mesh
5053 
5054   Not Collective
5055 
5056   Input Parameters:
5057 + dm   - The DM object
5058 - label - The DMLabel
5059 
5060   Level: developer
5061 
5062 .keywords: mesh
5063 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5064 @*/
5065 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
5066 {
5067   DMLabelLink    tmpLabel;
5068   PetscBool      hasLabel;
5069   PetscErrorCode ierr;
5070 
5071   PetscFunctionBegin;
5072   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5073   ierr = DMHasLabel(dm, label->name, &hasLabel);CHKERRQ(ierr);
5074   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", label->name);
5075   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5076   tmpLabel->label  = label;
5077   tmpLabel->output = PETSC_TRUE;
5078   tmpLabel->next   = dm->labels->next;
5079   dm->labels->next = tmpLabel;
5080   PetscFunctionReturn(0);
5081 }
5082 
5083 #undef __FUNCT__
5084 #define __FUNCT__ "DMRemoveLabel"
5085 /*@C
5086   DMRemoveLabel - Remove the label from this mesh
5087 
5088   Not Collective
5089 
5090   Input Parameters:
5091 + dm   - The DM object
5092 - name - The label name
5093 
5094   Output Parameter:
5095 . label - The DMLabel, or NULL if the label is absent
5096 
5097   Level: developer
5098 
5099 .keywords: mesh
5100 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5101 @*/
5102 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
5103 {
5104   DMLabelLink    next = dm->labels->next;
5105   DMLabelLink    last = NULL;
5106   PetscBool      hasLabel;
5107   PetscErrorCode ierr;
5108 
5109   PetscFunctionBegin;
5110   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5111   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
5112   *label = NULL;
5113   if (!hasLabel) PetscFunctionReturn(0);
5114   while (next) {
5115     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5116     if (hasLabel) {
5117       if (last) last->next       = next->next;
5118       else      dm->labels->next = next->next;
5119       next->next = NULL;
5120       *label     = next->label;
5121       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
5122       if (hasLabel) {
5123         dm->depthLabel = NULL;
5124       }
5125       ierr = PetscFree(next);CHKERRQ(ierr);
5126       break;
5127     }
5128     last = next;
5129     next = next->next;
5130   }
5131   PetscFunctionReturn(0);
5132 }
5133 
5134 #undef __FUNCT__
5135 #define __FUNCT__ "DMGetLabelOutput"
5136 /*@C
5137   DMGetLabelOutput - Get the output flag for a given label
5138 
5139   Not Collective
5140 
5141   Input Parameters:
5142 + dm   - The DM object
5143 - name - The label name
5144 
5145   Output Parameter:
5146 . output - The flag for output
5147 
5148   Level: developer
5149 
5150 .keywords: mesh
5151 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5152 @*/
5153 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
5154 {
5155   DMLabelLink    next = dm->labels->next;
5156   PetscErrorCode ierr;
5157 
5158   PetscFunctionBegin;
5159   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5160   PetscValidPointer(name, 2);
5161   PetscValidPointer(output, 3);
5162   while (next) {
5163     PetscBool flg;
5164 
5165     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5166     if (flg) {*output = next->output; PetscFunctionReturn(0);}
5167     next = next->next;
5168   }
5169   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5170 }
5171 
5172 #undef __FUNCT__
5173 #define __FUNCT__ "DMSetLabelOutput"
5174 /*@C
5175   DMSetLabelOutput - Set the output flag for a given label
5176 
5177   Not Collective
5178 
5179   Input Parameters:
5180 + dm     - The DM object
5181 . name   - The label name
5182 - output - The flag for output
5183 
5184   Level: developer
5185 
5186 .keywords: mesh
5187 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5188 @*/
5189 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
5190 {
5191   DMLabelLink    next = dm->labels->next;
5192   PetscErrorCode ierr;
5193 
5194   PetscFunctionBegin;
5195   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5196   PetscValidPointer(name, 2);
5197   while (next) {
5198     PetscBool flg;
5199 
5200     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5201     if (flg) {next->output = output; PetscFunctionReturn(0);}
5202     next = next->next;
5203   }
5204   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5205 }
5206 
5207 
5208 #undef __FUNCT__
5209 #define __FUNCT__ "DMCopyLabels"
5210 /*@
5211   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
5212 
5213   Collective on DM
5214 
5215   Input Parameter:
5216 . dmA - The DMPlex object with initial labels
5217 
5218   Output Parameter:
5219 . dmB - The DMPlex object with copied labels
5220 
5221   Level: intermediate
5222 
5223   Note: This is typically used when interpolating or otherwise adding to a mesh
5224 
5225 .keywords: mesh
5226 .seealso: DMCopyCoordinates(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
5227 @*/
5228 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
5229 {
5230   PetscInt       numLabels, l;
5231   PetscErrorCode ierr;
5232 
5233   PetscFunctionBegin;
5234   if (dmA == dmB) PetscFunctionReturn(0);
5235   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
5236   for (l = 0; l < numLabels; ++l) {
5237     DMLabel     label, labelNew;
5238     const char *name;
5239     PetscBool   flg;
5240 
5241     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
5242     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
5243     if (flg) continue;
5244     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
5245     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
5246     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
5247   }
5248   PetscFunctionReturn(0);
5249 }
5250 
5251 #undef __FUNCT__
5252 #define __FUNCT__ "DMGetCoarseDM"
5253 /*@
5254   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
5255 
5256   Input Parameter:
5257 . dm - The DM object
5258 
5259   Output Parameter:
5260 . cdm - The coarse DM
5261 
5262   Level: intermediate
5263 
5264 .seealso: DMSetCoarseDM()
5265 @*/
5266 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
5267 {
5268   PetscFunctionBegin;
5269   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5270   PetscValidPointer(cdm, 2);
5271   *cdm = dm->coarseMesh;
5272   PetscFunctionReturn(0);
5273 }
5274 
5275 #undef __FUNCT__
5276 #define __FUNCT__ "DMSetCoarseDM"
5277 /*@
5278   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
5279 
5280   Input Parameters:
5281 + dm - The DM object
5282 - cdm - The coarse DM
5283 
5284   Level: intermediate
5285 
5286 .seealso: DMGetCoarseDM()
5287 @*/
5288 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
5289 {
5290   PetscErrorCode ierr;
5291 
5292   PetscFunctionBegin;
5293   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5294   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
5295   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
5296   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
5297   dm->coarseMesh = cdm;
5298   PetscFunctionReturn(0);
5299 }
5300 
5301