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