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