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