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