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