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