xref: /petsc/src/dm/interface/dm.c (revision 29b3c8a1c1d29fc05018f23f4f087a3ebe1dff6f)
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 /******************************** FEM Support **********************************/
3742 
3743 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3744 {
3745   PetscInt       f;
3746   PetscErrorCode ierr;
3747 
3748   PetscFunctionBegin;
3749   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3750   for (f = 0; f < len; ++f) {
3751     ierr = PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));CHKERRQ(ierr);
3752   }
3753   PetscFunctionReturn(0);
3754 }
3755 
3756 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
3757 {
3758   PetscInt       f, g;
3759   PetscErrorCode ierr;
3760 
3761   PetscFunctionBegin;
3762   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
3763   for (f = 0; f < rows; ++f) {
3764     ierr = PetscPrintf(PETSC_COMM_SELF, "  |");CHKERRQ(ierr);
3765     for (g = 0; g < cols; ++g) {
3766       ierr = PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));CHKERRQ(ierr);
3767     }
3768     ierr = PetscPrintf(PETSC_COMM_SELF, " |\n");CHKERRQ(ierr);
3769   }
3770   PetscFunctionReturn(0);
3771 }
3772 
3773 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
3774 {
3775   PetscInt          localSize, bs;
3776   PetscMPIInt       size;
3777   Vec               x, xglob;
3778   const PetscScalar *xarray;
3779   PetscErrorCode    ierr;
3780 
3781   PetscFunctionBegin;
3782   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);CHKERRQ(ierr);
3783   ierr = VecDuplicate(X, &x);CHKERRQ(ierr);
3784   ierr = VecCopy(X, x);CHKERRQ(ierr);
3785   ierr = VecChop(x, tol);CHKERRQ(ierr);
3786   ierr = PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);CHKERRQ(ierr);
3787   if (size > 1) {
3788     ierr = VecGetLocalSize(x,&localSize);CHKERRQ(ierr);
3789     ierr = VecGetArrayRead(x,&xarray);CHKERRQ(ierr);
3790     ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr);
3791     ierr = VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);CHKERRQ(ierr);
3792   } else {
3793     xglob = x;
3794   }
3795   ierr = VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));CHKERRQ(ierr);
3796   if (size > 1) {
3797     ierr = VecDestroy(&xglob);CHKERRQ(ierr);
3798     ierr = VecRestoreArrayRead(x,&xarray);CHKERRQ(ierr);
3799   }
3800   ierr = VecDestroy(&x);CHKERRQ(ierr);
3801   PetscFunctionReturn(0);
3802 }
3803 
3804 /*@
3805   DMGetSection - Get the PetscSection encoding the local data layout for the DM.   This is equivalent to DMGetLocalSection(). Deprecated in v3.12
3806 
3807   Input Parameter:
3808 . dm - The DM
3809 
3810   Output Parameter:
3811 . section - The PetscSection
3812 
3813   Options Database Keys:
3814 . -dm_petscsection_view - View the Section created by the DM
3815 
3816   Level: advanced
3817 
3818   Notes:
3819   Use DMGetLocalSection() in new code.
3820 
3821   This gets a borrowed reference, so the user should not destroy this PetscSection.
3822 
3823 .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
3824 @*/
3825 PetscErrorCode DMGetSection(DM dm, PetscSection *section)
3826 {
3827   PetscErrorCode ierr;
3828 
3829   PetscFunctionBegin;
3830   ierr = DMGetLocalSection(dm,section);CHKERRQ(ierr);
3831   PetscFunctionReturn(0);
3832 }
3833 
3834 /*@
3835   DMGetLocalSection - Get the PetscSection encoding the local data layout for the DM.
3836 
3837   Input Parameter:
3838 . dm - The DM
3839 
3840   Output Parameter:
3841 . section - The PetscSection
3842 
3843   Options Database Keys:
3844 . -dm_petscsection_view - View the Section created by the DM
3845 
3846   Level: intermediate
3847 
3848   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
3849 
3850 .seealso: DMSetLocalSection(), DMGetGlobalSection()
3851 @*/
3852 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
3853 {
3854   PetscErrorCode ierr;
3855 
3856   PetscFunctionBegin;
3857   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3858   PetscValidPointer(section, 2);
3859   if (!dm->localSection && dm->ops->createlocalsection) {
3860     PetscInt d;
3861 
3862     if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {ierr = PetscDSSetFromOptions(dm->probs[d].ds);CHKERRQ(ierr);}
3863     ierr = (*dm->ops->createlocalsection)(dm);CHKERRQ(ierr);
3864     if (dm->localSection) {ierr = PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");CHKERRQ(ierr);}
3865   }
3866   *section = dm->localSection;
3867   PetscFunctionReturn(0);
3868 }
3869 
3870 /*@
3871   DMSetSection - Set the PetscSection encoding the local data layout for the DM.  This is equivalent to DMSetLocalSection(). Deprecated in v3.12
3872 
3873   Input Parameters:
3874 + dm - The DM
3875 - section - The PetscSection
3876 
3877   Level: advanced
3878 
3879   Notes:
3880   Use DMSetLocalSection() in new code.
3881 
3882   Any existing Section will be destroyed
3883 
3884 .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
3885 @*/
3886 PetscErrorCode DMSetSection(DM dm, PetscSection section)
3887 {
3888   PetscErrorCode ierr;
3889 
3890   PetscFunctionBegin;
3891   ierr = DMSetLocalSection(dm,section);CHKERRQ(ierr);
3892   PetscFunctionReturn(0);
3893 }
3894 
3895 /*@
3896   DMSetLocalSection - Set the PetscSection encoding the local data layout for the DM.
3897 
3898   Input Parameters:
3899 + dm - The DM
3900 - section - The PetscSection
3901 
3902   Level: intermediate
3903 
3904   Note: Any existing Section will be destroyed
3905 
3906 .seealso: DMGetLocalSection(), DMSetGlobalSection()
3907 @*/
3908 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
3909 {
3910   PetscInt       numFields = 0;
3911   PetscInt       f;
3912   PetscErrorCode ierr;
3913 
3914   PetscFunctionBegin;
3915   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3916   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3917   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3918   ierr = PetscSectionDestroy(&dm->localSection);CHKERRQ(ierr);
3919   dm->localSection = section;
3920   if (section) {ierr = PetscSectionGetNumFields(dm->localSection, &numFields);CHKERRQ(ierr);}
3921   if (numFields) {
3922     ierr = DMSetNumFields(dm, numFields);CHKERRQ(ierr);
3923     for (f = 0; f < numFields; ++f) {
3924       PetscObject disc;
3925       const char *name;
3926 
3927       ierr = PetscSectionGetFieldName(dm->localSection, f, &name);CHKERRQ(ierr);
3928       ierr = DMGetField(dm, f, NULL, &disc);CHKERRQ(ierr);
3929       ierr = PetscObjectSetName(disc, name);CHKERRQ(ierr);
3930     }
3931   }
3932   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
3933   ierr = PetscSectionDestroy(&dm->globalSection);CHKERRQ(ierr);
3934   PetscFunctionReturn(0);
3935 }
3936 
3937 /*@
3938   DMGetDefaultConstraints - Get the PetscSection and Mat that specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.
3939 
3940   not collective
3941 
3942   Input Parameter:
3943 . dm - The DM
3944 
3945   Output Parameter:
3946 + 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.
3947 - 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.
3948 
3949   Level: advanced
3950 
3951   Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.
3952 
3953 .seealso: DMSetDefaultConstraints()
3954 @*/
3955 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
3956 {
3957   PetscErrorCode ierr;
3958 
3959   PetscFunctionBegin;
3960   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3961   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {ierr = (*dm->ops->createdefaultconstraints)(dm);CHKERRQ(ierr);}
3962   if (section) {*section = dm->defaultConstraintSection;}
3963   if (mat) {*mat = dm->defaultConstraintMat;}
3964   PetscFunctionReturn(0);
3965 }
3966 
3967 /*@
3968   DMSetDefaultConstraints - Set the PetscSection and Mat that specify the local constraint interpolation.
3969 
3970   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().
3971 
3972   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.
3973 
3974   collective on dm
3975 
3976   Input Parameters:
3977 + dm - The DM
3978 + 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).
3979 - 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).
3980 
3981   Level: advanced
3982 
3983   Note: This increments the references of the PetscSection and the Mat, so they user can destroy them
3984 
3985 .seealso: DMGetDefaultConstraints()
3986 @*/
3987 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
3988 {
3989   PetscMPIInt result;
3990   PetscErrorCode ierr;
3991 
3992   PetscFunctionBegin;
3993   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3994   if (section) {
3995     PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3996     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);CHKERRQ(ierr);
3997     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
3998   }
3999   if (mat) {
4000     PetscValidHeaderSpecific(mat,MAT_CLASSID,3);
4001     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);CHKERRQ(ierr);
4002     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4003   }
4004   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
4005   ierr = PetscSectionDestroy(&dm->defaultConstraintSection);CHKERRQ(ierr);
4006   dm->defaultConstraintSection = section;
4007   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
4008   ierr = MatDestroy(&dm->defaultConstraintMat);CHKERRQ(ierr);
4009   dm->defaultConstraintMat = mat;
4010   PetscFunctionReturn(0);
4011 }
4012 
4013 #if defined(PETSC_USE_DEBUG)
4014 /*
4015   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.
4016 
4017   Input Parameters:
4018 + dm - The DM
4019 . localSection - PetscSection describing the local data layout
4020 - globalSection - PetscSection describing the global data layout
4021 
4022   Level: intermediate
4023 
4024 .seealso: DMGetSectionSF(), DMSetSectionSF()
4025 */
4026 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4027 {
4028   MPI_Comm        comm;
4029   PetscLayout     layout;
4030   const PetscInt *ranges;
4031   PetscInt        pStart, pEnd, p, nroots;
4032   PetscMPIInt     size, rank;
4033   PetscBool       valid = PETSC_TRUE, gvalid;
4034   PetscErrorCode  ierr;
4035 
4036   PetscFunctionBegin;
4037   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4038   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4039   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
4040   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4041   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
4042   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
4043   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
4044   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
4045   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
4046   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
4047   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
4048   for (p = pStart; p < pEnd; ++p) {
4049     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;
4050 
4051     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
4052     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
4053     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
4054     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
4055     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
4056     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
4057     if (!gdof) continue; /* Censored point */
4058     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;}
4059     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;}
4060     if (gdof < 0) {
4061       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4062       for (d = 0; d < gsize; ++d) {
4063         PetscInt offset = -(goff+1) + d, r;
4064 
4065         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
4066         if (r < 0) r = -(r+2);
4067         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;}
4068       }
4069     }
4070   }
4071   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
4072   ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
4073   ierr = MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);CHKERRQ(ierr);
4074   if (!gvalid) {
4075     ierr = DMView(dm, NULL);CHKERRQ(ierr);
4076     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4077   }
4078   PetscFunctionReturn(0);
4079 }
4080 #endif
4081 
4082 /*@
4083   DMGetGlobalSection - Get the PetscSection encoding the global data layout for the DM.
4084 
4085   Collective on dm
4086 
4087   Input Parameter:
4088 . dm - The DM
4089 
4090   Output Parameter:
4091 . section - The PetscSection
4092 
4093   Level: intermediate
4094 
4095   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
4096 
4097 .seealso: DMSetLocalSection(), DMGetLocalSection()
4098 @*/
4099 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4100 {
4101   PetscErrorCode ierr;
4102 
4103   PetscFunctionBegin;
4104   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4105   PetscValidPointer(section, 2);
4106   if (!dm->globalSection) {
4107     PetscSection s;
4108 
4109     ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr);
4110     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4111     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4112     ierr = PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);CHKERRQ(ierr);
4113     ierr = PetscLayoutDestroy(&dm->map);CHKERRQ(ierr);
4114     ierr = PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);CHKERRQ(ierr);
4115     ierr = PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");CHKERRQ(ierr);
4116   }
4117   *section = dm->globalSection;
4118   PetscFunctionReturn(0);
4119 }
4120 
4121 /*@
4122   DMSetGlobalSection - Set the PetscSection encoding the global data layout for the DM.
4123 
4124   Input Parameters:
4125 + dm - The DM
4126 - section - The PetscSection, or NULL
4127 
4128   Level: intermediate
4129 
4130   Note: Any existing Section will be destroyed
4131 
4132 .seealso: DMGetGlobalSection(), DMSetLocalSection()
4133 @*/
4134 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4135 {
4136   PetscErrorCode ierr;
4137 
4138   PetscFunctionBegin;
4139   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4140   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
4141   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
4142   ierr = PetscSectionDestroy(&dm->globalSection);CHKERRQ(ierr);
4143   dm->globalSection = section;
4144 #if defined(PETSC_USE_DEBUG)
4145   if (section) {ierr = DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);CHKERRQ(ierr);}
4146 #endif
4147   PetscFunctionReturn(0);
4148 }
4149 
4150 /*@
4151   DMGetSectionSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
4152   it is created from the default PetscSection layouts in the DM.
4153 
4154   Input Parameter:
4155 . dm - The DM
4156 
4157   Output Parameter:
4158 . sf - The PetscSF
4159 
4160   Level: intermediate
4161 
4162   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4163 
4164 .seealso: DMSetSectionSF(), DMCreateSectionSF()
4165 @*/
4166 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4167 {
4168   PetscInt       nroots;
4169   PetscErrorCode ierr;
4170 
4171   PetscFunctionBegin;
4172   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4173   PetscValidPointer(sf, 2);
4174   if (!dm->sectionSF) {
4175     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);CHKERRQ(ierr);
4176   }
4177   ierr = PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
4178   if (nroots < 0) {
4179     PetscSection section, gSection;
4180 
4181     ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
4182     if (section) {
4183       ierr = DMGetGlobalSection(dm, &gSection);CHKERRQ(ierr);
4184       ierr = DMCreateSectionSF(dm, section, gSection);CHKERRQ(ierr);
4185     } else {
4186       *sf = NULL;
4187       PetscFunctionReturn(0);
4188     }
4189   }
4190   *sf = dm->sectionSF;
4191   PetscFunctionReturn(0);
4192 }
4193 
4194 /*@
4195   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM
4196 
4197   Input Parameters:
4198 + dm - The DM
4199 - sf - The PetscSF
4200 
4201   Level: intermediate
4202 
4203   Note: Any previous SF is destroyed
4204 
4205 .seealso: DMGetSectionSF(), DMCreateSectionSF()
4206 @*/
4207 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4208 {
4209   PetscErrorCode ierr;
4210 
4211   PetscFunctionBegin;
4212   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4213   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4214   ierr = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
4215   ierr = PetscSFDestroy(&dm->sectionSF);CHKERRQ(ierr);
4216   dm->sectionSF = sf;
4217   PetscFunctionReturn(0);
4218 }
4219 
4220 /*@C
4221   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4222   describing the data layout.
4223 
4224   Input Parameters:
4225 + dm - The DM
4226 . localSection - PetscSection describing the local data layout
4227 - globalSection - PetscSection describing the global data layout
4228 
4229   Notes: One usually uses DMGetSectionSF() to obtain the PetscSF
4230 
4231   Level: developer
4232 
4233   Developer Note: Since this routine has for arguments the two sections from the DM and puts the resulting PetscSF
4234                   directly into the DM, perhaps this function should not take the local and global sections as
4235                   input and should just obtain them from the DM?
4236 
4237 .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4238 @*/
4239 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4240 {
4241   MPI_Comm       comm;
4242   PetscLayout    layout;
4243   const PetscInt *ranges;
4244   PetscInt       *local;
4245   PetscSFNode    *remote;
4246   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
4247   PetscMPIInt    size, rank;
4248   PetscErrorCode ierr;
4249 
4250   PetscFunctionBegin;
4251   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4252   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4253   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
4254   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4255   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
4256   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
4257   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
4258   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
4259   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
4260   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
4261   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
4262   for (p = pStart; p < pEnd; ++p) {
4263     PetscInt gdof, gcdof;
4264 
4265     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
4266     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
4267     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));
4268     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4269   }
4270   ierr = PetscMalloc1(nleaves, &local);CHKERRQ(ierr);
4271   ierr = PetscMalloc1(nleaves, &remote);CHKERRQ(ierr);
4272   for (p = pStart, l = 0; p < pEnd; ++p) {
4273     const PetscInt *cind;
4274     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
4275 
4276     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
4277     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
4278     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
4279     ierr = PetscSectionGetConstraintIndices(localSection, p, &cind);CHKERRQ(ierr);
4280     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
4281     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
4282     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
4283     if (!gdof) continue; /* Censored point */
4284     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4285     if (gsize != dof-cdof) {
4286       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);
4287       cdof = 0; /* Ignore constraints */
4288     }
4289     for (d = 0, c = 0; d < dof; ++d) {
4290       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
4291       local[l+d-c] = off+d;
4292     }
4293     if (gdof < 0) {
4294       for (d = 0; d < gsize; ++d, ++l) {
4295         PetscInt offset = -(goff+1) + d, r;
4296 
4297         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
4298         if (r < 0) r = -(r+2);
4299         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);
4300         remote[l].rank  = r;
4301         remote[l].index = offset - ranges[r];
4302       }
4303     } else {
4304       for (d = 0; d < gsize; ++d, ++l) {
4305         remote[l].rank  = rank;
4306         remote[l].index = goff+d - ranges[rank];
4307       }
4308     }
4309   }
4310   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
4311   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
4312   ierr = PetscSFSetGraph(dm->sectionSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
4313   PetscFunctionReturn(0);
4314 }
4315 
4316 /*@
4317   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
4318 
4319   Input Parameter:
4320 . dm - The DM
4321 
4322   Output Parameter:
4323 . sf - The PetscSF
4324 
4325   Level: intermediate
4326 
4327   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4328 
4329 .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4330 @*/
4331 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4332 {
4333   PetscFunctionBegin;
4334   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4335   PetscValidPointer(sf, 2);
4336   *sf = dm->sf;
4337   PetscFunctionReturn(0);
4338 }
4339 
4340 /*@
4341   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
4342 
4343   Input Parameters:
4344 + dm - The DM
4345 - sf - The PetscSF
4346 
4347   Level: intermediate
4348 
4349 .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4350 @*/
4351 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4352 {
4353   PetscErrorCode ierr;
4354 
4355   PetscFunctionBegin;
4356   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4357   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4358   ierr = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
4359   ierr = PetscSFDestroy(&dm->sf);CHKERRQ(ierr);
4360   dm->sf = sf;
4361   PetscFunctionReturn(0);
4362 }
4363 
4364 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4365 {
4366   PetscClassId   id;
4367   PetscErrorCode ierr;
4368 
4369   PetscFunctionBegin;
4370   ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr);
4371   if (id == PETSCFE_CLASSID) {
4372     ierr = DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);CHKERRQ(ierr);
4373   } else if (id == PETSCFV_CLASSID) {
4374     ierr = DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);CHKERRQ(ierr);
4375   } else {
4376     ierr = DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);CHKERRQ(ierr);
4377   }
4378   PetscFunctionReturn(0);
4379 }
4380 
4381 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4382 {
4383   RegionField   *tmpr;
4384   PetscInt       Nf = dm->Nf, f;
4385   PetscErrorCode ierr;
4386 
4387   PetscFunctionBegin;
4388   if (Nf >= NfNew) PetscFunctionReturn(0);
4389   ierr = PetscMalloc1(NfNew, &tmpr);CHKERRQ(ierr);
4390   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4391   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL;}
4392   ierr = PetscFree(dm->fields);CHKERRQ(ierr);
4393   dm->Nf     = NfNew;
4394   dm->fields = tmpr;
4395   PetscFunctionReturn(0);
4396 }
4397 
4398 /*@
4399   DMClearFields - Remove all fields from the DM
4400 
4401   Logically collective on dm
4402 
4403   Input Parameter:
4404 . dm - The DM
4405 
4406   Level: intermediate
4407 
4408 .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4409 @*/
4410 PetscErrorCode DMClearFields(DM dm)
4411 {
4412   PetscInt       f;
4413   PetscErrorCode ierr;
4414 
4415   PetscFunctionBegin;
4416   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4417   for (f = 0; f < dm->Nf; ++f) {
4418     ierr = PetscObjectDestroy(&dm->fields[f].disc);CHKERRQ(ierr);
4419     ierr = DMLabelDestroy(&dm->fields[f].label);CHKERRQ(ierr);
4420   }
4421   ierr = PetscFree(dm->fields);CHKERRQ(ierr);
4422   dm->fields = NULL;
4423   dm->Nf     = 0;
4424   PetscFunctionReturn(0);
4425 }
4426 
4427 /*@
4428   DMGetNumFields - Get the number of fields in the DM
4429 
4430   Not collective
4431 
4432   Input Parameter:
4433 . dm - The DM
4434 
4435   Output Parameter:
4436 . Nf - The number of fields
4437 
4438   Level: intermediate
4439 
4440 .seealso: DMSetNumFields(), DMSetField()
4441 @*/
4442 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4443 {
4444   PetscFunctionBegin;
4445   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4446   PetscValidIntPointer(numFields, 2);
4447   *numFields = dm->Nf;
4448   PetscFunctionReturn(0);
4449 }
4450 
4451 /*@
4452   DMSetNumFields - Set the number of fields in the DM
4453 
4454   Logically collective on dm
4455 
4456   Input Parameters:
4457 + dm - The DM
4458 - Nf - The number of fields
4459 
4460   Level: intermediate
4461 
4462 .seealso: DMGetNumFields(), DMSetField()
4463 @*/
4464 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4465 {
4466   PetscInt       Nf, f;
4467   PetscErrorCode ierr;
4468 
4469   PetscFunctionBegin;
4470   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4471   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4472   for (f = Nf; f < numFields; ++f) {
4473     PetscContainer obj;
4474 
4475     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
4476     ierr = DMAddField(dm, NULL, (PetscObject) obj);CHKERRQ(ierr);
4477     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
4478   }
4479   PetscFunctionReturn(0);
4480 }
4481 
4482 /*@
4483   DMGetField - Return the discretization object for a given DM field
4484 
4485   Not collective
4486 
4487   Input Parameters:
4488 + dm - The DM
4489 - f  - The field number
4490 
4491   Output Parameters:
4492 + label - The label indicating the support of the field, or NULL for the entire mesh
4493 - field - The discretization object
4494 
4495   Level: intermediate
4496 
4497 .seealso: DMAddField(), DMSetField()
4498 @*/
4499 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4500 {
4501   PetscFunctionBegin;
4502   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4503   PetscValidPointer(field, 3);
4504   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);
4505   if (label) *label = dm->fields[f].label;
4506   if (field) *field = dm->fields[f].disc;
4507   PetscFunctionReturn(0);
4508 }
4509 
4510 /*@
4511   DMSetField - Set the discretization object for a given DM field
4512 
4513   Logically collective on dm
4514 
4515   Input Parameters:
4516 + dm    - The DM
4517 . f     - The field number
4518 . label - The label indicating the support of the field, or NULL for the entire mesh
4519 - field - The discretization object
4520 
4521   Level: intermediate
4522 
4523 .seealso: DMAddField(), DMGetField()
4524 @*/
4525 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4526 {
4527   PetscErrorCode ierr;
4528 
4529   PetscFunctionBegin;
4530   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4531   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
4532   PetscValidHeader(field, 4);
4533   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4534   ierr = DMFieldEnlarge_Static(dm, f+1);CHKERRQ(ierr);
4535   ierr = DMLabelDestroy(&dm->fields[f].label);CHKERRQ(ierr);
4536   ierr = PetscObjectDestroy(&dm->fields[f].disc);CHKERRQ(ierr);
4537   dm->fields[f].label = label;
4538   dm->fields[f].disc  = field;
4539   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
4540   ierr = PetscObjectReference((PetscObject) field);CHKERRQ(ierr);
4541   ierr = DMSetDefaultAdjacency_Private(dm, f, field);CHKERRQ(ierr);
4542   ierr = DMClearDS(dm);CHKERRQ(ierr);
4543   PetscFunctionReturn(0);
4544 }
4545 
4546 /*@
4547   DMAddField - Add the discretization object for the given DM field
4548 
4549   Logically collective on dm
4550 
4551   Input Parameters:
4552 + dm    - The DM
4553 . label - The label indicating the support of the field, or NULL for the entire mesh
4554 - field - The discretization object
4555 
4556   Level: intermediate
4557 
4558 .seealso: DMSetField(), DMGetField()
4559 @*/
4560 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4561 {
4562   PetscInt       Nf = dm->Nf;
4563   PetscErrorCode ierr;
4564 
4565   PetscFunctionBegin;
4566   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4567   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
4568   PetscValidHeader(field, 3);
4569   ierr = DMFieldEnlarge_Static(dm, Nf+1);CHKERRQ(ierr);
4570   dm->fields[Nf].label = label;
4571   dm->fields[Nf].disc  = field;
4572   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
4573   ierr = PetscObjectReference((PetscObject) field);CHKERRQ(ierr);
4574   ierr = DMSetDefaultAdjacency_Private(dm, Nf, field);CHKERRQ(ierr);
4575   ierr = DMClearDS(dm);CHKERRQ(ierr);
4576   PetscFunctionReturn(0);
4577 }
4578 
4579 /*@
4580   DMCopyFields - Copy the discretizations for the DM into another DM
4581 
4582   Collective on dm
4583 
4584   Input Parameter:
4585 . dm - The DM
4586 
4587   Output Parameter:
4588 . newdm - The DM
4589 
4590   Level: advanced
4591 
4592 .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4593 @*/
4594 PetscErrorCode DMCopyFields(DM dm, DM newdm)
4595 {
4596   PetscInt       Nf, f;
4597   PetscErrorCode ierr;
4598 
4599   PetscFunctionBegin;
4600   if (dm == newdm) PetscFunctionReturn(0);
4601   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4602   ierr = DMClearFields(newdm);CHKERRQ(ierr);
4603   for (f = 0; f < Nf; ++f) {
4604     DMLabel     label;
4605     PetscObject field;
4606     PetscBool   useCone, useClosure;
4607 
4608     ierr = DMGetField(dm, f, &label, &field);CHKERRQ(ierr);
4609     ierr = DMSetField(newdm, f, label, field);CHKERRQ(ierr);
4610     ierr = DMGetAdjacency(dm, f, &useCone, &useClosure);CHKERRQ(ierr);
4611     ierr = DMSetAdjacency(newdm, f, useCone, useClosure);CHKERRQ(ierr);
4612   }
4613   PetscFunctionReturn(0);
4614 }
4615 
4616 /*@
4617   DMGetAdjacency - Returns the flags for determining variable influence
4618 
4619   Not collective
4620 
4621   Input Parameters:
4622 + dm - The DM object
4623 - f  - The field number, or PETSC_DEFAULT for the default adjacency
4624 
4625   Output Parameter:
4626 + useCone    - Flag for variable influence starting with the cone operation
4627 - useClosure - Flag for variable influence using transitive closure
4628 
4629   Notes:
4630 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4631 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4632 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4633   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4634 
4635   Level: developer
4636 
4637 .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4638 @*/
4639 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4640 {
4641   PetscFunctionBegin;
4642   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4643   if (useCone)    PetscValidBoolPointer(useCone, 3);
4644   if (useClosure) PetscValidBoolPointer(useClosure, 4);
4645   if (f < 0) {
4646     if (useCone)    *useCone    = dm->adjacency[0];
4647     if (useClosure) *useClosure = dm->adjacency[1];
4648   } else {
4649     PetscInt       Nf;
4650     PetscErrorCode ierr;
4651 
4652     ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4653     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4654     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4655     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4656   }
4657   PetscFunctionReturn(0);
4658 }
4659 
4660 /*@
4661   DMSetAdjacency - Set the flags for determining variable influence
4662 
4663   Not collective
4664 
4665   Input Parameters:
4666 + dm         - The DM object
4667 . f          - The field number
4668 . useCone    - Flag for variable influence starting with the cone operation
4669 - useClosure - Flag for variable influence using transitive closure
4670 
4671   Notes:
4672 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4673 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4674 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4675   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4676 
4677   Level: developer
4678 
4679 .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4680 @*/
4681 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4682 {
4683   PetscFunctionBegin;
4684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4685   if (f < 0) {
4686     dm->adjacency[0] = useCone;
4687     dm->adjacency[1] = useClosure;
4688   } else {
4689     PetscInt       Nf;
4690     PetscErrorCode ierr;
4691 
4692     ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4693     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4694     dm->fields[f].adjacency[0] = useCone;
4695     dm->fields[f].adjacency[1] = useClosure;
4696   }
4697   PetscFunctionReturn(0);
4698 }
4699 
4700 /*@
4701   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
4702 
4703   Not collective
4704 
4705   Input Parameters:
4706 . dm - The DM object
4707 
4708   Output Parameter:
4709 + useCone    - Flag for variable influence starting with the cone operation
4710 - useClosure - Flag for variable influence using transitive closure
4711 
4712   Notes:
4713 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4714 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4715 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4716 
4717   Level: developer
4718 
4719 .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4720 @*/
4721 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4722 {
4723   PetscInt       Nf;
4724   PetscErrorCode ierr;
4725 
4726   PetscFunctionBegin;
4727   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4728   if (useCone)    PetscValidBoolPointer(useCone, 3);
4729   if (useClosure) PetscValidBoolPointer(useClosure, 4);
4730   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4731   if (!Nf) {
4732     ierr = DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);CHKERRQ(ierr);
4733   } else {
4734     ierr = DMGetAdjacency(dm, 0, useCone, useClosure);CHKERRQ(ierr);
4735   }
4736   PetscFunctionReturn(0);
4737 }
4738 
4739 /*@
4740   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
4741 
4742   Not collective
4743 
4744   Input Parameters:
4745 + dm         - The DM object
4746 . useCone    - Flag for variable influence starting with the cone operation
4747 - useClosure - Flag for variable influence using transitive closure
4748 
4749   Notes:
4750 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4751 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4752 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4753 
4754   Level: developer
4755 
4756 .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
4757 @*/
4758 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
4759 {
4760   PetscInt       Nf;
4761   PetscErrorCode ierr;
4762 
4763   PetscFunctionBegin;
4764   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4765   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4766   if (!Nf) {
4767     ierr = DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);CHKERRQ(ierr);
4768   } else {
4769     ierr = DMSetAdjacency(dm, 0, useCone, useClosure);CHKERRQ(ierr);
4770   }
4771   PetscFunctionReturn(0);
4772 }
4773 
4774 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
4775 {
4776   DMSpace       *tmpd;
4777   PetscInt       Nds = dm->Nds, s;
4778   PetscErrorCode ierr;
4779 
4780   PetscFunctionBegin;
4781   if (Nds >= NdsNew) PetscFunctionReturn(0);
4782   ierr = PetscMalloc1(NdsNew, &tmpd);CHKERRQ(ierr);
4783   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
4784   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
4785   ierr = PetscFree(dm->probs);CHKERRQ(ierr);
4786   dm->Nds   = NdsNew;
4787   dm->probs = tmpd;
4788   PetscFunctionReturn(0);
4789 }
4790 
4791 /*@
4792   DMGetNumDS - Get the number of discrete systems in the DM
4793 
4794   Not collective
4795 
4796   Input Parameter:
4797 . dm - The DM
4798 
4799   Output Parameter:
4800 . Nds - The number of PetscDS objects
4801 
4802   Level: intermediate
4803 
4804 .seealso: DMGetDS(), DMGetCellDS()
4805 @*/
4806 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
4807 {
4808   PetscFunctionBegin;
4809   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4810   PetscValidIntPointer(Nds, 2);
4811   *Nds = dm->Nds;
4812   PetscFunctionReturn(0);
4813 }
4814 
4815 /*@
4816   DMClearDS - Remove all discrete systems from the DM
4817 
4818   Logically collective on dm
4819 
4820   Input Parameter:
4821 . dm - The DM
4822 
4823   Level: intermediate
4824 
4825 .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
4826 @*/
4827 PetscErrorCode DMClearDS(DM dm)
4828 {
4829   PetscInt       s;
4830   PetscErrorCode ierr;
4831 
4832   PetscFunctionBegin;
4833   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4834   for (s = 0; s < dm->Nds; ++s) {
4835     ierr = PetscDSDestroy(&dm->probs[s].ds);CHKERRQ(ierr);
4836     ierr = DMLabelDestroy(&dm->probs[s].label);CHKERRQ(ierr);
4837     ierr = ISDestroy(&dm->probs[s].fields);CHKERRQ(ierr);
4838   }
4839   ierr = PetscFree(dm->probs);CHKERRQ(ierr);
4840   dm->probs = NULL;
4841   dm->Nds   = 0;
4842   PetscFunctionReturn(0);
4843 }
4844 
4845 /*@
4846   DMGetDS - Get the default PetscDS
4847 
4848   Not collective
4849 
4850   Input Parameter:
4851 . dm    - The DM
4852 
4853   Output Parameter:
4854 . prob - The default PetscDS
4855 
4856   Level: intermediate
4857 
4858 .seealso: DMGetCellDS(), DMGetRegionDS()
4859 @*/
4860 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
4861 {
4862   PetscErrorCode ierr;
4863 
4864   PetscFunctionBeginHot;
4865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4866   PetscValidPointer(prob, 2);
4867   if (dm->Nds <= 0) {
4868     PetscDS ds;
4869 
4870     ierr = PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);CHKERRQ(ierr);
4871     ierr = DMSetRegionDS(dm, NULL, NULL, ds);CHKERRQ(ierr);
4872     ierr = PetscDSDestroy(&ds);CHKERRQ(ierr);
4873   }
4874   *prob = dm->probs[0].ds;
4875   PetscFunctionReturn(0);
4876 }
4877 
4878 /*@
4879   DMGetCellDS - Get the PetscDS defined on a given cell
4880 
4881   Not collective
4882 
4883   Input Parameters:
4884 + dm    - The DM
4885 - point - Cell for the DS
4886 
4887   Output Parameter:
4888 . prob - The PetscDS defined on the given cell
4889 
4890   Level: developer
4891 
4892 .seealso: DMGetDS(), DMSetRegionDS()
4893 @*/
4894 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
4895 {
4896   PetscDS        probDef = NULL;
4897   PetscInt       s;
4898   PetscErrorCode ierr;
4899 
4900   PetscFunctionBeginHot;
4901   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4902   PetscValidPointer(prob, 3);
4903   *prob = NULL;
4904   for (s = 0; s < dm->Nds; ++s) {
4905     PetscInt val;
4906 
4907     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
4908     else {
4909       ierr = DMLabelGetValue(dm->probs[s].label, point, &val);CHKERRQ(ierr);
4910       if (val >= 0) {*prob = dm->probs[s].ds; break;}
4911     }
4912   }
4913   if (!*prob) *prob = probDef;
4914   PetscFunctionReturn(0);
4915 }
4916 
4917 /*@
4918   DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
4919 
4920   Not collective
4921 
4922   Input Parameters:
4923 + dm    - The DM
4924 - label - The DMLabel defining the mesh region, or NULL for the entire mesh
4925 
4926   Output Parameters:
4927 + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
4928 - prob - The PetscDS defined on the given region, or NULL
4929 
4930   Note: If the label is missing, this function returns an error
4931 
4932   Level: advanced
4933 
4934 .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
4935 @*/
4936 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
4937 {
4938   PetscInt Nds = dm->Nds, s;
4939 
4940   PetscFunctionBegin;
4941   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4942   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
4943   if (fields) {PetscValidPointer(fields, 3); *fields = NULL;}
4944   if (ds)     {PetscValidPointer(ds, 4);     *ds     = NULL;}
4945   for (s = 0; s < Nds; ++s) {
4946     if (dm->probs[s].label == label) {
4947       if (fields) *fields = dm->probs[s].fields;
4948       if (ds)     *ds     = dm->probs[s].ds;
4949       PetscFunctionReturn(0);
4950     }
4951   }
4952   PetscFunctionReturn(0);
4953 }
4954 
4955 /*@
4956   DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
4957 
4958   Not collective
4959 
4960   Input Parameters:
4961 + dm  - The DM
4962 - num - The region number, in [0, Nds)
4963 
4964   Output Parameters:
4965 + label  - The region label, or NULL
4966 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
4967 - prob   - The PetscDS defined on the given region, or NULL
4968 
4969   Level: advanced
4970 
4971 .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
4972 @*/
4973 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
4974 {
4975   PetscInt       Nds;
4976   PetscErrorCode ierr;
4977 
4978   PetscFunctionBegin;
4979   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4980   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
4981   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
4982   if (label) {
4983     PetscValidPointer(label, 3);
4984     *label = dm->probs[num].label;
4985   }
4986   if (fields) {
4987     PetscValidPointer(fields, 4);
4988     *fields = dm->probs[num].fields;
4989   }
4990   if (ds) {
4991     PetscValidPointer(ds, 5);
4992     *ds = dm->probs[num].ds;
4993   }
4994   PetscFunctionReturn(0);
4995 }
4996 
4997 /*@
4998   DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel
4999 
5000   Collective on dm
5001 
5002   Input Parameters:
5003 + dm     - The DM
5004 . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5005 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5006 - prob   - The PetscDS defined on the given cell
5007 
5008   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. If DS is replaced,
5009   the fields argument is ignored.
5010 
5011   Level: advanced
5012 
5013 .seealso: DMGetRegionDS(), DMGetDS(), DMGetCellDS()
5014 @*/
5015 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5016 {
5017   PetscInt       Nds = dm->Nds, s;
5018   PetscErrorCode ierr;
5019 
5020   PetscFunctionBegin;
5021   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5022   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5023   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 3);
5024   for (s = 0; s < Nds; ++s) {
5025     if (dm->probs[s].label == label) {
5026       ierr = PetscDSDestroy(&dm->probs[s].ds);CHKERRQ(ierr);
5027       dm->probs[s].ds = ds;
5028       PetscFunctionReturn(0);
5029     }
5030   }
5031   ierr = DMDSEnlarge_Static(dm, Nds+1);CHKERRQ(ierr);
5032   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
5033   ierr = PetscObjectReference((PetscObject) fields);CHKERRQ(ierr);
5034   ierr = PetscObjectReference((PetscObject) ds);CHKERRQ(ierr);
5035   if (!label) {
5036     /* Put the NULL label at the front, so it is returned as the default */
5037     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5038     Nds = 0;
5039   }
5040   dm->probs[Nds].label  = label;
5041   dm->probs[Nds].fields = fields;
5042   dm->probs[Nds].ds     = ds;
5043   PetscFunctionReturn(0);
5044 }
5045 
5046 /*@
5047   DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM
5048 
5049   Collective on dm
5050 
5051   Input Parameter:
5052 . dm - The DM
5053 
5054   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
5055 
5056   Level: intermediate
5057 
5058 .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5059 @*/
5060 PetscErrorCode DMCreateDS(DM dm)
5061 {
5062   MPI_Comm       comm;
5063   PetscDS        prob, probh = NULL;
5064   PetscInt       dimEmbed, Nf = dm->Nf, f, s, field = 0, fieldh = 0;
5065   PetscBool      doSetup = PETSC_TRUE;
5066   PetscErrorCode ierr;
5067 
5068   PetscFunctionBegin;
5069   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5070   if (!dm->fields) PetscFunctionReturn(0);
5071   /* Can only handle two label cases right now:
5072    1) NULL
5073    2) Hybrid cells
5074   */
5075   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
5076   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
5077   /* Create default DS */
5078   ierr = DMGetRegionDS(dm, NULL, NULL, &prob);CHKERRQ(ierr);
5079   if (!prob) {
5080     IS        fields;
5081     PetscInt *fld, nf;
5082 
5083     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5084     ierr = PetscMalloc1(nf, &fld);CHKERRQ(ierr);
5085     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5086     ierr = ISCreate(PETSC_COMM_SELF, &fields);CHKERRQ(ierr);
5087     ierr = PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");CHKERRQ(ierr);
5088     ierr = ISSetType(fields, ISGENERAL);CHKERRQ(ierr);
5089     ierr = ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);CHKERRQ(ierr);
5090 
5091     ierr = PetscDSCreate(comm, &prob);CHKERRQ(ierr);
5092     ierr = DMSetRegionDS(dm, NULL, fields, prob);CHKERRQ(ierr);
5093     ierr = PetscDSDestroy(&prob);CHKERRQ(ierr);
5094     ierr = ISDestroy(&fields);CHKERRQ(ierr);
5095     ierr = DMGetRegionDS(dm, NULL, NULL, &prob);CHKERRQ(ierr);
5096   }
5097   ierr = PetscDSSetCoordinateDimension(prob, dimEmbed);CHKERRQ(ierr);
5098   /* Optionally create hybrid DS */
5099   for (f = 0; f < Nf; ++f) {
5100     DMLabel  label = dm->fields[f].label;
5101     PetscInt lStart, lEnd;
5102 
5103     if (label) {
5104       DM        plex;
5105       IS        fields;
5106       PetscInt *fld;
5107       PetscInt  depth, pMax[4];
5108 
5109       ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
5110       ierr = DMPlexGetDepth(plex, &depth);CHKERRQ(ierr);
5111       ierr = DMPlexGetHybridBounds(plex, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);CHKERRQ(ierr);
5112       ierr = DMDestroy(&plex);CHKERRQ(ierr);
5113 
5114       ierr = DMLabelGetBounds(label, &lStart, &lEnd);CHKERRQ(ierr);
5115       if (lStart < pMax[depth]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only support labels over hybrid cells right now");
5116       ierr = PetscDSCreate(comm, &probh);CHKERRQ(ierr);
5117       ierr = PetscMalloc1(1, &fld);CHKERRQ(ierr);
5118       fld[0] = f;
5119       ierr = ISCreate(PETSC_COMM_SELF, &fields);CHKERRQ(ierr);
5120       ierr = PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");CHKERRQ(ierr);
5121       ierr = ISSetType(fields, ISGENERAL);CHKERRQ(ierr);
5122       ierr = ISGeneralSetIndices(fields, 1, fld, PETSC_OWN_POINTER);CHKERRQ(ierr);
5123       ierr = DMSetRegionDS(dm, label, fields, probh);CHKERRQ(ierr);
5124       ierr = ISDestroy(&fields);CHKERRQ(ierr);
5125       ierr = PetscDSSetHybrid(probh, PETSC_TRUE);CHKERRQ(ierr);
5126       ierr = PetscDSSetCoordinateDimension(probh, dimEmbed);CHKERRQ(ierr);
5127       break;
5128     }
5129   }
5130   /* Set fields in DSes */
5131   for (f = 0; f < Nf; ++f) {
5132     DMLabel     label = dm->fields[f].label;
5133     PetscObject disc  = dm->fields[f].disc;
5134 
5135     if (!label) {
5136       ierr = PetscDSSetDiscretization(prob,  field++,  disc);CHKERRQ(ierr);
5137       if (probh) {
5138         PetscFE subfe;
5139 
5140         ierr = PetscFEGetHeightSubspace((PetscFE) disc, 1, &subfe);CHKERRQ(ierr);
5141         ierr = PetscDSSetDiscretization(probh, fieldh++, (PetscObject) subfe);CHKERRQ(ierr);
5142       }
5143     } else {
5144       ierr = PetscDSSetDiscretization(probh, fieldh++, disc);CHKERRQ(ierr);
5145     }
5146     /* We allow people to have placeholder fields and construct the Section by hand */
5147     {
5148       PetscClassId id;
5149 
5150       ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr);
5151       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5152     }
5153   }
5154   ierr = PetscDSDestroy(&probh);CHKERRQ(ierr);
5155   /* Setup DSes */
5156   if (doSetup) {
5157     for (s = 0; s < dm->Nds; ++s) {ierr = PetscDSSetUp(dm->probs[s].ds);CHKERRQ(ierr);}
5158   }
5159   PetscFunctionReturn(0);
5160 }
5161 
5162 /*@
5163   DMCopyDS - Copy the discrete systems for the DM into another DM
5164 
5165   Collective on dm
5166 
5167   Input Parameter:
5168 . dm - The DM
5169 
5170   Output Parameter:
5171 . newdm - The DM
5172 
5173   Level: advanced
5174 
5175 .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5176 @*/
5177 PetscErrorCode DMCopyDS(DM dm, DM newdm)
5178 {
5179   PetscInt       Nds, s;
5180   PetscErrorCode ierr;
5181 
5182   PetscFunctionBegin;
5183   if (dm == newdm) PetscFunctionReturn(0);
5184   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
5185   ierr = DMClearDS(newdm);CHKERRQ(ierr);
5186   for (s = 0; s < Nds; ++s) {
5187     DMLabel label;
5188     IS      fields;
5189     PetscDS ds;
5190 
5191     ierr = DMGetRegionNumDS(dm, s, &label, &fields, &ds);CHKERRQ(ierr);
5192     ierr = DMSetRegionDS(newdm, label, fields, ds);CHKERRQ(ierr);
5193   }
5194   PetscFunctionReturn(0);
5195 }
5196 
5197 /*@
5198   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
5199 
5200   Collective on dm
5201 
5202   Input Parameter:
5203 . dm - The DM
5204 
5205   Output Parameter:
5206 . newdm - The DM
5207 
5208   Level: advanced
5209 
5210 .seealso: DMCopyFields(), DMCopyDS()
5211 @*/
5212 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5213 {
5214   PetscErrorCode ierr;
5215 
5216   PetscFunctionBegin;
5217   if (dm == newdm) PetscFunctionReturn(0);
5218   ierr = DMCopyFields(dm, newdm);CHKERRQ(ierr);
5219   ierr = DMCopyDS(dm, newdm);CHKERRQ(ierr);
5220   PetscFunctionReturn(0);
5221 }
5222 
5223 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5224 {
5225   DM dm_coord,dmc_coord;
5226   PetscErrorCode ierr;
5227   Vec coords,ccoords;
5228   Mat inject;
5229   PetscFunctionBegin;
5230   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5231   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
5232   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5233   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
5234   if (coords && !ccoords) {
5235     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
5236     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5237     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
5238     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
5239     ierr = MatDestroy(&inject);CHKERRQ(ierr);
5240     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
5241     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5242   }
5243   PetscFunctionReturn(0);
5244 }
5245 
5246 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5247 {
5248   DM dm_coord,subdm_coord;
5249   PetscErrorCode ierr;
5250   Vec coords,ccoords,clcoords;
5251   VecScatter *scat_i,*scat_g;
5252   PetscFunctionBegin;
5253   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5254   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
5255   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5256   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
5257   if (coords && !ccoords) {
5258     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
5259     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5260     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
5261     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
5262     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
5263     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5264     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5265     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5266     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5267     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
5268     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
5269     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
5270     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
5271     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5272     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
5273     ierr = PetscFree(scat_i);CHKERRQ(ierr);
5274     ierr = PetscFree(scat_g);CHKERRQ(ierr);
5275   }
5276   PetscFunctionReturn(0);
5277 }
5278 
5279 /*@
5280   DMGetDimension - Return the topological dimension of the DM
5281 
5282   Not collective
5283 
5284   Input Parameter:
5285 . dm - The DM
5286 
5287   Output Parameter:
5288 . dim - The topological dimension
5289 
5290   Level: beginner
5291 
5292 .seealso: DMSetDimension(), DMCreate()
5293 @*/
5294 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5295 {
5296   PetscFunctionBegin;
5297   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5298   PetscValidIntPointer(dim, 2);
5299   *dim = dm->dim;
5300   PetscFunctionReturn(0);
5301 }
5302 
5303 /*@
5304   DMSetDimension - Set the topological dimension of the DM
5305 
5306   Collective on dm
5307 
5308   Input Parameters:
5309 + dm - The DM
5310 - dim - The topological dimension
5311 
5312   Level: beginner
5313 
5314 .seealso: DMGetDimension(), DMCreate()
5315 @*/
5316 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5317 {
5318   PetscDS        ds;
5319   PetscErrorCode ierr;
5320 
5321   PetscFunctionBegin;
5322   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5323   PetscValidLogicalCollectiveInt(dm, dim, 2);
5324   dm->dim = dim;
5325   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5326   if (ds->dimEmbed < 0) {ierr = PetscDSSetCoordinateDimension(ds, dm->dim);CHKERRQ(ierr);}
5327   PetscFunctionReturn(0);
5328 }
5329 
5330 /*@
5331   DMGetDimPoints - Get the half-open interval for all points of a given dimension
5332 
5333   Collective on dm
5334 
5335   Input Parameters:
5336 + dm - the DM
5337 - dim - the dimension
5338 
5339   Output Parameters:
5340 + pStart - The first point of the given dimension
5341 - pEnd - The first point following points of the given dimension
5342 
5343   Note:
5344   The points are vertices in the Hasse diagram encoding the topology. This is explained in
5345   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
5346   then the interval is empty.
5347 
5348   Level: intermediate
5349 
5350 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5351 @*/
5352 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5353 {
5354   PetscInt       d;
5355   PetscErrorCode ierr;
5356 
5357   PetscFunctionBegin;
5358   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5359   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
5360   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5361   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5362   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
5363   PetscFunctionReturn(0);
5364 }
5365 
5366 /*@
5367   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
5368 
5369   Collective on dm
5370 
5371   Input Parameters:
5372 + dm - the DM
5373 - c - coordinate vector
5374 
5375   Notes:
5376   The coordinates do include those for ghost points, which are in the local vector.
5377 
5378   The vector c should be destroyed by the caller.
5379 
5380   Level: intermediate
5381 
5382 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5383 @*/
5384 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5385 {
5386   PetscErrorCode ierr;
5387 
5388   PetscFunctionBegin;
5389   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5390   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5391   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5392   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5393   dm->coordinates = c;
5394   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5395   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5396   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5397   PetscFunctionReturn(0);
5398 }
5399 
5400 /*@
5401   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
5402 
5403   Not collective
5404 
5405    Input Parameters:
5406 +  dm - the DM
5407 -  c - coordinate vector
5408 
5409   Notes:
5410   The coordinates of ghost points can be set using DMSetCoordinates()
5411   followed by DMGetCoordinatesLocal(). This is intended to enable the
5412   setting of ghost coordinates outside of the domain.
5413 
5414   The vector c should be destroyed by the caller.
5415 
5416   Level: intermediate
5417 
5418 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5419 @*/
5420 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5421 {
5422   PetscErrorCode ierr;
5423 
5424   PetscFunctionBegin;
5425   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5426   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5427   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5428   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5429 
5430   dm->coordinatesLocal = c;
5431 
5432   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5433   PetscFunctionReturn(0);
5434 }
5435 
5436 /*@
5437   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
5438 
5439   Collective on dm
5440 
5441   Input Parameter:
5442 . dm - the DM
5443 
5444   Output Parameter:
5445 . c - global coordinate vector
5446 
5447   Note:
5448   This is a borrowed reference, so the user should NOT destroy this vector
5449 
5450   Each process has only the local coordinates (does NOT have the ghost coordinates).
5451 
5452   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5453   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5454 
5455   Level: intermediate
5456 
5457 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5458 @*/
5459 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5460 {
5461   PetscErrorCode ierr;
5462 
5463   PetscFunctionBegin;
5464   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5465   PetscValidPointer(c,2);
5466   if (!dm->coordinates && dm->coordinatesLocal) {
5467     DM        cdm = NULL;
5468     PetscBool localized;
5469 
5470     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5471     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
5472     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
5473     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
5474     if (localized) {
5475       PetscInt cdim;
5476 
5477       ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
5478       ierr = VecSetBlockSize(dm->coordinates, cdim);CHKERRQ(ierr);
5479     }
5480     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
5481     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
5482     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
5483   }
5484   *c = dm->coordinates;
5485   PetscFunctionReturn(0);
5486 }
5487 
5488 /*@
5489   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
5490 
5491   Collective on dm
5492 
5493   Input Parameter:
5494 . dm - the DM
5495 
5496   Level: advanced
5497 
5498 .seealso: DMGetCoordinatesLocalNoncollective()
5499 @*/
5500 PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
5501 {
5502   PetscErrorCode ierr;
5503 
5504   PetscFunctionBegin;
5505   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5506   if (!dm->coordinatesLocal && dm->coordinates) {
5507     DM        cdm = NULL;
5508     PetscBool localized;
5509 
5510     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5511     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
5512     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
5513     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
5514     if (localized) {
5515       PetscInt cdim;
5516 
5517       ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
5518       ierr = VecSetBlockSize(dm->coordinates, cdim);CHKERRQ(ierr);
5519     }
5520     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
5521     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
5522     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
5523   }
5524   PetscFunctionReturn(0);
5525 }
5526 
5527 /*@
5528   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
5529 
5530   Collective on dm
5531 
5532   Input Parameter:
5533 . dm - the DM
5534 
5535   Output Parameter:
5536 . c - coordinate vector
5537 
5538   Note:
5539   This is a borrowed reference, so the user should NOT destroy this vector
5540 
5541   Each process has the local and ghost coordinates
5542 
5543   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5544   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5545 
5546   Level: intermediate
5547 
5548 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
5549 @*/
5550 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
5551 {
5552   PetscErrorCode ierr;
5553 
5554   PetscFunctionBegin;
5555   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5556   PetscValidPointer(c,2);
5557   ierr = DMGetCoordinatesLocalSetUp(dm);CHKERRQ(ierr);
5558   *c = dm->coordinatesLocal;
5559   PetscFunctionReturn(0);
5560 }
5561 
5562 /*@
5563   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
5564 
5565   Not collective
5566 
5567   Input Parameter:
5568 . dm - the DM
5569 
5570   Output Parameter:
5571 . c - coordinate vector
5572 
5573   Level: advanced
5574 
5575 .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5576 @*/
5577 PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
5578 {
5579   PetscFunctionBegin;
5580   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5581   PetscValidPointer(c,2);
5582   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
5583   *c = dm->coordinatesLocal;
5584   PetscFunctionReturn(0);
5585 }
5586 
5587 /*@
5588   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
5589 
5590   Not collective
5591 
5592   Input Parameter:
5593 + dm - the DM
5594 - p - the IS of points whose coordinates will be returned
5595 
5596   Output Parameter:
5597 + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
5598 - pCoord - the Vec with coordinates of points in p
5599 
5600   Note:
5601   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
5602 
5603   This creates a new vector, so the user SHOULD destroy this vector
5604 
5605   Each process has the local and ghost coordinates
5606 
5607   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5608   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5609 
5610   Level: advanced
5611 
5612 .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5613 @*/
5614 PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
5615 {
5616   PetscSection        cs, newcs;
5617   Vec                 coords;
5618   const PetscScalar   *arr;
5619   PetscScalar         *newarr=NULL;
5620   PetscInt            n;
5621   PetscErrorCode      ierr;
5622 
5623   PetscFunctionBegin;
5624   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5625   PetscValidHeaderSpecific(p, IS_CLASSID, 2);
5626   if (pCoordSection) PetscValidPointer(pCoordSection, 3);
5627   if (pCoord) PetscValidPointer(pCoord, 4);
5628   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
5629   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
5630   cs = dm->coordinateDM->localSection;
5631   coords = dm->coordinatesLocal;
5632   ierr = VecGetArrayRead(coords, &arr);CHKERRQ(ierr);
5633   ierr = PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);CHKERRQ(ierr);
5634   ierr = VecRestoreArrayRead(coords, &arr);CHKERRQ(ierr);
5635   if (pCoord) {
5636     ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr);
5637     /* set array in two steps to mimic PETSC_OWN_POINTER */
5638     ierr = VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);CHKERRQ(ierr);
5639     ierr = VecReplaceArray(*pCoord, newarr);CHKERRQ(ierr);
5640   } else {
5641     ierr = PetscFree(newarr);CHKERRQ(ierr);
5642   }
5643   if (pCoordSection) {*pCoordSection = newcs;}
5644   else               {ierr = PetscSectionDestroy(&newcs);CHKERRQ(ierr);}
5645   PetscFunctionReturn(0);
5646 }
5647 
5648 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
5649 {
5650   PetscErrorCode ierr;
5651 
5652   PetscFunctionBegin;
5653   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5654   PetscValidPointer(field,2);
5655   if (!dm->coordinateField) {
5656     if (dm->ops->createcoordinatefield) {
5657       ierr = (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);CHKERRQ(ierr);
5658     }
5659   }
5660   *field = dm->coordinateField;
5661   PetscFunctionReturn(0);
5662 }
5663 
5664 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
5665 {
5666   PetscErrorCode ierr;
5667 
5668   PetscFunctionBegin;
5669   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5670   if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2);
5671   ierr = PetscObjectReference((PetscObject)field);CHKERRQ(ierr);
5672   ierr = DMFieldDestroy(&dm->coordinateField);CHKERRQ(ierr);
5673   dm->coordinateField = field;
5674   PetscFunctionReturn(0);
5675 }
5676 
5677 /*@
5678   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
5679 
5680   Collective on dm
5681 
5682   Input Parameter:
5683 . dm - the DM
5684 
5685   Output Parameter:
5686 . cdm - coordinate DM
5687 
5688   Level: intermediate
5689 
5690 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5691 @*/
5692 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
5693 {
5694   PetscErrorCode ierr;
5695 
5696   PetscFunctionBegin;
5697   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5698   PetscValidPointer(cdm,2);
5699   if (!dm->coordinateDM) {
5700     DM cdm;
5701 
5702     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
5703     ierr = (*dm->ops->createcoordinatedm)(dm, &cdm);CHKERRQ(ierr);
5704     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
5705      * until the call to CreateCoordinateDM) */
5706     ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
5707     dm->coordinateDM = cdm;
5708   }
5709   *cdm = dm->coordinateDM;
5710   PetscFunctionReturn(0);
5711 }
5712 
5713 /*@
5714   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
5715 
5716   Logically Collective on dm
5717 
5718   Input Parameters:
5719 + dm - the DM
5720 - cdm - coordinate DM
5721 
5722   Level: intermediate
5723 
5724 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5725 @*/
5726 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
5727 {
5728   PetscErrorCode ierr;
5729 
5730   PetscFunctionBegin;
5731   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5732   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
5733   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
5734   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
5735   dm->coordinateDM = cdm;
5736   PetscFunctionReturn(0);
5737 }
5738 
5739 /*@
5740   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
5741 
5742   Not Collective
5743 
5744   Input Parameter:
5745 . dm - The DM object
5746 
5747   Output Parameter:
5748 . dim - The embedding dimension
5749 
5750   Level: intermediate
5751 
5752 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
5753 @*/
5754 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
5755 {
5756   PetscFunctionBegin;
5757   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5758   PetscValidIntPointer(dim, 2);
5759   if (dm->dimEmbed == PETSC_DEFAULT) {
5760     dm->dimEmbed = dm->dim;
5761   }
5762   *dim = dm->dimEmbed;
5763   PetscFunctionReturn(0);
5764 }
5765 
5766 /*@
5767   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
5768 
5769   Not Collective
5770 
5771   Input Parameters:
5772 + dm  - The DM object
5773 - dim - The embedding dimension
5774 
5775   Level: intermediate
5776 
5777 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
5778 @*/
5779 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
5780 {
5781   PetscDS        ds;
5782   PetscErrorCode ierr;
5783 
5784   PetscFunctionBegin;
5785   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5786   dm->dimEmbed = dim;
5787   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5788   ierr = PetscDSSetCoordinateDimension(ds, dim);CHKERRQ(ierr);
5789   PetscFunctionReturn(0);
5790 }
5791 
5792 /*@
5793   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
5794 
5795   Collective on dm
5796 
5797   Input Parameter:
5798 . dm - The DM object
5799 
5800   Output Parameter:
5801 . section - The PetscSection object
5802 
5803   Level: intermediate
5804 
5805 .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
5806 @*/
5807 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
5808 {
5809   DM             cdm;
5810   PetscErrorCode ierr;
5811 
5812   PetscFunctionBegin;
5813   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5814   PetscValidPointer(section, 2);
5815   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5816   ierr = DMGetLocalSection(cdm, section);CHKERRQ(ierr);
5817   PetscFunctionReturn(0);
5818 }
5819 
5820 /*@
5821   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
5822 
5823   Not Collective
5824 
5825   Input Parameters:
5826 + dm      - The DM object
5827 . dim     - The embedding dimension, or PETSC_DETERMINE
5828 - section - The PetscSection object
5829 
5830   Level: intermediate
5831 
5832 .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
5833 @*/
5834 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
5835 {
5836   DM             cdm;
5837   PetscErrorCode ierr;
5838 
5839   PetscFunctionBegin;
5840   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5841   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
5842   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5843   ierr = DMSetLocalSection(cdm, section);CHKERRQ(ierr);
5844   if (dim == PETSC_DETERMINE) {
5845     PetscInt d = PETSC_DEFAULT;
5846     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
5847 
5848     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5849     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5850     pStart = PetscMax(vStart, pStart);
5851     pEnd   = PetscMin(vEnd, pEnd);
5852     for (v = pStart; v < pEnd; ++v) {
5853       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
5854       if (dd) {d = dd; break;}
5855     }
5856     if (d >= 0) {ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);}
5857   }
5858   PetscFunctionReturn(0);
5859 }
5860 
5861 /*@C
5862   DMGetPeriodicity - Get the description of mesh periodicity
5863 
5864   Input Parameters:
5865 . dm      - The DM object
5866 
5867   Output Parameters:
5868 + per     - Whether the DM is periodic or not
5869 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
5870 . L       - If we assume the mesh is a torus, this is the length of each coordinate
5871 - bd      - This describes the type of periodicity in each topological dimension
5872 
5873   Level: developer
5874 
5875 .seealso: DMGetPeriodicity()
5876 @*/
5877 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
5878 {
5879   PetscFunctionBegin;
5880   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5881   if (per)     *per     = dm->periodic;
5882   if (L)       *L       = dm->L;
5883   if (maxCell) *maxCell = dm->maxCell;
5884   if (bd)      *bd      = dm->bdtype;
5885   PetscFunctionReturn(0);
5886 }
5887 
5888 /*@C
5889   DMSetPeriodicity - Set the description of mesh periodicity
5890 
5891   Input Parameters:
5892 + dm      - The DM object
5893 . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
5894 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
5895 . L       - If we assume the mesh is a torus, this is the length of each coordinate
5896 - bd      - This describes the type of periodicity in each topological dimension
5897 
5898   Level: developer
5899 
5900 .seealso: DMGetPeriodicity()
5901 @*/
5902 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
5903 {
5904   PetscInt       dim, d;
5905   PetscErrorCode ierr;
5906 
5907   PetscFunctionBegin;
5908   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5909   PetscValidLogicalCollectiveBool(dm,per,2);
5910   if (maxCell) {
5911     PetscValidRealPointer(maxCell,3);
5912     PetscValidRealPointer(L,4);
5913     PetscValidPointer(bd,5);
5914   }
5915   ierr = PetscFree3(dm->L,dm->maxCell,dm->bdtype);CHKERRQ(ierr);
5916   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5917   if (maxCell) {
5918     ierr = PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);CHKERRQ(ierr);
5919     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
5920   }
5921   dm->periodic = per;
5922   PetscFunctionReturn(0);
5923 }
5924 
5925 /*@
5926   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.
5927 
5928   Input Parameters:
5929 + dm     - The DM
5930 . in     - The input coordinate point (dim numbers)
5931 - endpoint - Include the endpoint L_i
5932 
5933   Output Parameter:
5934 . out - The localized coordinate point
5935 
5936   Level: developer
5937 
5938 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
5939 @*/
5940 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
5941 {
5942   PetscInt       dim, d;
5943   PetscErrorCode ierr;
5944 
5945   PetscFunctionBegin;
5946   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
5947   if (!dm->maxCell) {
5948     for (d = 0; d < dim; ++d) out[d] = in[d];
5949   } else {
5950     if (endpoint) {
5951       for (d = 0; d < dim; ++d) {
5952         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)) {
5953           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
5954         } else {
5955           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
5956         }
5957       }
5958     } else {
5959       for (d = 0; d < dim; ++d) {
5960         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
5961       }
5962     }
5963   }
5964   PetscFunctionReturn(0);
5965 }
5966 
5967 /*
5968   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.
5969 
5970   Input Parameters:
5971 + dm     - The DM
5972 . dim    - The spatial dimension
5973 . anchor - The anchor point, the input point can be no more than maxCell away from it
5974 - in     - The input coordinate point (dim numbers)
5975 
5976   Output Parameter:
5977 . out - The localized coordinate point
5978 
5979   Level: developer
5980 
5981   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
5982 
5983 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
5984 */
5985 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
5986 {
5987   PetscInt d;
5988 
5989   PetscFunctionBegin;
5990   if (!dm->maxCell) {
5991     for (d = 0; d < dim; ++d) out[d] = in[d];
5992   } else {
5993     for (d = 0; d < dim; ++d) {
5994       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
5995         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
5996       } else {
5997         out[d] = in[d];
5998       }
5999     }
6000   }
6001   PetscFunctionReturn(0);
6002 }
6003 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6004 {
6005   PetscInt d;
6006 
6007   PetscFunctionBegin;
6008   if (!dm->maxCell) {
6009     for (d = 0; d < dim; ++d) out[d] = in[d];
6010   } else {
6011     for (d = 0; d < dim; ++d) {
6012       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6013         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6014       } else {
6015         out[d] = in[d];
6016       }
6017     }
6018   }
6019   PetscFunctionReturn(0);
6020 }
6021 
6022 /*
6023   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.
6024 
6025   Input Parameters:
6026 + dm     - The DM
6027 . dim    - The spatial dimension
6028 . anchor - The anchor point, the input point can be no more than maxCell away from it
6029 . in     - The input coordinate delta (dim numbers)
6030 - out    - The input coordinate point (dim numbers)
6031 
6032   Output Parameter:
6033 . out    - The localized coordinate in + out
6034 
6035   Level: developer
6036 
6037   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
6038 
6039 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6040 */
6041 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6042 {
6043   PetscInt d;
6044 
6045   PetscFunctionBegin;
6046   if (!dm->maxCell) {
6047     for (d = 0; d < dim; ++d) out[d] += in[d];
6048   } else {
6049     for (d = 0; d < dim; ++d) {
6050       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6051         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6052       } else {
6053         out[d] += in[d];
6054       }
6055     }
6056   }
6057   PetscFunctionReturn(0);
6058 }
6059 
6060 /*@
6061   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6062 
6063   Not collective
6064 
6065   Input Parameter:
6066 . dm - The DM
6067 
6068   Output Parameter:
6069   areLocalized - True if localized
6070 
6071   Level: developer
6072 
6073 .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6074 @*/
6075 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6076 {
6077   DM             cdm;
6078   PetscSection   coordSection;
6079   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6080   PetscBool      isPlex, alreadyLocalized;
6081   PetscErrorCode ierr;
6082 
6083   PetscFunctionBegin;
6084   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6085   PetscValidBoolPointer(areLocalized, 2);
6086   *areLocalized = PETSC_FALSE;
6087 
6088   /* We need some generic way of refering to cells/vertices */
6089   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6090   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
6091   if (!isPlex) PetscFunctionReturn(0);
6092 
6093   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6094   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6095   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
6096   alreadyLocalized = PETSC_FALSE;
6097   for (c = cStart; c < cEnd; ++c) {
6098     if (c < sStart || c >= sEnd) continue;
6099     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
6100     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6101   }
6102   *areLocalized = alreadyLocalized;
6103   PetscFunctionReturn(0);
6104 }
6105 
6106 /*@
6107   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6108 
6109   Collective on dm
6110 
6111   Input Parameter:
6112 . dm - The DM
6113 
6114   Output Parameter:
6115   areLocalized - True if localized
6116 
6117   Level: developer
6118 
6119 .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6120 @*/
6121 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6122 {
6123   PetscBool      localized;
6124   PetscErrorCode ierr;
6125 
6126   PetscFunctionBegin;
6127   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6128   PetscValidBoolPointer(areLocalized, 2);
6129   ierr = DMGetCoordinatesLocalizedLocal(dm,&localized);CHKERRQ(ierr);
6130   ierr = MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6131   PetscFunctionReturn(0);
6132 }
6133 
6134 /*@
6135   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
6136 
6137   Collective on dm
6138 
6139   Input Parameter:
6140 . dm - The DM
6141 
6142   Level: developer
6143 
6144 .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6145 @*/
6146 PetscErrorCode DMLocalizeCoordinates(DM dm)
6147 {
6148   DM             cdm;
6149   PetscSection   coordSection, cSection;
6150   Vec            coordinates,  cVec;
6151   PetscScalar   *coords, *coords2, *anchor, *localized;
6152   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6153   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6154   PetscInt       maxHeight = 0, h;
6155   PetscInt       *pStart = NULL, *pEnd = NULL;
6156   PetscErrorCode ierr;
6157 
6158   PetscFunctionBegin;
6159   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6160   if (!dm->periodic) PetscFunctionReturn(0);
6161   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
6162   if (alreadyLocalized) PetscFunctionReturn(0);
6163 
6164   /* We need some generic way of refering to cells/vertices */
6165   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6166   {
6167     PetscBool isplex;
6168 
6169     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
6170     if (isplex) {
6171       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6172       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
6173       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6174       pEnd = &pStart[maxHeight + 1];
6175       newStart = vStart;
6176       newEnd   = vEnd;
6177       for (h = 0; h <= maxHeight; h++) {
6178         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
6179         newStart = PetscMin(newStart,pStart[h]);
6180         newEnd   = PetscMax(newEnd,pEnd[h]);
6181       }
6182     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6183   }
6184   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6185   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6186   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6187   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6188   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
6189 
6190   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
6191   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
6192   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
6193   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
6194   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
6195 
6196   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6197   localized = &anchor[bs];
6198   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6199   for (h = 0; h <= maxHeight; h++) {
6200     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6201 
6202     for (c = cStart; c < cEnd; ++c) {
6203       PetscScalar *cellCoords = NULL;
6204       PetscInt     b;
6205 
6206       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6207       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6208       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6209       for (d = 0; d < dof/bs; ++d) {
6210         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
6211         for (b = 0; b < bs; b++) {
6212           if (cellCoords[d*bs + b] != localized[b]) break;
6213         }
6214         if (b < bs) break;
6215       }
6216       if (d < dof/bs) {
6217         if (c >= sStart && c < sEnd) {
6218           PetscInt cdof;
6219 
6220           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6221           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6222         }
6223         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
6224         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
6225       }
6226       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6227     }
6228   }
6229   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6230   if (alreadyLocalizedGlobal) {
6231     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6232     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6233     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6234     PetscFunctionReturn(0);
6235   }
6236   for (v = vStart; v < vEnd; ++v) {
6237     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6238     ierr = PetscSectionSetDof(cSection, v, dof);CHKERRQ(ierr);
6239     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
6240   }
6241   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
6242   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
6243   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
6244   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
6245   ierr = VecSetBlockSize(cVec, bs);CHKERRQ(ierr);
6246   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
6247   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
6248   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6249   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
6250   for (v = vStart; v < vEnd; ++v) {
6251     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6252     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6253     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
6254     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6255   }
6256   for (h = 0; h <= maxHeight; h++) {
6257     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6258 
6259     for (c = cStart; c < cEnd; ++c) {
6260       PetscScalar *cellCoords = NULL;
6261       PetscInt     b, cdof;
6262 
6263       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
6264       if (!cdof) continue;
6265       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6266       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
6267       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6268       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
6269       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6270     }
6271   }
6272   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6273   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6274   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6275   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
6276   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
6277   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
6278   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
6279   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6280   PetscFunctionReturn(0);
6281 }
6282 
6283 /*@
6284   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6285 
6286   Collective on v (see explanation below)
6287 
6288   Input Parameters:
6289 + dm - The DM
6290 . v - The Vec of points
6291 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6292 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
6293 
6294   Output Parameter:
6295 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6296 - cells - The PetscSF containing the ranks and local indices of the containing points.
6297 
6298 
6299   Level: developer
6300 
6301   Notes:
6302   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6303   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
6304 
6305   If *cellSF is NULL on input, a PetscSF will be created.
6306   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
6307 
6308   An array that maps each point to its containing cell can be obtained with
6309 
6310 $    const PetscSFNode *cells;
6311 $    PetscInt           nFound;
6312 $    const PetscInt    *found;
6313 $
6314 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
6315 
6316   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6317   the index of the cell in its rank's local numbering.
6318 
6319 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6320 @*/
6321 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6322 {
6323   PetscErrorCode ierr;
6324 
6325   PetscFunctionBegin;
6326   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6327   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
6328   PetscValidPointer(cellSF,4);
6329   if (*cellSF) {
6330     PetscMPIInt result;
6331 
6332     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
6333     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
6334     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6335   } else {
6336     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
6337   }
6338   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6339   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6340   ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
6341   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6342   PetscFunctionReturn(0);
6343 }
6344 
6345 /*@
6346   DMGetOutputDM - Retrieve the DM associated with the layout for output
6347 
6348   Collective on dm
6349 
6350   Input Parameter:
6351 . dm - The original DM
6352 
6353   Output Parameter:
6354 . odm - The DM which provides the layout for output
6355 
6356   Level: intermediate
6357 
6358 .seealso: VecView(), DMGetGlobalSection()
6359 @*/
6360 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6361 {
6362   PetscSection   section;
6363   PetscBool      hasConstraints, ghasConstraints;
6364   PetscErrorCode ierr;
6365 
6366   PetscFunctionBegin;
6367   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6368   PetscValidPointer(odm,2);
6369   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
6370   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
6371   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
6372   if (!ghasConstraints) {
6373     *odm = dm;
6374     PetscFunctionReturn(0);
6375   }
6376   if (!dm->dmBC) {
6377     PetscSection newSection, gsection;
6378     PetscSF      sf;
6379 
6380     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
6381     ierr = DMCopyDisc(dm, dm->dmBC);CHKERRQ(ierr);
6382     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
6383     ierr = DMSetLocalSection(dm->dmBC, newSection);CHKERRQ(ierr);
6384     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
6385     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
6386     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
6387     ierr = DMSetGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
6388     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
6389   }
6390   *odm = dm->dmBC;
6391   PetscFunctionReturn(0);
6392 }
6393 
6394 /*@
6395   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6396 
6397   Input Parameter:
6398 . dm - The original DM
6399 
6400   Output Parameters:
6401 + num - The output sequence number
6402 - val - The output sequence value
6403 
6404   Level: intermediate
6405 
6406   Note: This is intended for output that should appear in sequence, for instance
6407   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6408 
6409 .seealso: VecView()
6410 @*/
6411 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6412 {
6413   PetscFunctionBegin;
6414   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6415   if (num) {PetscValidIntPointer(num,2); *num = dm->outputSequenceNum;}
6416   if (val) {PetscValidRealPointer(val,3);*val = dm->outputSequenceVal;}
6417   PetscFunctionReturn(0);
6418 }
6419 
6420 /*@
6421   DMSetOutputSequenceNumber - Set the sequence number/value for output
6422 
6423   Input Parameters:
6424 + dm - The original DM
6425 . num - The output sequence number
6426 - val - The output sequence value
6427 
6428   Level: intermediate
6429 
6430   Note: This is intended for output that should appear in sequence, for instance
6431   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6432 
6433 .seealso: VecView()
6434 @*/
6435 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6436 {
6437   PetscFunctionBegin;
6438   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6439   dm->outputSequenceNum = num;
6440   dm->outputSequenceVal = val;
6441   PetscFunctionReturn(0);
6442 }
6443 
6444 /*@C
6445   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
6446 
6447   Input Parameters:
6448 + dm   - The original DM
6449 . name - The sequence name
6450 - num  - The output sequence number
6451 
6452   Output Parameter:
6453 . val  - The output sequence value
6454 
6455   Level: intermediate
6456 
6457   Note: This is intended for output that should appear in sequence, for instance
6458   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
6459 
6460 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
6461 @*/
6462 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6463 {
6464   PetscBool      ishdf5;
6465   PetscErrorCode ierr;
6466 
6467   PetscFunctionBegin;
6468   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6469   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
6470   PetscValidRealPointer(val,4);
6471   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
6472   if (ishdf5) {
6473 #if defined(PETSC_HAVE_HDF5)
6474     PetscScalar value;
6475 
6476     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
6477     *val = PetscRealPart(value);
6478 #endif
6479   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6480   PetscFunctionReturn(0);
6481 }
6482 
6483 /*@
6484   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
6485 
6486   Not collective
6487 
6488   Input Parameter:
6489 . dm - The DM
6490 
6491   Output Parameter:
6492 . useNatural - The flag to build the mapping to a natural order during distribution
6493 
6494   Level: beginner
6495 
6496 .seealso: DMSetUseNatural(), DMCreate()
6497 @*/
6498 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6499 {
6500   PetscFunctionBegin;
6501   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6502   PetscValidBoolPointer(useNatural, 2);
6503   *useNatural = dm->useNatural;
6504   PetscFunctionReturn(0);
6505 }
6506 
6507 /*@
6508   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
6509 
6510   Collective on dm
6511 
6512   Input Parameters:
6513 + dm - The DM
6514 - useNatural - The flag to build the mapping to a natural order during distribution
6515 
6516   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
6517 
6518   Level: beginner
6519 
6520 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
6521 @*/
6522 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6523 {
6524   PetscFunctionBegin;
6525   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6526   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6527   dm->useNatural = useNatural;
6528   PetscFunctionReturn(0);
6529 }
6530 
6531 
6532 /*@C
6533   DMCreateLabel - Create a label of the given name if it does not already exist
6534 
6535   Not Collective
6536 
6537   Input Parameters:
6538 + dm   - The DM object
6539 - name - The label name
6540 
6541   Level: intermediate
6542 
6543 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6544 @*/
6545 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6546 {
6547   DMLabelLink    next  = dm->labels->next;
6548   PetscBool      flg   = PETSC_FALSE;
6549   const char    *lname;
6550   PetscErrorCode ierr;
6551 
6552   PetscFunctionBegin;
6553   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6554   PetscValidCharPointer(name, 2);
6555   while (next) {
6556     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6557     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
6558     if (flg) break;
6559     next = next->next;
6560   }
6561   if (!flg) {
6562     DMLabelLink tmpLabel;
6563 
6564     ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
6565     ierr = DMLabelCreate(PETSC_COMM_SELF, name, &tmpLabel->label);CHKERRQ(ierr);
6566     tmpLabel->output = PETSC_TRUE;
6567     tmpLabel->next   = dm->labels->next;
6568     dm->labels->next = tmpLabel;
6569   }
6570   PetscFunctionReturn(0);
6571 }
6572 
6573 /*@C
6574   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
6575 
6576   Not Collective
6577 
6578   Input Parameters:
6579 + dm   - The DM object
6580 . name - The label name
6581 - point - The mesh point
6582 
6583   Output Parameter:
6584 . value - The label value for this point, or -1 if the point is not in the label
6585 
6586   Level: beginner
6587 
6588 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
6589 @*/
6590 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6591 {
6592   DMLabel        label;
6593   PetscErrorCode ierr;
6594 
6595   PetscFunctionBegin;
6596   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6597   PetscValidCharPointer(name, 2);
6598   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6599   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6600   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
6601   PetscFunctionReturn(0);
6602 }
6603 
6604 /*@C
6605   DMSetLabelValue - Add a point to a Sieve Label with given value
6606 
6607   Not Collective
6608 
6609   Input Parameters:
6610 + dm   - The DM object
6611 . name - The label name
6612 . point - The mesh point
6613 - value - The label value for this point
6614 
6615   Output Parameter:
6616 
6617   Level: beginner
6618 
6619 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
6620 @*/
6621 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6622 {
6623   DMLabel        label;
6624   PetscErrorCode ierr;
6625 
6626   PetscFunctionBegin;
6627   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6628   PetscValidCharPointer(name, 2);
6629   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6630   if (!label) {
6631     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
6632     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6633   }
6634   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
6635   PetscFunctionReturn(0);
6636 }
6637 
6638 /*@C
6639   DMClearLabelValue - Remove a point from a Sieve Label with given value
6640 
6641   Not Collective
6642 
6643   Input Parameters:
6644 + dm   - The DM object
6645 . name - The label name
6646 . point - The mesh point
6647 - value - The label value for this point
6648 
6649   Output Parameter:
6650 
6651   Level: beginner
6652 
6653 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
6654 @*/
6655 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6656 {
6657   DMLabel        label;
6658   PetscErrorCode ierr;
6659 
6660   PetscFunctionBegin;
6661   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6662   PetscValidCharPointer(name, 2);
6663   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6664   if (!label) PetscFunctionReturn(0);
6665   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
6666   PetscFunctionReturn(0);
6667 }
6668 
6669 /*@C
6670   DMGetLabelSize - Get the number of different integer ids in a Label
6671 
6672   Not Collective
6673 
6674   Input Parameters:
6675 + dm   - The DM object
6676 - name - The label name
6677 
6678   Output Parameter:
6679 . size - The number of different integer ids, or 0 if the label does not exist
6680 
6681   Level: beginner
6682 
6683 .seealso: DMLabelGetNumValues(), DMSetLabelValue()
6684 @*/
6685 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6686 {
6687   DMLabel        label;
6688   PetscErrorCode ierr;
6689 
6690   PetscFunctionBegin;
6691   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6692   PetscValidCharPointer(name, 2);
6693   PetscValidIntPointer(size, 3);
6694   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6695   *size = 0;
6696   if (!label) PetscFunctionReturn(0);
6697   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
6698   PetscFunctionReturn(0);
6699 }
6700 
6701 /*@C
6702   DMGetLabelIdIS - Get the integer ids in a label
6703 
6704   Not Collective
6705 
6706   Input Parameters:
6707 + mesh - The DM object
6708 - name - The label name
6709 
6710   Output Parameter:
6711 . ids - The integer ids, or NULL if the label does not exist
6712 
6713   Level: beginner
6714 
6715 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
6716 @*/
6717 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6718 {
6719   DMLabel        label;
6720   PetscErrorCode ierr;
6721 
6722   PetscFunctionBegin;
6723   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6724   PetscValidCharPointer(name, 2);
6725   PetscValidPointer(ids, 3);
6726   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6727   *ids = NULL;
6728  if (label) {
6729     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
6730   } else {
6731     /* returning an empty IS */
6732     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
6733   }
6734   PetscFunctionReturn(0);
6735 }
6736 
6737 /*@C
6738   DMGetStratumSize - Get the number of points in a label stratum
6739 
6740   Not Collective
6741 
6742   Input Parameters:
6743 + dm - The DM object
6744 . name - The label name
6745 - value - The stratum value
6746 
6747   Output Parameter:
6748 . size - The stratum size
6749 
6750   Level: beginner
6751 
6752 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
6753 @*/
6754 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6755 {
6756   DMLabel        label;
6757   PetscErrorCode ierr;
6758 
6759   PetscFunctionBegin;
6760   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6761   PetscValidCharPointer(name, 2);
6762   PetscValidIntPointer(size, 4);
6763   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6764   *size = 0;
6765   if (!label) PetscFunctionReturn(0);
6766   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
6767   PetscFunctionReturn(0);
6768 }
6769 
6770 /*@C
6771   DMGetStratumIS - Get the points in a label stratum
6772 
6773   Not Collective
6774 
6775   Input Parameters:
6776 + dm - The DM object
6777 . name - The label name
6778 - value - The stratum value
6779 
6780   Output Parameter:
6781 . points - The stratum points, or NULL if the label does not exist or does not have that value
6782 
6783   Level: beginner
6784 
6785 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
6786 @*/
6787 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6788 {
6789   DMLabel        label;
6790   PetscErrorCode ierr;
6791 
6792   PetscFunctionBegin;
6793   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6794   PetscValidCharPointer(name, 2);
6795   PetscValidPointer(points, 4);
6796   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6797   *points = NULL;
6798   if (!label) PetscFunctionReturn(0);
6799   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
6800   PetscFunctionReturn(0);
6801 }
6802 
6803 /*@C
6804   DMSetStratumIS - Set the points in a label stratum
6805 
6806   Not Collective
6807 
6808   Input Parameters:
6809 + dm - The DM object
6810 . name - The label name
6811 . value - The stratum value
6812 - points - The stratum points
6813 
6814   Level: beginner
6815 
6816 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
6817 @*/
6818 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6819 {
6820   DMLabel        label;
6821   PetscErrorCode ierr;
6822 
6823   PetscFunctionBegin;
6824   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6825   PetscValidCharPointer(name, 2);
6826   PetscValidPointer(points, 4);
6827   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6828   if (!label) PetscFunctionReturn(0);
6829   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
6830   PetscFunctionReturn(0);
6831 }
6832 
6833 /*@C
6834   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
6835 
6836   Not Collective
6837 
6838   Input Parameters:
6839 + dm   - The DM object
6840 . name - The label name
6841 - value - The label value for this point
6842 
6843   Output Parameter:
6844 
6845   Level: beginner
6846 
6847 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
6848 @*/
6849 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6850 {
6851   DMLabel        label;
6852   PetscErrorCode ierr;
6853 
6854   PetscFunctionBegin;
6855   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6856   PetscValidCharPointer(name, 2);
6857   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
6858   if (!label) PetscFunctionReturn(0);
6859   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
6860   PetscFunctionReturn(0);
6861 }
6862 
6863 /*@
6864   DMGetNumLabels - Return the number of labels defined by the mesh
6865 
6866   Not Collective
6867 
6868   Input Parameter:
6869 . dm   - The DM object
6870 
6871   Output Parameter:
6872 . numLabels - the number of Labels
6873 
6874   Level: intermediate
6875 
6876 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6877 @*/
6878 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6879 {
6880   DMLabelLink next = dm->labels->next;
6881   PetscInt  n    = 0;
6882 
6883   PetscFunctionBegin;
6884   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6885   PetscValidIntPointer(numLabels, 2);
6886   while (next) {++n; next = next->next;}
6887   *numLabels = n;
6888   PetscFunctionReturn(0);
6889 }
6890 
6891 /*@C
6892   DMGetLabelName - Return the name of nth label
6893 
6894   Not Collective
6895 
6896   Input Parameters:
6897 + dm - The DM object
6898 - n  - the label number
6899 
6900   Output Parameter:
6901 . name - the label name
6902 
6903   Level: intermediate
6904 
6905 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6906 @*/
6907 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
6908 {
6909   DMLabelLink    next = dm->labels->next;
6910   PetscInt       l    = 0;
6911   PetscErrorCode ierr;
6912 
6913   PetscFunctionBegin;
6914   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6915   PetscValidPointer(name, 3);
6916   while (next) {
6917     if (l == n) {
6918       ierr = PetscObjectGetName((PetscObject) next->label, name);CHKERRQ(ierr);
6919       PetscFunctionReturn(0);
6920     }
6921     ++l;
6922     next = next->next;
6923   }
6924   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
6925 }
6926 
6927 /*@C
6928   DMHasLabel - Determine whether the mesh has a label of a given name
6929 
6930   Not Collective
6931 
6932   Input Parameters:
6933 + dm   - The DM object
6934 - name - The label name
6935 
6936   Output Parameter:
6937 . hasLabel - PETSC_TRUE if the label is present
6938 
6939   Level: intermediate
6940 
6941 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6942 @*/
6943 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
6944 {
6945   DMLabelLink    next = dm->labels->next;
6946   const char    *lname;
6947   PetscErrorCode ierr;
6948 
6949   PetscFunctionBegin;
6950   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6951   PetscValidCharPointer(name, 2);
6952   PetscValidBoolPointer(hasLabel, 3);
6953   *hasLabel = PETSC_FALSE;
6954   while (next) {
6955     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6956     ierr = PetscStrcmp(name, lname, hasLabel);CHKERRQ(ierr);
6957     if (*hasLabel) break;
6958     next = next->next;
6959   }
6960   PetscFunctionReturn(0);
6961 }
6962 
6963 /*@C
6964   DMGetLabel - Return the label of a given name, or NULL
6965 
6966   Not Collective
6967 
6968   Input Parameters:
6969 + dm   - The DM object
6970 - name - The label name
6971 
6972   Output Parameter:
6973 . label - The DMLabel, or NULL if the label is absent
6974 
6975   Level: intermediate
6976 
6977 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6978 @*/
6979 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
6980 {
6981   DMLabelLink    next = dm->labels->next;
6982   PetscBool      hasLabel;
6983   const char    *lname;
6984   PetscErrorCode ierr;
6985 
6986   PetscFunctionBegin;
6987   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6988   PetscValidCharPointer(name, 2);
6989   PetscValidPointer(label, 3);
6990   *label = NULL;
6991   while (next) {
6992     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
6993     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
6994     if (hasLabel) {
6995       *label = next->label;
6996       break;
6997     }
6998     next = next->next;
6999   }
7000   PetscFunctionReturn(0);
7001 }
7002 
7003 /*@C
7004   DMGetLabelByNum - Return the nth label
7005 
7006   Not Collective
7007 
7008   Input Parameters:
7009 + dm - The DM object
7010 - n  - the label number
7011 
7012   Output Parameter:
7013 . label - the label
7014 
7015   Level: intermediate
7016 
7017 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7018 @*/
7019 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7020 {
7021   DMLabelLink next = dm->labels->next;
7022   PetscInt    l    = 0;
7023 
7024   PetscFunctionBegin;
7025   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7026   PetscValidPointer(label, 3);
7027   while (next) {
7028     if (l == n) {
7029       *label = next->label;
7030       PetscFunctionReturn(0);
7031     }
7032     ++l;
7033     next = next->next;
7034   }
7035   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7036 }
7037 
7038 /*@C
7039   DMAddLabel - Add the label to this mesh
7040 
7041   Not Collective
7042 
7043   Input Parameters:
7044 + dm   - The DM object
7045 - label - The DMLabel
7046 
7047   Level: developer
7048 
7049 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7050 @*/
7051 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7052 {
7053   DMLabelLink    tmpLabel;
7054   PetscBool      hasLabel;
7055   const char    *lname;
7056   PetscErrorCode ierr;
7057 
7058   PetscFunctionBegin;
7059   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7060   ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
7061   ierr = DMHasLabel(dm, lname, &hasLabel);CHKERRQ(ierr);
7062   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7063   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
7064   tmpLabel->label  = label;
7065   tmpLabel->output = PETSC_TRUE;
7066   tmpLabel->next   = dm->labels->next;
7067   dm->labels->next = tmpLabel;
7068   PetscFunctionReturn(0);
7069 }
7070 
7071 /*@C
7072   DMRemoveLabel - Remove the label from this mesh
7073 
7074   Not Collective
7075 
7076   Input Parameters:
7077 + dm   - The DM object
7078 - name - The label name
7079 
7080   Output Parameter:
7081 . label - The DMLabel, or NULL if the label is absent
7082 
7083   Level: developer
7084 
7085 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7086 @*/
7087 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7088 {
7089   DMLabelLink    next = dm->labels->next;
7090   DMLabelLink    last = NULL;
7091   PetscBool      hasLabel;
7092   const char    *lname;
7093   PetscErrorCode ierr;
7094 
7095   PetscFunctionBegin;
7096   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7097   ierr   = DMHasLabel(dm, name, &hasLabel);CHKERRQ(ierr);
7098   *label = NULL;
7099   if (!hasLabel) PetscFunctionReturn(0);
7100   while (next) {
7101     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7102     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
7103     if (hasLabel) {
7104       if (last) last->next       = next->next;
7105       else      dm->labels->next = next->next;
7106       next->next = NULL;
7107       *label     = next->label;
7108       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
7109       if (hasLabel) {
7110         dm->depthLabel = NULL;
7111       }
7112       ierr = PetscFree(next);CHKERRQ(ierr);
7113       break;
7114     }
7115     last = next;
7116     next = next->next;
7117   }
7118   PetscFunctionReturn(0);
7119 }
7120 
7121 /*@C
7122   DMGetLabelOutput - Get the output flag for a given label
7123 
7124   Not Collective
7125 
7126   Input Parameters:
7127 + dm   - The DM object
7128 - name - The label name
7129 
7130   Output Parameter:
7131 . output - The flag for output
7132 
7133   Level: developer
7134 
7135 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7136 @*/
7137 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7138 {
7139   DMLabelLink    next = dm->labels->next;
7140   const char    *lname;
7141   PetscErrorCode ierr;
7142 
7143   PetscFunctionBegin;
7144   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7145   PetscValidPointer(name, 2);
7146   PetscValidPointer(output, 3);
7147   while (next) {
7148     PetscBool flg;
7149 
7150     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7151     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7152     if (flg) {*output = next->output; PetscFunctionReturn(0);}
7153     next = next->next;
7154   }
7155   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7156 }
7157 
7158 /*@C
7159   DMSetLabelOutput - Set the output flag for a given label
7160 
7161   Not Collective
7162 
7163   Input Parameters:
7164 + dm     - The DM object
7165 . name   - The label name
7166 - output - The flag for output
7167 
7168   Level: developer
7169 
7170 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7171 @*/
7172 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7173 {
7174   DMLabelLink    next = dm->labels->next;
7175   const char    *lname;
7176   PetscErrorCode ierr;
7177 
7178   PetscFunctionBegin;
7179   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7180   PetscValidCharPointer(name, 2);
7181   while (next) {
7182     PetscBool flg;
7183 
7184     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7185     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7186     if (flg) {next->output = output; PetscFunctionReturn(0);}
7187     next = next->next;
7188   }
7189   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7190 }
7191 
7192 
7193 /*@
7194   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
7195 
7196   Collective on dmA
7197 
7198   Input Parameter:
7199 . dmA - The DM object with initial labels
7200 
7201   Output Parameter:
7202 . dmB - The DM object with copied labels
7203 
7204   Level: intermediate
7205 
7206   Note: This is typically used when interpolating or otherwise adding to a mesh
7207 
7208 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
7209 @*/
7210 PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
7211 {
7212   PetscInt       numLabels, l;
7213   PetscErrorCode ierr;
7214 
7215   PetscFunctionBegin;
7216   if (dmA == dmB) PetscFunctionReturn(0);
7217   ierr = DMGetNumLabels(dmA, &numLabels);CHKERRQ(ierr);
7218   for (l = 0; l < numLabels; ++l) {
7219     DMLabel     label, labelNew;
7220     const char *name;
7221     PetscBool   flg;
7222 
7223     ierr = DMGetLabelName(dmA, l, &name);CHKERRQ(ierr);
7224     ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
7225     if (flg) continue;
7226     ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
7227     if (flg) continue;
7228     ierr = DMGetLabel(dmA, name, &label);CHKERRQ(ierr);
7229     ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
7230     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
7231   }
7232   PetscFunctionReturn(0);
7233 }
7234 
7235 /*@
7236   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
7237 
7238   Input Parameter:
7239 . dm - The DM object
7240 
7241   Output Parameter:
7242 . cdm - The coarse DM
7243 
7244   Level: intermediate
7245 
7246 .seealso: DMSetCoarseDM()
7247 @*/
7248 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7249 {
7250   PetscFunctionBegin;
7251   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7252   PetscValidPointer(cdm, 2);
7253   *cdm = dm->coarseMesh;
7254   PetscFunctionReturn(0);
7255 }
7256 
7257 /*@
7258   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
7259 
7260   Input Parameters:
7261 + dm - The DM object
7262 - cdm - The coarse DM
7263 
7264   Level: intermediate
7265 
7266 .seealso: DMGetCoarseDM()
7267 @*/
7268 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7269 {
7270   PetscErrorCode ierr;
7271 
7272   PetscFunctionBegin;
7273   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7274   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7275   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
7276   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
7277   dm->coarseMesh = cdm;
7278   PetscFunctionReturn(0);
7279 }
7280 
7281 /*@
7282   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
7283 
7284   Input Parameter:
7285 . dm - The DM object
7286 
7287   Output Parameter:
7288 . fdm - The fine DM
7289 
7290   Level: intermediate
7291 
7292 .seealso: DMSetFineDM()
7293 @*/
7294 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7295 {
7296   PetscFunctionBegin;
7297   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7298   PetscValidPointer(fdm, 2);
7299   *fdm = dm->fineMesh;
7300   PetscFunctionReturn(0);
7301 }
7302 
7303 /*@
7304   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
7305 
7306   Input Parameters:
7307 + dm - The DM object
7308 - fdm - The fine DM
7309 
7310   Level: intermediate
7311 
7312 .seealso: DMGetFineDM()
7313 @*/
7314 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7315 {
7316   PetscErrorCode ierr;
7317 
7318   PetscFunctionBegin;
7319   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7320   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7321   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
7322   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
7323   dm->fineMesh = fdm;
7324   PetscFunctionReturn(0);
7325 }
7326 
7327 /*=== DMBoundary code ===*/
7328 
7329 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7330 {
7331   PetscInt       d;
7332   PetscErrorCode ierr;
7333 
7334   PetscFunctionBegin;
7335   for (d = 0; d < dm->Nds; ++d) {
7336     ierr = PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);CHKERRQ(ierr);
7337   }
7338   PetscFunctionReturn(0);
7339 }
7340 
7341 /*@C
7342   DMAddBoundary - Add a boundary condition to the model
7343 
7344   Input Parameters:
7345 + dm          - The DM, with a PetscDS that matches the problem being constrained
7346 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7347 . name        - The BC name
7348 . labelname   - The label defining constrained points
7349 . field       - The field to constrain
7350 . numcomps    - The number of constrained field components (0 will constrain all fields)
7351 . comps       - An array of constrained component numbers
7352 . bcFunc      - A pointwise function giving boundary values
7353 . numids      - The number of DMLabel ids for constrained points
7354 . ids         - An array of ids for constrained points
7355 - ctx         - An optional user context for bcFunc
7356 
7357   Options Database Keys:
7358 + -bc_<boundary name> <num> - Overrides the boundary ids
7359 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7360 
7361   Level: developer
7362 
7363 .seealso: DMGetBoundary()
7364 @*/
7365 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)
7366 {
7367   PetscDS        ds;
7368   PetscErrorCode ierr;
7369 
7370   PetscFunctionBegin;
7371   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7372   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7373   ierr = PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, numids, ids, ctx);CHKERRQ(ierr);
7374   PetscFunctionReturn(0);
7375 }
7376 
7377 /*@
7378   DMGetNumBoundary - Get the number of registered BC
7379 
7380   Input Parameters:
7381 . dm - The mesh object
7382 
7383   Output Parameters:
7384 . numBd - The number of BC
7385 
7386   Level: intermediate
7387 
7388 .seealso: DMAddBoundary(), DMGetBoundary()
7389 @*/
7390 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
7391 {
7392   PetscDS        ds;
7393   PetscErrorCode ierr;
7394 
7395   PetscFunctionBegin;
7396   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7397   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7398   ierr = PetscDSGetNumBoundary(ds, numBd);CHKERRQ(ierr);
7399   PetscFunctionReturn(0);
7400 }
7401 
7402 /*@C
7403   DMGetBoundary - Get a model boundary condition
7404 
7405   Input Parameters:
7406 + dm          - The mesh object
7407 - bd          - The BC number
7408 
7409   Output Parameters:
7410 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7411 . name        - The BC name
7412 . labelname   - The label defining constrained points
7413 . field       - The field to constrain
7414 . numcomps    - The number of constrained field components
7415 . comps       - An array of constrained component numbers
7416 . bcFunc      - A pointwise function giving boundary values
7417 . numids      - The number of DMLabel ids for constrained points
7418 . ids         - An array of ids for constrained points
7419 - ctx         - An optional user context for bcFunc
7420 
7421   Options Database Keys:
7422 + -bc_<boundary name> <num> - Overrides the boundary ids
7423 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7424 
7425   Level: developer
7426 
7427 .seealso: DMAddBoundary()
7428 @*/
7429 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)
7430 {
7431   PetscDS        ds;
7432   PetscErrorCode ierr;
7433 
7434   PetscFunctionBegin;
7435   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7436   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7437   ierr = PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, numids, ids, ctx);CHKERRQ(ierr);
7438   PetscFunctionReturn(0);
7439 }
7440 
7441 static PetscErrorCode DMPopulateBoundary(DM dm)
7442 {
7443   PetscDS        ds;
7444   DMBoundary    *lastnext;
7445   DSBoundary     dsbound;
7446   PetscErrorCode ierr;
7447 
7448   PetscFunctionBegin;
7449   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
7450   dsbound = ds->boundary;
7451   if (dm->boundary) {
7452     DMBoundary next = dm->boundary;
7453 
7454     /* quick check to see if the PetscDS has changed */
7455     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
7456     /* the PetscDS has changed: tear down and rebuild */
7457     while (next) {
7458       DMBoundary b = next;
7459 
7460       next = b->next;
7461       ierr = PetscFree(b);CHKERRQ(ierr);
7462     }
7463     dm->boundary = NULL;
7464   }
7465 
7466   lastnext = &(dm->boundary);
7467   while (dsbound) {
7468     DMBoundary dmbound;
7469 
7470     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
7471     dmbound->dsboundary = dsbound;
7472     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
7473     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
7474     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7475     *lastnext = dmbound;
7476     lastnext = &(dmbound->next);
7477     dsbound = dsbound->next;
7478   }
7479   PetscFunctionReturn(0);
7480 }
7481 
7482 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7483 {
7484   DMBoundary     b;
7485   PetscErrorCode ierr;
7486 
7487   PetscFunctionBegin;
7488   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7489   PetscValidBoolPointer(isBd, 3);
7490   *isBd = PETSC_FALSE;
7491   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
7492   b = dm->boundary;
7493   while (b && !(*isBd)) {
7494     DMLabel    label = b->label;
7495     DSBoundary dsb = b->dsboundary;
7496 
7497     if (label) {
7498       PetscInt i;
7499 
7500       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
7501         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
7502       }
7503     }
7504     b = b->next;
7505   }
7506   PetscFunctionReturn(0);
7507 }
7508 
7509 /*@C
7510   DMProjectFunction - This projects the given function into the function space provided.
7511 
7512   Input Parameters:
7513 + dm      - The DM
7514 . time    - The time
7515 . funcs   - The coordinate functions to evaluate, one per field
7516 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7517 - mode    - The insertion mode for values
7518 
7519   Output Parameter:
7520 . X - vector
7521 
7522    Calling sequence of func:
7523 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
7524 
7525 +  dim - The spatial dimension
7526 .  x   - The coordinates
7527 .  Nf  - The number of fields
7528 .  u   - The output field values
7529 -  ctx - optional user-defined function context
7530 
7531   Level: developer
7532 
7533 .seealso: DMComputeL2Diff()
7534 @*/
7535 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7536 {
7537   Vec            localX;
7538   PetscErrorCode ierr;
7539 
7540   PetscFunctionBegin;
7541   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7542   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
7543   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7544   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
7545   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
7546   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
7547   PetscFunctionReturn(0);
7548 }
7549 
7550 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7551 {
7552   PetscErrorCode ierr;
7553 
7554   PetscFunctionBegin;
7555   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7556   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
7557   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
7558   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7559   PetscFunctionReturn(0);
7560 }
7561 
7562 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)
7563 {
7564   Vec            localX;
7565   PetscErrorCode ierr;
7566 
7567   PetscFunctionBegin;
7568   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7569   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
7570   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7571   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
7572   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
7573   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
7574   PetscFunctionReturn(0);
7575 }
7576 
7577 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)
7578 {
7579   PetscErrorCode ierr;
7580 
7581   PetscFunctionBegin;
7582   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7583   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
7584   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
7585   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
7586   PetscFunctionReturn(0);
7587 }
7588 
7589 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
7590                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
7591                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7592                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7593                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7594                                    InsertMode mode, Vec localX)
7595 {
7596   PetscErrorCode ierr;
7597 
7598   PetscFunctionBegin;
7599   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7600   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
7601   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
7602   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7603   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
7604   PetscFunctionReturn(0);
7605 }
7606 
7607 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
7608                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
7609                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7610                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7611                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7612                                         InsertMode mode, Vec localX)
7613 {
7614   PetscErrorCode ierr;
7615 
7616   PetscFunctionBegin;
7617   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7618   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
7619   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
7620   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7621   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
7622   PetscFunctionReturn(0);
7623 }
7624 
7625 /*@C
7626   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
7627 
7628   Input Parameters:
7629 + dm    - The DM
7630 . time  - The time
7631 . funcs - The functions to evaluate for each field component
7632 . ctxs  - Optional array of contexts to pass to each function, or NULL.
7633 - X     - The coefficient vector u_h, a global vector
7634 
7635   Output Parameter:
7636 . diff - The diff ||u - u_h||_2
7637 
7638   Level: developer
7639 
7640 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
7641 @*/
7642 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
7643 {
7644   PetscErrorCode ierr;
7645 
7646   PetscFunctionBegin;
7647   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7648   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
7649   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
7650   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
7651   PetscFunctionReturn(0);
7652 }
7653 
7654 /*@C
7655   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
7656 
7657   Collective on dm
7658 
7659   Input Parameters:
7660 + dm    - The DM
7661 , time  - The time
7662 . funcs - The gradient functions to evaluate for each field component
7663 . ctxs  - Optional array of contexts to pass to each function, or NULL.
7664 . X     - The coefficient vector u_h, a global vector
7665 - n     - The vector to project along
7666 
7667   Output Parameter:
7668 . diff - The diff ||(grad u - grad u_h) . n||_2
7669 
7670   Level: developer
7671 
7672 .seealso: DMProjectFunction(), DMComputeL2Diff()
7673 @*/
7674 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)
7675 {
7676   PetscErrorCode ierr;
7677 
7678   PetscFunctionBegin;
7679   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7680   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
7681   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
7682   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
7683   PetscFunctionReturn(0);
7684 }
7685 
7686 /*@C
7687   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
7688 
7689   Collective on dm
7690 
7691   Input Parameters:
7692 + dm    - The DM
7693 . time  - The time
7694 . funcs - The functions to evaluate for each field component
7695 . ctxs  - Optional array of contexts to pass to each function, or NULL.
7696 - X     - The coefficient vector u_h, a global vector
7697 
7698   Output Parameter:
7699 . diff - The array of differences, ||u^f - u^f_h||_2
7700 
7701   Level: developer
7702 
7703 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
7704 @*/
7705 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
7706 {
7707   PetscErrorCode ierr;
7708 
7709   PetscFunctionBegin;
7710   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7711   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
7712   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
7713   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
7714   PetscFunctionReturn(0);
7715 }
7716 
7717 /*@C
7718   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
7719                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
7720 
7721   Collective on dm
7722 
7723   Input parameters:
7724 + dm - the pre-adaptation DM object
7725 - label - label with the flags
7726 
7727   Output parameters:
7728 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
7729 
7730   Level: intermediate
7731 
7732 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
7733 @*/
7734 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
7735 {
7736   PetscErrorCode ierr;
7737 
7738   PetscFunctionBegin;
7739   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7740   PetscValidPointer(label,2);
7741   PetscValidPointer(dmAdapt,3);
7742   *dmAdapt = NULL;
7743   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
7744   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
7745   PetscFunctionReturn(0);
7746 }
7747 
7748 /*@C
7749   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
7750 
7751   Input Parameters:
7752 + dm - The DM object
7753 . metric - The metric to which the mesh is adapted, defined vertex-wise.
7754 - 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_".
7755 
7756   Output Parameter:
7757 . dmAdapt  - Pointer to the DM object containing the adapted mesh
7758 
7759   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
7760 
7761   Level: advanced
7762 
7763 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
7764 @*/
7765 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
7766 {
7767   PetscErrorCode ierr;
7768 
7769   PetscFunctionBegin;
7770   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7771   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
7772   if (bdLabel) PetscValidPointer(bdLabel, 3);
7773   PetscValidPointer(dmAdapt, 4);
7774   *dmAdapt = NULL;
7775   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
7776   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
7777   PetscFunctionReturn(0);
7778 }
7779 
7780 /*@C
7781  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
7782 
7783  Not Collective
7784 
7785  Input Parameter:
7786  . dm    - The DM
7787 
7788  Output Parameter:
7789  . nranks - the number of neighbours
7790  . ranks - the neighbors ranks
7791 
7792  Notes:
7793  Do not free the array, it is freed when the DM is destroyed.
7794 
7795  Level: beginner
7796 
7797  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
7798 @*/
7799 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
7800 {
7801   PetscErrorCode ierr;
7802 
7803   PetscFunctionBegin;
7804   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7805   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
7806   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
7807   PetscFunctionReturn(0);
7808 }
7809 
7810 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
7811 
7812 /*
7813     Converts the input vector to a ghosted vector and then calls the standard coloring code.
7814     This has be a different function because it requires DM which is not defined in the Mat library
7815 */
7816 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
7817 {
7818   PetscErrorCode ierr;
7819 
7820   PetscFunctionBegin;
7821   if (coloring->ctype == IS_COLORING_LOCAL) {
7822     Vec x1local;
7823     DM  dm;
7824     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
7825     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
7826     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
7827     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
7828     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
7829     x1   = x1local;
7830   }
7831   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
7832   if (coloring->ctype == IS_COLORING_LOCAL) {
7833     DM  dm;
7834     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
7835     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
7836   }
7837   PetscFunctionReturn(0);
7838 }
7839 
7840 /*@
7841     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
7842 
7843     Input Parameter:
7844 .    coloring - the MatFDColoring object
7845 
7846     Developer Notes:
7847     this routine exists because the PETSc Mat library does not know about the DM objects
7848 
7849     Level: advanced
7850 
7851 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
7852 @*/
7853 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
7854 {
7855   PetscFunctionBegin;
7856   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
7857   PetscFunctionReturn(0);
7858 }
7859 
7860 /*@
7861     DMGetCompatibility - determine if two DMs are compatible
7862 
7863     Collective
7864 
7865     Input Parameters:
7866 +    dm - the first DM
7867 -    dm2 - the second DM
7868 
7869     Output Parameters:
7870 +    compatible - whether or not the two DMs are compatible
7871 -    set - whether or not the compatible value was set
7872 
7873     Notes:
7874     Two DMs are deemed compatible if they represent the same parallel decomposition
7875     of the same topology. This implies that the section (field data) on one
7876     "makes sense" with respect to the topology and parallel decomposition of the other.
7877     Loosely speaking, compatible DMs represent the same domain and parallel
7878     decomposition, but hold different data.
7879 
7880     Typically, one would confirm compatibility if intending to simultaneously iterate
7881     over a pair of vectors obtained from different DMs.
7882 
7883     For example, two DMDA objects are compatible if they have the same local
7884     and global sizes and the same stencil width. They can have different numbers
7885     of degrees of freedom per node. Thus, one could use the node numbering from
7886     either DM in bounds for a loop over vectors derived from either DM.
7887 
7888     Consider the operation of summing data living on a 2-dof DMDA to data living
7889     on a 1-dof DMDA, which should be compatible, as in the following snippet.
7890 .vb
7891   ...
7892   ierr = DMGetCompatibility(da1,da2,&compatible,&set);CHKERRQ(ierr);
7893   if (set && compatible)  {
7894     ierr = DMDAVecGetArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
7895     ierr = DMDAVecGetArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
7896     ierr = DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);CHKERRQ(ierr);
7897     for (j=y; j<y+n; ++j) {
7898       for (i=x; i<x+m, ++i) {
7899         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
7900       }
7901     }
7902     ierr = DMDAVecRestoreArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
7903     ierr = DMDAVecRestoreArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
7904   } else {
7905     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
7906   }
7907   ...
7908 .ve
7909 
7910     Checking compatibility might be expensive for a given implementation of DM,
7911     or might be impossible to unambiguously confirm or deny. For this reason,
7912     this function may decline to determine compatibility, and hence users should
7913     always check the "set" output parameter.
7914 
7915     A DM is always compatible with itself.
7916 
7917     In the current implementation, DMs which live on "unequal" communicators
7918     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
7919     incompatible.
7920 
7921     This function is labeled "Collective," as information about all subdomains
7922     is required on each rank. However, in DM implementations which store all this
7923     information locally, this function may be merely "Logically Collective".
7924 
7925     Developer Notes:
7926     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
7927     iff B is compatible with A. Thus, this function checks the implementations
7928     of both dm and dm2 (if they are of different types), attempting to determine
7929     compatibility. It is left to DM implementers to ensure that symmetry is
7930     preserved. The simplest way to do this is, when implementing type-specific
7931     logic for this function, is to check for existing logic in the implementation
7932     of other DM types and let *set = PETSC_FALSE if found.
7933 
7934     Level: advanced
7935 
7936 .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
7937 @*/
7938 
7939 PetscErrorCode DMGetCompatibility(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
7940 {
7941   PetscErrorCode ierr;
7942   PetscMPIInt    compareResult;
7943   DMType         type,type2;
7944   PetscBool      sameType;
7945 
7946   PetscFunctionBegin;
7947   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7948   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
7949 
7950   /* Declare a DM compatible with itself */
7951   if (dm == dm2) {
7952     *set = PETSC_TRUE;
7953     *compatible = PETSC_TRUE;
7954     PetscFunctionReturn(0);
7955   }
7956 
7957   /* Declare a DM incompatible with a DM that lives on an "unequal"
7958      communicator. Note that this does not preclude compatibility with
7959      DMs living on "congruent" or "similar" communicators, but this must be
7960      determined by the implementation-specific logic */
7961   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)dm),PetscObjectComm((PetscObject)dm2),&compareResult);CHKERRQ(ierr);
7962   if (compareResult == MPI_UNEQUAL) {
7963     *set = PETSC_TRUE;
7964     *compatible = PETSC_FALSE;
7965     PetscFunctionReturn(0);
7966   }
7967 
7968   /* Pass to the implementation-specific routine, if one exists. */
7969   if (dm->ops->getcompatibility) {
7970     ierr = (*dm->ops->getcompatibility)(dm,dm2,compatible,set);CHKERRQ(ierr);
7971     if (*set) PetscFunctionReturn(0);
7972   }
7973 
7974   /* If dm and dm2 are of different types, then attempt to check compatibility
7975      with an implementation of this function from dm2 */
7976   ierr = DMGetType(dm,&type);CHKERRQ(ierr);
7977   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
7978   ierr = PetscStrcmp(type,type2,&sameType);CHKERRQ(ierr);
7979   if (!sameType && dm2->ops->getcompatibility) {
7980     ierr = (*dm2->ops->getcompatibility)(dm2,dm,compatible,set);CHKERRQ(ierr); /* Note argument order */
7981   } else {
7982     *set = PETSC_FALSE;
7983   }
7984   PetscFunctionReturn(0);
7985 }
7986