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