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