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