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