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