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