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