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