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