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