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