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