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