xref: /petsc/src/dm/interface/dm.c (revision 94ef8dde638caef1d0cd84a7dc8a2db65fcda8b6)
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, size;
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), &size);CHKERRQ(ierr);
3159   ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "%s:\n", name);CHKERRQ(ierr);
3160   for (p = 0; p < size; ++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 /*@
4441   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
4442 
4443   Input Parameter:
4444 . dm - The DM
4445 
4446   Output Parameter:
4447   areLocalized - True if localized
4448 
4449   Level: developer
4450 
4451 .seealso: DMLocalizeCoordinates()
4452 @*/
4453 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
4454 {
4455   DM             cdm;
4456   PetscSection   coordSection;
4457   PetscInt       cStart, cEnd, c, sStart, sEnd, dof;
4458   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
4459   PetscErrorCode ierr;
4460 
4461   PetscFunctionBegin;
4462   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4463   if (!dm->maxCell) {
4464     *areLocalized = PETSC_FALSE;
4465     PetscFunctionReturn(0);
4466   }
4467   /* We need some generic way of refering to cells/vertices */
4468   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4469   {
4470     PetscBool isplex;
4471 
4472     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
4473     if (isplex) {
4474       ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4475     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4476   }
4477   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4478   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
4479   alreadyLocalized = alreadyLocalizedGlobal = PETSC_FALSE;
4480   for (c = cStart; c < cEnd; ++c) {
4481     if (c < sStart || c >= sEnd) {
4482       alreadyLocalized = PETSC_FALSE;
4483       break;
4484     }
4485     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
4486     if (dof) {
4487       alreadyLocalized = PETSC_TRUE;
4488       break;
4489     }
4490   }
4491   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
4492   *areLocalized = alreadyLocalizedGlobal;
4493   PetscFunctionReturn(0);
4494 }
4495 
4496 
4497 /*@
4498   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for each cell
4499 
4500   Input Parameter:
4501 . dm - The DM
4502 
4503   Level: developer
4504 
4505 .seealso: DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
4506 @*/
4507 PetscErrorCode DMLocalizeCoordinates(DM dm)
4508 {
4509   DM             cdm;
4510   PetscSection   coordSection, cSection;
4511   Vec            coordinates,  cVec;
4512   PetscScalar   *coords, *coords2, *anchor, *localized;
4513   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
4514   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
4515   PetscInt       maxHeight = 0, h;
4516   PetscInt       *pStart = NULL, *pEnd = NULL;
4517   PetscErrorCode ierr;
4518 
4519   PetscFunctionBegin;
4520   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4521   if (!dm->maxCell) PetscFunctionReturn(0);
4522   /* We need some generic way of refering to cells/vertices */
4523   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4524   {
4525     PetscBool isplex;
4526 
4527     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
4528     if (isplex) {
4529       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4530       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
4531       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),PETSC_INT,&pStart);CHKERRQ(ierr);
4532       pEnd = &pStart[maxHeight + 1];
4533       newStart = vStart;
4534       newEnd   = vEnd;
4535       for (h = 0; h <= maxHeight; h++) {
4536         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
4537         newStart = PetscMin(newStart,pStart[h]);
4538         newEnd   = PetscMax(newEnd,pEnd[h]);
4539       }
4540     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4541   }
4542   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4543   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4544   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
4545   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
4546 
4547   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
4548   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
4549   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
4550   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
4551   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
4552 
4553   ierr = DMGetWorkArray(dm, 2 * bs, PETSC_SCALAR, &anchor);CHKERRQ(ierr);
4554   localized = &anchor[bs];
4555   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
4556   for (h = 0; h <= maxHeight; h++) {
4557     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
4558 
4559     for (c = cStart; c < cEnd; ++c) {
4560       PetscScalar *cellCoords = NULL;
4561       PetscInt     b;
4562 
4563       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
4564       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4565       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
4566       for (d = 0; d < dof/bs; ++d) {
4567         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
4568         for (b = 0; b < bs; b++) {
4569           if (cellCoords[d*bs + b] != localized[b]) break;
4570         }
4571         if (b < bs) break;
4572       }
4573       if (d < dof/bs) {
4574         if (c >= sStart && c < sEnd) {
4575           PetscInt cdof;
4576 
4577           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
4578           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
4579         }
4580         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
4581         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
4582       }
4583       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4584     }
4585   }
4586   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
4587   if (alreadyLocalizedGlobal) {
4588     ierr = DMRestoreWorkArray(dm, 2 * bs, PETSC_SCALAR, &anchor);CHKERRQ(ierr);
4589     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
4590     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),PETSC_INT,&pStart);CHKERRQ(ierr);
4591     PetscFunctionReturn(0);
4592   }
4593   for (v = vStart; v < vEnd; ++v) {
4594     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
4595     ierr = PetscSectionSetDof(cSection,     v,  dof);CHKERRQ(ierr);
4596     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
4597   }
4598   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
4599   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
4600   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
4601   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
4602   ierr = VecSetBlockSize(cVec,         bs);CHKERRQ(ierr);
4603   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4604   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
4605   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
4606   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
4607   for (v = vStart; v < vEnd; ++v) {
4608     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
4609     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4610     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
4611     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
4612   }
4613   for (h = 0; h <= maxHeight; h++) {
4614     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
4615 
4616     for (c = cStart; c < cEnd; ++c) {
4617       PetscScalar *cellCoords = NULL;
4618       PetscInt     b, cdof;
4619 
4620       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
4621       if (!cdof) continue;
4622       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4623       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
4624       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
4625       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
4626       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4627     }
4628   }
4629   ierr = DMRestoreWorkArray(dm, 2 * bs, PETSC_SCALAR, &anchor);CHKERRQ(ierr);
4630   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),PETSC_INT,&pStart);CHKERRQ(ierr);
4631   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
4632   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
4633   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
4634   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
4635   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
4636   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
4637   PetscFunctionReturn(0);
4638 }
4639 
4640 /*@
4641   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
4642 
4643   Collective on Vec v (see explanation below)
4644 
4645   Input Parameters:
4646 + dm - The DM
4647 . v - The Vec of points
4648 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
4649 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
4650 
4651   Output Parameter:
4652 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
4653 - cells - The PetscSF containing the ranks and local indices of the containing points.
4654 
4655 
4656   Level: developer
4657 
4658   Notes:
4659   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
4660   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
4661 
4662   If *cellSF is NULL on input, a PetscSF will be created.
4663   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
4664 
4665   An array that maps each point to its containing cell can be obtained with
4666 
4667 $    const PetscSFNode *cells;
4668 $    PetscInt           nFound;
4669 $    const PetscSFNode *found;
4670 $
4671 $    PetscSFGetGraph(cells,NULL,&nFound,&found,&cells);
4672 
4673   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
4674   the index of the cell in its rank's local numbering.
4675 
4676 .keywords: point location, mesh
4677 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
4678 @*/
4679 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
4680 {
4681   PetscErrorCode ierr;
4682 
4683   PetscFunctionBegin;
4684   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4685   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
4686   PetscValidPointer(cellSF,4);
4687   if (*cellSF) {
4688     PetscMPIInt result;
4689 
4690     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
4691     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)cellSF),&result);CHKERRQ(ierr);
4692     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
4693   } else {
4694     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
4695   }
4696   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
4697   if (dm->ops->locatepoints) {
4698     ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
4699   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
4700   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
4701   PetscFunctionReturn(0);
4702 }
4703 
4704 /*@
4705   DMGetOutputDM - Retrieve the DM associated with the layout for output
4706 
4707   Input Parameter:
4708 . dm - The original DM
4709 
4710   Output Parameter:
4711 . odm - The DM which provides the layout for output
4712 
4713   Level: intermediate
4714 
4715 .seealso: VecView(), DMGetDefaultGlobalSection()
4716 @*/
4717 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
4718 {
4719   PetscSection   section;
4720   PetscBool      hasConstraints, ghasConstraints;
4721   PetscErrorCode ierr;
4722 
4723   PetscFunctionBegin;
4724   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4725   PetscValidPointer(odm,2);
4726   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
4727   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
4728   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
4729   if (!ghasConstraints) {
4730     *odm = dm;
4731     PetscFunctionReturn(0);
4732   }
4733   if (!dm->dmBC) {
4734     PetscDS      ds;
4735     PetscSection newSection, gsection;
4736     PetscSF      sf;
4737 
4738     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
4739     ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
4740     ierr = DMSetDS(dm->dmBC, ds);CHKERRQ(ierr);
4741     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
4742     ierr = DMSetDefaultSection(dm->dmBC, newSection);CHKERRQ(ierr);
4743     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
4744     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
4745     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
4746     ierr = DMSetDefaultGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
4747     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
4748   }
4749   *odm = dm->dmBC;
4750   PetscFunctionReturn(0);
4751 }
4752 
4753 /*@
4754   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
4755 
4756   Input Parameter:
4757 . dm - The original DM
4758 
4759   Output Parameters:
4760 + num - The output sequence number
4761 - val - The output sequence value
4762 
4763   Level: intermediate
4764 
4765   Note: This is intended for output that should appear in sequence, for instance
4766   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4767 
4768 .seealso: VecView()
4769 @*/
4770 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
4771 {
4772   PetscFunctionBegin;
4773   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4774   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
4775   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
4776   PetscFunctionReturn(0);
4777 }
4778 
4779 /*@
4780   DMSetOutputSequenceNumber - Set the sequence number/value for output
4781 
4782   Input Parameters:
4783 + dm - The original DM
4784 . num - The output sequence number
4785 - val - The output sequence value
4786 
4787   Level: intermediate
4788 
4789   Note: This is intended for output that should appear in sequence, for instance
4790   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4791 
4792 .seealso: VecView()
4793 @*/
4794 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
4795 {
4796   PetscFunctionBegin;
4797   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4798   dm->outputSequenceNum = num;
4799   dm->outputSequenceVal = val;
4800   PetscFunctionReturn(0);
4801 }
4802 
4803 /*@C
4804   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
4805 
4806   Input Parameters:
4807 + dm   - The original DM
4808 . name - The sequence name
4809 - num  - The output sequence number
4810 
4811   Output Parameter:
4812 . val  - The output sequence value
4813 
4814   Level: intermediate
4815 
4816   Note: This is intended for output that should appear in sequence, for instance
4817   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4818 
4819 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
4820 @*/
4821 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
4822 {
4823   PetscBool      ishdf5;
4824   PetscErrorCode ierr;
4825 
4826   PetscFunctionBegin;
4827   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4828   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
4829   PetscValidPointer(val,4);
4830   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
4831   if (ishdf5) {
4832 #if defined(PETSC_HAVE_HDF5)
4833     PetscScalar value;
4834 
4835     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
4836     *val = PetscRealPart(value);
4837 #endif
4838   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
4839   PetscFunctionReturn(0);
4840 }
4841 
4842 /*@
4843   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
4844 
4845   Not collective
4846 
4847   Input Parameter:
4848 . dm - The DM
4849 
4850   Output Parameter:
4851 . useNatural - The flag to build the mapping to a natural order during distribution
4852 
4853   Level: beginner
4854 
4855 .seealso: DMSetUseNatural(), DMCreate()
4856 @*/
4857 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
4858 {
4859   PetscFunctionBegin;
4860   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4861   PetscValidPointer(useNatural, 2);
4862   *useNatural = dm->useNatural;
4863   PetscFunctionReturn(0);
4864 }
4865 
4866 /*@
4867   DMSetUseNatural - Set the flag for creating a mapping to the natural order on distribution
4868 
4869   Collective on dm
4870 
4871   Input Parameters:
4872 + dm - The DM
4873 - useNatural - The flag to build the mapping to a natural order during distribution
4874 
4875   Level: beginner
4876 
4877 .seealso: DMGetUseNatural(), DMCreate()
4878 @*/
4879 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
4880 {
4881   PetscFunctionBegin;
4882   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4883   PetscValidLogicalCollectiveInt(dm, useNatural, 2);
4884   dm->useNatural = useNatural;
4885   PetscFunctionReturn(0);
4886 }
4887 
4888 
4889 /*@C
4890   DMCreateLabel - Create a label of the given name if it does not already exist
4891 
4892   Not Collective
4893 
4894   Input Parameters:
4895 + dm   - The DM object
4896 - name - The label name
4897 
4898   Level: intermediate
4899 
4900 .keywords: mesh
4901 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4902 @*/
4903 PetscErrorCode DMCreateLabel(DM dm, const char name[])
4904 {
4905   DMLabelLink    next  = dm->labels->next;
4906   PetscBool      flg   = PETSC_FALSE;
4907   PetscErrorCode ierr;
4908 
4909   PetscFunctionBegin;
4910   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4911   PetscValidCharPointer(name, 2);
4912   while (next) {
4913     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
4914     if (flg) break;
4915     next = next->next;
4916   }
4917   if (!flg) {
4918     DMLabelLink tmpLabel;
4919 
4920     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
4921     ierr = DMLabelCreate(name, &tmpLabel->label);CHKERRQ(ierr);
4922     tmpLabel->output = PETSC_TRUE;
4923     tmpLabel->next   = dm->labels->next;
4924     dm->labels->next = tmpLabel;
4925   }
4926   PetscFunctionReturn(0);
4927 }
4928 
4929 /*@C
4930   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
4931 
4932   Not Collective
4933 
4934   Input Parameters:
4935 + dm   - The DM object
4936 . name - The label name
4937 - point - The mesh point
4938 
4939   Output Parameter:
4940 . value - The label value for this point, or -1 if the point is not in the label
4941 
4942   Level: beginner
4943 
4944 .keywords: mesh
4945 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
4946 @*/
4947 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
4948 {
4949   DMLabel        label;
4950   PetscErrorCode ierr;
4951 
4952   PetscFunctionBegin;
4953   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4954   PetscValidCharPointer(name, 2);
4955   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4956   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);CHKERRQ(ierr);
4957   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
4958   PetscFunctionReturn(0);
4959 }
4960 
4961 /*@C
4962   DMSetLabelValue - Add a point to a Sieve Label with given value
4963 
4964   Not Collective
4965 
4966   Input Parameters:
4967 + dm   - The DM object
4968 . name - The label name
4969 . point - The mesh point
4970 - value - The label value for this point
4971 
4972   Output Parameter:
4973 
4974   Level: beginner
4975 
4976 .keywords: mesh
4977 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
4978 @*/
4979 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
4980 {
4981   DMLabel        label;
4982   PetscErrorCode ierr;
4983 
4984   PetscFunctionBegin;
4985   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4986   PetscValidCharPointer(name, 2);
4987   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4988   if (!label) {
4989     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
4990     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4991   }
4992   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
4993   PetscFunctionReturn(0);
4994 }
4995 
4996 /*@C
4997   DMClearLabelValue - Remove a point from a Sieve Label with given value
4998 
4999   Not Collective
5000 
5001   Input Parameters:
5002 + dm   - The DM object
5003 . name - The label name
5004 . point - The mesh point
5005 - value - The label value for this point
5006 
5007   Output Parameter:
5008 
5009   Level: beginner
5010 
5011 .keywords: mesh
5012 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
5013 @*/
5014 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5015 {
5016   DMLabel        label;
5017   PetscErrorCode ierr;
5018 
5019   PetscFunctionBegin;
5020   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5021   PetscValidCharPointer(name, 2);
5022   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5023   if (!label) PetscFunctionReturn(0);
5024   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
5025   PetscFunctionReturn(0);
5026 }
5027 
5028 /*@C
5029   DMGetLabelSize - Get the number of different integer ids in a Label
5030 
5031   Not Collective
5032 
5033   Input Parameters:
5034 + dm   - The DM object
5035 - name - The label name
5036 
5037   Output Parameter:
5038 . size - The number of different integer ids, or 0 if the label does not exist
5039 
5040   Level: beginner
5041 
5042 .keywords: mesh
5043 .seealso: DMLabeGetNumValues(), DMSetLabelValue()
5044 @*/
5045 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
5046 {
5047   DMLabel        label;
5048   PetscErrorCode ierr;
5049 
5050   PetscFunctionBegin;
5051   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5052   PetscValidCharPointer(name, 2);
5053   PetscValidPointer(size, 3);
5054   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5055   *size = 0;
5056   if (!label) PetscFunctionReturn(0);
5057   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
5058   PetscFunctionReturn(0);
5059 }
5060 
5061 /*@C
5062   DMGetLabelIdIS - Get the integer ids in a label
5063 
5064   Not Collective
5065 
5066   Input Parameters:
5067 + mesh - The DM object
5068 - name - The label name
5069 
5070   Output Parameter:
5071 . ids - The integer ids, or NULL if the label does not exist
5072 
5073   Level: beginner
5074 
5075 .keywords: mesh
5076 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
5077 @*/
5078 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
5079 {
5080   DMLabel        label;
5081   PetscErrorCode ierr;
5082 
5083   PetscFunctionBegin;
5084   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5085   PetscValidCharPointer(name, 2);
5086   PetscValidPointer(ids, 3);
5087   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5088   *ids = NULL;
5089   if (!label) PetscFunctionReturn(0);
5090   ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
5091   PetscFunctionReturn(0);
5092 }
5093 
5094 /*@C
5095   DMGetStratumSize - Get the number of points in a label stratum
5096 
5097   Not Collective
5098 
5099   Input Parameters:
5100 + dm - The DM object
5101 . name - The label name
5102 - value - The stratum value
5103 
5104   Output Parameter:
5105 . size - The stratum size
5106 
5107   Level: beginner
5108 
5109 .keywords: mesh
5110 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
5111 @*/
5112 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
5113 {
5114   DMLabel        label;
5115   PetscErrorCode ierr;
5116 
5117   PetscFunctionBegin;
5118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5119   PetscValidCharPointer(name, 2);
5120   PetscValidPointer(size, 4);
5121   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5122   *size = 0;
5123   if (!label) PetscFunctionReturn(0);
5124   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
5125   PetscFunctionReturn(0);
5126 }
5127 
5128 /*@C
5129   DMGetStratumIS - Get the points in a label stratum
5130 
5131   Not Collective
5132 
5133   Input Parameters:
5134 + dm - The DM object
5135 . name - The label name
5136 - value - The stratum value
5137 
5138   Output Parameter:
5139 . points - The stratum points, or NULL if the label does not exist or does not have that value
5140 
5141   Level: beginner
5142 
5143 .keywords: mesh
5144 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
5145 @*/
5146 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
5147 {
5148   DMLabel        label;
5149   PetscErrorCode ierr;
5150 
5151   PetscFunctionBegin;
5152   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5153   PetscValidCharPointer(name, 2);
5154   PetscValidPointer(points, 4);
5155   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5156   *points = NULL;
5157   if (!label) PetscFunctionReturn(0);
5158   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
5159   PetscFunctionReturn(0);
5160 }
5161 
5162 /*@C
5163   DMGetStratumIS - Set the points in a label stratum
5164 
5165   Not Collective
5166 
5167   Input Parameters:
5168 + dm - The DM object
5169 . name - The label name
5170 . value - The stratum value
5171 - points - The stratum points
5172 
5173   Level: beginner
5174 
5175 .keywords: mesh
5176 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
5177 @*/
5178 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
5179 {
5180   DMLabel        label;
5181   PetscErrorCode ierr;
5182 
5183   PetscFunctionBegin;
5184   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5185   PetscValidCharPointer(name, 2);
5186   PetscValidPointer(points, 4);
5187   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5188   if (!label) PetscFunctionReturn(0);
5189   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
5190   PetscFunctionReturn(0);
5191 }
5192 
5193 /*@C
5194   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
5195 
5196   Not Collective
5197 
5198   Input Parameters:
5199 + dm   - The DM object
5200 . name - The label name
5201 - value - The label value for this point
5202 
5203   Output Parameter:
5204 
5205   Level: beginner
5206 
5207 .keywords: mesh
5208 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
5209 @*/
5210 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
5211 {
5212   DMLabel        label;
5213   PetscErrorCode ierr;
5214 
5215   PetscFunctionBegin;
5216   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5217   PetscValidCharPointer(name, 2);
5218   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5219   if (!label) PetscFunctionReturn(0);
5220   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
5221   PetscFunctionReturn(0);
5222 }
5223 
5224 /*@
5225   DMGetNumLabels - Return the number of labels defined by the mesh
5226 
5227   Not Collective
5228 
5229   Input Parameter:
5230 . dm   - The DM object
5231 
5232   Output Parameter:
5233 . numLabels - the number of Labels
5234 
5235   Level: intermediate
5236 
5237 .keywords: mesh
5238 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5239 @*/
5240 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
5241 {
5242   DMLabelLink next = dm->labels->next;
5243   PetscInt  n    = 0;
5244 
5245   PetscFunctionBegin;
5246   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5247   PetscValidPointer(numLabels, 2);
5248   while (next) {++n; next = next->next;}
5249   *numLabels = n;
5250   PetscFunctionReturn(0);
5251 }
5252 
5253 /*@C
5254   DMGetLabelName - Return the name of nth label
5255 
5256   Not Collective
5257 
5258   Input Parameters:
5259 + dm - The DM object
5260 - n  - the label number
5261 
5262   Output Parameter:
5263 . name - the label name
5264 
5265   Level: intermediate
5266 
5267 .keywords: mesh
5268 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5269 @*/
5270 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
5271 {
5272   DMLabelLink next = dm->labels->next;
5273   PetscInt  l    = 0;
5274 
5275   PetscFunctionBegin;
5276   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5277   PetscValidPointer(name, 3);
5278   while (next) {
5279     if (l == n) {
5280       *name = next->label->name;
5281       PetscFunctionReturn(0);
5282     }
5283     ++l;
5284     next = next->next;
5285   }
5286   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5287 }
5288 
5289 /*@C
5290   DMHasLabel - Determine whether the mesh has a label of a given name
5291 
5292   Not Collective
5293 
5294   Input Parameters:
5295 + dm   - The DM object
5296 - name - The label name
5297 
5298   Output Parameter:
5299 . hasLabel - PETSC_TRUE if the label is present
5300 
5301   Level: intermediate
5302 
5303 .keywords: mesh
5304 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5305 @*/
5306 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
5307 {
5308   DMLabelLink    next = dm->labels->next;
5309   PetscErrorCode ierr;
5310 
5311   PetscFunctionBegin;
5312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5313   PetscValidCharPointer(name, 2);
5314   PetscValidPointer(hasLabel, 3);
5315   *hasLabel = PETSC_FALSE;
5316   while (next) {
5317     ierr = PetscStrcmp(name, next->label->name, hasLabel);CHKERRQ(ierr);
5318     if (*hasLabel) break;
5319     next = next->next;
5320   }
5321   PetscFunctionReturn(0);
5322 }
5323 
5324 /*@C
5325   DMGetLabel - Return the label of a given name, or NULL
5326 
5327   Not Collective
5328 
5329   Input Parameters:
5330 + dm   - The DM object
5331 - name - The label name
5332 
5333   Output Parameter:
5334 . label - The DMLabel, or NULL if the label is absent
5335 
5336   Level: intermediate
5337 
5338 .keywords: mesh
5339 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5340 @*/
5341 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
5342 {
5343   DMLabelLink    next = dm->labels->next;
5344   PetscBool      hasLabel;
5345   PetscErrorCode ierr;
5346 
5347   PetscFunctionBegin;
5348   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5349   PetscValidCharPointer(name, 2);
5350   PetscValidPointer(label, 3);
5351   *label = NULL;
5352   while (next) {
5353     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5354     if (hasLabel) {
5355       *label = next->label;
5356       break;
5357     }
5358     next = next->next;
5359   }
5360   PetscFunctionReturn(0);
5361 }
5362 
5363 /*@C
5364   DMGetLabelByNum - Return the nth label
5365 
5366   Not Collective
5367 
5368   Input Parameters:
5369 + dm - The DM object
5370 - n  - the label number
5371 
5372   Output Parameter:
5373 . label - the label
5374 
5375   Level: intermediate
5376 
5377 .keywords: mesh
5378 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5379 @*/
5380 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
5381 {
5382   DMLabelLink next = dm->labels->next;
5383   PetscInt    l    = 0;
5384 
5385   PetscFunctionBegin;
5386   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5387   PetscValidPointer(label, 3);
5388   while (next) {
5389     if (l == n) {
5390       *label = next->label;
5391       PetscFunctionReturn(0);
5392     }
5393     ++l;
5394     next = next->next;
5395   }
5396   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5397 }
5398 
5399 /*@C
5400   DMAddLabel - Add the label to this mesh
5401 
5402   Not Collective
5403 
5404   Input Parameters:
5405 + dm   - The DM object
5406 - label - The DMLabel
5407 
5408   Level: developer
5409 
5410 .keywords: mesh
5411 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5412 @*/
5413 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
5414 {
5415   DMLabelLink    tmpLabel;
5416   PetscBool      hasLabel;
5417   PetscErrorCode ierr;
5418 
5419   PetscFunctionBegin;
5420   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5421   ierr = DMHasLabel(dm, label->name, &hasLabel);CHKERRQ(ierr);
5422   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", label->name);
5423   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5424   tmpLabel->label  = label;
5425   tmpLabel->output = PETSC_TRUE;
5426   tmpLabel->next   = dm->labels->next;
5427   dm->labels->next = tmpLabel;
5428   PetscFunctionReturn(0);
5429 }
5430 
5431 /*@C
5432   DMRemoveLabel - Remove the label from this mesh
5433 
5434   Not Collective
5435 
5436   Input Parameters:
5437 + dm   - The DM object
5438 - name - The label name
5439 
5440   Output Parameter:
5441 . label - The DMLabel, or NULL if the label is absent
5442 
5443   Level: developer
5444 
5445 .keywords: mesh
5446 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5447 @*/
5448 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
5449 {
5450   DMLabelLink    next = dm->labels->next;
5451   DMLabelLink    last = NULL;
5452   PetscBool      hasLabel;
5453   PetscErrorCode ierr;
5454 
5455   PetscFunctionBegin;
5456   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5457   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
5458   *label = NULL;
5459   if (!hasLabel) PetscFunctionReturn(0);
5460   while (next) {
5461     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5462     if (hasLabel) {
5463       if (last) last->next       = next->next;
5464       else      dm->labels->next = next->next;
5465       next->next = NULL;
5466       *label     = next->label;
5467       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
5468       if (hasLabel) {
5469         dm->depthLabel = NULL;
5470       }
5471       ierr = PetscFree(next);CHKERRQ(ierr);
5472       break;
5473     }
5474     last = next;
5475     next = next->next;
5476   }
5477   PetscFunctionReturn(0);
5478 }
5479 
5480 /*@C
5481   DMGetLabelOutput - Get the output flag for a given label
5482 
5483   Not Collective
5484 
5485   Input Parameters:
5486 + dm   - The DM object
5487 - name - The label name
5488 
5489   Output Parameter:
5490 . output - The flag for output
5491 
5492   Level: developer
5493 
5494 .keywords: mesh
5495 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5496 @*/
5497 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
5498 {
5499   DMLabelLink    next = dm->labels->next;
5500   PetscErrorCode ierr;
5501 
5502   PetscFunctionBegin;
5503   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5504   PetscValidPointer(name, 2);
5505   PetscValidPointer(output, 3);
5506   while (next) {
5507     PetscBool flg;
5508 
5509     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5510     if (flg) {*output = next->output; PetscFunctionReturn(0);}
5511     next = next->next;
5512   }
5513   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5514 }
5515 
5516 /*@C
5517   DMSetLabelOutput - Set the output flag for a given label
5518 
5519   Not Collective
5520 
5521   Input Parameters:
5522 + dm     - The DM object
5523 . name   - The label name
5524 - output - The flag for output
5525 
5526   Level: developer
5527 
5528 .keywords: mesh
5529 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5530 @*/
5531 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
5532 {
5533   DMLabelLink    next = dm->labels->next;
5534   PetscErrorCode ierr;
5535 
5536   PetscFunctionBegin;
5537   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5538   PetscValidPointer(name, 2);
5539   while (next) {
5540     PetscBool flg;
5541 
5542     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5543     if (flg) {next->output = output; PetscFunctionReturn(0);}
5544     next = next->next;
5545   }
5546   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5547 }
5548 
5549 
5550 /*@
5551   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
5552 
5553   Collective on DM
5554 
5555   Input Parameter:
5556 . dmA - The DM object with initial labels
5557 
5558   Output Parameter:
5559 . dmB - The DM object with copied labels
5560 
5561   Level: intermediate
5562 
5563   Note: This is typically used when interpolating or otherwise adding to a mesh
5564 
5565 .keywords: mesh
5566 .seealso: DMCopyCoordinates(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
5567 @*/
5568 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
5569 {
5570   PetscInt       numLabels, l;
5571   PetscErrorCode ierr;
5572 
5573   PetscFunctionBegin;
5574   if (dmA == dmB) PetscFunctionReturn(0);
5575   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
5576   for (l = 0; l < numLabels; ++l) {
5577     DMLabel     label, labelNew;
5578     const char *name;
5579     PetscBool   flg;
5580 
5581     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
5582     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
5583     if (flg) continue;
5584     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
5585     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
5586     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
5587   }
5588   PetscFunctionReturn(0);
5589 }
5590 
5591 /*@
5592   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
5593 
5594   Input Parameter:
5595 . dm - The DM object
5596 
5597   Output Parameter:
5598 . cdm - The coarse DM
5599 
5600   Level: intermediate
5601 
5602 .seealso: DMSetCoarseDM()
5603 @*/
5604 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
5605 {
5606   PetscFunctionBegin;
5607   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5608   PetscValidPointer(cdm, 2);
5609   *cdm = dm->coarseMesh;
5610   PetscFunctionReturn(0);
5611 }
5612 
5613 /*@
5614   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
5615 
5616   Input Parameters:
5617 + dm - The DM object
5618 - cdm - The coarse DM
5619 
5620   Level: intermediate
5621 
5622 .seealso: DMGetCoarseDM()
5623 @*/
5624 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
5625 {
5626   PetscErrorCode ierr;
5627 
5628   PetscFunctionBegin;
5629   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5630   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
5631   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
5632   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
5633   dm->coarseMesh = cdm;
5634   PetscFunctionReturn(0);
5635 }
5636 
5637 /*@
5638   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
5639 
5640   Input Parameter:
5641 . dm - The DM object
5642 
5643   Output Parameter:
5644 . fdm - The fine DM
5645 
5646   Level: intermediate
5647 
5648 .seealso: DMSetFineDM()
5649 @*/
5650 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
5651 {
5652   PetscFunctionBegin;
5653   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5654   PetscValidPointer(fdm, 2);
5655   *fdm = dm->fineMesh;
5656   PetscFunctionReturn(0);
5657 }
5658 
5659 /*@
5660   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
5661 
5662   Input Parameters:
5663 + dm - The DM object
5664 - fdm - The fine DM
5665 
5666   Level: intermediate
5667 
5668 .seealso: DMGetFineDM()
5669 @*/
5670 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
5671 {
5672   PetscErrorCode ierr;
5673 
5674   PetscFunctionBegin;
5675   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5676   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
5677   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
5678   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
5679   dm->fineMesh = fdm;
5680   PetscFunctionReturn(0);
5681 }
5682 
5683 /*=== DMBoundary code ===*/
5684 
5685 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
5686 {
5687   PetscErrorCode ierr;
5688 
5689   PetscFunctionBegin;
5690   ierr = PetscDSCopyBoundary(dm->prob,dmNew->prob);CHKERRQ(ierr);
5691   PetscFunctionReturn(0);
5692 }
5693 
5694 /*@C
5695   DMAddBoundary - Add a boundary condition to the model
5696 
5697   Input Parameters:
5698 + dm          - The DM, with a PetscDS that matches the problem being constrained
5699 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
5700 . name        - The BC name
5701 . labelname   - The label defining constrained points
5702 . field       - The field to constrain
5703 . numcomps    - The number of constrained field components
5704 . comps       - An array of constrained component numbers
5705 . bcFunc      - A pointwise function giving boundary values
5706 . numids      - The number of DMLabel ids for constrained points
5707 . ids         - An array of ids for constrained points
5708 - ctx         - An optional user context for bcFunc
5709 
5710   Options Database Keys:
5711 + -bc_<boundary name> <num> - Overrides the boundary ids
5712 - -bc_<boundary name>_comp <num> - Overrides the boundary components
5713 
5714   Level: developer
5715 
5716 .seealso: DMGetBoundary()
5717 @*/
5718 PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), PetscInt numids, const PetscInt *ids, void *ctx)
5719 {
5720   PetscErrorCode ierr;
5721 
5722   PetscFunctionBegin;
5723   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5724   ierr = PetscDSAddBoundary(dm->prob,type,name,labelname,field,numcomps,comps,bcFunc,numids,ids,ctx);CHKERRQ(ierr);
5725   PetscFunctionReturn(0);
5726 }
5727 
5728 /*@
5729   DMGetNumBoundary - Get the number of registered BC
5730 
5731   Input Parameters:
5732 . dm - The mesh object
5733 
5734   Output Parameters:
5735 . numBd - The number of BC
5736 
5737   Level: intermediate
5738 
5739 .seealso: DMAddBoundary(), DMGetBoundary()
5740 @*/
5741 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
5742 {
5743   PetscErrorCode ierr;
5744 
5745   PetscFunctionBegin;
5746   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5747   ierr = PetscDSGetNumBoundary(dm->prob,numBd);CHKERRQ(ierr);
5748   PetscFunctionReturn(0);
5749 }
5750 
5751 /*@C
5752   DMGetBoundary - Add a boundary condition to the model
5753 
5754   Input Parameters:
5755 + dm          - The mesh object
5756 - bd          - The BC number
5757 
5758   Output Parameters:
5759 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
5760 . name        - The BC name
5761 . labelname   - The label defining constrained points
5762 . field       - The field to constrain
5763 . numcomps    - The number of constrained field components
5764 . comps       - An array of constrained component numbers
5765 . bcFunc      - A pointwise function giving boundary values
5766 . numids      - The number of DMLabel ids for constrained points
5767 . ids         - An array of ids for constrained points
5768 - ctx         - An optional user context for bcFunc
5769 
5770   Options Database Keys:
5771 + -bc_<boundary name> <num> - Overrides the boundary ids
5772 - -bc_<boundary name>_comp <num> - Overrides the boundary components
5773 
5774   Level: developer
5775 
5776 .seealso: DMAddBoundary()
5777 @*/
5778 PetscErrorCode DMGetBoundary(DM dm, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
5779 {
5780   PetscErrorCode ierr;
5781 
5782   PetscFunctionBegin;
5783   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5784   ierr = PetscDSGetBoundary(dm->prob,bd,type,name,labelname,field,numcomps,comps,func,numids,ids,ctx);CHKERRQ(ierr);
5785   PetscFunctionReturn(0);
5786 }
5787 
5788 static PetscErrorCode DMPopulateBoundary(DM dm)
5789 {
5790   DMBoundary *lastnext;
5791   DSBoundary dsbound;
5792   PetscErrorCode ierr;
5793 
5794   PetscFunctionBegin;
5795   dsbound = dm->prob->boundary;
5796   if (dm->boundary) {
5797     DMBoundary next = dm->boundary;
5798 
5799     /* quick check to see if the PetscDS has changed */
5800     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
5801     /* the PetscDS has changed: tear down and rebuild */
5802     while (next) {
5803       DMBoundary b = next;
5804 
5805       next = b->next;
5806       ierr = PetscFree(b);CHKERRQ(ierr);
5807     }
5808     dm->boundary = NULL;
5809   }
5810 
5811   lastnext = &(dm->boundary);
5812   while (dsbound) {
5813     DMBoundary dmbound;
5814 
5815     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
5816     dmbound->dsboundary = dsbound;
5817     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
5818     if (!dmbound->label) PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);
5819     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
5820     *lastnext = dmbound;
5821     lastnext = &(dmbound->next);
5822     dsbound = dsbound->next;
5823   }
5824   PetscFunctionReturn(0);
5825 }
5826 
5827 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
5828 {
5829   DMBoundary     b;
5830   PetscErrorCode ierr;
5831 
5832   PetscFunctionBegin;
5833   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5834   PetscValidPointer(isBd, 3);
5835   *isBd = PETSC_FALSE;
5836   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
5837   b = dm->boundary;
5838   while (b && !(*isBd)) {
5839     DMLabel    label = b->label;
5840     DSBoundary dsb = b->dsboundary;
5841 
5842     if (label) {
5843       PetscInt i;
5844 
5845       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
5846         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
5847       }
5848     }
5849     b = b->next;
5850   }
5851   PetscFunctionReturn(0);
5852 }
5853 
5854 /*@C
5855   DMProjectFunction - This projects the given function into the function space provided.
5856 
5857   Input Parameters:
5858 + dm      - The DM
5859 . time    - The time
5860 . funcs   - The coordinate functions to evaluate, one per field
5861 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
5862 - mode    - The insertion mode for values
5863 
5864   Output Parameter:
5865 . X - vector
5866 
5867    Calling sequence of func:
5868 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
5869 
5870 +  dim - The spatial dimension
5871 .  x   - The coordinates
5872 .  Nf  - The number of fields
5873 .  u   - The output field values
5874 -  ctx - optional user-defined function context
5875 
5876   Level: developer
5877 
5878 .seealso: DMComputeL2Diff()
5879 @*/
5880 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
5881 {
5882   Vec            localX;
5883   PetscErrorCode ierr;
5884 
5885   PetscFunctionBegin;
5886   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5887   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
5888   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
5889   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
5890   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
5891   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
5892   PetscFunctionReturn(0);
5893 }
5894 
5895 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
5896 {
5897   PetscErrorCode ierr;
5898 
5899   PetscFunctionBegin;
5900   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5901   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
5902   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFunctionLocal",((PetscObject)dm)->type_name);
5903   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
5904   PetscFunctionReturn(0);
5905 }
5906 
5907 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)
5908 {
5909   PetscErrorCode ierr;
5910 
5911   PetscFunctionBegin;
5912   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5913   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
5914   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
5915   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, funcs, ctxs, mode, localX);CHKERRQ(ierr);
5916   PetscFunctionReturn(0);
5917 }
5918 
5919 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
5920                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
5921                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
5922                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
5923                                                   PetscReal, const PetscReal[], PetscScalar[]),
5924                                    InsertMode mode, Vec localX)
5925 {
5926   PetscErrorCode ierr;
5927 
5928   PetscFunctionBegin;
5929   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5930   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
5931   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
5932   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFieldLocal",((PetscObject)dm)->type_name);
5933   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
5934   PetscFunctionReturn(0);
5935 }
5936 
5937 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], Vec localU,
5938                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
5939                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
5940                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
5941                                                        PetscReal, const PetscReal[], PetscScalar[]),
5942                                         InsertMode mode, Vec localX)
5943 {
5944   PetscErrorCode ierr;
5945 
5946   PetscFunctionBegin;
5947   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5948   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
5949   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
5950   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFieldLocal",((PetscObject)dm)->type_name);
5951   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, localU, funcs, mode, localX);CHKERRQ(ierr);
5952   PetscFunctionReturn(0);
5953 }
5954 
5955 /*@C
5956   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
5957 
5958   Input Parameters:
5959 + dm    - The DM
5960 . time  - The time
5961 . funcs - The functions to evaluate for each field component
5962 . ctxs  - Optional array of contexts to pass to each function, or NULL.
5963 - X     - The coefficient vector u_h
5964 
5965   Output Parameter:
5966 . diff - The diff ||u - u_h||_2
5967 
5968   Level: developer
5969 
5970 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
5971 @*/
5972 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
5973 {
5974   PetscErrorCode ierr;
5975 
5976   PetscFunctionBegin;
5977   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5978   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
5979   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMComputeL2Diff",((PetscObject)dm)->type_name);
5980   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
5981   PetscFunctionReturn(0);
5982 }
5983 
5984 /*@C
5985   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
5986 
5987   Input Parameters:
5988 + dm    - The DM
5989 , time  - The time
5990 . funcs - The gradient functions to evaluate for each field component
5991 . ctxs  - Optional array of contexts to pass to each function, or NULL.
5992 . X     - The coefficient vector u_h
5993 - n     - The vector to project along
5994 
5995   Output Parameter:
5996 . diff - The diff ||(grad u - grad u_h) . n||_2
5997 
5998   Level: developer
5999 
6000 .seealso: DMProjectFunction(), DMComputeL2Diff()
6001 @*/
6002 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)
6003 {
6004   PetscErrorCode ierr;
6005 
6006   PetscFunctionBegin;
6007   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6008   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6009   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
6010   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
6011   PetscFunctionReturn(0);
6012 }
6013 
6014 /*@C
6015   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
6016 
6017   Input Parameters:
6018 + dm    - The DM
6019 . time  - The time
6020 . funcs - The functions to evaluate for each field component
6021 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6022 - X     - The coefficient vector u_h
6023 
6024   Output Parameter:
6025 . diff - The array of differences, ||u^f - u^f_h||_2
6026 
6027   Level: developer
6028 
6029 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6030 @*/
6031 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
6032 {
6033   PetscErrorCode ierr;
6034 
6035   PetscFunctionBegin;
6036   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6037   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6038   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
6039   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6040   PetscFunctionReturn(0);
6041 }
6042 
6043 /*@C
6044   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
6045                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
6046 
6047   Collective on dm
6048 
6049   Input parameters:
6050 + dm - the pre-adaptation DM object
6051 - label - label with the flags
6052 
6053   Output parameters:
6054 . adaptedDM - the adapted DM object: may be NULL if an adapted DM could not be produced.
6055 
6056   Level: intermediate
6057 @*/
6058 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *adaptedDM)
6059 {
6060   PetscErrorCode ierr;
6061 
6062   PetscFunctionBegin;
6063   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6064   PetscValidPointer(label,2);
6065   PetscValidPointer(adaptedDM,3);
6066   *adaptedDM = NULL;
6067   ierr = PetscTryMethod((PetscObject)dm,"DMAdaptLabel_C",(DM,DMLabel, DM*),(dm,label,adaptedDM));CHKERRQ(ierr);
6068   PetscFunctionReturn(0);
6069 }
6070 
6071 /*@C
6072  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
6073 
6074  Not Collective
6075 
6076  Input Parameter:
6077  . dm    - The DM
6078 
6079  Output Parameter:
6080  . nranks - the number of neighbours
6081  . ranks - the neighbors ranks
6082 
6083  Notes:
6084  Do not free the array, it is freed when the DM is destroyed.
6085 
6086  Level: beginner
6087 
6088  .seealso: DMDAGetNeighbors(), PetscSFGetRanks()
6089 @*/
6090 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
6091 {
6092   PetscErrorCode ierr;
6093 
6094   PetscFunctionBegin;
6095   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6096   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMGetNeighbors",((PetscObject)dm)->type_name);
6097   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
6098   PetscFunctionReturn(0);
6099 }
6100 
6101 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
6102 
6103 /*
6104     Converts the input vector to a ghosted vector and then calls the standard coloring code.
6105     This has be a different function because it requires DM which is not defined in the Mat library
6106 */
6107 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
6108 {
6109   PetscErrorCode ierr;
6110 
6111   PetscFunctionBegin;
6112   if (coloring->ctype == IS_COLORING_LOCAL) {
6113     Vec x1local;
6114     DM  dm;
6115     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6116     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
6117     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
6118     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6119     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6120     x1   = x1local;
6121   }
6122   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
6123   if (coloring->ctype == IS_COLORING_LOCAL) {
6124     DM  dm;
6125     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6126     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
6127   }
6128   PetscFunctionReturn(0);
6129 }
6130 
6131 /*@
6132     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
6133 
6134     Input Parameter:
6135 .    coloring - the MatFDColoring object
6136 
6137     Developer Notes: this routine exists because the PETSc Mat library does not know about the DM objects
6138 
6139     Level: advanced
6140 
6141 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
6142 @*/
6143 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
6144 {
6145   PetscFunctionBegin;
6146   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
6147   PetscFunctionReturn(0);
6148 }
6149