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