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