xref: /petsc/src/dm/interface/dm.c (revision 07acc2aeea7a273014b10cda4fb272aa3ba8a1b1)
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 = ISCreate(PETSC_COMM_SELF, &fields);CHKERRQ(ierr);
4906     ierr = PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");CHKERRQ(ierr);
4907     ierr = ISSetType(fields, ISGENERAL);CHKERRQ(ierr);
4908     ierr = ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);CHKERRQ(ierr);
4909 
4910     ierr = PetscDSCreate(comm, &prob);CHKERRQ(ierr);
4911     ierr = DMSetRegionDS(dm, NULL, fields, prob);CHKERRQ(ierr);
4912     ierr = PetscDSDestroy(&prob);CHKERRQ(ierr);
4913     ierr = ISDestroy(&fields);CHKERRQ(ierr);
4914     ierr = DMGetRegionDS(dm, NULL, NULL, &prob);CHKERRQ(ierr);
4915   }
4916   ierr = PetscDSSetCoordinateDimension(prob, dimEmbed);CHKERRQ(ierr);
4917   /* Optionally create hybrid DS */
4918   for (f = 0; f < Nf; ++f) {
4919     DMLabel  label = dm->fields[f].label;
4920     PetscInt lStart, lEnd;
4921 
4922     if (label) {
4923       DM       plex;
4924       PetscInt depth, pMax[4];
4925 
4926       ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
4927       ierr = DMPlexGetDepth(plex, &depth);CHKERRQ(ierr);
4928       ierr = DMPlexGetHybridBounds(plex, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);CHKERRQ(ierr);
4929       ierr = DMDestroy(&plex);CHKERRQ(ierr);
4930 
4931       ierr = DMLabelGetBounds(label, &lStart, &lEnd);CHKERRQ(ierr);
4932       if (lStart < pMax[depth]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only support labels over hybrid cells right now");
4933       ierr = PetscDSCreate(comm, &probh);CHKERRQ(ierr);
4934       ierr = DMSetRegionDS(dm, label, NULL, probh);CHKERRQ(ierr);
4935       ierr = PetscDSSetHybrid(probh, PETSC_TRUE);CHKERRQ(ierr);
4936       ierr = PetscDSSetCoordinateDimension(probh, dimEmbed);CHKERRQ(ierr);
4937       break;
4938     }
4939   }
4940   /* Set fields in DSes */
4941   for (f = 0; f < Nf; ++f) {
4942     DMLabel     label = dm->fields[f].label;
4943     PetscObject disc  = dm->fields[f].disc;
4944 
4945     if (!label) {
4946       ierr = PetscDSSetDiscretization(prob,  field++,  disc);CHKERRQ(ierr);
4947       if (probh) {
4948         PetscFE subfe;
4949 
4950         ierr = PetscFEGetHeightSubspace((PetscFE) disc, 1, &subfe);CHKERRQ(ierr);
4951         ierr = PetscDSSetDiscretization(probh, fieldh++, (PetscObject) subfe);CHKERRQ(ierr);
4952       }
4953     } else {
4954       ierr = PetscDSSetDiscretization(probh, fieldh++, disc);CHKERRQ(ierr);
4955     }
4956     /* We allow people to have placeholder fields and construct the Section by hand */
4957     {
4958       PetscClassId id;
4959 
4960       ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr);
4961       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
4962     }
4963   }
4964   ierr = PetscDSDestroy(&probh);CHKERRQ(ierr);
4965   /* Setup DSes */
4966   if (doSetup) {
4967     for (s = 0; s < dm->Nds; ++s) {ierr = PetscDSSetUp(dm->probs[s].ds);CHKERRQ(ierr);}
4968   }
4969   PetscFunctionReturn(0);
4970 }
4971 
4972 /*@
4973   DMCopyDS - Copy the discrete systems for the DM into another DM
4974 
4975   Collective on DM
4976 
4977   Input Parameter:
4978 . dm - The DM
4979 
4980   Output Parameter:
4981 . newdm - The DM
4982 
4983   Level: advanced
4984 
4985 .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
4986 @*/
4987 PetscErrorCode DMCopyDS(DM dm, DM newdm)
4988 {
4989   PetscInt       Nds, s;
4990   PetscErrorCode ierr;
4991 
4992   PetscFunctionBegin;
4993   if (dm == newdm) PetscFunctionReturn(0);
4994   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
4995   ierr = DMClearDS(newdm);CHKERRQ(ierr);
4996   for (s = 0; s < Nds; ++s) {
4997     DMLabel label;
4998     IS      fields;
4999     PetscDS ds;
5000 
5001     ierr = DMGetRegionNumDS(dm, s, &label, &fields, &ds);CHKERRQ(ierr);
5002     ierr = DMSetRegionDS(newdm, label, fields, ds);CHKERRQ(ierr);
5003   }
5004   PetscFunctionReturn(0);
5005 }
5006 
5007 /*@
5008   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
5009 
5010   Collective on DM
5011 
5012   Input Parameter:
5013 . dm - The DM
5014 
5015   Output Parameter:
5016 . newdm - The DM
5017 
5018   Level: advanced
5019 
5020 .seealso: DMCopyFields(), DMCopyDS()
5021 @*/
5022 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5023 {
5024   PetscErrorCode ierr;
5025 
5026   PetscFunctionBegin;
5027   if (dm == newdm) PetscFunctionReturn(0);
5028   ierr = DMCopyFields(dm, newdm);CHKERRQ(ierr);
5029   ierr = DMCopyDS(dm, newdm);CHKERRQ(ierr);
5030   PetscFunctionReturn(0);
5031 }
5032 
5033 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5034 {
5035   DM dm_coord,dmc_coord;
5036   PetscErrorCode ierr;
5037   Vec coords,ccoords;
5038   Mat inject;
5039   PetscFunctionBegin;
5040   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5041   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
5042   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5043   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
5044   if (coords && !ccoords) {
5045     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
5046     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5047     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
5048     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
5049     ierr = MatDestroy(&inject);CHKERRQ(ierr);
5050     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
5051     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5052   }
5053   PetscFunctionReturn(0);
5054 }
5055 
5056 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5057 {
5058   DM dm_coord,subdm_coord;
5059   PetscErrorCode ierr;
5060   Vec coords,ccoords,clcoords;
5061   VecScatter *scat_i,*scat_g;
5062   PetscFunctionBegin;
5063   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5064   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
5065   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5066   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
5067   if (coords && !ccoords) {
5068     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
5069     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5070     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
5071     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
5072     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
5073     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5074     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5075     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5076     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5077     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
5078     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
5079     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
5080     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
5081     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5082     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
5083     ierr = PetscFree(scat_i);CHKERRQ(ierr);
5084     ierr = PetscFree(scat_g);CHKERRQ(ierr);
5085   }
5086   PetscFunctionReturn(0);
5087 }
5088 
5089 /*@
5090   DMGetDimension - Return the topological dimension of the DM
5091 
5092   Not collective
5093 
5094   Input Parameter:
5095 . dm - The DM
5096 
5097   Output Parameter:
5098 . dim - The topological dimension
5099 
5100   Level: beginner
5101 
5102 .seealso: DMSetDimension(), DMCreate()
5103 @*/
5104 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5105 {
5106   PetscFunctionBegin;
5107   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5108   PetscValidPointer(dim, 2);
5109   *dim = dm->dim;
5110   PetscFunctionReturn(0);
5111 }
5112 
5113 /*@
5114   DMSetDimension - Set the topological dimension of the DM
5115 
5116   Collective on dm
5117 
5118   Input Parameters:
5119 + dm - The DM
5120 - dim - The topological dimension
5121 
5122   Level: beginner
5123 
5124 .seealso: DMGetDimension(), DMCreate()
5125 @*/
5126 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5127 {
5128   PetscDS        ds;
5129   PetscErrorCode ierr;
5130 
5131   PetscFunctionBegin;
5132   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5133   PetscValidLogicalCollectiveInt(dm, dim, 2);
5134   dm->dim = dim;
5135   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5136   if (ds->dimEmbed < 0) {ierr = PetscDSSetCoordinateDimension(ds, dm->dim);CHKERRQ(ierr);}
5137   PetscFunctionReturn(0);
5138 }
5139 
5140 /*@
5141   DMGetDimPoints - Get the half-open interval for all points of a given dimension
5142 
5143   Collective on DM
5144 
5145   Input Parameters:
5146 + dm - the DM
5147 - dim - the dimension
5148 
5149   Output Parameters:
5150 + pStart - The first point of the given dimension
5151 . pEnd - The first point following points of the given dimension
5152 
5153   Note:
5154   The points are vertices in the Hasse diagram encoding the topology. This is explained in
5155   http://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
5156   then the interval is empty.
5157 
5158   Level: intermediate
5159 
5160 .keywords: point, Hasse Diagram, dimension
5161 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5162 @*/
5163 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5164 {
5165   PetscInt       d;
5166   PetscErrorCode ierr;
5167 
5168   PetscFunctionBegin;
5169   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5170   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
5171   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5172   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
5173   PetscFunctionReturn(0);
5174 }
5175 
5176 /*@
5177   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
5178 
5179   Collective on DM
5180 
5181   Input Parameters:
5182 + dm - the DM
5183 - c - coordinate vector
5184 
5185   Notes:
5186   The coordinates do include those for ghost points, which are in the local vector.
5187 
5188   The vector c should be destroyed by the caller.
5189 
5190   Level: intermediate
5191 
5192 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5193 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5194 @*/
5195 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5196 {
5197   PetscErrorCode ierr;
5198 
5199   PetscFunctionBegin;
5200   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5201   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5202   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5203   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5204   dm->coordinates = c;
5205   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5206   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5207   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5208   PetscFunctionReturn(0);
5209 }
5210 
5211 /*@
5212   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
5213 
5214   Not collective
5215 
5216    Input Parameters:
5217 +  dm - the DM
5218 -  c - coordinate vector
5219 
5220   Notes:
5221   The coordinates of ghost points can be set using DMSetCoordinates()
5222   followed by DMGetCoordinatesLocal(). This is intended to enable the
5223   setting of ghost coordinates outside of the domain.
5224 
5225   The vector c should be destroyed by the caller.
5226 
5227   Level: intermediate
5228 
5229 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5230 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5231 @*/
5232 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5233 {
5234   PetscErrorCode ierr;
5235 
5236   PetscFunctionBegin;
5237   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5238   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5239   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5240   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5241 
5242   dm->coordinatesLocal = c;
5243 
5244   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5245   PetscFunctionReturn(0);
5246 }
5247 
5248 /*@
5249   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
5250 
5251   Collective on DM
5252 
5253   Input Parameter:
5254 . dm - the DM
5255 
5256   Output Parameter:
5257 . c - global coordinate vector
5258 
5259   Note:
5260   This is a borrowed reference, so the user should NOT destroy this vector
5261 
5262   Each process has only the local coordinates (does NOT have the ghost coordinates).
5263 
5264   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5265   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5266 
5267   Level: intermediate
5268 
5269 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5270 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5271 @*/
5272 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5273 {
5274   PetscErrorCode ierr;
5275 
5276   PetscFunctionBegin;
5277   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5278   PetscValidPointer(c,2);
5279   if (!dm->coordinates && dm->coordinatesLocal) {
5280     DM        cdm = NULL;
5281     PetscBool localized;
5282 
5283     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5284     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
5285     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
5286     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
5287     if (localized) {
5288       PetscInt cdim;
5289 
5290       ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
5291       ierr = VecSetBlockSize(dm->coordinates, cdim);CHKERRQ(ierr);
5292     }
5293     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
5294     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
5295     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
5296   }
5297   *c = dm->coordinates;
5298   PetscFunctionReturn(0);
5299 }
5300 
5301 /*@
5302   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
5303 
5304   Collective on DM
5305 
5306   Input Parameter:
5307 . dm - the DM
5308 
5309   Level: advanced
5310 
5311 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5312 .seealso: DMGetCoordinatesLocalNoncollective()
5313 @*/
5314 PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
5315 {
5316   PetscErrorCode ierr;
5317 
5318   PetscFunctionBegin;
5319   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5320   if (!dm->coordinatesLocal && dm->coordinates) {
5321     DM        cdm = NULL;
5322     PetscBool localized;
5323 
5324     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5325     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
5326     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
5327     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
5328     if (localized) {
5329       PetscInt cdim;
5330 
5331       ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
5332       ierr = VecSetBlockSize(dm->coordinates, cdim);CHKERRQ(ierr);
5333     }
5334     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
5335     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
5336     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
5337   }
5338   PetscFunctionReturn(0);
5339 }
5340 
5341 /*@
5342   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
5343 
5344   Collective on DM
5345 
5346   Input Parameter:
5347 . dm - the DM
5348 
5349   Output Parameter:
5350 . c - coordinate vector
5351 
5352   Note:
5353   This is a borrowed reference, so the user should NOT destroy this vector
5354 
5355   Each process has the local and ghost coordinates
5356 
5357   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5358   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5359 
5360   Level: intermediate
5361 
5362 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5363 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
5364 @*/
5365 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
5366 {
5367   PetscErrorCode ierr;
5368 
5369   PetscFunctionBegin;
5370   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5371   PetscValidPointer(c,2);
5372   ierr = DMGetCoordinatesLocalSetUp(dm);CHKERRQ(ierr);
5373   *c = dm->coordinatesLocal;
5374   PetscFunctionReturn(0);
5375 }
5376 
5377 /*@
5378   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
5379 
5380   Not collective
5381 
5382   Input Parameter:
5383 . dm - the DM
5384 
5385   Output Parameter:
5386 . c - coordinate vector
5387 
5388   Level: advanced
5389 
5390 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5391 .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5392 @*/
5393 PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
5394 {
5395   PetscFunctionBegin;
5396   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5397   PetscValidPointer(c,2);
5398   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
5399   *c = dm->coordinatesLocal;
5400   PetscFunctionReturn(0);
5401 }
5402 
5403 /*@
5404   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
5405 
5406   Not collective
5407 
5408   Input Parameter:
5409 + dm - the DM
5410 - p - the IS of points whose coordinates will be returned
5411 
5412   Output Parameter:
5413 + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
5414 - pCoord - the Vec with coordinates of points in p
5415 
5416   Note:
5417   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
5418 
5419   This creates a new vector, so the user SHOULD destroy this vector
5420 
5421   Each process has the local and ghost coordinates
5422 
5423   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5424   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5425 
5426   Level: advanced
5427 
5428 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5429 .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5430 @*/
5431 PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
5432 {
5433   PetscSection        cs, newcs;
5434   Vec                 coords;
5435   const PetscScalar   *arr;
5436   PetscScalar         *newarr=NULL;
5437   PetscInt            n;
5438   PetscErrorCode      ierr;
5439 
5440   PetscFunctionBegin;
5441   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5442   PetscValidHeaderSpecific(p, IS_CLASSID, 2);
5443   if (pCoordSection) PetscValidPointer(pCoordSection, 3);
5444   if (pCoord) PetscValidPointer(pCoord, 4);
5445   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
5446   if (!dm->coordinateDM || !dm->coordinateDM->defaultSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
5447   cs = dm->coordinateDM->defaultSection;
5448   coords = dm->coordinatesLocal;
5449   ierr = VecGetArrayRead(coords, &arr);CHKERRQ(ierr);
5450   ierr = PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);CHKERRQ(ierr);
5451   ierr = VecRestoreArrayRead(coords, &arr);CHKERRQ(ierr);
5452   if (pCoord) {
5453     ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr);
5454     /* set array in two steps to mimic PETSC_OWN_POINTER */
5455     ierr = VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);CHKERRQ(ierr);
5456     ierr = VecReplaceArray(*pCoord, newarr);CHKERRQ(ierr);
5457   } else {
5458     ierr = PetscFree(newarr);CHKERRQ(ierr);
5459   }
5460   if (pCoordSection) {*pCoordSection = newcs;}
5461   else               {ierr = PetscSectionDestroy(&newcs);CHKERRQ(ierr);}
5462   PetscFunctionReturn(0);
5463 }
5464 
5465 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
5466 {
5467   PetscErrorCode ierr;
5468 
5469   PetscFunctionBegin;
5470   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5471   PetscValidPointer(field,2);
5472   if (!dm->coordinateField) {
5473     if (dm->ops->createcoordinatefield) {
5474       ierr = (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);CHKERRQ(ierr);
5475     }
5476   }
5477   *field = dm->coordinateField;
5478   PetscFunctionReturn(0);
5479 }
5480 
5481 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
5482 {
5483   PetscErrorCode ierr;
5484 
5485   PetscFunctionBegin;
5486   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5487   if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2);
5488   ierr = PetscObjectReference((PetscObject)field);CHKERRQ(ierr);
5489   ierr = DMFieldDestroy(&dm->coordinateField);CHKERRQ(ierr);
5490   dm->coordinateField = field;
5491   PetscFunctionReturn(0);
5492 }
5493 
5494 /*@
5495   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
5496 
5497   Collective on DM
5498 
5499   Input Parameter:
5500 . dm - the DM
5501 
5502   Output Parameter:
5503 . cdm - coordinate DM
5504 
5505   Level: intermediate
5506 
5507 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5508 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5509 @*/
5510 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
5511 {
5512   PetscErrorCode ierr;
5513 
5514   PetscFunctionBegin;
5515   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5516   PetscValidPointer(cdm,2);
5517   if (!dm->coordinateDM) {
5518     DM cdm;
5519 
5520     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
5521     ierr = (*dm->ops->createcoordinatedm)(dm, &cdm);CHKERRQ(ierr);
5522     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
5523      * until the call to CreateCoordinateDM) */
5524     ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
5525     dm->coordinateDM = cdm;
5526   }
5527   *cdm = dm->coordinateDM;
5528   PetscFunctionReturn(0);
5529 }
5530 
5531 /*@
5532   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
5533 
5534   Logically Collective on DM
5535 
5536   Input Parameters:
5537 + dm - the DM
5538 - cdm - coordinate DM
5539 
5540   Level: intermediate
5541 
5542 .keywords: distributed array, get, corners, nodes, local indices, coordinates
5543 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5544 @*/
5545 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
5546 {
5547   PetscErrorCode ierr;
5548 
5549   PetscFunctionBegin;
5550   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5551   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
5552   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
5553   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
5554   dm->coordinateDM = cdm;
5555   PetscFunctionReturn(0);
5556 }
5557 
5558 /*@
5559   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
5560 
5561   Not Collective
5562 
5563   Input Parameter:
5564 . dm - The DM object
5565 
5566   Output Parameter:
5567 . dim - The embedding dimension
5568 
5569   Level: intermediate
5570 
5571 .keywords: mesh, coordinates
5572 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetSection(), DMSetSection()
5573 @*/
5574 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
5575 {
5576   PetscFunctionBegin;
5577   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5578   PetscValidPointer(dim, 2);
5579   if (dm->dimEmbed == PETSC_DEFAULT) {
5580     dm->dimEmbed = dm->dim;
5581   }
5582   *dim = dm->dimEmbed;
5583   PetscFunctionReturn(0);
5584 }
5585 
5586 /*@
5587   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
5588 
5589   Not Collective
5590 
5591   Input Parameters:
5592 + dm  - The DM object
5593 - dim - The embedding dimension
5594 
5595   Level: intermediate
5596 
5597 .keywords: mesh, coordinates
5598 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetSection(), DMSetSection()
5599 @*/
5600 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
5601 {
5602   PetscDS        ds;
5603   PetscErrorCode ierr;
5604 
5605   PetscFunctionBegin;
5606   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5607   dm->dimEmbed = dim;
5608   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5609   ierr = PetscDSSetCoordinateDimension(ds, dim);CHKERRQ(ierr);
5610   PetscFunctionReturn(0);
5611 }
5612 
5613 /*@
5614   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
5615 
5616   Collective on DM
5617 
5618   Input Parameter:
5619 . dm - The DM object
5620 
5621   Output Parameter:
5622 . section - The PetscSection object
5623 
5624   Level: intermediate
5625 
5626 .keywords: mesh, coordinates
5627 .seealso: DMGetCoordinateDM(), DMGetSection(), DMSetSection()
5628 @*/
5629 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
5630 {
5631   DM             cdm;
5632   PetscErrorCode ierr;
5633 
5634   PetscFunctionBegin;
5635   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5636   PetscValidPointer(section, 2);
5637   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5638   ierr = DMGetSection(cdm, section);CHKERRQ(ierr);
5639   PetscFunctionReturn(0);
5640 }
5641 
5642 /*@
5643   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
5644 
5645   Not Collective
5646 
5647   Input Parameters:
5648 + dm      - The DM object
5649 . dim     - The embedding dimension, or PETSC_DETERMINE
5650 - section - The PetscSection object
5651 
5652   Level: intermediate
5653 
5654 .keywords: mesh, coordinates
5655 .seealso: DMGetCoordinateSection(), DMGetSection(), DMSetSection()
5656 @*/
5657 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
5658 {
5659   DM             cdm;
5660   PetscErrorCode ierr;
5661 
5662   PetscFunctionBegin;
5663   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5664   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
5665   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5666   ierr = DMSetSection(cdm, section);CHKERRQ(ierr);
5667   if (dim == PETSC_DETERMINE) {
5668     PetscInt d = PETSC_DEFAULT;
5669     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
5670 
5671     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5672     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5673     pStart = PetscMax(vStart, pStart);
5674     pEnd   = PetscMin(vEnd, pEnd);
5675     for (v = pStart; v < pEnd; ++v) {
5676       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
5677       if (dd) {d = dd; break;}
5678     }
5679     if (d >= 0) {ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);}
5680   }
5681   PetscFunctionReturn(0);
5682 }
5683 
5684 /*@C
5685   DMGetPeriodicity - Get the description of mesh periodicity
5686 
5687   Input Parameters:
5688 . dm      - The DM object
5689 
5690   Output Parameters:
5691 + per     - Whether the DM is periodic or not
5692 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
5693 . L       - If we assume the mesh is a torus, this is the length of each coordinate
5694 - bd      - This describes the type of periodicity in each topological dimension
5695 
5696   Level: developer
5697 
5698 .seealso: DMGetPeriodicity()
5699 @*/
5700 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
5701 {
5702   PetscFunctionBegin;
5703   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5704   if (per)     *per     = dm->periodic;
5705   if (L)       *L       = dm->L;
5706   if (maxCell) *maxCell = dm->maxCell;
5707   if (bd)      *bd      = dm->bdtype;
5708   PetscFunctionReturn(0);
5709 }
5710 
5711 /*@C
5712   DMSetPeriodicity - Set the description of mesh periodicity
5713 
5714   Input Parameters:
5715 + dm      - The DM object
5716 . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
5717 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
5718 . L       - If we assume the mesh is a torus, this is the length of each coordinate
5719 - bd      - This describes the type of periodicity in each topological dimension
5720 
5721   Level: developer
5722 
5723 .seealso: DMGetPeriodicity()
5724 @*/
5725 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
5726 {
5727   PetscInt       dim, d;
5728   PetscErrorCode ierr;
5729 
5730   PetscFunctionBegin;
5731   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5732   PetscValidLogicalCollectiveBool(dm,per,2);
5733   if (maxCell) {
5734     PetscValidPointer(maxCell,3);
5735     PetscValidPointer(L,4);
5736     PetscValidPointer(bd,5);
5737   }
5738   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
5739   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5740   if (maxCell) {
5741     ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
5742     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
5743   }
5744   dm->periodic = per;
5745   PetscFunctionReturn(0);
5746 }
5747 
5748 /*@
5749   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.
5750 
5751   Input Parameters:
5752 + dm     - The DM
5753 . in     - The input coordinate point (dim numbers)
5754 - endpoint - Include the endpoint L_i
5755 
5756   Output Parameter:
5757 . out - The localized coordinate point
5758 
5759   Level: developer
5760 
5761 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
5762 @*/
5763 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
5764 {
5765   PetscInt       dim, d;
5766   PetscErrorCode ierr;
5767 
5768   PetscFunctionBegin;
5769   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
5770   if (!dm->maxCell) {
5771     for (d = 0; d < dim; ++d) out[d] = in[d];
5772   } else {
5773     if (endpoint) {
5774       for (d = 0; d < dim; ++d) {
5775         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)) {
5776           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
5777         } else {
5778           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
5779         }
5780       }
5781     } else {
5782       for (d = 0; d < dim; ++d) {
5783         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
5784       }
5785     }
5786   }
5787   PetscFunctionReturn(0);
5788 }
5789 
5790 /*
5791   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.
5792 
5793   Input Parameters:
5794 + dm     - The DM
5795 . dim    - The spatial dimension
5796 . anchor - The anchor point, the input point can be no more than maxCell away from it
5797 - in     - The input coordinate point (dim numbers)
5798 
5799   Output Parameter:
5800 . out - The localized coordinate point
5801 
5802   Level: developer
5803 
5804   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
5805 
5806 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
5807 */
5808 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
5809 {
5810   PetscInt d;
5811 
5812   PetscFunctionBegin;
5813   if (!dm->maxCell) {
5814     for (d = 0; d < dim; ++d) out[d] = in[d];
5815   } else {
5816     for (d = 0; d < dim; ++d) {
5817       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
5818         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
5819       } else {
5820         out[d] = in[d];
5821       }
5822     }
5823   }
5824   PetscFunctionReturn(0);
5825 }
5826 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
5827 {
5828   PetscInt d;
5829 
5830   PetscFunctionBegin;
5831   if (!dm->maxCell) {
5832     for (d = 0; d < dim; ++d) out[d] = in[d];
5833   } else {
5834     for (d = 0; d < dim; ++d) {
5835       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
5836         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
5837       } else {
5838         out[d] = in[d];
5839       }
5840     }
5841   }
5842   PetscFunctionReturn(0);
5843 }
5844 
5845 /*
5846   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.
5847 
5848   Input Parameters:
5849 + dm     - The DM
5850 . dim    - The spatial dimension
5851 . anchor - The anchor point, the input point can be no more than maxCell away from it
5852 . in     - The input coordinate delta (dim numbers)
5853 - out    - The input coordinate point (dim numbers)
5854 
5855   Output Parameter:
5856 . out    - The localized coordinate in + out
5857 
5858   Level: developer
5859 
5860   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
5861 
5862 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
5863 */
5864 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
5865 {
5866   PetscInt d;
5867 
5868   PetscFunctionBegin;
5869   if (!dm->maxCell) {
5870     for (d = 0; d < dim; ++d) out[d] += in[d];
5871   } else {
5872     for (d = 0; d < dim; ++d) {
5873       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
5874         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
5875       } else {
5876         out[d] += in[d];
5877       }
5878     }
5879   }
5880   PetscFunctionReturn(0);
5881 }
5882 
5883 /*@
5884   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
5885 
5886   Not collective
5887 
5888   Input Parameter:
5889 . dm - The DM
5890 
5891   Output Parameter:
5892   areLocalized - True if localized
5893 
5894   Level: developer
5895 
5896 .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
5897 @*/
5898 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
5899 {
5900   DM             cdm;
5901   PetscSection   coordSection;
5902   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
5903   PetscBool      isPlex, alreadyLocalized;
5904   PetscErrorCode ierr;
5905 
5906   PetscFunctionBegin;
5907   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5908   PetscValidPointer(areLocalized, 2);
5909   *areLocalized = PETSC_FALSE;
5910 
5911   /* We need some generic way of refering to cells/vertices */
5912   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5913   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
5914   if (!isPlex) PetscFunctionReturn(0);
5915 
5916   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5917   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5918   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
5919   alreadyLocalized = PETSC_FALSE;
5920   for (c = cStart; c < cEnd; ++c) {
5921     if (c < sStart || c >= sEnd) continue;
5922     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
5923     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
5924   }
5925   *areLocalized = alreadyLocalized;
5926   PetscFunctionReturn(0);
5927 }
5928 
5929 /*@
5930   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
5931 
5932   Collective on dm
5933 
5934   Input Parameter:
5935 . dm - The DM
5936 
5937   Output Parameter:
5938   areLocalized - True if localized
5939 
5940   Level: developer
5941 
5942 .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
5943 @*/
5944 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
5945 {
5946   PetscBool      localized;
5947   PetscErrorCode ierr;
5948 
5949   PetscFunctionBegin;
5950   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5951   PetscValidPointer(areLocalized, 2);
5952   ierr = DMGetCoordinatesLocalizedLocal(dm,&localized);CHKERRQ(ierr);
5953   ierr = MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
5954   PetscFunctionReturn(0);
5955 }
5956 
5957 /*@
5958   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
5959 
5960   Collective on dm
5961 
5962   Input Parameter:
5963 . dm - The DM
5964 
5965   Level: developer
5966 
5967 .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
5968 @*/
5969 PetscErrorCode DMLocalizeCoordinates(DM dm)
5970 {
5971   DM             cdm;
5972   PetscSection   coordSection, cSection;
5973   Vec            coordinates,  cVec;
5974   PetscScalar   *coords, *coords2, *anchor, *localized;
5975   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
5976   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
5977   PetscInt       maxHeight = 0, h;
5978   PetscInt       *pStart = NULL, *pEnd = NULL;
5979   PetscErrorCode ierr;
5980 
5981   PetscFunctionBegin;
5982   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5983   if (!dm->periodic) PetscFunctionReturn(0);
5984   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
5985   if (alreadyLocalized) PetscFunctionReturn(0);
5986 
5987   /* We need some generic way of refering to cells/vertices */
5988   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5989   {
5990     PetscBool isplex;
5991 
5992     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
5993     if (isplex) {
5994       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5995       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
5996       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
5997       pEnd = &pStart[maxHeight + 1];
5998       newStart = vStart;
5999       newEnd   = vEnd;
6000       for (h = 0; h <= maxHeight; h++) {
6001         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
6002         newStart = PetscMin(newStart,pStart[h]);
6003         newEnd   = PetscMax(newEnd,pEnd[h]);
6004       }
6005     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6006   }
6007   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6008   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6009   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6010   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6011   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
6012 
6013   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
6014   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
6015   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
6016   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
6017   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
6018 
6019   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6020   localized = &anchor[bs];
6021   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6022   for (h = 0; h <= maxHeight; h++) {
6023     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6024 
6025     for (c = cStart; c < cEnd; ++c) {
6026       PetscScalar *cellCoords = NULL;
6027       PetscInt     b;
6028 
6029       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6030       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6031       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6032       for (d = 0; d < dof/bs; ++d) {
6033         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
6034         for (b = 0; b < bs; b++) {
6035           if (cellCoords[d*bs + b] != localized[b]) break;
6036         }
6037         if (b < bs) break;
6038       }
6039       if (d < dof/bs) {
6040         if (c >= sStart && c < sEnd) {
6041           PetscInt cdof;
6042 
6043           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6044           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6045         }
6046         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
6047         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
6048       }
6049       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6050     }
6051   }
6052   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6053   if (alreadyLocalizedGlobal) {
6054     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6055     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6056     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6057     PetscFunctionReturn(0);
6058   }
6059   for (v = vStart; v < vEnd; ++v) {
6060     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6061     ierr = PetscSectionSetDof(cSection, v, dof);CHKERRQ(ierr);
6062     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
6063   }
6064   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
6065   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
6066   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
6067   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
6068   ierr = VecSetBlockSize(cVec, bs);CHKERRQ(ierr);
6069   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
6070   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
6071   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6072   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
6073   for (v = vStart; v < vEnd; ++v) {
6074     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6075     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6076     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
6077     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6078   }
6079   for (h = 0; h <= maxHeight; h++) {
6080     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6081 
6082     for (c = cStart; c < cEnd; ++c) {
6083       PetscScalar *cellCoords = NULL;
6084       PetscInt     b, cdof;
6085 
6086       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
6087       if (!cdof) continue;
6088       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6089       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
6090       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6091       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
6092       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6093     }
6094   }
6095   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6096   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6097   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6098   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
6099   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
6100   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
6101   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
6102   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6103   PetscFunctionReturn(0);
6104 }
6105 
6106 /*@
6107   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6108 
6109   Collective on Vec v (see explanation below)
6110 
6111   Input Parameters:
6112 + dm - The DM
6113 . v - The Vec of points
6114 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6115 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
6116 
6117   Output Parameter:
6118 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6119 - cells - The PetscSF containing the ranks and local indices of the containing points.
6120 
6121 
6122   Level: developer
6123 
6124   Notes:
6125   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6126   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
6127 
6128   If *cellSF is NULL on input, a PetscSF will be created.
6129   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
6130 
6131   An array that maps each point to its containing cell can be obtained with
6132 
6133 $    const PetscSFNode *cells;
6134 $    PetscInt           nFound;
6135 $    const PetscInt    *found;
6136 $
6137 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
6138 
6139   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6140   the index of the cell in its rank's local numbering.
6141 
6142 .keywords: point location, mesh
6143 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6144 @*/
6145 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6146 {
6147   PetscErrorCode ierr;
6148 
6149   PetscFunctionBegin;
6150   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6151   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
6152   PetscValidPointer(cellSF,4);
6153   if (*cellSF) {
6154     PetscMPIInt result;
6155 
6156     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
6157     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
6158     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6159   } else {
6160     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
6161   }
6162   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6163   if (dm->ops->locatepoints) {
6164     ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
6165   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6166   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6167   PetscFunctionReturn(0);
6168 }
6169 
6170 /*@
6171   DMGetOutputDM - Retrieve the DM associated with the layout for output
6172 
6173   Collective on dm
6174 
6175   Input Parameter:
6176 . dm - The original DM
6177 
6178   Output Parameter:
6179 . odm - The DM which provides the layout for output
6180 
6181   Level: intermediate
6182 
6183 .seealso: VecView(), DMGetGlobalSection()
6184 @*/
6185 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6186 {
6187   PetscSection   section;
6188   PetscBool      hasConstraints, ghasConstraints;
6189   PetscErrorCode ierr;
6190 
6191   PetscFunctionBegin;
6192   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6193   PetscValidPointer(odm,2);
6194   ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
6195   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
6196   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
6197   if (!ghasConstraints) {
6198     *odm = dm;
6199     PetscFunctionReturn(0);
6200   }
6201   if (!dm->dmBC) {
6202     PetscSection newSection, gsection;
6203     PetscSF      sf;
6204 
6205     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
6206     ierr = DMCopyDisc(dm, dm->dmBC);CHKERRQ(ierr);
6207     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
6208     ierr = DMSetSection(dm->dmBC, newSection);CHKERRQ(ierr);
6209     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
6210     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
6211     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
6212     ierr = DMSetGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
6213     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
6214   }
6215   *odm = dm->dmBC;
6216   PetscFunctionReturn(0);
6217 }
6218 
6219 /*@
6220   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6221 
6222   Input Parameter:
6223 . dm - The original DM
6224 
6225   Output Parameters:
6226 + num - The output sequence number
6227 - val - The output sequence value
6228 
6229   Level: intermediate
6230 
6231   Note: This is intended for output that should appear in sequence, for instance
6232   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6233 
6234 .seealso: VecView()
6235 @*/
6236 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6237 {
6238   PetscFunctionBegin;
6239   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6240   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
6241   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
6242   PetscFunctionReturn(0);
6243 }
6244 
6245 /*@
6246   DMSetOutputSequenceNumber - Set the sequence number/value for output
6247 
6248   Input Parameters:
6249 + dm - The original DM
6250 . num - The output sequence number
6251 - val - The output sequence value
6252 
6253   Level: intermediate
6254 
6255   Note: This is intended for output that should appear in sequence, for instance
6256   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6257 
6258 .seealso: VecView()
6259 @*/
6260 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6261 {
6262   PetscFunctionBegin;
6263   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6264   dm->outputSequenceNum = num;
6265   dm->outputSequenceVal = val;
6266   PetscFunctionReturn(0);
6267 }
6268 
6269 /*@C
6270   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
6271 
6272   Input Parameters:
6273 + dm   - The original DM
6274 . name - The sequence name
6275 - num  - The output sequence number
6276 
6277   Output Parameter:
6278 . val  - The output sequence value
6279 
6280   Level: intermediate
6281 
6282   Note: This is intended for output that should appear in sequence, for instance
6283   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6284 
6285 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
6286 @*/
6287 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6288 {
6289   PetscBool      ishdf5;
6290   PetscErrorCode ierr;
6291 
6292   PetscFunctionBegin;
6293   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6294   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
6295   PetscValidPointer(val,4);
6296   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
6297   if (ishdf5) {
6298 #if defined(PETSC_HAVE_HDF5)
6299     PetscScalar value;
6300 
6301     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
6302     *val = PetscRealPart(value);
6303 #endif
6304   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6305   PetscFunctionReturn(0);
6306 }
6307 
6308 /*@
6309   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
6310 
6311   Not collective
6312 
6313   Input Parameter:
6314 . dm - The DM
6315 
6316   Output Parameter:
6317 . useNatural - The flag to build the mapping to a natural order during distribution
6318 
6319   Level: beginner
6320 
6321 .seealso: DMSetUseNatural(), DMCreate()
6322 @*/
6323 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6324 {
6325   PetscFunctionBegin;
6326   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6327   PetscValidPointer(useNatural, 2);
6328   *useNatural = dm->useNatural;
6329   PetscFunctionReturn(0);
6330 }
6331 
6332 /*@
6333   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
6334 
6335   Collective on dm
6336 
6337   Input Parameters:
6338 + dm - The DM
6339 - useNatural - The flag to build the mapping to a natural order during distribution
6340 
6341   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
6342 
6343   Level: beginner
6344 
6345 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
6346 @*/
6347 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6348 {
6349   PetscFunctionBegin;
6350   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6351   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6352   dm->useNatural = useNatural;
6353   PetscFunctionReturn(0);
6354 }
6355 
6356 
6357 /*@C
6358   DMCreateLabel - Create a label of the given name if it does not already exist
6359 
6360   Not Collective
6361 
6362   Input Parameters:
6363 + dm   - The DM object
6364 - name - The label name
6365 
6366   Level: intermediate
6367 
6368 .keywords: mesh
6369 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6370 @*/
6371 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6372 {
6373   DMLabelLink    next  = dm->labels->next;
6374   PetscBool      flg   = PETSC_FALSE;
6375   const char    *lname;
6376   PetscErrorCode ierr;
6377 
6378   PetscFunctionBegin;
6379   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6380   PetscValidCharPointer(name, 2);
6381   while (next) {
6382     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6383     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
6384     if (flg) break;
6385     next = next->next;
6386   }
6387   if (!flg) {
6388     DMLabelLink tmpLabel;
6389 
6390     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
6391     ierr = DMLabelCreate(PETSC_COMM_SELF, name, &tmpLabel->label);CHKERRQ(ierr);
6392     tmpLabel->output = PETSC_TRUE;
6393     tmpLabel->next   = dm->labels->next;
6394     dm->labels->next = tmpLabel;
6395   }
6396   PetscFunctionReturn(0);
6397 }
6398 
6399 /*@C
6400   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
6401 
6402   Not Collective
6403 
6404   Input Parameters:
6405 + dm   - The DM object
6406 . name - The label name
6407 - point - The mesh point
6408 
6409   Output Parameter:
6410 . value - The label value for this point, or -1 if the point is not in the label
6411 
6412   Level: beginner
6413 
6414 .keywords: mesh
6415 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
6416 @*/
6417 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6418 {
6419   DMLabel        label;
6420   PetscErrorCode ierr;
6421 
6422   PetscFunctionBegin;
6423   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6424   PetscValidCharPointer(name, 2);
6425   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6426   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6427   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
6428   PetscFunctionReturn(0);
6429 }
6430 
6431 /*@C
6432   DMSetLabelValue - Add a point to a Sieve Label with given value
6433 
6434   Not Collective
6435 
6436   Input Parameters:
6437 + dm   - The DM object
6438 . name - The label name
6439 . point - The mesh point
6440 - value - The label value for this point
6441 
6442   Output Parameter:
6443 
6444   Level: beginner
6445 
6446 .keywords: mesh
6447 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
6448 @*/
6449 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6450 {
6451   DMLabel        label;
6452   PetscErrorCode ierr;
6453 
6454   PetscFunctionBegin;
6455   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6456   PetscValidCharPointer(name, 2);
6457   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6458   if (!label) {
6459     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
6460     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6461   }
6462   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
6463   PetscFunctionReturn(0);
6464 }
6465 
6466 /*@C
6467   DMClearLabelValue - Remove a point from a Sieve Label with given value
6468 
6469   Not Collective
6470 
6471   Input Parameters:
6472 + dm   - The DM object
6473 . name - The label name
6474 . point - The mesh point
6475 - value - The label value for this point
6476 
6477   Output Parameter:
6478 
6479   Level: beginner
6480 
6481 .keywords: mesh
6482 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
6483 @*/
6484 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6485 {
6486   DMLabel        label;
6487   PetscErrorCode ierr;
6488 
6489   PetscFunctionBegin;
6490   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6491   PetscValidCharPointer(name, 2);
6492   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6493   if (!label) PetscFunctionReturn(0);
6494   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
6495   PetscFunctionReturn(0);
6496 }
6497 
6498 /*@C
6499   DMGetLabelSize - Get the number of different integer ids in a Label
6500 
6501   Not Collective
6502 
6503   Input Parameters:
6504 + dm   - The DM object
6505 - name - The label name
6506 
6507   Output Parameter:
6508 . size - The number of different integer ids, or 0 if the label does not exist
6509 
6510   Level: beginner
6511 
6512 .keywords: mesh
6513 .seealso: DMLabelGetNumValues(), DMSetLabelValue()
6514 @*/
6515 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6516 {
6517   DMLabel        label;
6518   PetscErrorCode ierr;
6519 
6520   PetscFunctionBegin;
6521   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6522   PetscValidCharPointer(name, 2);
6523   PetscValidPointer(size, 3);
6524   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6525   *size = 0;
6526   if (!label) PetscFunctionReturn(0);
6527   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
6528   PetscFunctionReturn(0);
6529 }
6530 
6531 /*@C
6532   DMGetLabelIdIS - Get the integer ids in a label
6533 
6534   Not Collective
6535 
6536   Input Parameters:
6537 + mesh - The DM object
6538 - name - The label name
6539 
6540   Output Parameter:
6541 . ids - The integer ids, or NULL if the label does not exist
6542 
6543   Level: beginner
6544 
6545 .keywords: mesh
6546 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
6547 @*/
6548 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6549 {
6550   DMLabel        label;
6551   PetscErrorCode ierr;
6552 
6553   PetscFunctionBegin;
6554   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6555   PetscValidCharPointer(name, 2);
6556   PetscValidPointer(ids, 3);
6557   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6558   *ids = NULL;
6559  if (label) {
6560     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
6561   } else {
6562     /* returning an empty IS */
6563     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
6564   }
6565   PetscFunctionReturn(0);
6566 }
6567 
6568 /*@C
6569   DMGetStratumSize - Get the number of points in a label stratum
6570 
6571   Not Collective
6572 
6573   Input Parameters:
6574 + dm - The DM object
6575 . name - The label name
6576 - value - The stratum value
6577 
6578   Output Parameter:
6579 . size - The stratum size
6580 
6581   Level: beginner
6582 
6583 .keywords: mesh
6584 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
6585 @*/
6586 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6587 {
6588   DMLabel        label;
6589   PetscErrorCode ierr;
6590 
6591   PetscFunctionBegin;
6592   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6593   PetscValidCharPointer(name, 2);
6594   PetscValidPointer(size, 4);
6595   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6596   *size = 0;
6597   if (!label) PetscFunctionReturn(0);
6598   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
6599   PetscFunctionReturn(0);
6600 }
6601 
6602 /*@C
6603   DMGetStratumIS - Get the points in a label stratum
6604 
6605   Not Collective
6606 
6607   Input Parameters:
6608 + dm - The DM object
6609 . name - The label name
6610 - value - The stratum value
6611 
6612   Output Parameter:
6613 . points - The stratum points, or NULL if the label does not exist or does not have that value
6614 
6615   Level: beginner
6616 
6617 .keywords: mesh
6618 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
6619 @*/
6620 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6621 {
6622   DMLabel        label;
6623   PetscErrorCode ierr;
6624 
6625   PetscFunctionBegin;
6626   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6627   PetscValidCharPointer(name, 2);
6628   PetscValidPointer(points, 4);
6629   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6630   *points = NULL;
6631   if (!label) PetscFunctionReturn(0);
6632   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
6633   PetscFunctionReturn(0);
6634 }
6635 
6636 /*@C
6637   DMSetStratumIS - Set the points in a label stratum
6638 
6639   Not Collective
6640 
6641   Input Parameters:
6642 + dm - The DM object
6643 . name - The label name
6644 . value - The stratum value
6645 - points - The stratum points
6646 
6647   Level: beginner
6648 
6649 .keywords: mesh
6650 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
6651 @*/
6652 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6653 {
6654   DMLabel        label;
6655   PetscErrorCode ierr;
6656 
6657   PetscFunctionBegin;
6658   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6659   PetscValidCharPointer(name, 2);
6660   PetscValidPointer(points, 4);
6661   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6662   if (!label) PetscFunctionReturn(0);
6663   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
6664   PetscFunctionReturn(0);
6665 }
6666 
6667 /*@C
6668   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
6669 
6670   Not Collective
6671 
6672   Input Parameters:
6673 + dm   - The DM object
6674 . name - The label name
6675 - value - The label value for this point
6676 
6677   Output Parameter:
6678 
6679   Level: beginner
6680 
6681 .keywords: mesh
6682 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
6683 @*/
6684 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6685 {
6686   DMLabel        label;
6687   PetscErrorCode ierr;
6688 
6689   PetscFunctionBegin;
6690   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6691   PetscValidCharPointer(name, 2);
6692   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6693   if (!label) PetscFunctionReturn(0);
6694   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
6695   PetscFunctionReturn(0);
6696 }
6697 
6698 /*@
6699   DMGetNumLabels - Return the number of labels defined by the mesh
6700 
6701   Not Collective
6702 
6703   Input Parameter:
6704 . dm   - The DM object
6705 
6706   Output Parameter:
6707 . numLabels - the number of Labels
6708 
6709   Level: intermediate
6710 
6711 .keywords: mesh
6712 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6713 @*/
6714 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6715 {
6716   DMLabelLink next = dm->labels->next;
6717   PetscInt  n    = 0;
6718 
6719   PetscFunctionBegin;
6720   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6721   PetscValidPointer(numLabels, 2);
6722   while (next) {++n; next = next->next;}
6723   *numLabels = n;
6724   PetscFunctionReturn(0);
6725 }
6726 
6727 /*@C
6728   DMGetLabelName - Return the name of nth label
6729 
6730   Not Collective
6731 
6732   Input Parameters:
6733 + dm - The DM object
6734 - n  - the label number
6735 
6736   Output Parameter:
6737 . name - the label name
6738 
6739   Level: intermediate
6740 
6741 .keywords: mesh
6742 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6743 @*/
6744 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
6745 {
6746   DMLabelLink    next = dm->labels->next;
6747   PetscInt       l    = 0;
6748   PetscErrorCode ierr;
6749 
6750   PetscFunctionBegin;
6751   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6752   PetscValidPointer(name, 3);
6753   while (next) {
6754     if (l == n) {
6755       ierr = PetscObjectGetName((PetscObject) next->label, name);CHKERRQ(ierr);
6756       PetscFunctionReturn(0);
6757     }
6758     ++l;
6759     next = next->next;
6760   }
6761   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
6762 }
6763 
6764 /*@C
6765   DMHasLabel - Determine whether the mesh has a label of a given name
6766 
6767   Not Collective
6768 
6769   Input Parameters:
6770 + dm   - The DM object
6771 - name - The label name
6772 
6773   Output Parameter:
6774 . hasLabel - PETSC_TRUE if the label is present
6775 
6776   Level: intermediate
6777 
6778 .keywords: mesh
6779 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6780 @*/
6781 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
6782 {
6783   DMLabelLink    next = dm->labels->next;
6784   const char    *lname;
6785   PetscErrorCode ierr;
6786 
6787   PetscFunctionBegin;
6788   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6789   PetscValidCharPointer(name, 2);
6790   PetscValidPointer(hasLabel, 3);
6791   *hasLabel = PETSC_FALSE;
6792   while (next) {
6793     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6794     ierr = PetscStrcmp(name, lname, hasLabel);CHKERRQ(ierr);
6795     if (*hasLabel) break;
6796     next = next->next;
6797   }
6798   PetscFunctionReturn(0);
6799 }
6800 
6801 /*@C
6802   DMGetLabel - Return the label of a given name, or NULL
6803 
6804   Not Collective
6805 
6806   Input Parameters:
6807 + dm   - The DM object
6808 - name - The label name
6809 
6810   Output Parameter:
6811 . label - The DMLabel, or NULL if the label is absent
6812 
6813   Level: intermediate
6814 
6815 .keywords: mesh
6816 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6817 @*/
6818 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
6819 {
6820   DMLabelLink    next = dm->labels->next;
6821   PetscBool      hasLabel;
6822   const char    *lname;
6823   PetscErrorCode ierr;
6824 
6825   PetscFunctionBegin;
6826   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6827   PetscValidCharPointer(name, 2);
6828   PetscValidPointer(label, 3);
6829   *label = NULL;
6830   while (next) {
6831     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6832     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
6833     if (hasLabel) {
6834       *label = next->label;
6835       break;
6836     }
6837     next = next->next;
6838   }
6839   PetscFunctionReturn(0);
6840 }
6841 
6842 /*@C
6843   DMGetLabelByNum - Return the nth label
6844 
6845   Not Collective
6846 
6847   Input Parameters:
6848 + dm - The DM object
6849 - n  - the label number
6850 
6851   Output Parameter:
6852 . label - the label
6853 
6854   Level: intermediate
6855 
6856 .keywords: mesh
6857 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6858 @*/
6859 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
6860 {
6861   DMLabelLink next = dm->labels->next;
6862   PetscInt    l    = 0;
6863 
6864   PetscFunctionBegin;
6865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6866   PetscValidPointer(label, 3);
6867   while (next) {
6868     if (l == n) {
6869       *label = next->label;
6870       PetscFunctionReturn(0);
6871     }
6872     ++l;
6873     next = next->next;
6874   }
6875   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
6876 }
6877 
6878 /*@C
6879   DMAddLabel - Add the label to this mesh
6880 
6881   Not Collective
6882 
6883   Input Parameters:
6884 + dm   - The DM object
6885 - label - The DMLabel
6886 
6887   Level: developer
6888 
6889 .keywords: mesh
6890 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6891 @*/
6892 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
6893 {
6894   DMLabelLink    tmpLabel;
6895   PetscBool      hasLabel;
6896   const char    *lname;
6897   PetscErrorCode ierr;
6898 
6899   PetscFunctionBegin;
6900   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6901   ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
6902   ierr = DMHasLabel(dm, lname, &hasLabel);CHKERRQ(ierr);
6903   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
6904   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
6905   tmpLabel->label  = label;
6906   tmpLabel->output = PETSC_TRUE;
6907   tmpLabel->next   = dm->labels->next;
6908   dm->labels->next = tmpLabel;
6909   PetscFunctionReturn(0);
6910 }
6911 
6912 /*@C
6913   DMRemoveLabel - Remove the label from this mesh
6914 
6915   Not Collective
6916 
6917   Input Parameters:
6918 + dm   - The DM object
6919 - name - The label name
6920 
6921   Output Parameter:
6922 . label - The DMLabel, or NULL if the label is absent
6923 
6924   Level: developer
6925 
6926 .keywords: mesh
6927 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6928 @*/
6929 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
6930 {
6931   DMLabelLink    next = dm->labels->next;
6932   DMLabelLink    last = NULL;
6933   PetscBool      hasLabel;
6934   const char    *lname;
6935   PetscErrorCode ierr;
6936 
6937   PetscFunctionBegin;
6938   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6939   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
6940   *label = NULL;
6941   if (!hasLabel) PetscFunctionReturn(0);
6942   while (next) {
6943     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6944     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
6945     if (hasLabel) {
6946       if (last) last->next       = next->next;
6947       else      dm->labels->next = next->next;
6948       next->next = NULL;
6949       *label     = next->label;
6950       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
6951       if (hasLabel) {
6952         dm->depthLabel = NULL;
6953       }
6954       ierr = PetscFree(next);CHKERRQ(ierr);
6955       break;
6956     }
6957     last = next;
6958     next = next->next;
6959   }
6960   PetscFunctionReturn(0);
6961 }
6962 
6963 /*@C
6964   DMGetLabelOutput - Get the output flag for a given label
6965 
6966   Not Collective
6967 
6968   Input Parameters:
6969 + dm   - The DM object
6970 - name - The label name
6971 
6972   Output Parameter:
6973 . output - The flag for output
6974 
6975   Level: developer
6976 
6977 .keywords: mesh
6978 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6979 @*/
6980 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
6981 {
6982   DMLabelLink    next = dm->labels->next;
6983   const char    *lname;
6984   PetscErrorCode ierr;
6985 
6986   PetscFunctionBegin;
6987   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6988   PetscValidPointer(name, 2);
6989   PetscValidPointer(output, 3);
6990   while (next) {
6991     PetscBool flg;
6992 
6993     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6994     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
6995     if (flg) {*output = next->output; PetscFunctionReturn(0);}
6996     next = next->next;
6997   }
6998   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
6999 }
7000 
7001 /*@C
7002   DMSetLabelOutput - Set the output flag for a given label
7003 
7004   Not Collective
7005 
7006   Input Parameters:
7007 + dm     - The DM object
7008 . name   - The label name
7009 - output - The flag for output
7010 
7011   Level: developer
7012 
7013 .keywords: mesh
7014 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7015 @*/
7016 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7017 {
7018   DMLabelLink    next = dm->labels->next;
7019   const char    *lname;
7020   PetscErrorCode ierr;
7021 
7022   PetscFunctionBegin;
7023   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7024   PetscValidPointer(name, 2);
7025   while (next) {
7026     PetscBool flg;
7027 
7028     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7029     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7030     if (flg) {next->output = output; PetscFunctionReturn(0);}
7031     next = next->next;
7032   }
7033   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7034 }
7035 
7036 
7037 /*@
7038   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
7039 
7040   Collective on DM
7041 
7042   Input Parameter:
7043 . dmA - The DM object with initial labels
7044 
7045   Output Parameter:
7046 . dmB - The DM object with copied labels
7047 
7048   Level: intermediate
7049 
7050   Note: This is typically used when interpolating or otherwise adding to a mesh
7051 
7052 .keywords: mesh
7053 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
7054 @*/
7055 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
7056 {
7057   PetscInt       numLabels, l;
7058   PetscErrorCode ierr;
7059 
7060   PetscFunctionBegin;
7061   if (dmA == dmB) PetscFunctionReturn(0);
7062   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
7063   for (l = 0; l < numLabels; ++l) {
7064     DMLabel     label, labelNew;
7065     const char *name;
7066     PetscBool   flg;
7067 
7068     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
7069     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
7070     if (flg) continue;
7071     ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
7072     if (flg) continue;
7073     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
7074     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
7075     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
7076   }
7077   PetscFunctionReturn(0);
7078 }
7079 
7080 /*@
7081   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
7082 
7083   Input Parameter:
7084 . dm - The DM object
7085 
7086   Output Parameter:
7087 . cdm - The coarse DM
7088 
7089   Level: intermediate
7090 
7091 .seealso: DMSetCoarseDM()
7092 @*/
7093 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7094 {
7095   PetscFunctionBegin;
7096   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7097   PetscValidPointer(cdm, 2);
7098   *cdm = dm->coarseMesh;
7099   PetscFunctionReturn(0);
7100 }
7101 
7102 /*@
7103   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
7104 
7105   Input Parameters:
7106 + dm - The DM object
7107 - cdm - The coarse DM
7108 
7109   Level: intermediate
7110 
7111 .seealso: DMGetCoarseDM()
7112 @*/
7113 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7114 {
7115   PetscErrorCode ierr;
7116 
7117   PetscFunctionBegin;
7118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7119   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7120   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
7121   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
7122   dm->coarseMesh = cdm;
7123   PetscFunctionReturn(0);
7124 }
7125 
7126 /*@
7127   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
7128 
7129   Input Parameter:
7130 . dm - The DM object
7131 
7132   Output Parameter:
7133 . fdm - The fine DM
7134 
7135   Level: intermediate
7136 
7137 .seealso: DMSetFineDM()
7138 @*/
7139 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7140 {
7141   PetscFunctionBegin;
7142   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7143   PetscValidPointer(fdm, 2);
7144   *fdm = dm->fineMesh;
7145   PetscFunctionReturn(0);
7146 }
7147 
7148 /*@
7149   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
7150 
7151   Input Parameters:
7152 + dm - The DM object
7153 - fdm - The fine DM
7154 
7155   Level: intermediate
7156 
7157 .seealso: DMGetFineDM()
7158 @*/
7159 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7160 {
7161   PetscErrorCode ierr;
7162 
7163   PetscFunctionBegin;
7164   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7165   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7166   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
7167   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
7168   dm->fineMesh = fdm;
7169   PetscFunctionReturn(0);
7170 }
7171 
7172 /*=== DMBoundary code ===*/
7173 
7174 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7175 {
7176   PetscInt       d;
7177   PetscErrorCode ierr;
7178 
7179   PetscFunctionBegin;
7180   for (d = 0; d < dm->Nds; ++d) {
7181     ierr = PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);CHKERRQ(ierr);
7182   }
7183   PetscFunctionReturn(0);
7184 }
7185 
7186 /*@C
7187   DMAddBoundary - Add a boundary condition to the model
7188 
7189   Input Parameters:
7190 + dm          - The DM, with a PetscDS that matches the problem being constrained
7191 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7192 . name        - The BC name
7193 . labelname   - The label defining constrained points
7194 . field       - The field to constrain
7195 . numcomps    - The number of constrained field components (0 will constrain all fields)
7196 . comps       - An array of constrained component numbers
7197 . bcFunc      - A pointwise function giving boundary values
7198 . numids      - The number of DMLabel ids for constrained points
7199 . ids         - An array of ids for constrained points
7200 - ctx         - An optional user context for bcFunc
7201 
7202   Options Database Keys:
7203 + -bc_<boundary name> <num> - Overrides the boundary ids
7204 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7205 
7206   Level: developer
7207 
7208 .seealso: DMGetBoundary()
7209 @*/
7210 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)
7211 {
7212   PetscDS        ds;
7213   PetscErrorCode ierr;
7214 
7215   PetscFunctionBegin;
7216   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7217   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7218   ierr = PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, numids, ids, ctx);CHKERRQ(ierr);
7219   PetscFunctionReturn(0);
7220 }
7221 
7222 /*@
7223   DMGetNumBoundary - Get the number of registered BC
7224 
7225   Input Parameters:
7226 . dm - The mesh object
7227 
7228   Output Parameters:
7229 . numBd - The number of BC
7230 
7231   Level: intermediate
7232 
7233 .seealso: DMAddBoundary(), DMGetBoundary()
7234 @*/
7235 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
7236 {
7237   PetscDS        ds;
7238   PetscErrorCode ierr;
7239 
7240   PetscFunctionBegin;
7241   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7242   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7243   ierr = PetscDSGetNumBoundary(ds, numBd);CHKERRQ(ierr);
7244   PetscFunctionReturn(0);
7245 }
7246 
7247 /*@C
7248   DMGetBoundary - Get a model boundary condition
7249 
7250   Input Parameters:
7251 + dm          - The mesh object
7252 - bd          - The BC number
7253 
7254   Output Parameters:
7255 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7256 . name        - The BC name
7257 . labelname   - The label defining constrained points
7258 . field       - The field to constrain
7259 . numcomps    - The number of constrained field components
7260 . comps       - An array of constrained component numbers
7261 . bcFunc      - A pointwise function giving boundary values
7262 . numids      - The number of DMLabel ids for constrained points
7263 . ids         - An array of ids for constrained points
7264 - ctx         - An optional user context for bcFunc
7265 
7266   Options Database Keys:
7267 + -bc_<boundary name> <num> - Overrides the boundary ids
7268 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7269 
7270   Level: developer
7271 
7272 .seealso: DMAddBoundary()
7273 @*/
7274 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)
7275 {
7276   PetscDS        ds;
7277   PetscErrorCode ierr;
7278 
7279   PetscFunctionBegin;
7280   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7281   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7282   ierr = PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, numids, ids, ctx);CHKERRQ(ierr);
7283   PetscFunctionReturn(0);
7284 }
7285 
7286 static PetscErrorCode DMPopulateBoundary(DM dm)
7287 {
7288   PetscDS        ds;
7289   DMBoundary    *lastnext;
7290   DSBoundary     dsbound;
7291   PetscErrorCode ierr;
7292 
7293   PetscFunctionBegin;
7294   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7295   dsbound = ds->boundary;
7296   if (dm->boundary) {
7297     DMBoundary next = dm->boundary;
7298 
7299     /* quick check to see if the PetscDS has changed */
7300     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
7301     /* the PetscDS has changed: tear down and rebuild */
7302     while (next) {
7303       DMBoundary b = next;
7304 
7305       next = b->next;
7306       ierr = PetscFree(b);CHKERRQ(ierr);
7307     }
7308     dm->boundary = NULL;
7309   }
7310 
7311   lastnext = &(dm->boundary);
7312   while (dsbound) {
7313     DMBoundary dmbound;
7314 
7315     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
7316     dmbound->dsboundary = dsbound;
7317     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
7318     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
7319     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7320     *lastnext = dmbound;
7321     lastnext = &(dmbound->next);
7322     dsbound = dsbound->next;
7323   }
7324   PetscFunctionReturn(0);
7325 }
7326 
7327 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7328 {
7329   DMBoundary     b;
7330   PetscErrorCode ierr;
7331 
7332   PetscFunctionBegin;
7333   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7334   PetscValidPointer(isBd, 3);
7335   *isBd = PETSC_FALSE;
7336   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
7337   b = dm->boundary;
7338   while (b && !(*isBd)) {
7339     DMLabel    label = b->label;
7340     DSBoundary dsb = b->dsboundary;
7341 
7342     if (label) {
7343       PetscInt i;
7344 
7345       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
7346         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
7347       }
7348     }
7349     b = b->next;
7350   }
7351   PetscFunctionReturn(0);
7352 }
7353 
7354 /*@C
7355   DMProjectFunction - This projects the given function into the function space provided.
7356 
7357   Input Parameters:
7358 + dm      - The DM
7359 . time    - The time
7360 . funcs   - The coordinate functions to evaluate, one per field
7361 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7362 - mode    - The insertion mode for values
7363 
7364   Output Parameter:
7365 . X - vector
7366 
7367    Calling sequence of func:
7368 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7369 
7370 +  dim - The spatial dimension
7371 .  x   - The coordinates
7372 .  Nf  - The number of fields
7373 .  u   - The output field values
7374 -  ctx - optional user-defined function context
7375 
7376   Level: developer
7377 
7378 .seealso: DMComputeL2Diff()
7379 @*/
7380 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7381 {
7382   Vec            localX;
7383   PetscErrorCode ierr;
7384 
7385   PetscFunctionBegin;
7386   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7387   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
7388   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7389   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
7390   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
7391   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
7392   PetscFunctionReturn(0);
7393 }
7394 
7395 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7396 {
7397   PetscErrorCode ierr;
7398 
7399   PetscFunctionBegin;
7400   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7401   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
7402   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
7403   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7404   PetscFunctionReturn(0);
7405 }
7406 
7407 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)
7408 {
7409   Vec            localX;
7410   PetscErrorCode ierr;
7411 
7412   PetscFunctionBegin;
7413   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7414   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
7415   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7416   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
7417   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
7418   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
7419   PetscFunctionReturn(0);
7420 }
7421 
7422 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)
7423 {
7424   PetscErrorCode ierr;
7425 
7426   PetscFunctionBegin;
7427   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7428   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
7429   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
7430   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7431   PetscFunctionReturn(0);
7432 }
7433 
7434 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
7435                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
7436                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7437                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7438                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7439                                    InsertMode mode, Vec localX)
7440 {
7441   PetscErrorCode ierr;
7442 
7443   PetscFunctionBegin;
7444   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7445   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
7446   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
7447   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7448   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
7449   PetscFunctionReturn(0);
7450 }
7451 
7452 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
7453                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
7454                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7455                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7456                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7457                                         InsertMode mode, Vec localX)
7458 {
7459   PetscErrorCode ierr;
7460 
7461   PetscFunctionBegin;
7462   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7463   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
7464   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
7465   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7466   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
7467   PetscFunctionReturn(0);
7468 }
7469 
7470 /*@C
7471   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
7472 
7473   Input Parameters:
7474 + dm    - The DM
7475 . time  - The time
7476 . funcs - The functions to evaluate for each field component
7477 . ctxs  - Optional array of contexts to pass to each function, or NULL.
7478 - X     - The coefficient vector u_h, a global vector
7479 
7480   Output Parameter:
7481 . diff - The diff ||u - u_h||_2
7482 
7483   Level: developer
7484 
7485 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
7486 @*/
7487 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
7488 {
7489   PetscErrorCode ierr;
7490 
7491   PetscFunctionBegin;
7492   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7493   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
7494   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
7495   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
7496   PetscFunctionReturn(0);
7497 }
7498 
7499 /*@C
7500   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
7501 
7502   Input Parameters:
7503 + dm    - The DM
7504 , time  - The time
7505 . funcs - The gradient functions to evaluate for each field component
7506 . ctxs  - Optional array of contexts to pass to each function, or NULL.
7507 . X     - The coefficient vector u_h, a global vector
7508 - n     - The vector to project along
7509 
7510   Output Parameter:
7511 . diff - The diff ||(grad u - grad u_h) . n||_2
7512 
7513   Level: developer
7514 
7515 .seealso: DMProjectFunction(), DMComputeL2Diff()
7516 @*/
7517 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)
7518 {
7519   PetscErrorCode ierr;
7520 
7521   PetscFunctionBegin;
7522   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7523   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
7524   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
7525   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
7526   PetscFunctionReturn(0);
7527 }
7528 
7529 /*@C
7530   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
7531 
7532   Input Parameters:
7533 + dm    - The DM
7534 . time  - The time
7535 . funcs - The functions to evaluate for each field component
7536 . ctxs  - Optional array of contexts to pass to each function, or NULL.
7537 - X     - The coefficient vector u_h, a global vector
7538 
7539   Output Parameter:
7540 . diff - The array of differences, ||u^f - u^f_h||_2
7541 
7542   Level: developer
7543 
7544 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
7545 @*/
7546 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
7547 {
7548   PetscErrorCode ierr;
7549 
7550   PetscFunctionBegin;
7551   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7552   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
7553   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
7554   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
7555   PetscFunctionReturn(0);
7556 }
7557 
7558 /*@C
7559   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
7560                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
7561 
7562   Collective on dm
7563 
7564   Input parameters:
7565 + dm - the pre-adaptation DM object
7566 - label - label with the flags
7567 
7568   Output parameters:
7569 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
7570 
7571   Level: intermediate
7572 
7573 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
7574 @*/
7575 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
7576 {
7577   PetscErrorCode ierr;
7578 
7579   PetscFunctionBegin;
7580   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7581   PetscValidPointer(label,2);
7582   PetscValidPointer(dmAdapt,3);
7583   *dmAdapt = NULL;
7584   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
7585   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
7586   PetscFunctionReturn(0);
7587 }
7588 
7589 /*@C
7590   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
7591 
7592   Input Parameters:
7593 + dm - The DM object
7594 . metric - The metric to which the mesh is adapted, defined vertex-wise.
7595 - 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_".
7596 
7597   Output Parameter:
7598 . dmAdapt  - Pointer to the DM object containing the adapted mesh
7599 
7600   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
7601 
7602   Level: advanced
7603 
7604 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
7605 @*/
7606 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
7607 {
7608   PetscErrorCode ierr;
7609 
7610   PetscFunctionBegin;
7611   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7612   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
7613   if (bdLabel) PetscValidPointer(bdLabel, 3);
7614   PetscValidPointer(dmAdapt, 4);
7615   *dmAdapt = NULL;
7616   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
7617   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
7618   PetscFunctionReturn(0);
7619 }
7620 
7621 /*@C
7622  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
7623 
7624  Not Collective
7625 
7626  Input Parameter:
7627  . dm    - The DM
7628 
7629  Output Parameter:
7630  . nranks - the number of neighbours
7631  . ranks - the neighbors ranks
7632 
7633  Notes:
7634  Do not free the array, it is freed when the DM is destroyed.
7635 
7636  Level: beginner
7637 
7638  .seealso: DMDAGetNeighbors(), PetscSFGetRanks()
7639 @*/
7640 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
7641 {
7642   PetscErrorCode ierr;
7643 
7644   PetscFunctionBegin;
7645   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7646   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
7647   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
7648   PetscFunctionReturn(0);
7649 }
7650 
7651 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
7652 
7653 /*
7654     Converts the input vector to a ghosted vector and then calls the standard coloring code.
7655     This has be a different function because it requires DM which is not defined in the Mat library
7656 */
7657 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
7658 {
7659   PetscErrorCode ierr;
7660 
7661   PetscFunctionBegin;
7662   if (coloring->ctype == IS_COLORING_LOCAL) {
7663     Vec x1local;
7664     DM  dm;
7665     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
7666     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
7667     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
7668     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
7669     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
7670     x1   = x1local;
7671   }
7672   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
7673   if (coloring->ctype == IS_COLORING_LOCAL) {
7674     DM  dm;
7675     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
7676     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
7677   }
7678   PetscFunctionReturn(0);
7679 }
7680 
7681 /*@
7682     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
7683 
7684     Input Parameter:
7685 .    coloring - the MatFDColoring object
7686 
7687     Developer Notes:
7688     this routine exists because the PETSc Mat library does not know about the DM objects
7689 
7690     Level: advanced
7691 
7692 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
7693 @*/
7694 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
7695 {
7696   PetscFunctionBegin;
7697   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
7698   PetscFunctionReturn(0);
7699 }
7700 
7701 /*@
7702     DMGetCompatibility - determine if two DMs are compatible
7703 
7704     Collective
7705 
7706     Input Parameters:
7707 +    dm - the first DM
7708 -    dm2 - the second DM
7709 
7710     Output Parameters:
7711 +    compatible - whether or not the two DMs are compatible
7712 -    set - whether or not the compatible value was set
7713 
7714     Notes:
7715     Two DMs are deemed compatible if they represent the same parallel decomposition
7716     of the same topology. This implies that the section (field data) on one
7717     "makes sense" with respect to the topology and parallel decomposition of the other.
7718     Loosely speaking, compatible DMs represent the same domain and parallel
7719     decomposition, but hold different data.
7720 
7721     Typically, one would confirm compatibility if intending to simultaneously iterate
7722     over a pair of vectors obtained from different DMs.
7723 
7724     For example, two DMDA objects are compatible if they have the same local
7725     and global sizes and the same stencil width. They can have different numbers
7726     of degrees of freedom per node. Thus, one could use the node numbering from
7727     either DM in bounds for a loop over vectors derived from either DM.
7728 
7729     Consider the operation of summing data living on a 2-dof DMDA to data living
7730     on a 1-dof DMDA, which should be compatible, as in the following snippet.
7731 .vb
7732   ...
7733   ierr = DMGetCompatibility(da1,da2,&compatible,&set);CHKERRQ(ierr);
7734   if (set && compatible)  {
7735     ierr = DMDAVecGetArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
7736     ierr = DMDAVecGetArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
7737     ierr = DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);CHKERRQ(ierr);
7738     for (j=y; j<y+n; ++j) {
7739       for (i=x; i<x+m, ++i) {
7740         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
7741       }
7742     }
7743     ierr = DMDAVecRestoreArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
7744     ierr = DMDAVecRestoreArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
7745   } else {
7746     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
7747   }
7748   ...
7749 .ve
7750 
7751     Checking compatibility might be expensive for a given implementation of DM,
7752     or might be impossible to unambiguously confirm or deny. For this reason,
7753     this function may decline to determine compatibility, and hence users should
7754     always check the "set" output parameter.
7755 
7756     A DM is always compatible with itself.
7757 
7758     In the current implementation, DMs which live on "unequal" communicators
7759     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
7760     incompatible.
7761 
7762     This function is labeled "Collective," as information about all subdomains
7763     is required on each rank. However, in DM implementations which store all this
7764     information locally, this function may be merely "Logically Collective".
7765 
7766     Developer Notes:
7767     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
7768     iff B is compatible with A. Thus, this function checks the implementations
7769     of both dm and dm2 (if they are of different types), attempting to determine
7770     compatibility. It is left to DM implementers to ensure that symmetry is
7771     preserved. The simplest way to do this is, when implementing type-specific
7772     logic for this function, is to check for existing logic in the implementation
7773     of other DM types and let *set = PETSC_FALSE if found.
7774 
7775     Level: advanced
7776 
7777 .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
7778 @*/
7779 
7780 PetscErrorCode DMGetCompatibility(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
7781 {
7782   PetscErrorCode ierr;
7783   PetscMPIInt    compareResult;
7784   DMType         type,type2;
7785   PetscBool      sameType;
7786 
7787   PetscFunctionBegin;
7788   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7789   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
7790 
7791   /* Declare a DM compatible with itself */
7792   if (dm == dm2) {
7793     *set = PETSC_TRUE;
7794     *compatible = PETSC_TRUE;
7795     PetscFunctionReturn(0);
7796   }
7797 
7798   /* Declare a DM incompatible with a DM that lives on an "unequal"
7799      communicator. Note that this does not preclude compatibility with
7800      DMs living on "congruent" or "similar" communicators, but this must be
7801      determined by the implementation-specific logic */
7802   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)dm),PetscObjectComm((PetscObject)dm2),&compareResult);CHKERRQ(ierr);
7803   if (compareResult == MPI_UNEQUAL) {
7804     *set = PETSC_TRUE;
7805     *compatible = PETSC_FALSE;
7806     PetscFunctionReturn(0);
7807   }
7808 
7809   /* Pass to the implementation-specific routine, if one exists. */
7810   if (dm->ops->getcompatibility) {
7811     ierr = (*dm->ops->getcompatibility)(dm,dm2,compatible,set);CHKERRQ(ierr);
7812     if (*set) {
7813       PetscFunctionReturn(0);
7814     }
7815   }
7816 
7817   /* If dm and dm2 are of different types, then attempt to check compatibility
7818      with an implementation of this function from dm2 */
7819   ierr = DMGetType(dm,&type);CHKERRQ(ierr);
7820   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
7821   ierr = PetscStrcmp(type,type2,&sameType);CHKERRQ(ierr);
7822   if (!sameType && dm2->ops->getcompatibility) {
7823     ierr = (*dm2->ops->getcompatibility)(dm2,dm,compatible,set);CHKERRQ(ierr); /* Note argument order */
7824   } else {
7825     *set = PETSC_FALSE;
7826   }
7827   PetscFunctionReturn(0);
7828 }
7829