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