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