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