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