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