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