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