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