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