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