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