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