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