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