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