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