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