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