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