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