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