xref: /petsc/src/dm/interface/dm.c (revision a22c4e5a54e302278e4c0b986377f75252d11daa)
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   PetscInt          localSize, bs;
3153   PetscMPIInt       size;
3154   Vec               x, xglob;
3155   const PetscScalar *xarray;
3156   PetscErrorCode    ierr;
3157 
3158   PetscFunctionBegin;
3159   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);CHKERRQ(ierr);
3160   ierr = VecDuplicate(X, &x);CHKERRQ(ierr);
3161   ierr = VecCopy(X, x);CHKERRQ(ierr);
3162   ierr = VecChop(x, tol);CHKERRQ(ierr);
3163   ierr = PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);CHKERRQ(ierr);
3164   if (size > 1) {
3165     ierr = VecGetLocalSize(x,&localSize);CHKERRQ(ierr);
3166     ierr = VecGetArrayRead(x,&xarray);CHKERRQ(ierr);
3167     ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr);
3168     ierr = VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);CHKERRQ(ierr);
3169   } else {
3170     xglob = x;
3171   }
3172   ierr = VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));CHKERRQ(ierr);
3173   if (size > 1) {
3174     ierr = VecDestroy(&xglob);CHKERRQ(ierr);
3175     ierr = VecRestoreArrayRead(x,&xarray);CHKERRQ(ierr);
3176   }
3177   ierr = VecDestroy(&x);CHKERRQ(ierr);
3178   PetscFunctionReturn(0);
3179 }
3180 
3181 /*@
3182   DMGetDefaultSection - Get the PetscSection encoding the local data layout for the DM.
3183 
3184   Input Parameter:
3185 . dm - The DM
3186 
3187   Output Parameter:
3188 . section - The PetscSection
3189 
3190   Level: intermediate
3191 
3192   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3193 
3194 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3195 @*/
3196 PetscErrorCode DMGetDefaultSection(DM dm, PetscSection *section)
3197 {
3198   PetscErrorCode ierr;
3199 
3200   PetscFunctionBegin;
3201   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3202   PetscValidPointer(section, 2);
3203   if (!dm->defaultSection && dm->ops->createdefaultsection) {
3204     ierr = (*dm->ops->createdefaultsection)(dm);CHKERRQ(ierr);
3205     if (dm->defaultSection) {ierr = PetscObjectViewFromOptions((PetscObject) dm->defaultSection, NULL, "-dm_petscsection_view");CHKERRQ(ierr);}
3206   }
3207   *section = dm->defaultSection;
3208   PetscFunctionReturn(0);
3209 }
3210 
3211 /*@
3212   DMSetDefaultSection - Set the PetscSection encoding the local data layout for the DM.
3213 
3214   Input Parameters:
3215 + dm - The DM
3216 - section - The PetscSection
3217 
3218   Level: intermediate
3219 
3220   Note: Any existing Section will be destroyed
3221 
3222 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3223 @*/
3224 PetscErrorCode DMSetDefaultSection(DM dm, PetscSection section)
3225 {
3226   PetscInt       numFields = 0;
3227   PetscInt       f;
3228   PetscErrorCode ierr;
3229 
3230   PetscFunctionBegin;
3231   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3232   if (section) {
3233     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3234     ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3235   }
3236   ierr = PetscSectionDestroy(&dm->defaultSection);CHKERRQ(ierr);
3237   dm->defaultSection = section;
3238   if (section) {ierr = PetscSectionGetNumFields(dm->defaultSection, &numFields);CHKERRQ(ierr);}
3239   if (numFields) {
3240     ierr = DMSetNumFields(dm, numFields);CHKERRQ(ierr);
3241     for (f = 0; f < numFields; ++f) {
3242       PetscObject disc;
3243       const char *name;
3244 
3245       ierr = PetscSectionGetFieldName(dm->defaultSection, f, &name);CHKERRQ(ierr);
3246       ierr = DMGetField(dm, f, &disc);CHKERRQ(ierr);
3247       ierr = PetscObjectSetName(disc, name);CHKERRQ(ierr);
3248     }
3249   }
3250   /* The global section will be rebuilt in the next call to DMGetDefaultGlobalSection(). */
3251   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3252   PetscFunctionReturn(0);
3253 }
3254 
3255 /*@
3256   DMGetDefaultConstraints - Get the PetscSection and Mat the specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
3257 
3258   not collective
3259 
3260   Input Parameter:
3261 . dm - The DM
3262 
3263   Output Parameter:
3264 + 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.
3265 - 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.
3266 
3267   Level: advanced
3268 
3269   Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
3270 
3271 .seealso: DMSetDefaultConstraints()
3272 @*/
3273 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
3274 {
3275   PetscErrorCode ierr;
3276 
3277   PetscFunctionBegin;
3278   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3279   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {ierr = (*dm->ops->createdefaultconstraints)(dm);CHKERRQ(ierr);}
3280   if (section) {*section = dm->defaultConstraintSection;}
3281   if (mat) {*mat = dm->defaultConstraintMat;}
3282   PetscFunctionReturn(0);
3283 }
3284 
3285 /*@
3286   DMSetDefaultConstraints - Set the PetscSection and Mat the specify the local constraint interpolation.
3287 
3288   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().
3289 
3290   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.
3291 
3292   collective on dm
3293 
3294   Input Parameters:
3295 + dm - The DM
3296 + 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).
3297 - 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).
3298 
3299   Level: advanced
3300 
3301   Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
3302 
3303 .seealso: DMGetDefaultConstraints()
3304 @*/
3305 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
3306 {
3307   PetscMPIInt result;
3308   PetscErrorCode ierr;
3309 
3310   PetscFunctionBegin;
3311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3312   if (section) {
3313     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3314     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);CHKERRQ(ierr);
3315     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
3316   }
3317   if (mat) {
3318     PetscValidHeaderSpecific(mat,MAT_CLASSID,3);
3319     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);CHKERRQ(ierr);
3320     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
3321   }
3322   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3323   ierr = PetscSectionDestroy(&dm->defaultConstraintSection);CHKERRQ(ierr);
3324   dm->defaultConstraintSection = section;
3325   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
3326   ierr = MatDestroy(&dm->defaultConstraintMat);CHKERRQ(ierr);
3327   dm->defaultConstraintMat = mat;
3328   PetscFunctionReturn(0);
3329 }
3330 
3331 #ifdef PETSC_USE_DEBUG
3332 /*
3333   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
3334 
3335   Input Parameters:
3336 + dm - The DM
3337 . localSection - PetscSection describing the local data layout
3338 - globalSection - PetscSection describing the global data layout
3339 
3340   Level: intermediate
3341 
3342 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3343 */
3344 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
3345 {
3346   MPI_Comm        comm;
3347   PetscLayout     layout;
3348   const PetscInt *ranges;
3349   PetscInt        pStart, pEnd, p, nroots;
3350   PetscMPIInt     size, rank;
3351   PetscBool       valid = PETSC_TRUE, gvalid;
3352   PetscErrorCode  ierr;
3353 
3354   PetscFunctionBegin;
3355   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3356   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3357   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3358   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3359   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3360   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3361   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3362   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3363   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3364   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3365   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3366   for (p = pStart; p < pEnd; ++p) {
3367     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;
3368 
3369     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3370     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3371     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3372     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3373     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3374     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3375     if (!gdof) continue; /* Censored point */
3376     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;}
3377     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;}
3378     if (gdof < 0) {
3379       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3380       for (d = 0; d < gsize; ++d) {
3381         PetscInt offset = -(goff+1) + d, r;
3382 
3383         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3384         if (r < 0) r = -(r+2);
3385         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;}
3386       }
3387     }
3388   }
3389   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3390   ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
3391   ierr = MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);CHKERRQ(ierr);
3392   if (!gvalid) {
3393     ierr = DMView(dm, NULL);CHKERRQ(ierr);
3394     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
3395   }
3396   PetscFunctionReturn(0);
3397 }
3398 #endif
3399 
3400 /*@
3401   DMGetDefaultGlobalSection - Get the PetscSection encoding the global data layout for the DM.
3402 
3403   Collective on DM
3404 
3405   Input Parameter:
3406 . dm - The DM
3407 
3408   Output Parameter:
3409 . section - The PetscSection
3410 
3411   Level: intermediate
3412 
3413   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3414 
3415 .seealso: DMSetDefaultSection(), DMGetDefaultSection()
3416 @*/
3417 PetscErrorCode DMGetDefaultGlobalSection(DM dm, PetscSection *section)
3418 {
3419   PetscErrorCode ierr;
3420 
3421   PetscFunctionBegin;
3422   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3423   PetscValidPointer(section, 2);
3424   if (!dm->defaultGlobalSection) {
3425     PetscSection s;
3426 
3427     ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
3428     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
3429     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSF in order to create a global PetscSection");
3430     ierr = PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->defaultGlobalSection);CHKERRQ(ierr);
3431     ierr = PetscLayoutDestroy(&dm->map);CHKERRQ(ierr);
3432     ierr = PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->defaultGlobalSection, &dm->map);CHKERRQ(ierr);
3433     ierr = PetscSectionViewFromOptions(dm->defaultGlobalSection, NULL, "-global_section_view");CHKERRQ(ierr);
3434   }
3435   *section = dm->defaultGlobalSection;
3436   PetscFunctionReturn(0);
3437 }
3438 
3439 /*@
3440   DMSetDefaultGlobalSection - Set the PetscSection encoding the global data layout for the DM.
3441 
3442   Input Parameters:
3443 + dm - The DM
3444 - section - The PetscSection, or NULL
3445 
3446   Level: intermediate
3447 
3448   Note: Any existing Section will be destroyed
3449 
3450 .seealso: DMGetDefaultGlobalSection(), DMSetDefaultSection()
3451 @*/
3452 PetscErrorCode DMSetDefaultGlobalSection(DM dm, PetscSection section)
3453 {
3454   PetscErrorCode ierr;
3455 
3456   PetscFunctionBegin;
3457   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3458   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3459   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3460   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3461   dm->defaultGlobalSection = section;
3462 #ifdef PETSC_USE_DEBUG
3463   if (section) {ierr = DMDefaultSectionCheckConsistency_Internal(dm, dm->defaultSection, section);CHKERRQ(ierr);}
3464 #endif
3465   PetscFunctionReturn(0);
3466 }
3467 
3468 /*@
3469   DMGetDefaultSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
3470   it is created from the default PetscSection layouts in the DM.
3471 
3472   Input Parameter:
3473 . dm - The DM
3474 
3475   Output Parameter:
3476 . sf - The PetscSF
3477 
3478   Level: intermediate
3479 
3480   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3481 
3482 .seealso: DMSetDefaultSF(), DMCreateDefaultSF()
3483 @*/
3484 PetscErrorCode DMGetDefaultSF(DM dm, PetscSF *sf)
3485 {
3486   PetscInt       nroots;
3487   PetscErrorCode ierr;
3488 
3489   PetscFunctionBegin;
3490   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3491   PetscValidPointer(sf, 2);
3492   ierr = PetscSFGetGraph(dm->defaultSF, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
3493   if (nroots < 0) {
3494     PetscSection section, gSection;
3495 
3496     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
3497     if (section) {
3498       ierr = DMGetDefaultGlobalSection(dm, &gSection);CHKERRQ(ierr);
3499       ierr = DMCreateDefaultSF(dm, section, gSection);CHKERRQ(ierr);
3500     } else {
3501       *sf = NULL;
3502       PetscFunctionReturn(0);
3503     }
3504   }
3505   *sf = dm->defaultSF;
3506   PetscFunctionReturn(0);
3507 }
3508 
3509 /*@
3510   DMSetDefaultSF - Set the PetscSF encoding the parallel dof overlap for the DM
3511 
3512   Input Parameters:
3513 + dm - The DM
3514 - sf - The PetscSF
3515 
3516   Level: intermediate
3517 
3518   Note: Any previous SF is destroyed
3519 
3520 .seealso: DMGetDefaultSF(), DMCreateDefaultSF()
3521 @*/
3522 PetscErrorCode DMSetDefaultSF(DM dm, PetscSF sf)
3523 {
3524   PetscErrorCode ierr;
3525 
3526   PetscFunctionBegin;
3527   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3528   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
3529   ierr          = PetscSFDestroy(&dm->defaultSF);CHKERRQ(ierr);
3530   dm->defaultSF = sf;
3531   PetscFunctionReturn(0);
3532 }
3533 
3534 /*@C
3535   DMCreateDefaultSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
3536   describing the data layout.
3537 
3538   Input Parameters:
3539 + dm - The DM
3540 . localSection - PetscSection describing the local data layout
3541 - globalSection - PetscSection describing the global data layout
3542 
3543   Level: intermediate
3544 
3545 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3546 @*/
3547 PetscErrorCode DMCreateDefaultSF(DM dm, PetscSection localSection, PetscSection globalSection)
3548 {
3549   MPI_Comm       comm;
3550   PetscLayout    layout;
3551   const PetscInt *ranges;
3552   PetscInt       *local;
3553   PetscSFNode    *remote;
3554   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
3555   PetscMPIInt    size, rank;
3556   PetscErrorCode ierr;
3557 
3558   PetscFunctionBegin;
3559   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3560   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3561   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3562   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3563   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3564   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3565   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3566   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3567   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3568   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3569   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3570   for (p = pStart; p < pEnd; ++p) {
3571     PetscInt gdof, gcdof;
3572 
3573     ierr     = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3574     ierr     = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3575     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));
3576     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3577   }
3578   ierr = PetscMalloc1(nleaves, &local);CHKERRQ(ierr);
3579   ierr = PetscMalloc1(nleaves, &remote);CHKERRQ(ierr);
3580   for (p = pStart, l = 0; p < pEnd; ++p) {
3581     const PetscInt *cind;
3582     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
3583 
3584     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3585     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3586     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3587     ierr = PetscSectionGetConstraintIndices(localSection, p, &cind);CHKERRQ(ierr);
3588     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3589     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3590     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3591     if (!gdof) continue; /* Censored point */
3592     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3593     if (gsize != dof-cdof) {
3594       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);
3595       cdof = 0; /* Ignore constraints */
3596     }
3597     for (d = 0, c = 0; d < dof; ++d) {
3598       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
3599       local[l+d-c] = off+d;
3600     }
3601     if (gdof < 0) {
3602       for (d = 0; d < gsize; ++d, ++l) {
3603         PetscInt offset = -(goff+1) + d, r;
3604 
3605         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3606         if (r < 0) r = -(r+2);
3607         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);
3608         remote[l].rank  = r;
3609         remote[l].index = offset - ranges[r];
3610       }
3611     } else {
3612       for (d = 0; d < gsize; ++d, ++l) {
3613         remote[l].rank  = rank;
3614         remote[l].index = goff+d - ranges[rank];
3615       }
3616     }
3617   }
3618   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
3619   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3620   ierr = PetscSFSetGraph(dm->defaultSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
3621   PetscFunctionReturn(0);
3622 }
3623 
3624 /*@
3625   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
3626 
3627   Input Parameter:
3628 . dm - The DM
3629 
3630   Output Parameter:
3631 . sf - The PetscSF
3632 
3633   Level: intermediate
3634 
3635   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3636 
3637 .seealso: DMSetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3638 @*/
3639 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
3640 {
3641   PetscFunctionBegin;
3642   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3643   PetscValidPointer(sf, 2);
3644   *sf = dm->sf;
3645   PetscFunctionReturn(0);
3646 }
3647 
3648 /*@
3649   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
3650 
3651   Input Parameters:
3652 + dm - The DM
3653 - sf - The PetscSF
3654 
3655   Level: intermediate
3656 
3657 .seealso: DMGetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3658 @*/
3659 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
3660 {
3661   PetscErrorCode ierr;
3662 
3663   PetscFunctionBegin;
3664   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3665   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
3666   ierr   = PetscSFDestroy(&dm->sf);CHKERRQ(ierr);
3667   ierr   = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
3668   dm->sf = sf;
3669   PetscFunctionReturn(0);
3670 }
3671 
3672 /*@
3673   DMGetDS - Get the PetscDS
3674 
3675   Input Parameter:
3676 . dm - The DM
3677 
3678   Output Parameter:
3679 . prob - The PetscDS
3680 
3681   Level: developer
3682 
3683 .seealso: DMSetDS()
3684 @*/
3685 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
3686 {
3687   PetscFunctionBegin;
3688   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3689   PetscValidPointer(prob, 2);
3690   *prob = dm->prob;
3691   PetscFunctionReturn(0);
3692 }
3693 
3694 /*@
3695   DMSetDS - Set the PetscDS
3696 
3697   Input Parameters:
3698 + dm - The DM
3699 - prob - The PetscDS
3700 
3701   Level: developer
3702 
3703 .seealso: DMGetDS()
3704 @*/
3705 PetscErrorCode DMSetDS(DM dm, PetscDS prob)
3706 {
3707   PetscErrorCode ierr;
3708 
3709   PetscFunctionBegin;
3710   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3711   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 2);
3712   ierr = PetscObjectReference((PetscObject) prob);CHKERRQ(ierr);
3713   ierr = PetscDSDestroy(&dm->prob);CHKERRQ(ierr);
3714   dm->prob = prob;
3715   PetscFunctionReturn(0);
3716 }
3717 
3718 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
3719 {
3720   PetscErrorCode ierr;
3721 
3722   PetscFunctionBegin;
3723   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3724   ierr = PetscDSGetNumFields(dm->prob, numFields);CHKERRQ(ierr);
3725   PetscFunctionReturn(0);
3726 }
3727 
3728 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
3729 {
3730   PetscInt       Nf, f;
3731   PetscErrorCode ierr;
3732 
3733   PetscFunctionBegin;
3734   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3735   ierr = PetscDSGetNumFields(dm->prob, &Nf);CHKERRQ(ierr);
3736   for (f = Nf; f < numFields; ++f) {
3737     PetscContainer obj;
3738 
3739     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
3740     ierr = PetscDSSetDiscretization(dm->prob, f, (PetscObject) obj);CHKERRQ(ierr);
3741     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
3742   }
3743   PetscFunctionReturn(0);
3744 }
3745 
3746 /*@
3747   DMGetField - Return the discretization object for a given DM field
3748 
3749   Not collective
3750 
3751   Input Parameters:
3752 + dm - The DM
3753 - f  - The field number
3754 
3755   Output Parameter:
3756 . field - The discretization object
3757 
3758   Level: developer
3759 
3760 .seealso: DMSetField()
3761 @*/
3762 PetscErrorCode DMGetField(DM dm, PetscInt f, PetscObject *field)
3763 {
3764   PetscErrorCode ierr;
3765 
3766   PetscFunctionBegin;
3767   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3768   ierr = PetscDSGetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3769   PetscFunctionReturn(0);
3770 }
3771 
3772 /*@
3773   DMSetField - Set the discretization object for a given DM field
3774 
3775   Logically collective on DM
3776 
3777   Input Parameters:
3778 + dm - The DM
3779 . f  - The field number
3780 - field - The discretization object
3781 
3782   Level: developer
3783 
3784 .seealso: DMGetField()
3785 @*/
3786 PetscErrorCode DMSetField(DM dm, PetscInt f, PetscObject field)
3787 {
3788   PetscErrorCode ierr;
3789 
3790   PetscFunctionBegin;
3791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3792   ierr = PetscDSSetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3793   PetscFunctionReturn(0);
3794 }
3795 
3796 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
3797 {
3798   DM dm_coord,dmc_coord;
3799   PetscErrorCode ierr;
3800   Vec coords,ccoords;
3801   Mat inject;
3802   PetscFunctionBegin;
3803   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3804   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
3805   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3806   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
3807   if (coords && !ccoords) {
3808     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
3809     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
3810     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
3811     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
3812     ierr = MatDestroy(&inject);CHKERRQ(ierr);
3813     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
3814     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3815   }
3816   PetscFunctionReturn(0);
3817 }
3818 
3819 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
3820 {
3821   DM dm_coord,subdm_coord;
3822   PetscErrorCode ierr;
3823   Vec coords,ccoords,clcoords;
3824   VecScatter *scat_i,*scat_g;
3825   PetscFunctionBegin;
3826   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3827   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
3828   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3829   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
3830   if (coords && !ccoords) {
3831     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
3832     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
3833     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
3834     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
3835     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
3836     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3837     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3838     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3839     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3840     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
3841     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
3842     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
3843     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
3844     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3845     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
3846     ierr = PetscFree(scat_i);CHKERRQ(ierr);
3847     ierr = PetscFree(scat_g);CHKERRQ(ierr);
3848   }
3849   PetscFunctionReturn(0);
3850 }
3851 
3852 /*@
3853   DMGetDimension - Return the topological dimension of the DM
3854 
3855   Not collective
3856 
3857   Input Parameter:
3858 . dm - The DM
3859 
3860   Output Parameter:
3861 . dim - The topological dimension
3862 
3863   Level: beginner
3864 
3865 .seealso: DMSetDimension(), DMCreate()
3866 @*/
3867 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
3868 {
3869   PetscFunctionBegin;
3870   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3871   PetscValidPointer(dim, 2);
3872   *dim = dm->dim;
3873   PetscFunctionReturn(0);
3874 }
3875 
3876 /*@
3877   DMSetDimension - Set the topological dimension of the DM
3878 
3879   Collective on dm
3880 
3881   Input Parameters:
3882 + dm - The DM
3883 - dim - The topological dimension
3884 
3885   Level: beginner
3886 
3887 .seealso: DMGetDimension(), DMCreate()
3888 @*/
3889 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
3890 {
3891   PetscFunctionBegin;
3892   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3893   PetscValidLogicalCollectiveInt(dm, dim, 2);
3894   dm->dim = dim;
3895   PetscFunctionReturn(0);
3896 }
3897 
3898 /*@
3899   DMGetDimPoints - Get the half-open interval for all points of a given dimension
3900 
3901   Collective on DM
3902 
3903   Input Parameters:
3904 + dm - the DM
3905 - dim - the dimension
3906 
3907   Output Parameters:
3908 + pStart - The first point of the given dimension
3909 . pEnd - The first point following points of the given dimension
3910 
3911   Note:
3912   The points are vertices in the Hasse diagram encoding the topology. This is explained in
3913   http://arxiv.org/abs/0908.4427. If not points exist of this dimension in the storage scheme,
3914   then the interval is empty.
3915 
3916   Level: intermediate
3917 
3918 .keywords: point, Hasse Diagram, dimension
3919 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
3920 @*/
3921 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
3922 {
3923   PetscInt       d;
3924   PetscErrorCode ierr;
3925 
3926   PetscFunctionBegin;
3927   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3928   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
3929   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
3930   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
3931   PetscFunctionReturn(0);
3932 }
3933 
3934 /*@
3935   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
3936 
3937   Collective on DM
3938 
3939   Input Parameters:
3940 + dm - the DM
3941 - c - coordinate vector
3942 
3943   Note:
3944   The coordinates do include those for ghost points, which are in the local vector
3945 
3946   Level: intermediate
3947 
3948 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3949 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLoca(), DMGetCoordinateDM()
3950 @*/
3951 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
3952 {
3953   PetscErrorCode ierr;
3954 
3955   PetscFunctionBegin;
3956   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3957   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3958   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3959   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3960   dm->coordinates = c;
3961   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3962   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3963   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3964   PetscFunctionReturn(0);
3965 }
3966 
3967 /*@
3968   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
3969 
3970   Collective on DM
3971 
3972    Input Parameters:
3973 +  dm - the DM
3974 -  c - coordinate vector
3975 
3976   Note:
3977   The coordinates of ghost points can be set using DMSetCoordinates()
3978   followed by DMGetCoordinatesLocal(). This is intended to enable the
3979   setting of ghost coordinates outside of the domain.
3980 
3981   Level: intermediate
3982 
3983 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3984 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
3985 @*/
3986 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
3987 {
3988   PetscErrorCode ierr;
3989 
3990   PetscFunctionBegin;
3991   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3992   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3993   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3994   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3995 
3996   dm->coordinatesLocal = c;
3997 
3998   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3999   PetscFunctionReturn(0);
4000 }
4001 
4002 /*@
4003   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
4004 
4005   Not Collective
4006 
4007   Input Parameter:
4008 . dm - the DM
4009 
4010   Output Parameter:
4011 . c - global coordinate vector
4012 
4013   Note:
4014   This is a borrowed reference, so the user should NOT destroy this vector
4015 
4016   Each process has only the local coordinates (does NOT have the ghost coordinates).
4017 
4018   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4019   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4020 
4021   Level: intermediate
4022 
4023 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4024 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
4025 @*/
4026 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
4027 {
4028   PetscErrorCode ierr;
4029 
4030   PetscFunctionBegin;
4031   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4032   PetscValidPointer(c,2);
4033   if (!dm->coordinates && dm->coordinatesLocal) {
4034     DM cdm = NULL;
4035 
4036     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4037     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
4038     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
4039     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4040     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
4041   }
4042   *c = dm->coordinates;
4043   PetscFunctionReturn(0);
4044 }
4045 
4046 /*@
4047   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
4048 
4049   Collective on DM
4050 
4051   Input Parameter:
4052 . dm - the DM
4053 
4054   Output Parameter:
4055 . c - coordinate vector
4056 
4057   Note:
4058   This is a borrowed reference, so the user should NOT destroy this vector
4059 
4060   Each process has the local and ghost coordinates
4061 
4062   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
4063   and (x_0,y_0,z_0,x_1,y_1,z_1...)
4064 
4065   Level: intermediate
4066 
4067 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4068 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
4069 @*/
4070 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
4071 {
4072   PetscErrorCode ierr;
4073 
4074   PetscFunctionBegin;
4075   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4076   PetscValidPointer(c,2);
4077   if (!dm->coordinatesLocal && dm->coordinates) {
4078     DM cdm = NULL;
4079 
4080     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4081     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
4082     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
4083     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4084     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
4085   }
4086   *c = dm->coordinatesLocal;
4087   PetscFunctionReturn(0);
4088 }
4089 
4090 /*@
4091   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
4092 
4093   Collective on DM
4094 
4095   Input Parameter:
4096 . dm - the DM
4097 
4098   Output Parameter:
4099 . cdm - coordinate DM
4100 
4101   Level: intermediate
4102 
4103 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4104 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4105 @*/
4106 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
4107 {
4108   PetscErrorCode ierr;
4109 
4110   PetscFunctionBegin;
4111   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4112   PetscValidPointer(cdm,2);
4113   if (!dm->coordinateDM) {
4114     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
4115     ierr = (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);CHKERRQ(ierr);
4116   }
4117   *cdm = dm->coordinateDM;
4118   PetscFunctionReturn(0);
4119 }
4120 
4121 /*@
4122   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
4123 
4124   Logically Collective on DM
4125 
4126   Input Parameters:
4127 + dm - the DM
4128 - cdm - coordinate DM
4129 
4130   Level: intermediate
4131 
4132 .keywords: distributed array, get, corners, nodes, local indices, coordinates
4133 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4134 @*/
4135 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
4136 {
4137   PetscErrorCode ierr;
4138 
4139   PetscFunctionBegin;
4140   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4141   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
4142   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
4143   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
4144   dm->coordinateDM = cdm;
4145   PetscFunctionReturn(0);
4146 }
4147 
4148 /*@
4149   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
4150 
4151   Not Collective
4152 
4153   Input Parameter:
4154 . dm - The DM object
4155 
4156   Output Parameter:
4157 . dim - The embedding dimension
4158 
4159   Level: intermediate
4160 
4161 .keywords: mesh, coordinates
4162 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4163 @*/
4164 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
4165 {
4166   PetscFunctionBegin;
4167   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4168   PetscValidPointer(dim, 2);
4169   if (dm->dimEmbed == PETSC_DEFAULT) {
4170     dm->dimEmbed = dm->dim;
4171   }
4172   *dim = dm->dimEmbed;
4173   PetscFunctionReturn(0);
4174 }
4175 
4176 /*@
4177   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
4178 
4179   Not Collective
4180 
4181   Input Parameters:
4182 + dm  - The DM object
4183 - dim - The embedding dimension
4184 
4185   Level: intermediate
4186 
4187 .keywords: mesh, coordinates
4188 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4189 @*/
4190 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
4191 {
4192   PetscFunctionBegin;
4193   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4194   dm->dimEmbed = dim;
4195   PetscFunctionReturn(0);
4196 }
4197 
4198 /*@
4199   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
4200 
4201   Not Collective
4202 
4203   Input Parameter:
4204 . dm - The DM object
4205 
4206   Output Parameter:
4207 . section - The PetscSection object
4208 
4209   Level: intermediate
4210 
4211 .keywords: mesh, coordinates
4212 .seealso: DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4213 @*/
4214 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
4215 {
4216   DM             cdm;
4217   PetscErrorCode ierr;
4218 
4219   PetscFunctionBegin;
4220   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4221   PetscValidPointer(section, 2);
4222   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4223   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
4224   PetscFunctionReturn(0);
4225 }
4226 
4227 /*@
4228   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
4229 
4230   Not Collective
4231 
4232   Input Parameters:
4233 + dm      - The DM object
4234 . dim     - The embedding dimension, or PETSC_DETERMINE
4235 - section - The PetscSection object
4236 
4237   Level: intermediate
4238 
4239 .keywords: mesh, coordinates
4240 .seealso: DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4241 @*/
4242 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
4243 {
4244   DM             cdm;
4245   PetscErrorCode ierr;
4246 
4247   PetscFunctionBegin;
4248   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4249   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
4250   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4251   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
4252   if (dim == PETSC_DETERMINE) {
4253     PetscInt d = dim;
4254     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
4255 
4256     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4257     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4258     pStart = PetscMax(vStart, pStart);
4259     pEnd   = PetscMin(vEnd, pEnd);
4260     for (v = pStart; v < pEnd; ++v) {
4261       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
4262       if (dd) {d = dd; break;}
4263     }
4264     if (d < 0) d = PETSC_DEFAULT;
4265     ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);
4266   }
4267   PetscFunctionReturn(0);
4268 }
4269 
4270 /*@C
4271   DMSetPeriodicity - Set the description of mesh periodicity
4272 
4273   Input Parameters:
4274 + dm      - The DM object
4275 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4276 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4277 - bd      - This describes the type of periodicity in each topological dimension
4278 
4279   Level: developer
4280 
4281 .seealso: DMGetPeriodicity()
4282 @*/
4283 PetscErrorCode DMGetPeriodicity(DM dm, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
4284 {
4285   PetscFunctionBegin;
4286   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4287   if (L)       *L       = dm->L;
4288   if (maxCell) *maxCell = dm->maxCell;
4289   if (bd)      *bd      = dm->bdtype;
4290   PetscFunctionReturn(0);
4291 }
4292 
4293 /*@C
4294   DMSetPeriodicity - Set the description of mesh periodicity
4295 
4296   Input Parameters:
4297 + dm      - The DM object
4298 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4299 . L       - If we assume the mesh is a torus, this is the length of each coordinate
4300 - bd      - This describes the type of periodicity in each topological dimension
4301 
4302   Level: developer
4303 
4304 .seealso: DMGetPeriodicity()
4305 @*/
4306 PetscErrorCode DMSetPeriodicity(DM dm, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
4307 {
4308   PetscInt       dim, d;
4309   PetscErrorCode ierr;
4310 
4311   PetscFunctionBegin;
4312   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4313   PetscValidPointer(L,3);PetscValidPointer(maxCell,2);PetscValidPointer(bd,4);
4314   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
4315   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4316   ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
4317   for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
4318   PetscFunctionReturn(0);
4319 }
4320 
4321 /*@
4322   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.
4323 
4324   Input Parameters:
4325 + dm     - The DM
4326 - in     - The input coordinate point (dim numbers)
4327 
4328   Output Parameter:
4329 . out - The localized coordinate point
4330 
4331   Level: developer
4332 
4333 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4334 @*/
4335 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscScalar out[])
4336 {
4337   PetscInt       dim, d;
4338   PetscErrorCode ierr;
4339 
4340   PetscFunctionBegin;
4341   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
4342   if (!dm->maxCell) {
4343     for (d = 0; d < dim; ++d) out[d] = in[d];
4344   } else {
4345     for (d = 0; d < dim; ++d) {
4346       out[d] = in[d] - dm->L[d]*floor(PetscRealPart(in[d])/dm->L[d]);
4347     }
4348   }
4349   PetscFunctionReturn(0);
4350 }
4351 
4352 /*
4353   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.
4354 
4355   Input Parameters:
4356 + dm     - The DM
4357 . dim    - The spatial dimension
4358 . anchor - The anchor point, the input point can be no more than maxCell away from it
4359 - in     - The input coordinate point (dim numbers)
4360 
4361   Output Parameter:
4362 . out - The localized coordinate point
4363 
4364   Level: developer
4365 
4366   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
4367 
4368 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4369 */
4370 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4371 {
4372   PetscInt d;
4373 
4374   PetscFunctionBegin;
4375   if (!dm->maxCell) {
4376     for (d = 0; d < dim; ++d) out[d] = in[d];
4377   } else {
4378     for (d = 0; d < dim; ++d) {
4379       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4380         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4381       } else {
4382         out[d] = in[d];
4383       }
4384     }
4385   }
4386   PetscFunctionReturn(0);
4387 }
4388 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
4389 {
4390   PetscInt d;
4391 
4392   PetscFunctionBegin;
4393   if (!dm->maxCell) {
4394     for (d = 0; d < dim; ++d) out[d] = in[d];
4395   } else {
4396     for (d = 0; d < dim; ++d) {
4397       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
4398         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
4399       } else {
4400         out[d] = in[d];
4401       }
4402     }
4403   }
4404   PetscFunctionReturn(0);
4405 }
4406 
4407 /*
4408   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.
4409 
4410   Input Parameters:
4411 + dm     - The DM
4412 . dim    - The spatial dimension
4413 . anchor - The anchor point, the input point can be no more than maxCell away from it
4414 . in     - The input coordinate delta (dim numbers)
4415 - out    - The input coordinate point (dim numbers)
4416 
4417   Output Parameter:
4418 . out    - The localized coordinate in + out
4419 
4420   Level: developer
4421 
4422   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
4423 
4424 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
4425 */
4426 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4427 {
4428   PetscInt d;
4429 
4430   PetscFunctionBegin;
4431   if (!dm->maxCell) {
4432     for (d = 0; d < dim; ++d) out[d] += in[d];
4433   } else {
4434     for (d = 0; d < dim; ++d) {
4435       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4436         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4437       } else {
4438         out[d] += in[d];
4439       }
4440     }
4441   }
4442   PetscFunctionReturn(0);
4443 }
4444 
4445 /*@
4446   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
4447 
4448   Input Parameter:
4449 . dm - The DM
4450 
4451   Output Parameter:
4452   areLocalized - True if localized
4453 
4454   Level: developer
4455 
4456 .seealso: DMLocalizeCoordinates()
4457 @*/
4458 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
4459 {
4460   DM             cdm;
4461   PetscSection   coordSection;
4462   PetscInt       cStart, cEnd, c, sStart, sEnd, dof;
4463   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
4464   PetscErrorCode ierr;
4465 
4466   PetscFunctionBegin;
4467   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4468   if (!dm->maxCell) {
4469     *areLocalized = PETSC_FALSE;
4470     PetscFunctionReturn(0);
4471   }
4472   /* We need some generic way of refering to cells/vertices */
4473   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4474   {
4475     PetscBool isplex;
4476 
4477     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
4478     if (isplex) {
4479       ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4480     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4481   }
4482   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4483   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
4484   alreadyLocalized = alreadyLocalizedGlobal = PETSC_FALSE;
4485   for (c = cStart; c < cEnd; ++c) {
4486     if (c < sStart || c >= sEnd) {
4487       alreadyLocalized = PETSC_FALSE;
4488       break;
4489     }
4490     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
4491     if (dof) {
4492       alreadyLocalized = PETSC_TRUE;
4493       break;
4494     }
4495   }
4496   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
4497   *areLocalized = alreadyLocalizedGlobal;
4498   PetscFunctionReturn(0);
4499 }
4500 
4501 
4502 /*@
4503   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for each cell
4504 
4505   Input Parameter:
4506 . dm - The DM
4507 
4508   Level: developer
4509 
4510 .seealso: DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
4511 @*/
4512 PetscErrorCode DMLocalizeCoordinates(DM dm)
4513 {
4514   DM             cdm;
4515   PetscSection   coordSection, cSection;
4516   Vec            coordinates,  cVec;
4517   PetscScalar   *coords, *coords2, *anchor, *localized;
4518   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
4519   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
4520   PetscInt       maxHeight = 0, h;
4521   PetscInt       *pStart = NULL, *pEnd = NULL;
4522   PetscErrorCode ierr;
4523 
4524   PetscFunctionBegin;
4525   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4526   if (!dm->maxCell) PetscFunctionReturn(0);
4527   /* We need some generic way of refering to cells/vertices */
4528   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4529   {
4530     PetscBool isplex;
4531 
4532     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
4533     if (isplex) {
4534       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4535       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
4536       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),PETSC_INT,&pStart);CHKERRQ(ierr);
4537       pEnd = &pStart[maxHeight + 1];
4538       newStart = vStart;
4539       newEnd   = vEnd;
4540       for (h = 0; h <= maxHeight; h++) {
4541         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
4542         newStart = PetscMin(newStart,pStart[h]);
4543         newEnd   = PetscMax(newEnd,pEnd[h]);
4544       }
4545     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4546   }
4547   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4548   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4549   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
4550   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
4551 
4552   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
4553   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
4554   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
4555   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
4556   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
4557 
4558   ierr = DMGetWorkArray(dm, 2 * bs, PETSC_SCALAR, &anchor);CHKERRQ(ierr);
4559   localized = &anchor[bs];
4560   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
4561   for (h = 0; h <= maxHeight; h++) {
4562     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
4563 
4564     for (c = cStart; c < cEnd; ++c) {
4565       PetscScalar *cellCoords = NULL;
4566       PetscInt     b;
4567 
4568       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
4569       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4570       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
4571       for (d = 0; d < dof/bs; ++d) {
4572         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
4573         for (b = 0; b < bs; b++) {
4574           if (cellCoords[d*bs + b] != localized[b]) break;
4575         }
4576         if (b < bs) break;
4577       }
4578       if (d < dof/bs) {
4579         if (c >= sStart && c < sEnd) {
4580           PetscInt cdof;
4581 
4582           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
4583           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
4584         }
4585         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
4586         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
4587       }
4588       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4589     }
4590   }
4591   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
4592   if (alreadyLocalizedGlobal) {
4593     ierr = DMRestoreWorkArray(dm, 2 * bs, PETSC_SCALAR, &anchor);CHKERRQ(ierr);
4594     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
4595     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),PETSC_INT,&pStart);CHKERRQ(ierr);
4596     PetscFunctionReturn(0);
4597   }
4598   for (v = vStart; v < vEnd; ++v) {
4599     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
4600     ierr = PetscSectionSetDof(cSection,     v,  dof);CHKERRQ(ierr);
4601     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
4602   }
4603   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
4604   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
4605   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
4606   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
4607   ierr = VecSetBlockSize(cVec,         bs);CHKERRQ(ierr);
4608   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4609   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
4610   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
4611   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
4612   for (v = vStart; v < vEnd; ++v) {
4613     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
4614     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4615     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
4616     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
4617   }
4618   for (h = 0; h <= maxHeight; h++) {
4619     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
4620 
4621     for (c = cStart; c < cEnd; ++c) {
4622       PetscScalar *cellCoords = NULL;
4623       PetscInt     b, cdof;
4624 
4625       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
4626       if (!cdof) continue;
4627       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4628       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
4629       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
4630       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
4631       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
4632     }
4633   }
4634   ierr = DMRestoreWorkArray(dm, 2 * bs, PETSC_SCALAR, &anchor);CHKERRQ(ierr);
4635   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),PETSC_INT,&pStart);CHKERRQ(ierr);
4636   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
4637   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
4638   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
4639   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
4640   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
4641   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
4642   PetscFunctionReturn(0);
4643 }
4644 
4645 /*@
4646   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
4647 
4648   Collective on Vec v (see explanation below)
4649 
4650   Input Parameters:
4651 + dm - The DM
4652 . v - The Vec of points
4653 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
4654 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
4655 
4656   Output Parameter:
4657 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
4658 - cells - The PetscSF containing the ranks and local indices of the containing points.
4659 
4660 
4661   Level: developer
4662 
4663   Notes:
4664   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
4665   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
4666 
4667   If *cellSF is NULL on input, a PetscSF will be created.
4668   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
4669 
4670   An array that maps each point to its containing cell can be obtained with
4671 
4672 $    const PetscSFNode *cells;
4673 $    PetscInt           nFound;
4674 $    const PetscSFNode *found;
4675 $
4676 $    PetscSFGetGraph(cells,NULL,&nFound,&found,&cells);
4677 
4678   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
4679   the index of the cell in its rank's local numbering.
4680 
4681 .keywords: point location, mesh
4682 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
4683 @*/
4684 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
4685 {
4686   PetscErrorCode ierr;
4687 
4688   PetscFunctionBegin;
4689   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4690   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
4691   PetscValidPointer(cellSF,4);
4692   if (*cellSF) {
4693     PetscMPIInt result;
4694 
4695     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
4696     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)cellSF),&result);CHKERRQ(ierr);
4697     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
4698   } else {
4699     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
4700   }
4701   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
4702   if (dm->ops->locatepoints) {
4703     ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
4704   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
4705   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
4706   PetscFunctionReturn(0);
4707 }
4708 
4709 /*@
4710   DMGetOutputDM - Retrieve the DM associated with the layout for output
4711 
4712   Input Parameter:
4713 . dm - The original DM
4714 
4715   Output Parameter:
4716 . odm - The DM which provides the layout for output
4717 
4718   Level: intermediate
4719 
4720 .seealso: VecView(), DMGetDefaultGlobalSection()
4721 @*/
4722 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
4723 {
4724   PetscSection   section;
4725   PetscBool      hasConstraints, ghasConstraints;
4726   PetscErrorCode ierr;
4727 
4728   PetscFunctionBegin;
4729   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4730   PetscValidPointer(odm,2);
4731   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
4732   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
4733   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
4734   if (!ghasConstraints) {
4735     *odm = dm;
4736     PetscFunctionReturn(0);
4737   }
4738   if (!dm->dmBC) {
4739     PetscDS      ds;
4740     PetscSection newSection, gsection;
4741     PetscSF      sf;
4742 
4743     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
4744     ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
4745     ierr = DMSetDS(dm->dmBC, ds);CHKERRQ(ierr);
4746     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
4747     ierr = DMSetDefaultSection(dm->dmBC, newSection);CHKERRQ(ierr);
4748     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
4749     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
4750     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
4751     ierr = DMSetDefaultGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
4752     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
4753   }
4754   *odm = dm->dmBC;
4755   PetscFunctionReturn(0);
4756 }
4757 
4758 /*@
4759   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
4760 
4761   Input Parameter:
4762 . dm - The original DM
4763 
4764   Output Parameters:
4765 + num - The output sequence number
4766 - val - The output sequence value
4767 
4768   Level: intermediate
4769 
4770   Note: This is intended for output that should appear in sequence, for instance
4771   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4772 
4773 .seealso: VecView()
4774 @*/
4775 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
4776 {
4777   PetscFunctionBegin;
4778   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4779   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
4780   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
4781   PetscFunctionReturn(0);
4782 }
4783 
4784 /*@
4785   DMSetOutputSequenceNumber - Set the sequence number/value for output
4786 
4787   Input Parameters:
4788 + dm - The original DM
4789 . num - The output sequence number
4790 - val - The output sequence value
4791 
4792   Level: intermediate
4793 
4794   Note: This is intended for output that should appear in sequence, for instance
4795   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4796 
4797 .seealso: VecView()
4798 @*/
4799 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
4800 {
4801   PetscFunctionBegin;
4802   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4803   dm->outputSequenceNum = num;
4804   dm->outputSequenceVal = val;
4805   PetscFunctionReturn(0);
4806 }
4807 
4808 /*@C
4809   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
4810 
4811   Input Parameters:
4812 + dm   - The original DM
4813 . name - The sequence name
4814 - num  - The output sequence number
4815 
4816   Output Parameter:
4817 . val  - The output sequence value
4818 
4819   Level: intermediate
4820 
4821   Note: This is intended for output that should appear in sequence, for instance
4822   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4823 
4824 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
4825 @*/
4826 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
4827 {
4828   PetscBool      ishdf5;
4829   PetscErrorCode ierr;
4830 
4831   PetscFunctionBegin;
4832   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4833   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
4834   PetscValidPointer(val,4);
4835   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
4836   if (ishdf5) {
4837 #if defined(PETSC_HAVE_HDF5)
4838     PetscScalar value;
4839 
4840     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
4841     *val = PetscRealPart(value);
4842 #endif
4843   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
4844   PetscFunctionReturn(0);
4845 }
4846 
4847 /*@
4848   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
4849 
4850   Not collective
4851 
4852   Input Parameter:
4853 . dm - The DM
4854 
4855   Output Parameter:
4856 . useNatural - The flag to build the mapping to a natural order during distribution
4857 
4858   Level: beginner
4859 
4860 .seealso: DMSetUseNatural(), DMCreate()
4861 @*/
4862 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
4863 {
4864   PetscFunctionBegin;
4865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4866   PetscValidPointer(useNatural, 2);
4867   *useNatural = dm->useNatural;
4868   PetscFunctionReturn(0);
4869 }
4870 
4871 /*@
4872   DMSetUseNatural - Set the flag for creating a mapping to the natural order on distribution
4873 
4874   Collective on dm
4875 
4876   Input Parameters:
4877 + dm - The DM
4878 - useNatural - The flag to build the mapping to a natural order during distribution
4879 
4880   Level: beginner
4881 
4882 .seealso: DMGetUseNatural(), DMCreate()
4883 @*/
4884 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
4885 {
4886   PetscFunctionBegin;
4887   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4888   PetscValidLogicalCollectiveInt(dm, useNatural, 2);
4889   dm->useNatural = useNatural;
4890   PetscFunctionReturn(0);
4891 }
4892 
4893 
4894 /*@C
4895   DMCreateLabel - Create a label of the given name if it does not already exist
4896 
4897   Not Collective
4898 
4899   Input Parameters:
4900 + dm   - The DM object
4901 - name - The label name
4902 
4903   Level: intermediate
4904 
4905 .keywords: mesh
4906 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
4907 @*/
4908 PetscErrorCode DMCreateLabel(DM dm, const char name[])
4909 {
4910   DMLabelLink    next  = dm->labels->next;
4911   PetscBool      flg   = PETSC_FALSE;
4912   PetscErrorCode ierr;
4913 
4914   PetscFunctionBegin;
4915   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4916   PetscValidCharPointer(name, 2);
4917   while (next) {
4918     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
4919     if (flg) break;
4920     next = next->next;
4921   }
4922   if (!flg) {
4923     DMLabelLink tmpLabel;
4924 
4925     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
4926     ierr = DMLabelCreate(name, &tmpLabel->label);CHKERRQ(ierr);
4927     tmpLabel->output = PETSC_TRUE;
4928     tmpLabel->next   = dm->labels->next;
4929     dm->labels->next = tmpLabel;
4930   }
4931   PetscFunctionReturn(0);
4932 }
4933 
4934 /*@C
4935   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
4936 
4937   Not Collective
4938 
4939   Input Parameters:
4940 + dm   - The DM object
4941 . name - The label name
4942 - point - The mesh point
4943 
4944   Output Parameter:
4945 . value - The label value for this point, or -1 if the point is not in the label
4946 
4947   Level: beginner
4948 
4949 .keywords: mesh
4950 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
4951 @*/
4952 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
4953 {
4954   DMLabel        label;
4955   PetscErrorCode ierr;
4956 
4957   PetscFunctionBegin;
4958   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4959   PetscValidCharPointer(name, 2);
4960   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4961   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);CHKERRQ(ierr);
4962   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
4963   PetscFunctionReturn(0);
4964 }
4965 
4966 /*@C
4967   DMSetLabelValue - Add a point to a Sieve Label with given value
4968 
4969   Not Collective
4970 
4971   Input Parameters:
4972 + dm   - The DM object
4973 . name - The label name
4974 . point - The mesh point
4975 - value - The label value for this point
4976 
4977   Output Parameter:
4978 
4979   Level: beginner
4980 
4981 .keywords: mesh
4982 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
4983 @*/
4984 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
4985 {
4986   DMLabel        label;
4987   PetscErrorCode ierr;
4988 
4989   PetscFunctionBegin;
4990   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4991   PetscValidCharPointer(name, 2);
4992   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4993   if (!label) {
4994     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
4995     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
4996   }
4997   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
4998   PetscFunctionReturn(0);
4999 }
5000 
5001 /*@C
5002   DMClearLabelValue - Remove a point from a Sieve Label with given value
5003 
5004   Not Collective
5005 
5006   Input Parameters:
5007 + dm   - The DM object
5008 . name - The label name
5009 . point - The mesh point
5010 - value - The label value for this point
5011 
5012   Output Parameter:
5013 
5014   Level: beginner
5015 
5016 .keywords: mesh
5017 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
5018 @*/
5019 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5020 {
5021   DMLabel        label;
5022   PetscErrorCode ierr;
5023 
5024   PetscFunctionBegin;
5025   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5026   PetscValidCharPointer(name, 2);
5027   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5028   if (!label) PetscFunctionReturn(0);
5029   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
5030   PetscFunctionReturn(0);
5031 }
5032 
5033 /*@C
5034   DMGetLabelSize - Get the number of different integer ids in a Label
5035 
5036   Not Collective
5037 
5038   Input Parameters:
5039 + dm   - The DM object
5040 - name - The label name
5041 
5042   Output Parameter:
5043 . size - The number of different integer ids, or 0 if the label does not exist
5044 
5045   Level: beginner
5046 
5047 .keywords: mesh
5048 .seealso: DMLabeGetNumValues(), DMSetLabelValue()
5049 @*/
5050 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
5051 {
5052   DMLabel        label;
5053   PetscErrorCode ierr;
5054 
5055   PetscFunctionBegin;
5056   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5057   PetscValidCharPointer(name, 2);
5058   PetscValidPointer(size, 3);
5059   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5060   *size = 0;
5061   if (!label) PetscFunctionReturn(0);
5062   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
5063   PetscFunctionReturn(0);
5064 }
5065 
5066 /*@C
5067   DMGetLabelIdIS - Get the integer ids in a label
5068 
5069   Not Collective
5070 
5071   Input Parameters:
5072 + mesh - The DM object
5073 - name - The label name
5074 
5075   Output Parameter:
5076 . ids - The integer ids, or NULL if the label does not exist
5077 
5078   Level: beginner
5079 
5080 .keywords: mesh
5081 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
5082 @*/
5083 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
5084 {
5085   DMLabel        label;
5086   PetscErrorCode ierr;
5087 
5088   PetscFunctionBegin;
5089   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5090   PetscValidCharPointer(name, 2);
5091   PetscValidPointer(ids, 3);
5092   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5093   *ids = NULL;
5094   if (!label) PetscFunctionReturn(0);
5095   ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
5096   PetscFunctionReturn(0);
5097 }
5098 
5099 /*@C
5100   DMGetStratumSize - Get the number of points in a label stratum
5101 
5102   Not Collective
5103 
5104   Input Parameters:
5105 + dm - The DM object
5106 . name - The label name
5107 - value - The stratum value
5108 
5109   Output Parameter:
5110 . size - The stratum size
5111 
5112   Level: beginner
5113 
5114 .keywords: mesh
5115 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
5116 @*/
5117 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
5118 {
5119   DMLabel        label;
5120   PetscErrorCode ierr;
5121 
5122   PetscFunctionBegin;
5123   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5124   PetscValidCharPointer(name, 2);
5125   PetscValidPointer(size, 4);
5126   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5127   *size = 0;
5128   if (!label) PetscFunctionReturn(0);
5129   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
5130   PetscFunctionReturn(0);
5131 }
5132 
5133 /*@C
5134   DMGetStratumIS - Get the points in a label stratum
5135 
5136   Not Collective
5137 
5138   Input Parameters:
5139 + dm - The DM object
5140 . name - The label name
5141 - value - The stratum value
5142 
5143   Output Parameter:
5144 . points - The stratum points, or NULL if the label does not exist or does not have that value
5145 
5146   Level: beginner
5147 
5148 .keywords: mesh
5149 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
5150 @*/
5151 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
5152 {
5153   DMLabel        label;
5154   PetscErrorCode ierr;
5155 
5156   PetscFunctionBegin;
5157   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5158   PetscValidCharPointer(name, 2);
5159   PetscValidPointer(points, 4);
5160   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5161   *points = NULL;
5162   if (!label) PetscFunctionReturn(0);
5163   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
5164   PetscFunctionReturn(0);
5165 }
5166 
5167 /*@C
5168   DMGetStratumIS - Set the points in a label stratum
5169 
5170   Not Collective
5171 
5172   Input Parameters:
5173 + dm - The DM object
5174 . name - The label name
5175 . value - The stratum value
5176 - points - The stratum points
5177 
5178   Level: beginner
5179 
5180 .keywords: mesh
5181 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
5182 @*/
5183 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
5184 {
5185   DMLabel        label;
5186   PetscErrorCode ierr;
5187 
5188   PetscFunctionBegin;
5189   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5190   PetscValidCharPointer(name, 2);
5191   PetscValidPointer(points, 4);
5192   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5193   if (!label) PetscFunctionReturn(0);
5194   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
5195   PetscFunctionReturn(0);
5196 }
5197 
5198 /*@C
5199   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
5200 
5201   Not Collective
5202 
5203   Input Parameters:
5204 + dm   - The DM object
5205 . name - The label name
5206 - value - The label value for this point
5207 
5208   Output Parameter:
5209 
5210   Level: beginner
5211 
5212 .keywords: mesh
5213 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
5214 @*/
5215 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
5216 {
5217   DMLabel        label;
5218   PetscErrorCode ierr;
5219 
5220   PetscFunctionBegin;
5221   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5222   PetscValidCharPointer(name, 2);
5223   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
5224   if (!label) PetscFunctionReturn(0);
5225   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
5226   PetscFunctionReturn(0);
5227 }
5228 
5229 /*@
5230   DMGetNumLabels - Return the number of labels defined by the mesh
5231 
5232   Not Collective
5233 
5234   Input Parameter:
5235 . dm   - The DM object
5236 
5237   Output Parameter:
5238 . numLabels - the number of Labels
5239 
5240   Level: intermediate
5241 
5242 .keywords: mesh
5243 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5244 @*/
5245 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
5246 {
5247   DMLabelLink next = dm->labels->next;
5248   PetscInt  n    = 0;
5249 
5250   PetscFunctionBegin;
5251   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5252   PetscValidPointer(numLabels, 2);
5253   while (next) {++n; next = next->next;}
5254   *numLabels = n;
5255   PetscFunctionReturn(0);
5256 }
5257 
5258 /*@C
5259   DMGetLabelName - Return the name of nth label
5260 
5261   Not Collective
5262 
5263   Input Parameters:
5264 + dm - The DM object
5265 - n  - the label number
5266 
5267   Output Parameter:
5268 . name - the label name
5269 
5270   Level: intermediate
5271 
5272 .keywords: mesh
5273 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5274 @*/
5275 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
5276 {
5277   DMLabelLink next = dm->labels->next;
5278   PetscInt  l    = 0;
5279 
5280   PetscFunctionBegin;
5281   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5282   PetscValidPointer(name, 3);
5283   while (next) {
5284     if (l == n) {
5285       *name = next->label->name;
5286       PetscFunctionReturn(0);
5287     }
5288     ++l;
5289     next = next->next;
5290   }
5291   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5292 }
5293 
5294 /*@C
5295   DMHasLabel - Determine whether the mesh has a label of a given name
5296 
5297   Not Collective
5298 
5299   Input Parameters:
5300 + dm   - The DM object
5301 - name - The label name
5302 
5303   Output Parameter:
5304 . hasLabel - PETSC_TRUE if the label is present
5305 
5306   Level: intermediate
5307 
5308 .keywords: mesh
5309 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5310 @*/
5311 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
5312 {
5313   DMLabelLink    next = dm->labels->next;
5314   PetscErrorCode ierr;
5315 
5316   PetscFunctionBegin;
5317   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5318   PetscValidCharPointer(name, 2);
5319   PetscValidPointer(hasLabel, 3);
5320   *hasLabel = PETSC_FALSE;
5321   while (next) {
5322     ierr = PetscStrcmp(name, next->label->name, hasLabel);CHKERRQ(ierr);
5323     if (*hasLabel) break;
5324     next = next->next;
5325   }
5326   PetscFunctionReturn(0);
5327 }
5328 
5329 /*@C
5330   DMGetLabel - Return the label of a given name, or NULL
5331 
5332   Not Collective
5333 
5334   Input Parameters:
5335 + dm   - The DM object
5336 - name - The label name
5337 
5338   Output Parameter:
5339 . label - The DMLabel, or NULL if the label is absent
5340 
5341   Level: intermediate
5342 
5343 .keywords: mesh
5344 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5345 @*/
5346 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
5347 {
5348   DMLabelLink    next = dm->labels->next;
5349   PetscBool      hasLabel;
5350   PetscErrorCode ierr;
5351 
5352   PetscFunctionBegin;
5353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5354   PetscValidCharPointer(name, 2);
5355   PetscValidPointer(label, 3);
5356   *label = NULL;
5357   while (next) {
5358     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5359     if (hasLabel) {
5360       *label = next->label;
5361       break;
5362     }
5363     next = next->next;
5364   }
5365   PetscFunctionReturn(0);
5366 }
5367 
5368 /*@C
5369   DMGetLabelByNum - Return the nth label
5370 
5371   Not Collective
5372 
5373   Input Parameters:
5374 + dm - The DM object
5375 - n  - the label number
5376 
5377   Output Parameter:
5378 . label - the label
5379 
5380   Level: intermediate
5381 
5382 .keywords: mesh
5383 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5384 @*/
5385 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
5386 {
5387   DMLabelLink next = dm->labels->next;
5388   PetscInt    l    = 0;
5389 
5390   PetscFunctionBegin;
5391   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5392   PetscValidPointer(label, 3);
5393   while (next) {
5394     if (l == n) {
5395       *label = next->label;
5396       PetscFunctionReturn(0);
5397     }
5398     ++l;
5399     next = next->next;
5400   }
5401   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5402 }
5403 
5404 /*@C
5405   DMAddLabel - Add the label to this mesh
5406 
5407   Not Collective
5408 
5409   Input Parameters:
5410 + dm   - The DM object
5411 - label - The DMLabel
5412 
5413   Level: developer
5414 
5415 .keywords: mesh
5416 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5417 @*/
5418 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
5419 {
5420   DMLabelLink    tmpLabel;
5421   PetscBool      hasLabel;
5422   PetscErrorCode ierr;
5423 
5424   PetscFunctionBegin;
5425   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5426   ierr = DMHasLabel(dm, label->name, &hasLabel);CHKERRQ(ierr);
5427   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", label->name);
5428   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
5429   tmpLabel->label  = label;
5430   tmpLabel->output = PETSC_TRUE;
5431   tmpLabel->next   = dm->labels->next;
5432   dm->labels->next = tmpLabel;
5433   PetscFunctionReturn(0);
5434 }
5435 
5436 /*@C
5437   DMRemoveLabel - Remove the label from this mesh
5438 
5439   Not Collective
5440 
5441   Input Parameters:
5442 + dm   - The DM object
5443 - name - The label name
5444 
5445   Output Parameter:
5446 . label - The DMLabel, or NULL if the label is absent
5447 
5448   Level: developer
5449 
5450 .keywords: mesh
5451 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5452 @*/
5453 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
5454 {
5455   DMLabelLink    next = dm->labels->next;
5456   DMLabelLink    last = NULL;
5457   PetscBool      hasLabel;
5458   PetscErrorCode ierr;
5459 
5460   PetscFunctionBegin;
5461   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5462   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
5463   *label = NULL;
5464   if (!hasLabel) PetscFunctionReturn(0);
5465   while (next) {
5466     ierr = PetscStrcmp(name, next->label->name, &hasLabel);CHKERRQ(ierr);
5467     if (hasLabel) {
5468       if (last) last->next       = next->next;
5469       else      dm->labels->next = next->next;
5470       next->next = NULL;
5471       *label     = next->label;
5472       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
5473       if (hasLabel) {
5474         dm->depthLabel = NULL;
5475       }
5476       ierr = PetscFree(next);CHKERRQ(ierr);
5477       break;
5478     }
5479     last = next;
5480     next = next->next;
5481   }
5482   PetscFunctionReturn(0);
5483 }
5484 
5485 /*@C
5486   DMGetLabelOutput - Get the output flag for a given label
5487 
5488   Not Collective
5489 
5490   Input Parameters:
5491 + dm   - The DM object
5492 - name - The label name
5493 
5494   Output Parameter:
5495 . output - The flag for output
5496 
5497   Level: developer
5498 
5499 .keywords: mesh
5500 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5501 @*/
5502 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
5503 {
5504   DMLabelLink    next = dm->labels->next;
5505   PetscErrorCode ierr;
5506 
5507   PetscFunctionBegin;
5508   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5509   PetscValidPointer(name, 2);
5510   PetscValidPointer(output, 3);
5511   while (next) {
5512     PetscBool flg;
5513 
5514     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5515     if (flg) {*output = next->output; PetscFunctionReturn(0);}
5516     next = next->next;
5517   }
5518   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5519 }
5520 
5521 /*@C
5522   DMSetLabelOutput - Set the output flag for a given label
5523 
5524   Not Collective
5525 
5526   Input Parameters:
5527 + dm     - The DM object
5528 . name   - The label name
5529 - output - The flag for output
5530 
5531   Level: developer
5532 
5533 .keywords: mesh
5534 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5535 @*/
5536 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
5537 {
5538   DMLabelLink    next = dm->labels->next;
5539   PetscErrorCode ierr;
5540 
5541   PetscFunctionBegin;
5542   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5543   PetscValidPointer(name, 2);
5544   while (next) {
5545     PetscBool flg;
5546 
5547     ierr = PetscStrcmp(name, next->label->name, &flg);CHKERRQ(ierr);
5548     if (flg) {next->output = output; PetscFunctionReturn(0);}
5549     next = next->next;
5550   }
5551   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5552 }
5553 
5554 
5555 /*@
5556   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
5557 
5558   Collective on DM
5559 
5560   Input Parameter:
5561 . dmA - The DM object with initial labels
5562 
5563   Output Parameter:
5564 . dmB - The DM object with copied labels
5565 
5566   Level: intermediate
5567 
5568   Note: This is typically used when interpolating or otherwise adding to a mesh
5569 
5570 .keywords: mesh
5571 .seealso: DMCopyCoordinates(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
5572 @*/
5573 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
5574 {
5575   PetscInt       numLabels, l;
5576   PetscErrorCode ierr;
5577 
5578   PetscFunctionBegin;
5579   if (dmA == dmB) PetscFunctionReturn(0);
5580   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
5581   for (l = 0; l < numLabels; ++l) {
5582     DMLabel     label, labelNew;
5583     const char *name;
5584     PetscBool   flg;
5585 
5586     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
5587     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
5588     if (flg) continue;
5589     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
5590     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
5591     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
5592   }
5593   PetscFunctionReturn(0);
5594 }
5595 
5596 /*@
5597   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
5598 
5599   Input Parameter:
5600 . dm - The DM object
5601 
5602   Output Parameter:
5603 . cdm - The coarse DM
5604 
5605   Level: intermediate
5606 
5607 .seealso: DMSetCoarseDM()
5608 @*/
5609 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
5610 {
5611   PetscFunctionBegin;
5612   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5613   PetscValidPointer(cdm, 2);
5614   *cdm = dm->coarseMesh;
5615   PetscFunctionReturn(0);
5616 }
5617 
5618 /*@
5619   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
5620 
5621   Input Parameters:
5622 + dm - The DM object
5623 - cdm - The coarse DM
5624 
5625   Level: intermediate
5626 
5627 .seealso: DMGetCoarseDM()
5628 @*/
5629 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
5630 {
5631   PetscErrorCode ierr;
5632 
5633   PetscFunctionBegin;
5634   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5635   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
5636   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
5637   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
5638   dm->coarseMesh = cdm;
5639   PetscFunctionReturn(0);
5640 }
5641 
5642 /*@
5643   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
5644 
5645   Input Parameter:
5646 . dm - The DM object
5647 
5648   Output Parameter:
5649 . fdm - The fine DM
5650 
5651   Level: intermediate
5652 
5653 .seealso: DMSetFineDM()
5654 @*/
5655 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
5656 {
5657   PetscFunctionBegin;
5658   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5659   PetscValidPointer(fdm, 2);
5660   *fdm = dm->fineMesh;
5661   PetscFunctionReturn(0);
5662 }
5663 
5664 /*@
5665   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
5666 
5667   Input Parameters:
5668 + dm - The DM object
5669 - fdm - The fine DM
5670 
5671   Level: intermediate
5672 
5673 .seealso: DMGetFineDM()
5674 @*/
5675 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
5676 {
5677   PetscErrorCode ierr;
5678 
5679   PetscFunctionBegin;
5680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5681   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
5682   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
5683   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
5684   dm->fineMesh = fdm;
5685   PetscFunctionReturn(0);
5686 }
5687 
5688 /*=== DMBoundary code ===*/
5689 
5690 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
5691 {
5692   PetscErrorCode ierr;
5693 
5694   PetscFunctionBegin;
5695   ierr = PetscDSCopyBoundary(dm->prob,dmNew->prob);CHKERRQ(ierr);
5696   PetscFunctionReturn(0);
5697 }
5698 
5699 /*@C
5700   DMAddBoundary - Add a boundary condition to the model
5701 
5702   Input Parameters:
5703 + dm          - The DM, with a PetscDS that matches the problem being constrained
5704 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
5705 . name        - The BC name
5706 . labelname   - The label defining constrained points
5707 . field       - The field to constrain
5708 . numcomps    - The number of constrained field components
5709 . comps       - An array of constrained component numbers
5710 . bcFunc      - A pointwise function giving boundary values
5711 . numids      - The number of DMLabel ids for constrained points
5712 . ids         - An array of ids for constrained points
5713 - ctx         - An optional user context for bcFunc
5714 
5715   Options Database Keys:
5716 + -bc_<boundary name> <num> - Overrides the boundary ids
5717 - -bc_<boundary name>_comp <num> - Overrides the boundary components
5718 
5719   Level: developer
5720 
5721 .seealso: DMGetBoundary()
5722 @*/
5723 PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), PetscInt numids, const PetscInt *ids, void *ctx)
5724 {
5725   PetscErrorCode ierr;
5726 
5727   PetscFunctionBegin;
5728   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5729   ierr = PetscDSAddBoundary(dm->prob,type,name,labelname,field,numcomps,comps,bcFunc,numids,ids,ctx);CHKERRQ(ierr);
5730   PetscFunctionReturn(0);
5731 }
5732 
5733 /*@
5734   DMGetNumBoundary - Get the number of registered BC
5735 
5736   Input Parameters:
5737 . dm - The mesh object
5738 
5739   Output Parameters:
5740 . numBd - The number of BC
5741 
5742   Level: intermediate
5743 
5744 .seealso: DMAddBoundary(), DMGetBoundary()
5745 @*/
5746 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
5747 {
5748   PetscErrorCode ierr;
5749 
5750   PetscFunctionBegin;
5751   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5752   ierr = PetscDSGetNumBoundary(dm->prob,numBd);CHKERRQ(ierr);
5753   PetscFunctionReturn(0);
5754 }
5755 
5756 /*@C
5757   DMGetBoundary - Add a boundary condition to the model
5758 
5759   Input Parameters:
5760 + dm          - The mesh object
5761 - bd          - The BC number
5762 
5763   Output Parameters:
5764 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
5765 . name        - The BC name
5766 . labelname   - The label defining constrained points
5767 . field       - The field to constrain
5768 . numcomps    - The number of constrained field components
5769 . comps       - An array of constrained component numbers
5770 . bcFunc      - A pointwise function giving boundary values
5771 . numids      - The number of DMLabel ids for constrained points
5772 . ids         - An array of ids for constrained points
5773 - ctx         - An optional user context for bcFunc
5774 
5775   Options Database Keys:
5776 + -bc_<boundary name> <num> - Overrides the boundary ids
5777 - -bc_<boundary name>_comp <num> - Overrides the boundary components
5778 
5779   Level: developer
5780 
5781 .seealso: DMAddBoundary()
5782 @*/
5783 PetscErrorCode DMGetBoundary(DM dm, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
5784 {
5785   PetscErrorCode ierr;
5786 
5787   PetscFunctionBegin;
5788   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5789   ierr = PetscDSGetBoundary(dm->prob,bd,type,name,labelname,field,numcomps,comps,func,numids,ids,ctx);CHKERRQ(ierr);
5790   PetscFunctionReturn(0);
5791 }
5792 
5793 static PetscErrorCode DMPopulateBoundary(DM dm)
5794 {
5795   DMBoundary *lastnext;
5796   DSBoundary dsbound;
5797   PetscErrorCode ierr;
5798 
5799   PetscFunctionBegin;
5800   dsbound = dm->prob->boundary;
5801   if (dm->boundary) {
5802     DMBoundary next = dm->boundary;
5803 
5804     /* quick check to see if the PetscDS has changed */
5805     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
5806     /* the PetscDS has changed: tear down and rebuild */
5807     while (next) {
5808       DMBoundary b = next;
5809 
5810       next = b->next;
5811       ierr = PetscFree(b);CHKERRQ(ierr);
5812     }
5813     dm->boundary = NULL;
5814   }
5815 
5816   lastnext = &(dm->boundary);
5817   while (dsbound) {
5818     DMBoundary dmbound;
5819 
5820     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
5821     dmbound->dsboundary = dsbound;
5822     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
5823     if (!dmbound->label) PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);
5824     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
5825     *lastnext = dmbound;
5826     lastnext = &(dmbound->next);
5827     dsbound = dsbound->next;
5828   }
5829   PetscFunctionReturn(0);
5830 }
5831 
5832 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
5833 {
5834   DMBoundary     b;
5835   PetscErrorCode ierr;
5836 
5837   PetscFunctionBegin;
5838   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5839   PetscValidPointer(isBd, 3);
5840   *isBd = PETSC_FALSE;
5841   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
5842   b = dm->boundary;
5843   while (b && !(*isBd)) {
5844     DMLabel    label = b->label;
5845     DSBoundary dsb = b->dsboundary;
5846 
5847     if (label) {
5848       PetscInt i;
5849 
5850       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
5851         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
5852       }
5853     }
5854     b = b->next;
5855   }
5856   PetscFunctionReturn(0);
5857 }
5858 
5859 /*@C
5860   DMProjectFunction - This projects the given function into the function space provided.
5861 
5862   Input Parameters:
5863 + dm      - The DM
5864 . time    - The time
5865 . funcs   - The coordinate functions to evaluate, one per field
5866 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
5867 - mode    - The insertion mode for values
5868 
5869   Output Parameter:
5870 . X - vector
5871 
5872    Calling sequence of func:
5873 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
5874 
5875 +  dim - The spatial dimension
5876 .  x   - The coordinates
5877 .  Nf  - The number of fields
5878 .  u   - The output field values
5879 -  ctx - optional user-defined function context
5880 
5881   Level: developer
5882 
5883 .seealso: DMComputeL2Diff()
5884 @*/
5885 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
5886 {
5887   Vec            localX;
5888   PetscErrorCode ierr;
5889 
5890   PetscFunctionBegin;
5891   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5892   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
5893   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
5894   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
5895   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
5896   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
5897   PetscFunctionReturn(0);
5898 }
5899 
5900 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
5901 {
5902   PetscErrorCode ierr;
5903 
5904   PetscFunctionBegin;
5905   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5906   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
5907   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFunctionLocal",((PetscObject)dm)->type_name);
5908   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
5909   PetscFunctionReturn(0);
5910 }
5911 
5912 PetscErrorCode DMProjectFunctionLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
5913 {
5914   PetscErrorCode ierr;
5915 
5916   PetscFunctionBegin;
5917   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5918   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
5919   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
5920   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, funcs, ctxs, mode, localX);CHKERRQ(ierr);
5921   PetscFunctionReturn(0);
5922 }
5923 
5924 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
5925                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
5926                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
5927                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
5928                                                   PetscReal, const PetscReal[], PetscScalar[]),
5929                                    InsertMode mode, Vec localX)
5930 {
5931   PetscErrorCode ierr;
5932 
5933   PetscFunctionBegin;
5934   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5935   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
5936   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
5937   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFieldLocal",((PetscObject)dm)->type_name);
5938   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
5939   PetscFunctionReturn(0);
5940 }
5941 
5942 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], Vec localU,
5943                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
5944                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
5945                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
5946                                                        PetscReal, const PetscReal[], PetscScalar[]),
5947                                         InsertMode mode, Vec localX)
5948 {
5949   PetscErrorCode ierr;
5950 
5951   PetscFunctionBegin;
5952   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5953   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
5954   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
5955   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFieldLocal",((PetscObject)dm)->type_name);
5956   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, localU, funcs, mode, localX);CHKERRQ(ierr);
5957   PetscFunctionReturn(0);
5958 }
5959 
5960 /*@C
5961   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
5962 
5963   Input Parameters:
5964 + dm    - The DM
5965 . time  - The time
5966 . funcs - The functions to evaluate for each field component
5967 . ctxs  - Optional array of contexts to pass to each function, or NULL.
5968 - X     - The coefficient vector u_h
5969 
5970   Output Parameter:
5971 . diff - The diff ||u - u_h||_2
5972 
5973   Level: developer
5974 
5975 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
5976 @*/
5977 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
5978 {
5979   PetscErrorCode ierr;
5980 
5981   PetscFunctionBegin;
5982   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5983   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
5984   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMComputeL2Diff",((PetscObject)dm)->type_name);
5985   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
5986   PetscFunctionReturn(0);
5987 }
5988 
5989 /*@C
5990   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
5991 
5992   Input Parameters:
5993 + dm    - The DM
5994 , time  - The time
5995 . funcs - The gradient functions to evaluate for each field component
5996 . ctxs  - Optional array of contexts to pass to each function, or NULL.
5997 . X     - The coefficient vector u_h
5998 - n     - The vector to project along
5999 
6000   Output Parameter:
6001 . diff - The diff ||(grad u - grad u_h) . n||_2
6002 
6003   Level: developer
6004 
6005 .seealso: DMProjectFunction(), DMComputeL2Diff()
6006 @*/
6007 PetscErrorCode DMComputeL2GradientDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
6008 {
6009   PetscErrorCode ierr;
6010 
6011   PetscFunctionBegin;
6012   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6013   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6014   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
6015   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
6016   PetscFunctionReturn(0);
6017 }
6018 
6019 /*@C
6020   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
6021 
6022   Input Parameters:
6023 + dm    - The DM
6024 . time  - The time
6025 . funcs - The functions to evaluate for each field component
6026 . ctxs  - Optional array of contexts to pass to each function, or NULL.
6027 - X     - The coefficient vector u_h
6028 
6029   Output Parameter:
6030 . diff - The array of differences, ||u^f - u^f_h||_2
6031 
6032   Level: developer
6033 
6034 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6035 @*/
6036 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
6037 {
6038   PetscErrorCode ierr;
6039 
6040   PetscFunctionBegin;
6041   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6042   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
6043   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
6044   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
6045   PetscFunctionReturn(0);
6046 }
6047 
6048 /*@C
6049   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
6050                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
6051 
6052   Collective on dm
6053 
6054   Input parameters:
6055 + dm - the pre-adaptation DM object
6056 - label - label with the flags
6057 
6058   Output parameters:
6059 . adaptedDM - the adapted DM object: may be NULL if an adapted DM could not be produced.
6060 
6061   Level: intermediate
6062 @*/
6063 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *adaptedDM)
6064 {
6065   PetscErrorCode ierr;
6066 
6067   PetscFunctionBegin;
6068   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6069   PetscValidPointer(label,2);
6070   PetscValidPointer(adaptedDM,3);
6071   *adaptedDM = NULL;
6072   ierr = PetscTryMethod((PetscObject)dm,"DMAdaptLabel_C",(DM,DMLabel, DM*),(dm,label,adaptedDM));CHKERRQ(ierr);
6073   PetscFunctionReturn(0);
6074 }
6075 
6076 /*@C
6077  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
6078 
6079  Not Collective
6080 
6081  Input Parameter:
6082  . dm    - The DM
6083 
6084  Output Parameter:
6085  . nranks - the number of neighbours
6086  . ranks - the neighbors ranks
6087 
6088  Notes:
6089  Do not free the array, it is freed when the DM is destroyed.
6090 
6091  Level: beginner
6092 
6093  .seealso: DMDAGetNeighbors(), PetscSFGetRanks()
6094 @*/
6095 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
6096 {
6097   PetscErrorCode ierr;
6098 
6099   PetscFunctionBegin;
6100   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6101   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMGetNeighbors",((PetscObject)dm)->type_name);
6102   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
6103   PetscFunctionReturn(0);
6104 }
6105 
6106 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
6107 
6108 /*
6109     Converts the input vector to a ghosted vector and then calls the standard coloring code.
6110     This has be a different function because it requires DM which is not defined in the Mat library
6111 */
6112 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
6113 {
6114   PetscErrorCode ierr;
6115 
6116   PetscFunctionBegin;
6117   if (coloring->ctype == IS_COLORING_LOCAL) {
6118     Vec x1local;
6119     DM  dm;
6120     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6121     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
6122     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
6123     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6124     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
6125     x1   = x1local;
6126   }
6127   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
6128   if (coloring->ctype == IS_COLORING_LOCAL) {
6129     DM  dm;
6130     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
6131     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
6132   }
6133   PetscFunctionReturn(0);
6134 }
6135 
6136 /*@
6137     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
6138 
6139     Input Parameter:
6140 .    coloring - the MatFDColoring object
6141 
6142     Developer Notes: this routine exists because the PETSc Mat library does not know about the DM objects
6143 
6144     Level: advanced
6145 
6146 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
6147 @*/
6148 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
6149 {
6150   PetscFunctionBegin;
6151   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
6152   PetscFunctionReturn(0);
6153 }
6154