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