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