xref: /petsc/src/dm/label/dmlabel.c (revision f4cdcedc560ba874484051761a47add6dfd7bd6b)
1 #include <petscdm.h>
2 #include <petsc/private/dmlabelimpl.h>   /*I      "petscdmlabel.h"   I*/
3 #include <petsc/private/isimpl.h>        /*I      "petscis.h"        I*/
4 #include <petscsf.h>
5 
6 /*@C
7   DMLabelCreate - Create a DMLabel object, which is a multimap
8 
9   Collective
10 
11   Input parameters:
12 + comm - The communicator, usually PETSC_COMM_SELF
13 - name - The label name
14 
15   Output parameter:
16 . label - The DMLabel
17 
18   Level: beginner
19 
20 .seealso: DMLabelDestroy()
21 @*/
22 PetscErrorCode DMLabelCreate(MPI_Comm comm, const char name[], DMLabel *label)
23 {
24   PetscErrorCode ierr;
25 
26   PetscFunctionBegin;
27   PetscValidPointer(label,2);
28   ierr = DMInitializePackage();CHKERRQ(ierr);
29 
30   ierr = PetscHeaderCreate(*label,DMLABEL_CLASSID,"DMLabel","DMLabel","DM",comm,DMLabelDestroy,DMLabelView);CHKERRQ(ierr);
31 
32   (*label)->numStrata      = 0;
33   (*label)->defaultValue   = -1;
34   (*label)->stratumValues  = NULL;
35   (*label)->validIS        = NULL;
36   (*label)->stratumSizes   = NULL;
37   (*label)->points         = NULL;
38   (*label)->ht             = NULL;
39   (*label)->pStart         = -1;
40   (*label)->pEnd           = -1;
41   (*label)->bt             = NULL;
42   ierr = PetscHMapICreate(&(*label)->hmap);CHKERRQ(ierr);
43   ierr = PetscObjectSetName((PetscObject) *label, name);CHKERRQ(ierr);
44   PetscFunctionReturn(0);
45 }
46 
47 /*
48   DMLabelMakeValid_Private - Transfer stratum data from the hash format to the sorted list format
49 
50   Not collective
51 
52   Input parameter:
53 + label - The DMLabel
54 - v - The stratum value
55 
56   Output parameter:
57 . label - The DMLabel with stratum in sorted list format
58 
59   Level: developer
60 
61 .seealso: DMLabelCreate()
62 */
63 static PetscErrorCode DMLabelMakeValid_Private(DMLabel label, PetscInt v)
64 {
65   IS             is;
66   PetscInt       off = 0, *pointArray, p;
67   PetscErrorCode ierr;
68 
69   if (PetscLikely(v >= 0 && v < label->numStrata) && label->validIS[v]) return 0;
70   PetscFunctionBegin;
71   if (v < 0 || v >= label->numStrata) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to access invalid stratum %D in DMLabelMakeValid_Private\n", v);
72   ierr = PetscHSetIGetSize(label->ht[v], &label->stratumSizes[v]);CHKERRQ(ierr);
73   ierr = PetscMalloc1(label->stratumSizes[v], &pointArray);CHKERRQ(ierr);
74   ierr = PetscHSetIGetElems(label->ht[v], &off, pointArray);CHKERRQ(ierr);
75   ierr = PetscHSetIClear(label->ht[v]);CHKERRQ(ierr);
76   ierr = PetscSortInt(label->stratumSizes[v], pointArray);CHKERRQ(ierr);
77   if (label->bt) {
78     for (p = 0; p < label->stratumSizes[v]; ++p) {
79       const PetscInt point = pointArray[p];
80       if ((point < label->pStart) || (point >= label->pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, label->pStart, label->pEnd);
81       ierr = PetscBTSet(label->bt, point - label->pStart);CHKERRQ(ierr);
82     }
83   }
84   ierr = ISCreateGeneral(PETSC_COMM_SELF, label->stratumSizes[v], pointArray, PETSC_OWN_POINTER, &is);CHKERRQ(ierr);
85   ierr = PetscObjectSetName((PetscObject) is, "indices");CHKERRQ(ierr);
86   label->points[v]  = is;
87   label->validIS[v] = PETSC_TRUE;
88   ierr = PetscObjectStateIncrease((PetscObject) label);CHKERRQ(ierr);
89   PetscFunctionReturn(0);
90 }
91 
92 /*
93   DMLabelMakeAllValid_Private - Transfer all strata from the hash format to the sorted list format
94 
95   Not collective
96 
97   Input parameter:
98 . label - The DMLabel
99 
100   Output parameter:
101 . label - The DMLabel with all strata in sorted list format
102 
103   Level: developer
104 
105 .seealso: DMLabelCreate()
106 */
107 static PetscErrorCode DMLabelMakeAllValid_Private(DMLabel label)
108 {
109   PetscInt       v;
110   PetscErrorCode ierr;
111 
112   PetscFunctionBegin;
113   for (v = 0; v < label->numStrata; v++){
114     ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
115   }
116   PetscFunctionReturn(0);
117 }
118 
119 /*
120   DMLabelMakeInvalid_Private - Transfer stratum data from the sorted list format to the hash format
121 
122   Not collective
123 
124   Input parameter:
125 + label - The DMLabel
126 - v - The stratum value
127 
128   Output parameter:
129 . label - The DMLabel with stratum in hash format
130 
131   Level: developer
132 
133 .seealso: DMLabelCreate()
134 */
135 static PetscErrorCode DMLabelMakeInvalid_Private(DMLabel label, PetscInt v)
136 {
137   PetscInt       p;
138   const PetscInt *points;
139   PetscErrorCode ierr;
140 
141   if (PetscLikely(v >= 0 && v < label->numStrata) && !label->validIS[v]) return 0;
142   PetscFunctionBegin;
143   if (v < 0 || v >= label->numStrata) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to access invalid stratum %D in DMLabelMakeInvalid_Private\n", v);
144   if (label->points[v]) {
145     ierr = ISGetIndices(label->points[v], &points);CHKERRQ(ierr);
146     for (p = 0; p < label->stratumSizes[v]; ++p) {
147       ierr = PetscHSetIAdd(label->ht[v], points[p]);CHKERRQ(ierr);
148     }
149     ierr = ISRestoreIndices(label->points[v],&points);CHKERRQ(ierr);
150     ierr = ISDestroy(&(label->points[v]));CHKERRQ(ierr);
151   }
152   label->validIS[v] = PETSC_FALSE;
153   PetscFunctionReturn(0);
154 }
155 
156 #if !defined(DMLABEL_LOOKUP_THRESHOLD)
157 #define DMLABEL_LOOKUP_THRESHOLD 16
158 #endif
159 
160 PETSC_STATIC_INLINE PetscErrorCode DMLabelLookupStratum(DMLabel label, PetscInt value, PetscInt *index)
161 {
162   PetscInt       v;
163   PetscErrorCode ierr;
164 
165   PetscFunctionBegin;
166   *index = -1;
167   if (label->numStrata <= DMLABEL_LOOKUP_THRESHOLD) {
168     for (v = 0; v < label->numStrata; ++v)
169       if (label->stratumValues[v] == value) {*index = v; break;}
170   } else {
171     ierr = PetscHMapIGet(label->hmap, value, index);CHKERRQ(ierr);
172   }
173 #if defined(PETSC_USE_DEBUG)
174   { /* Check strata hash map consistency */
175     PetscInt len, loc = -1;
176     ierr = PetscHMapIGetSize(label->hmap, &len);CHKERRQ(ierr);
177     if (len != label->numStrata) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent strata hash map size");
178     if (label->numStrata <= DMLABEL_LOOKUP_THRESHOLD) {
179       ierr = PetscHMapIGet(label->hmap, value, &loc);CHKERRQ(ierr);
180     } else {
181       for (v = 0; v < label->numStrata; ++v)
182         if (label->stratumValues[v] == value) {loc = v; break;}
183     }
184     if (loc != *index) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent strata hash map lookup");
185   }
186 #endif
187   PetscFunctionReturn(0);
188 }
189 
190 PETSC_STATIC_INLINE PetscErrorCode DMLabelNewStratum(DMLabel label, PetscInt value, PetscInt *index)
191 {
192   PetscInt       v;
193   PetscInt      *tmpV;
194   PetscInt      *tmpS;
195   PetscHSetI    *tmpH, ht;
196   IS            *tmpP, is;
197   PetscBool     *tmpB;
198   PetscHMapI     hmap = label->hmap;
199   PetscErrorCode ierr;
200 
201   PetscFunctionBegin;
202   v    = label->numStrata;
203   tmpV = label->stratumValues;
204   tmpS = label->stratumSizes;
205   tmpH = label->ht;
206   tmpP = label->points;
207   tmpB = label->validIS;
208   { /* TODO: PetscRealloc() is broken, use malloc+memcpy+free  */
209     PetscInt   *oldV = tmpV;
210     PetscInt   *oldS = tmpS;
211     PetscHSetI *oldH = tmpH;
212     IS         *oldP = tmpP;
213     PetscBool  *oldB = tmpB;
214     ierr = PetscMalloc((v+1)*sizeof(*tmpV), &tmpV);CHKERRQ(ierr);
215     ierr = PetscMalloc((v+1)*sizeof(*tmpS), &tmpS);CHKERRQ(ierr);
216     ierr = PetscMalloc((v+1)*sizeof(*tmpH), &tmpH);CHKERRQ(ierr);
217     ierr = PetscMalloc((v+1)*sizeof(*tmpP), &tmpP);CHKERRQ(ierr);
218     ierr = PetscMalloc((v+1)*sizeof(*tmpB), &tmpB);CHKERRQ(ierr);
219     ierr = PetscArraycpy(tmpV, oldV, v);CHKERRQ(ierr);
220     ierr = PetscArraycpy(tmpS, oldS, v);CHKERRQ(ierr);
221     ierr = PetscArraycpy(tmpH, oldH, v);CHKERRQ(ierr);
222     ierr = PetscArraycpy(tmpP, oldP, v);CHKERRQ(ierr);
223     ierr = PetscArraycpy(tmpB, oldB, v);CHKERRQ(ierr);
224     ierr = PetscFree(oldV);CHKERRQ(ierr);
225     ierr = PetscFree(oldS);CHKERRQ(ierr);
226     ierr = PetscFree(oldH);CHKERRQ(ierr);
227     ierr = PetscFree(oldP);CHKERRQ(ierr);
228     ierr = PetscFree(oldB);CHKERRQ(ierr);
229   }
230   label->numStrata     = v+1;
231   label->stratumValues = tmpV;
232   label->stratumSizes  = tmpS;
233   label->ht            = tmpH;
234   label->points        = tmpP;
235   label->validIS       = tmpB;
236   ierr = PetscHSetICreate(&ht);CHKERRQ(ierr);
237   ierr = ISCreateStride(PETSC_COMM_SELF,0,0,1,&is);CHKERRQ(ierr);
238   ierr = PetscHMapISet(hmap, value, v);CHKERRQ(ierr);
239   tmpV[v] = value;
240   tmpS[v] = 0;
241   tmpH[v] = ht;
242   tmpP[v] = is;
243   tmpB[v] = PETSC_TRUE;
244   ierr = PetscObjectStateIncrease((PetscObject) label);CHKERRQ(ierr);
245   *index = v;
246   PetscFunctionReturn(0);
247 }
248 
249 PETSC_STATIC_INLINE PetscErrorCode DMLabelLookupAddStratum(DMLabel label, PetscInt value, PetscInt *index)
250 {
251   PetscErrorCode ierr;
252   PetscFunctionBegin;
253   ierr = DMLabelLookupStratum(label, value, index);CHKERRQ(ierr);
254   if (*index < 0) {ierr = DMLabelNewStratum(label, value, index);CHKERRQ(ierr);}
255   PetscFunctionReturn(0);
256 }
257 
258 /*@
259   DMLabelAddStratum - Adds a new stratum value in a DMLabel
260 
261   Input Parameter:
262 + label - The DMLabel
263 - value - The stratum value
264 
265   Level: beginner
266 
267 .seealso:  DMLabelCreate(), DMLabelDestroy()
268 @*/
269 PetscErrorCode DMLabelAddStratum(DMLabel label, PetscInt value)
270 {
271   PetscInt       v;
272   PetscErrorCode ierr;
273 
274   PetscFunctionBegin;
275   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
276   ierr = DMLabelLookupAddStratum(label, value, &v);CHKERRQ(ierr);
277   PetscFunctionReturn(0);
278 }
279 
280 /*@
281   DMLabelAddStrata - Adds new stratum values in a DMLabel
282 
283   Not collective
284 
285   Input Parameter:
286 + label - The DMLabel
287 . numStrata - The number of stratum values
288 - stratumValues - The stratum values
289 
290   Level: beginner
291 
292 .seealso:  DMLabelCreate(), DMLabelDestroy()
293 @*/
294 PetscErrorCode DMLabelAddStrata(DMLabel label, PetscInt numStrata, const PetscInt stratumValues[])
295 {
296   PetscInt       *values, v;
297   PetscErrorCode ierr;
298 
299   PetscFunctionBegin;
300   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
301   if (numStrata) PetscValidIntPointer(stratumValues, 3);
302   ierr = PetscMalloc1(numStrata, &values);CHKERRQ(ierr);
303   ierr = PetscArraycpy(values, stratumValues, numStrata);CHKERRQ(ierr);
304   ierr = PetscSortRemoveDupsInt(&numStrata, values);CHKERRQ(ierr);
305   if (!label->numStrata) { /* Fast preallocation */
306     PetscInt   *tmpV;
307     PetscInt   *tmpS;
308     PetscHSetI *tmpH, ht;
309     IS         *tmpP, is;
310     PetscBool  *tmpB;
311     PetscHMapI  hmap = label->hmap;
312 
313     ierr = PetscMalloc1(numStrata, &tmpV);CHKERRQ(ierr);
314     ierr = PetscMalloc1(numStrata, &tmpS);CHKERRQ(ierr);
315     ierr = PetscMalloc1(numStrata, &tmpH);CHKERRQ(ierr);
316     ierr = PetscMalloc1(numStrata, &tmpP);CHKERRQ(ierr);
317     ierr = PetscMalloc1(numStrata, &tmpB);CHKERRQ(ierr);
318     label->numStrata     = numStrata;
319     label->stratumValues = tmpV;
320     label->stratumSizes  = tmpS;
321     label->ht            = tmpH;
322     label->points        = tmpP;
323     label->validIS       = tmpB;
324     for (v = 0; v < numStrata; ++v) {
325       ierr = PetscHSetICreate(&ht);CHKERRQ(ierr);
326       ierr = ISCreateStride(PETSC_COMM_SELF,0,0,1,&is);CHKERRQ(ierr);
327       ierr = PetscHMapISet(hmap, values[v], v);CHKERRQ(ierr);
328       tmpV[v] = values[v];
329       tmpS[v] = 0;
330       tmpH[v] = ht;
331       tmpP[v] = is;
332       tmpB[v] = PETSC_TRUE;
333     }
334     ierr = PetscObjectStateIncrease((PetscObject) label);CHKERRQ(ierr);
335   } else {
336     for (v = 0; v < numStrata; ++v) {
337       ierr = DMLabelAddStratum(label, values[v]);CHKERRQ(ierr);
338     }
339   }
340   ierr = PetscFree(values);CHKERRQ(ierr);
341   PetscFunctionReturn(0);
342 }
343 
344 /*@
345   DMLabelAddStrataIS - Adds new stratum values in a DMLabel
346 
347   Not collective
348 
349   Input Parameter:
350 + label - The DMLabel
351 - valueIS - Index set with stratum values
352 
353   Level: beginner
354 
355 .seealso:  DMLabelCreate(), DMLabelDestroy()
356 @*/
357 PetscErrorCode DMLabelAddStrataIS(DMLabel label, IS valueIS)
358 {
359   PetscInt       numStrata;
360   const PetscInt *stratumValues;
361   PetscErrorCode ierr;
362 
363   PetscFunctionBegin;
364   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
365   PetscValidHeaderSpecific(valueIS, IS_CLASSID, 2);
366   ierr = ISGetLocalSize(valueIS, &numStrata);CHKERRQ(ierr);
367   ierr = ISGetIndices(valueIS, &stratumValues);CHKERRQ(ierr);
368   ierr = DMLabelAddStrata(label, numStrata, stratumValues);CHKERRQ(ierr);
369   PetscFunctionReturn(0);
370 }
371 
372 static PetscErrorCode DMLabelView_Ascii(DMLabel label, PetscViewer viewer)
373 {
374   PetscInt       v;
375   PetscMPIInt    rank;
376   PetscErrorCode ierr;
377 
378   PetscFunctionBegin;
379   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank);CHKERRQ(ierr);
380   ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
381   if (label) {
382     const char *name;
383 
384     ierr = PetscObjectGetName((PetscObject) label, &name);CHKERRQ(ierr);
385     ierr = PetscViewerASCIIPrintf(viewer, "Label '%s':\n", name);CHKERRQ(ierr);
386     if (label->bt) {ierr = PetscViewerASCIIPrintf(viewer, "  Index has been calculated in [%D, %D)\n", label->pStart, label->pEnd);CHKERRQ(ierr);}
387     for (v = 0; v < label->numStrata; ++v) {
388       const PetscInt value = label->stratumValues[v];
389       const PetscInt *points;
390       PetscInt       p;
391 
392       ierr = ISGetIndices(label->points[v], &points);CHKERRQ(ierr);
393       for (p = 0; p < label->stratumSizes[v]; ++p) {
394         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D (%D)\n", rank, points[p], value);CHKERRQ(ierr);
395       }
396       ierr = ISRestoreIndices(label->points[v],&points);CHKERRQ(ierr);
397     }
398   }
399   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
400   ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
401   PetscFunctionReturn(0);
402 }
403 
404 /*@C
405   DMLabelView - View the label
406 
407   Collective on viewer
408 
409   Input Parameters:
410 + label - The DMLabel
411 - viewer - The PetscViewer
412 
413   Level: intermediate
414 
415 .seealso: DMLabelCreate(), DMLabelDestroy()
416 @*/
417 PetscErrorCode DMLabelView(DMLabel label, PetscViewer viewer)
418 {
419   PetscBool      iascii;
420   PetscErrorCode ierr;
421 
422   PetscFunctionBegin;
423   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
424   if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)label), &viewer);CHKERRQ(ierr);}
425   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
426   if (label) {ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);}
427   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
428   if (iascii) {
429     ierr = DMLabelView_Ascii(label, viewer);CHKERRQ(ierr);
430   }
431   PetscFunctionReturn(0);
432 }
433 
434 /*@
435   DMLabelReset - Destroys internal data structures in a DMLabel
436 
437   Not collective
438 
439   Input Parameter:
440 . label - The DMLabel
441 
442   Level: beginner
443 
444 .seealso: DMLabelDestroy(), DMLabelCreate()
445 @*/
446 PetscErrorCode DMLabelReset(DMLabel label)
447 {
448   PetscInt       v;
449   PetscErrorCode ierr;
450 
451   PetscFunctionBegin;
452   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
453   for (v = 0; v < label->numStrata; ++v) {
454     ierr = PetscHSetIDestroy(&label->ht[v]);CHKERRQ(ierr);
455     ierr = ISDestroy(&label->points[v]);CHKERRQ(ierr);
456   }
457   label->numStrata = 0;
458   ierr = PetscFree(label->stratumValues);CHKERRQ(ierr);
459   ierr = PetscFree(label->stratumSizes);CHKERRQ(ierr);
460   ierr = PetscFree(label->ht);CHKERRQ(ierr);
461   ierr = PetscFree(label->points);CHKERRQ(ierr);
462   ierr = PetscFree(label->validIS);CHKERRQ(ierr);
463   ierr = PetscHMapIReset(label->hmap);CHKERRQ(ierr);
464   label->pStart = -1;
465   label->pEnd   = -1;
466   ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);
467   PetscFunctionReturn(0);
468 }
469 
470 /*@
471   DMLabelDestroy - Destroys a DMLabel
472 
473   Collective on label
474 
475   Input Parameter:
476 . label - The DMLabel
477 
478   Level: beginner
479 
480 .seealso: DMLabelReset(), DMLabelCreate()
481 @*/
482 PetscErrorCode DMLabelDestroy(DMLabel *label)
483 {
484   PetscErrorCode ierr;
485 
486   PetscFunctionBegin;
487   if (!*label) PetscFunctionReturn(0);
488   PetscValidHeaderSpecific((*label),DMLABEL_CLASSID,1);
489   if (--((PetscObject)(*label))->refct > 0) {*label = NULL; PetscFunctionReturn(0);}
490   ierr = DMLabelReset(*label);CHKERRQ(ierr);
491   ierr = PetscHMapIDestroy(&(*label)->hmap);CHKERRQ(ierr);
492   ierr = PetscHeaderDestroy(label);CHKERRQ(ierr);
493   PetscFunctionReturn(0);
494 }
495 
496 /*@
497   DMLabelDuplicate - Duplicates a DMLabel
498 
499   Collective on label
500 
501   Input Parameter:
502 . label - The DMLabel
503 
504   Output Parameter:
505 . labelnew - location to put new vector
506 
507   Level: intermediate
508 
509 .seealso: DMLabelCreate(), DMLabelDestroy()
510 @*/
511 PetscErrorCode DMLabelDuplicate(DMLabel label, DMLabel *labelnew)
512 {
513   const char    *name;
514   PetscInt       v;
515   PetscErrorCode ierr;
516 
517   PetscFunctionBegin;
518   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
519   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
520   ierr = PetscObjectGetName((PetscObject) label, &name);CHKERRQ(ierr);
521   ierr = DMLabelCreate(PetscObjectComm((PetscObject) label), name, labelnew);CHKERRQ(ierr);
522 
523   (*labelnew)->numStrata    = label->numStrata;
524   (*labelnew)->defaultValue = label->defaultValue;
525   ierr = PetscMalloc1(label->numStrata, &(*labelnew)->stratumValues);CHKERRQ(ierr);
526   ierr = PetscMalloc1(label->numStrata, &(*labelnew)->stratumSizes);CHKERRQ(ierr);
527   ierr = PetscMalloc1(label->numStrata, &(*labelnew)->ht);CHKERRQ(ierr);
528   ierr = PetscMalloc1(label->numStrata, &(*labelnew)->points);CHKERRQ(ierr);
529   ierr = PetscMalloc1(label->numStrata, &(*labelnew)->validIS);CHKERRQ(ierr);
530   for (v = 0; v < label->numStrata; ++v) {
531     ierr = PetscHSetICreate(&(*labelnew)->ht[v]);CHKERRQ(ierr);
532     (*labelnew)->stratumValues[v]  = label->stratumValues[v];
533     (*labelnew)->stratumSizes[v]   = label->stratumSizes[v];
534     ierr = PetscObjectReference((PetscObject) (label->points[v]));CHKERRQ(ierr);
535     (*labelnew)->points[v]         = label->points[v];
536     (*labelnew)->validIS[v]        = PETSC_TRUE;
537   }
538   ierr = PetscHMapIDestroy(&(*labelnew)->hmap);CHKERRQ(ierr);
539   ierr = PetscHMapIDuplicate(label->hmap,&(*labelnew)->hmap);CHKERRQ(ierr);
540   (*labelnew)->pStart = -1;
541   (*labelnew)->pEnd   = -1;
542   (*labelnew)->bt     = NULL;
543   PetscFunctionReturn(0);
544 }
545 
546 /*@
547   DMLabelComputeIndex - Create an index structure for membership determination, automatically determining the bounds
548 
549   Not collective
550 
551   Input Parameter:
552 . label  - The DMLabel
553 
554   Level: intermediate
555 
556 .seealso: DMLabelHasPoint(), DMLabelCreateIndex(), DMLabelDestroyIndex(), DMLabelGetValue(), DMLabelSetValue()
557 @*/
558 PetscErrorCode DMLabelComputeIndex(DMLabel label)
559 {
560   PetscInt       pStart = PETSC_MAX_INT, pEnd = -1, v;
561   PetscErrorCode ierr;
562 
563   PetscFunctionBegin;
564   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
565   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
566   for (v = 0; v < label->numStrata; ++v) {
567     const PetscInt *points;
568     PetscInt       i;
569 
570     ierr = ISGetIndices(label->points[v], &points);CHKERRQ(ierr);
571     for (i = 0; i < label->stratumSizes[v]; ++i) {
572       const PetscInt point = points[i];
573 
574       pStart = PetscMin(point,   pStart);
575       pEnd   = PetscMax(point+1, pEnd);
576     }
577     ierr = ISRestoreIndices(label->points[v], &points);CHKERRQ(ierr);
578   }
579   label->pStart = pStart == PETSC_MAX_INT ? -1 : pStart;
580   label->pEnd   = pEnd;
581   ierr = DMLabelCreateIndex(label, label->pStart, label->pEnd);CHKERRQ(ierr);
582   PetscFunctionReturn(0);
583 }
584 
585 /*@
586   DMLabelCreateIndex - Create an index structure for membership determination
587 
588   Not collective
589 
590   Input Parameters:
591 + label  - The DMLabel
592 . pStart - The smallest point
593 - pEnd   - The largest point + 1
594 
595   Level: intermediate
596 
597 .seealso: DMLabelHasPoint(), DMLabelComputeIndex(), DMLabelDestroyIndex(), DMLabelGetValue(), DMLabelSetValue()
598 @*/
599 PetscErrorCode DMLabelCreateIndex(DMLabel label, PetscInt pStart, PetscInt pEnd)
600 {
601   PetscInt       v;
602   PetscErrorCode ierr;
603 
604   PetscFunctionBegin;
605   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
606   ierr = DMLabelDestroyIndex(label);CHKERRQ(ierr);
607   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
608   label->pStart = pStart;
609   label->pEnd   = pEnd;
610   /* This can be hooked into SetValue(),  ClearValue(), etc. for updating */
611   ierr = PetscBTCreate(pEnd - pStart, &label->bt);CHKERRQ(ierr);
612   for (v = 0; v < label->numStrata; ++v) {
613     const PetscInt *points;
614     PetscInt       i;
615 
616     ierr = ISGetIndices(label->points[v], &points);CHKERRQ(ierr);
617     for (i = 0; i < label->stratumSizes[v]; ++i) {
618       const PetscInt point = points[i];
619 
620       if ((point < pStart) || (point >= pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, pStart, pEnd);
621       ierr = PetscBTSet(label->bt, point - pStart);CHKERRQ(ierr);
622     }
623     ierr = ISRestoreIndices(label->points[v], &points);CHKERRQ(ierr);
624   }
625   PetscFunctionReturn(0);
626 }
627 
628 /*@
629   DMLabelDestroyIndex - Destroy the index structure
630 
631   Not collective
632 
633   Input Parameter:
634 . label - the DMLabel
635 
636   Level: intermediate
637 
638 .seealso: DMLabelHasPoint(), DMLabelCreateIndex(), DMLabelGetValue(), DMLabelSetValue()
639 @*/
640 PetscErrorCode DMLabelDestroyIndex(DMLabel label)
641 {
642   PetscErrorCode ierr;
643 
644   PetscFunctionBegin;
645   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
646   label->pStart = -1;
647   label->pEnd   = -1;
648   ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);
649   PetscFunctionReturn(0);
650 }
651 
652 /*@
653   DMLabelGetBounds - Return the smallest and largest point in the label
654 
655   Not collective
656 
657   Input Parameter:
658 . label - the DMLabel
659 
660   Output Parameters:
661 + pStart - The smallest point
662 - pEnd   - The largest point + 1
663 
664   Note: This will compute an index for the label if one does not exist.
665 
666   Level: intermediate
667 
668 .seealso: DMLabelHasPoint(), DMLabelCreateIndex(), DMLabelGetValue(), DMLabelSetValue()
669 @*/
670 PetscErrorCode DMLabelGetBounds(DMLabel label, PetscInt *pStart, PetscInt *pEnd)
671 {
672   PetscErrorCode ierr;
673 
674   PetscFunctionBegin;
675   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
676   if ((label->pStart == -1) && (label->pEnd == -1)) {ierr = DMLabelComputeIndex(label);CHKERRQ(ierr);}
677   if (pStart) {
678     PetscValidIntPointer(pStart, 2);
679     *pStart = label->pStart;
680   }
681   if (pEnd) {
682     PetscValidIntPointer(pEnd, 3);
683     *pEnd = label->pEnd;
684   }
685   PetscFunctionReturn(0);
686 }
687 
688 /*@
689   DMLabelHasValue - Determine whether a label assigns the value to any point
690 
691   Not collective
692 
693   Input Parameters:
694 + label - the DMLabel
695 - value - the value
696 
697   Output Parameter:
698 . contains - Flag indicating whether the label maps this value to any point
699 
700   Level: developer
701 
702 .seealso: DMLabelHasPoint(), DMLabelGetValue(), DMLabelSetValue()
703 @*/
704 PetscErrorCode DMLabelHasValue(DMLabel label, PetscInt value, PetscBool *contains)
705 {
706   PetscInt v;
707   PetscErrorCode ierr;
708 
709   PetscFunctionBegin;
710   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
711   PetscValidBoolPointer(contains, 3);
712   ierr = DMLabelLookupStratum(label, value, &v);CHKERRQ(ierr);
713   *contains = v < 0 ? PETSC_FALSE : PETSC_TRUE;
714   PetscFunctionReturn(0);
715 }
716 
717 /*@
718   DMLabelHasPoint - Determine whether a label assigns a value to a point
719 
720   Not collective
721 
722   Input Parameters:
723 + label - the DMLabel
724 - point - the point
725 
726   Output Parameter:
727 . contains - Flag indicating whether the label maps this point to a value
728 
729   Note: The user must call DMLabelCreateIndex() before this function.
730 
731   Level: developer
732 
733 .seealso: DMLabelCreateIndex(), DMLabelGetValue(), DMLabelSetValue()
734 @*/
735 PetscErrorCode DMLabelHasPoint(DMLabel label, PetscInt point, PetscBool *contains)
736 {
737   PetscErrorCode ierr;
738 
739   PetscFunctionBeginHot;
740   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
741   PetscValidBoolPointer(contains, 3);
742   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
743 #if defined(PETSC_USE_DEBUG)
744   if (!label->bt) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call DMLabelCreateIndex() before DMLabelHasPoint()");
745   if ((point < label->pStart) || (point >= label->pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, label->pStart, label->pEnd);
746 #endif
747   *contains = PetscBTLookup(label->bt, point - label->pStart) ? PETSC_TRUE : PETSC_FALSE;
748   PetscFunctionReturn(0);
749 }
750 
751 /*@
752   DMLabelStratumHasPoint - Return true if the stratum contains a point
753 
754   Not collective
755 
756   Input Parameters:
757 + label - the DMLabel
758 . value - the stratum value
759 - point - the point
760 
761   Output Parameter:
762 . contains - true if the stratum contains the point
763 
764   Level: intermediate
765 
766 .seealso: DMLabelCreate(), DMLabelSetValue(), DMLabelClearValue()
767 @*/
768 PetscErrorCode DMLabelStratumHasPoint(DMLabel label, PetscInt value, PetscInt point, PetscBool *contains)
769 {
770   PetscInt       v;
771   PetscErrorCode ierr;
772 
773   PetscFunctionBeginHot;
774   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
775   PetscValidBoolPointer(contains, 4);
776   *contains = PETSC_FALSE;
777   ierr = DMLabelLookupStratum(label, value, &v);CHKERRQ(ierr);
778   if (v < 0) PetscFunctionReturn(0);
779 
780   if (label->validIS[v]) {
781     PetscInt i;
782 
783     ierr = ISLocate(label->points[v], point, &i);CHKERRQ(ierr);
784     if (i >= 0) *contains = PETSC_TRUE;
785   } else {
786     PetscBool has;
787 
788     ierr = PetscHSetIHas(label->ht[v], point, &has);CHKERRQ(ierr);
789     if (has) *contains = PETSC_TRUE;
790   }
791   PetscFunctionReturn(0);
792 }
793 
794 /*@
795   DMLabelGetDefaultValue - Get the default value returned by DMLabelGetValue() if a point has not been explicitly given a value.
796   When a label is created, it is initialized to -1.
797 
798   Not collective
799 
800   Input parameter:
801 . label - a DMLabel object
802 
803   Output parameter:
804 . defaultValue - the default value
805 
806   Level: beginner
807 
808 .seealso: DMLabelSetDefaultValue(), DMLabelGetValue(), DMLabelSetValue()
809 @*/
810 PetscErrorCode DMLabelGetDefaultValue(DMLabel label, PetscInt *defaultValue)
811 {
812   PetscFunctionBegin;
813   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
814   *defaultValue = label->defaultValue;
815   PetscFunctionReturn(0);
816 }
817 
818 /*@
819   DMLabelSetDefaultValue - Set the default value returned by DMLabelGetValue() if a point has not been explicitly given a value.
820   When a label is created, it is initialized to -1.
821 
822   Not collective
823 
824   Input parameter:
825 . label - a DMLabel object
826 
827   Output parameter:
828 . defaultValue - the default value
829 
830   Level: beginner
831 
832 .seealso: DMLabelGetDefaultValue(), DMLabelGetValue(), DMLabelSetValue()
833 @*/
834 PetscErrorCode DMLabelSetDefaultValue(DMLabel label, PetscInt defaultValue)
835 {
836   PetscFunctionBegin;
837   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
838   label->defaultValue = defaultValue;
839   PetscFunctionReturn(0);
840 }
841 
842 /*@
843   DMLabelGetValue - Return the value a label assigns to a point, or the label's default value (which is initially -1, and can be changed with DMLabelSetDefaultValue())
844 
845   Not collective
846 
847   Input Parameters:
848 + label - the DMLabel
849 - point - the point
850 
851   Output Parameter:
852 . value - The point value, or the default value (-1 by default)
853 
854   Level: intermediate
855 
856 .seealso: DMLabelCreate(), DMLabelSetValue(), DMLabelClearValue(), DMLabelGetDefaultValue(), DMLabelSetDefaultValue()
857 @*/
858 PetscErrorCode DMLabelGetValue(DMLabel label, PetscInt point, PetscInt *value)
859 {
860   PetscInt       v;
861   PetscErrorCode ierr;
862 
863   PetscFunctionBeginHot;
864   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
865   PetscValidPointer(value, 3);
866   *value = label->defaultValue;
867   for (v = 0; v < label->numStrata; ++v) {
868     if (label->validIS[v]) {
869       PetscInt i;
870 
871       ierr = ISLocate(label->points[v], point, &i);CHKERRQ(ierr);
872       if (i >= 0) {
873         *value = label->stratumValues[v];
874         break;
875       }
876     } else {
877       PetscBool has;
878 
879       ierr = PetscHSetIHas(label->ht[v], point, &has);CHKERRQ(ierr);
880       if (has) {
881         *value = label->stratumValues[v];
882         break;
883       }
884     }
885   }
886   PetscFunctionReturn(0);
887 }
888 
889 /*@
890   DMLabelSetValue - Set the value a label assigns to a point.  If the value is the same as the label's default value (which is initially -1, and can be changed with DMLabelSetDefaultValue() to something different), then this function will do nothing.
891 
892   Not collective
893 
894   Input Parameters:
895 + label - the DMLabel
896 . point - the point
897 - value - The point value
898 
899   Level: intermediate
900 
901 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelClearValue(), DMLabelGetDefaultValue(), DMLabelSetDefaultValue()
902 @*/
903 PetscErrorCode DMLabelSetValue(DMLabel label, PetscInt point, PetscInt value)
904 {
905   PetscInt       v;
906   PetscErrorCode ierr;
907 
908   PetscFunctionBegin;
909   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
910   /* Find label value, add new entry if needed */
911   if (value == label->defaultValue) PetscFunctionReturn(0);
912   ierr = DMLabelLookupAddStratum(label, value, &v);CHKERRQ(ierr);
913   /* Set key */
914   ierr = DMLabelMakeInvalid_Private(label, v);CHKERRQ(ierr);
915   ierr = PetscHSetIAdd(label->ht[v], point);CHKERRQ(ierr);
916   PetscFunctionReturn(0);
917 }
918 
919 /*@
920   DMLabelClearValue - Clear the value a label assigns to a point
921 
922   Not collective
923 
924   Input Parameters:
925 + label - the DMLabel
926 . point - the point
927 - value - The point value
928 
929   Level: intermediate
930 
931 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue()
932 @*/
933 PetscErrorCode DMLabelClearValue(DMLabel label, PetscInt point, PetscInt value)
934 {
935   PetscInt       v;
936   PetscErrorCode ierr;
937 
938   PetscFunctionBegin;
939   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
940   /* Find label value */
941   ierr = DMLabelLookupStratum(label, value, &v);CHKERRQ(ierr);
942   if (v < 0) PetscFunctionReturn(0);
943 
944   if (label->bt) {
945     if ((point < label->pStart) || (point >= label->pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, label->pStart, label->pEnd);
946     ierr = PetscBTClear(label->bt, point - label->pStart);CHKERRQ(ierr);
947   }
948 
949   /* Delete key */
950   ierr = DMLabelMakeInvalid_Private(label, v);CHKERRQ(ierr);
951   ierr = PetscHSetIDel(label->ht[v], point);CHKERRQ(ierr);
952   PetscFunctionReturn(0);
953 }
954 
955 /*@
956   DMLabelInsertIS - Set all points in the IS to a value
957 
958   Not collective
959 
960   Input Parameters:
961 + label - the DMLabel
962 . is    - the point IS
963 - value - The point value
964 
965   Level: intermediate
966 
967 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
968 @*/
969 PetscErrorCode DMLabelInsertIS(DMLabel label, IS is, PetscInt value)
970 {
971   PetscInt        v, n, p;
972   const PetscInt *points;
973   PetscErrorCode  ierr;
974 
975   PetscFunctionBegin;
976   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
977   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
978   /* Find label value, add new entry if needed */
979   if (value == label->defaultValue) PetscFunctionReturn(0);
980   ierr = DMLabelLookupAddStratum(label, value, &v);CHKERRQ(ierr);
981   /* Set keys */
982   ierr = DMLabelMakeInvalid_Private(label, v);CHKERRQ(ierr);
983   ierr = ISGetLocalSize(is, &n);CHKERRQ(ierr);
984   ierr = ISGetIndices(is, &points);CHKERRQ(ierr);
985   for (p = 0; p < n; ++p) {ierr = PetscHSetIAdd(label->ht[v], points[p]);CHKERRQ(ierr);}
986   ierr = ISRestoreIndices(is, &points);CHKERRQ(ierr);
987   PetscFunctionReturn(0);
988 }
989 
990 /*@
991   DMLabelGetNumValues - Get the number of values that the DMLabel takes
992 
993   Not collective
994 
995   Input Parameter:
996 . label - the DMLabel
997 
998   Output Paramater:
999 . numValues - the number of values
1000 
1001   Level: intermediate
1002 
1003 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1004 @*/
1005 PetscErrorCode DMLabelGetNumValues(DMLabel label, PetscInt *numValues)
1006 {
1007   PetscFunctionBegin;
1008   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1009   PetscValidPointer(numValues, 2);
1010   *numValues = label->numStrata;
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 /*@
1015   DMLabelGetValueIS - Get an IS of all values that the DMlabel takes
1016 
1017   Not collective
1018 
1019   Input Parameter:
1020 . label - the DMLabel
1021 
1022   Output Paramater:
1023 . is    - the value IS
1024 
1025   Level: intermediate
1026 
1027 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1028 @*/
1029 PetscErrorCode DMLabelGetValueIS(DMLabel label, IS *values)
1030 {
1031   PetscErrorCode ierr;
1032 
1033   PetscFunctionBegin;
1034   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1035   PetscValidPointer(values, 2);
1036   ierr = ISCreateGeneral(PETSC_COMM_SELF, label->numStrata, label->stratumValues, PETSC_USE_POINTER, values);CHKERRQ(ierr);
1037   PetscFunctionReturn(0);
1038 }
1039 
1040 /*@
1041   DMLabelHasStratum - Determine whether points exist with the given value
1042 
1043   Not collective
1044 
1045   Input Parameters:
1046 + label - the DMLabel
1047 - value - the stratum value
1048 
1049   Output Paramater:
1050 . exists - Flag saying whether points exist
1051 
1052   Level: intermediate
1053 
1054 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1055 @*/
1056 PetscErrorCode DMLabelHasStratum(DMLabel label, PetscInt value, PetscBool *exists)
1057 {
1058   PetscInt       v;
1059   PetscErrorCode ierr;
1060 
1061   PetscFunctionBegin;
1062   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1063   PetscValidPointer(exists, 3);
1064   ierr = DMLabelLookupStratum(label, value, &v);CHKERRQ(ierr);
1065   *exists = v < 0 ? PETSC_FALSE : PETSC_TRUE;
1066   PetscFunctionReturn(0);
1067 }
1068 
1069 /*@
1070   DMLabelGetStratumSize - Get the size of a stratum
1071 
1072   Not collective
1073 
1074   Input Parameters:
1075 + label - the DMLabel
1076 - value - the stratum value
1077 
1078   Output Paramater:
1079 . size - The number of points in the stratum
1080 
1081   Level: intermediate
1082 
1083 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1084 @*/
1085 PetscErrorCode DMLabelGetStratumSize(DMLabel label, PetscInt value, PetscInt *size)
1086 {
1087   PetscInt       v;
1088   PetscErrorCode ierr;
1089 
1090   PetscFunctionBegin;
1091   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1092   PetscValidPointer(size, 3);
1093   *size = 0;
1094   ierr = DMLabelLookupStratum(label, value, &v);CHKERRQ(ierr);
1095   if (v < 0) PetscFunctionReturn(0);
1096   ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
1097   *size = label->stratumSizes[v];
1098   PetscFunctionReturn(0);
1099 }
1100 
1101 /*@
1102   DMLabelGetStratumBounds - Get the largest and smallest point of a stratum
1103 
1104   Not collective
1105 
1106   Input Parameters:
1107 + label - the DMLabel
1108 - value - the stratum value
1109 
1110   Output Paramaters:
1111 + start - the smallest point in the stratum
1112 - end - the largest point in the stratum
1113 
1114   Level: intermediate
1115 
1116 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1117 @*/
1118 PetscErrorCode DMLabelGetStratumBounds(DMLabel label, PetscInt value, PetscInt *start, PetscInt *end)
1119 {
1120   PetscInt       v, min, max;
1121   PetscErrorCode ierr;
1122 
1123   PetscFunctionBegin;
1124   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1125   if (start) {PetscValidPointer(start, 3); *start = 0;}
1126   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
1127   ierr = DMLabelLookupStratum(label, value, &v);CHKERRQ(ierr);
1128   if (v < 0) PetscFunctionReturn(0);
1129   ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
1130   if (label->stratumSizes[v] <= 0) PetscFunctionReturn(0);
1131   ierr = ISGetMinMax(label->points[v], &min, &max);CHKERRQ(ierr);
1132   if (start) *start = min;
1133   if (end)   *end   = max+1;
1134   PetscFunctionReturn(0);
1135 }
1136 
1137 /*@
1138   DMLabelGetStratumIS - Get an IS with the stratum points
1139 
1140   Not collective
1141 
1142   Input Parameters:
1143 + label - the DMLabel
1144 - value - the stratum value
1145 
1146   Output Paramater:
1147 . points - The stratum points
1148 
1149   Level: intermediate
1150 
1151   Notes:
1152   The output IS should be destroyed when no longer needed.
1153   Returns NULL if the stratum is empty.
1154 
1155 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1156 @*/
1157 PetscErrorCode DMLabelGetStratumIS(DMLabel label, PetscInt value, IS *points)
1158 {
1159   PetscInt       v;
1160   PetscErrorCode ierr;
1161 
1162   PetscFunctionBegin;
1163   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1164   PetscValidPointer(points, 3);
1165   *points = NULL;
1166   ierr = DMLabelLookupStratum(label, value, &v);CHKERRQ(ierr);
1167   if (v < 0) PetscFunctionReturn(0);
1168   ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
1169   ierr = PetscObjectReference((PetscObject) label->points[v]);CHKERRQ(ierr);
1170   *points = label->points[v];
1171   PetscFunctionReturn(0);
1172 }
1173 
1174 /*@
1175   DMLabelSetStratumIS - Set the stratum points using an IS
1176 
1177   Not collective
1178 
1179   Input Parameters:
1180 + label - the DMLabel
1181 . value - the stratum value
1182 - points - The stratum points
1183 
1184   Level: intermediate
1185 
1186 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1187 @*/
1188 PetscErrorCode DMLabelSetStratumIS(DMLabel label, PetscInt value, IS is)
1189 {
1190   PetscInt       v;
1191   PetscErrorCode ierr;
1192 
1193   PetscFunctionBegin;
1194   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1195   PetscValidHeaderSpecific(is, IS_CLASSID, 3);
1196   ierr = DMLabelLookupAddStratum(label, value, &v);CHKERRQ(ierr);
1197   if (is == label->points[v]) PetscFunctionReturn(0);
1198   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
1199   ierr = ISGetLocalSize(is, &(label->stratumSizes[v]));CHKERRQ(ierr);
1200   ierr = PetscObjectReference((PetscObject)is);CHKERRQ(ierr);
1201   ierr = ISDestroy(&(label->points[v]));CHKERRQ(ierr);
1202   label->points[v]  = is;
1203   label->validIS[v] = PETSC_TRUE;
1204   ierr = PetscObjectStateIncrease((PetscObject) label);CHKERRQ(ierr);
1205   if (label->bt) {
1206     const PetscInt *points;
1207     PetscInt p;
1208 
1209     ierr = ISGetIndices(is,&points);CHKERRQ(ierr);
1210     for (p = 0; p < label->stratumSizes[v]; ++p) {
1211       const PetscInt point = points[p];
1212 
1213       if ((point < label->pStart) || (point >= label->pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, label->pStart, label->pEnd);
1214       ierr = PetscBTSet(label->bt, point - label->pStart);CHKERRQ(ierr);
1215     }
1216   }
1217   PetscFunctionReturn(0);
1218 }
1219 
1220 /*@
1221   DMLabelClearStratum - Remove a stratum
1222 
1223   Not collective
1224 
1225   Input Parameters:
1226 + label - the DMLabel
1227 - value - the stratum value
1228 
1229   Level: intermediate
1230 
1231 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1232 @*/
1233 PetscErrorCode DMLabelClearStratum(DMLabel label, PetscInt value)
1234 {
1235   PetscInt       v;
1236   PetscErrorCode ierr;
1237 
1238   PetscFunctionBegin;
1239   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1240   ierr = DMLabelLookupStratum(label, value, &v);CHKERRQ(ierr);
1241   if (v < 0) PetscFunctionReturn(0);
1242   if (label->validIS[v]) {
1243     if (label->bt) {
1244       PetscInt       i;
1245       const PetscInt *points;
1246 
1247       ierr = ISGetIndices(label->points[v], &points);CHKERRQ(ierr);
1248       for (i = 0; i < label->stratumSizes[v]; ++i) {
1249         const PetscInt point = points[i];
1250 
1251         if ((point < label->pStart) || (point >= label->pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, label->pStart, label->pEnd);
1252         ierr = PetscBTClear(label->bt, point - label->pStart);CHKERRQ(ierr);
1253       }
1254       ierr = ISRestoreIndices(label->points[v], &points);CHKERRQ(ierr);
1255     }
1256     label->stratumSizes[v] = 0;
1257     ierr = ISDestroy(&label->points[v]);CHKERRQ(ierr);
1258     ierr = ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, &label->points[v]);CHKERRQ(ierr);
1259     ierr = PetscObjectSetName((PetscObject) label->points[v], "indices");CHKERRQ(ierr);
1260     ierr = PetscObjectStateIncrease((PetscObject) label);CHKERRQ(ierr);
1261   } else {
1262     ierr = PetscHSetIClear(label->ht[v]);CHKERRQ(ierr);
1263   }
1264   PetscFunctionReturn(0);
1265 }
1266 
1267 /*@
1268   DMLabelFilter - Remove all points outside of [start, end)
1269 
1270   Not collective
1271 
1272   Input Parameters:
1273 + label - the DMLabel
1274 . start - the first point kept
1275 - end - one more than the last point kept
1276 
1277   Level: intermediate
1278 
1279 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1280 @*/
1281 PetscErrorCode DMLabelFilter(DMLabel label, PetscInt start, PetscInt end)
1282 {
1283   PetscInt       v;
1284   PetscErrorCode ierr;
1285 
1286   PetscFunctionBegin;
1287   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1288   ierr = DMLabelDestroyIndex(label);CHKERRQ(ierr);
1289   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
1290   for (v = 0; v < label->numStrata; ++v) {
1291     ierr = ISGeneralFilter(label->points[v], start, end);CHKERRQ(ierr);
1292   }
1293   ierr = DMLabelCreateIndex(label, start, end);CHKERRQ(ierr);
1294   PetscFunctionReturn(0);
1295 }
1296 
1297 /*@
1298   DMLabelPermute - Create a new label with permuted points
1299 
1300   Not collective
1301 
1302   Input Parameters:
1303 + label - the DMLabel
1304 - permutation - the point permutation
1305 
1306   Output Parameter:
1307 . labelnew - the new label containing the permuted points
1308 
1309   Level: intermediate
1310 
1311 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1312 @*/
1313 PetscErrorCode DMLabelPermute(DMLabel label, IS permutation, DMLabel *labelNew)
1314 {
1315   const PetscInt *perm;
1316   PetscInt        numValues, numPoints, v, q;
1317   PetscErrorCode  ierr;
1318 
1319   PetscFunctionBegin;
1320   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1321   PetscValidHeaderSpecific(permutation, IS_CLASSID, 2);
1322   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
1323   ierr = DMLabelDuplicate(label, labelNew);CHKERRQ(ierr);
1324   ierr = DMLabelGetNumValues(*labelNew, &numValues);CHKERRQ(ierr);
1325   ierr = ISGetLocalSize(permutation, &numPoints);CHKERRQ(ierr);
1326   ierr = ISGetIndices(permutation, &perm);CHKERRQ(ierr);
1327   for (v = 0; v < numValues; ++v) {
1328     const PetscInt size   = (*labelNew)->stratumSizes[v];
1329     const PetscInt *points;
1330     PetscInt *pointsNew;
1331 
1332     ierr = ISGetIndices((*labelNew)->points[v],&points);CHKERRQ(ierr);
1333     ierr = PetscMalloc1(size,&pointsNew);CHKERRQ(ierr);
1334     for (q = 0; q < size; ++q) {
1335       const PetscInt point = points[q];
1336 
1337       if ((point < 0) || (point >= numPoints)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [0, %D) for the remapping", point, numPoints);
1338       pointsNew[q] = perm[point];
1339     }
1340     ierr = ISRestoreIndices((*labelNew)->points[v],&points);CHKERRQ(ierr);
1341     ierr = PetscSortInt(size, pointsNew);CHKERRQ(ierr);
1342     ierr = ISDestroy(&((*labelNew)->points[v]));CHKERRQ(ierr);
1343     if (size > 0 && pointsNew[size - 1] == pointsNew[0] + size - 1) {
1344       ierr = ISCreateStride(PETSC_COMM_SELF,size,pointsNew[0],1,&((*labelNew)->points[v]));CHKERRQ(ierr);
1345       ierr = PetscFree(pointsNew);CHKERRQ(ierr);
1346     } else {
1347       ierr = ISCreateGeneral(PETSC_COMM_SELF,size,pointsNew,PETSC_OWN_POINTER,&((*labelNew)->points[v]));CHKERRQ(ierr);
1348     }
1349     ierr = PetscObjectSetName((PetscObject) ((*labelNew)->points[v]), "indices");CHKERRQ(ierr);
1350   }
1351   ierr = ISRestoreIndices(permutation, &perm);CHKERRQ(ierr);
1352   if (label->bt) {
1353     ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);
1354     ierr = DMLabelCreateIndex(label, label->pStart, label->pEnd);CHKERRQ(ierr);
1355   }
1356   PetscFunctionReturn(0);
1357 }
1358 
1359 PetscErrorCode DMLabelDistribute_Internal(DMLabel label, PetscSF sf, PetscSection *leafSection, PetscInt **leafStrata)
1360 {
1361   MPI_Comm       comm;
1362   PetscInt       s, l, nroots, nleaves, dof, offset, size;
1363   PetscInt      *remoteOffsets, *rootStrata, *rootIdx;
1364   PetscSection   rootSection;
1365   PetscSF        labelSF;
1366   PetscErrorCode ierr;
1367 
1368   PetscFunctionBegin;
1369   if (label) {ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);}
1370   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
1371   /* Build a section of stratum values per point, generate the according SF
1372      and distribute point-wise stratum values to leaves. */
1373   ierr = PetscSFGetGraph(sf, &nroots, &nleaves, NULL, NULL);CHKERRQ(ierr);
1374   ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr);
1375   ierr = PetscSectionSetChart(rootSection, 0, nroots);CHKERRQ(ierr);
1376   if (label) {
1377     for (s = 0; s < label->numStrata; ++s) {
1378       const PetscInt *points;
1379 
1380       ierr = ISGetIndices(label->points[s], &points);CHKERRQ(ierr);
1381       for (l = 0; l < label->stratumSizes[s]; l++) {
1382         ierr = PetscSectionGetDof(rootSection, points[l], &dof);CHKERRQ(ierr);
1383         ierr = PetscSectionSetDof(rootSection, points[l], dof+1);CHKERRQ(ierr);
1384       }
1385       ierr = ISRestoreIndices(label->points[s], &points);CHKERRQ(ierr);
1386     }
1387   }
1388   ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
1389   /* Create a point-wise array of stratum values */
1390   ierr = PetscSectionGetStorageSize(rootSection, &size);CHKERRQ(ierr);
1391   ierr = PetscMalloc1(size, &rootStrata);CHKERRQ(ierr);
1392   ierr = PetscCalloc1(nroots, &rootIdx);CHKERRQ(ierr);
1393   if (label) {
1394     for (s = 0; s < label->numStrata; ++s) {
1395       const PetscInt *points;
1396 
1397       ierr = ISGetIndices(label->points[s], &points);CHKERRQ(ierr);
1398       for (l = 0; l < label->stratumSizes[s]; l++) {
1399         const PetscInt p = points[l];
1400         ierr = PetscSectionGetOffset(rootSection, p, &offset);CHKERRQ(ierr);
1401         rootStrata[offset+rootIdx[p]++] = label->stratumValues[s];
1402       }
1403       ierr = ISRestoreIndices(label->points[s], &points);CHKERRQ(ierr);
1404     }
1405   }
1406   /* Build SF that maps label points to remote processes */
1407   ierr = PetscSectionCreate(comm, leafSection);CHKERRQ(ierr);
1408   ierr = PetscSFDistributeSection(sf, rootSection, &remoteOffsets, *leafSection);CHKERRQ(ierr);
1409   ierr = PetscSFCreateSectionSF(sf, rootSection, remoteOffsets, *leafSection, &labelSF);CHKERRQ(ierr);
1410   ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
1411   /* Send the strata for each point over the derived SF */
1412   ierr = PetscSectionGetStorageSize(*leafSection, &size);CHKERRQ(ierr);
1413   ierr = PetscMalloc1(size, leafStrata);CHKERRQ(ierr);
1414   ierr = PetscSFBcastBegin(labelSF, MPIU_INT, rootStrata, *leafStrata);CHKERRQ(ierr);
1415   ierr = PetscSFBcastEnd(labelSF, MPIU_INT, rootStrata, *leafStrata);CHKERRQ(ierr);
1416   /* Clean up */
1417   ierr = PetscFree(rootStrata);CHKERRQ(ierr);
1418   ierr = PetscFree(rootIdx);CHKERRQ(ierr);
1419   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
1420   ierr = PetscSFDestroy(&labelSF);CHKERRQ(ierr);
1421   PetscFunctionReturn(0);
1422 }
1423 
1424 /*@
1425   DMLabelDistribute - Create a new label pushed forward over the PetscSF
1426 
1427   Collective on sf
1428 
1429   Input Parameters:
1430 + label - the DMLabel
1431 - sf    - the map from old to new distribution
1432 
1433   Output Parameter:
1434 . labelnew - the new redistributed label
1435 
1436   Level: intermediate
1437 
1438 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1439 @*/
1440 PetscErrorCode DMLabelDistribute(DMLabel label, PetscSF sf, DMLabel *labelNew)
1441 {
1442   MPI_Comm       comm;
1443   PetscSection   leafSection;
1444   PetscInt       p, pStart, pEnd, s, size, dof, offset, stratum;
1445   PetscInt      *leafStrata, *strataIdx;
1446   PetscInt     **points;
1447   const char    *lname = NULL;
1448   char          *name;
1449   PetscInt       nameSize;
1450   PetscHSetI     stratumHash;
1451   size_t         len = 0;
1452   PetscMPIInt    rank;
1453   PetscErrorCode ierr;
1454 
1455   PetscFunctionBegin;
1456   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
1457   if (label) {
1458     PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1459     ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
1460   }
1461   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
1462   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1463   /* Bcast name */
1464   if (!rank) {
1465     ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
1466     ierr = PetscStrlen(lname, &len);CHKERRQ(ierr);
1467   }
1468   nameSize = len;
1469   ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
1470   ierr = PetscMalloc1(nameSize+1, &name);CHKERRQ(ierr);
1471   if (!rank) {ierr = PetscArraycpy(name, lname, nameSize+1);CHKERRQ(ierr);}
1472   ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
1473   ierr = DMLabelCreate(PETSC_COMM_SELF, name, labelNew);CHKERRQ(ierr);
1474   ierr = PetscFree(name);CHKERRQ(ierr);
1475   /* Bcast defaultValue */
1476   if (!rank) (*labelNew)->defaultValue = label->defaultValue;
1477   ierr = MPI_Bcast(&(*labelNew)->defaultValue, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
1478   /* Distribute stratum values over the SF and get the point mapping on the receiver */
1479   ierr = DMLabelDistribute_Internal(label, sf, &leafSection, &leafStrata);CHKERRQ(ierr);
1480   /* Determine received stratum values and initialise new label*/
1481   ierr = PetscHSetICreate(&stratumHash);CHKERRQ(ierr);
1482   ierr = PetscSectionGetStorageSize(leafSection, &size);CHKERRQ(ierr);
1483   for (p = 0; p < size; ++p) {ierr = PetscHSetIAdd(stratumHash, leafStrata[p]);CHKERRQ(ierr);}
1484   ierr = PetscHSetIGetSize(stratumHash, &(*labelNew)->numStrata);CHKERRQ(ierr);
1485   ierr = PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->validIS);CHKERRQ(ierr);
1486   for (s = 0; s < (*labelNew)->numStrata; ++s) (*labelNew)->validIS[s] = PETSC_TRUE;
1487   ierr = PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->stratumValues);CHKERRQ(ierr);
1488   /* Turn leafStrata into indices rather than stratum values */
1489   offset = 0;
1490   ierr = PetscHSetIGetElems(stratumHash, &offset, (*labelNew)->stratumValues);CHKERRQ(ierr);
1491   ierr = PetscSortInt((*labelNew)->numStrata,(*labelNew)->stratumValues);CHKERRQ(ierr);
1492   for (s = 0; s < (*labelNew)->numStrata; ++s) {
1493     ierr = PetscHMapISet((*labelNew)->hmap, (*labelNew)->stratumValues[s], s);CHKERRQ(ierr);
1494   }
1495   for (p = 0; p < size; ++p) {
1496     for (s = 0; s < (*labelNew)->numStrata; ++s) {
1497       if (leafStrata[p] == (*labelNew)->stratumValues[s]) {leafStrata[p] = s; break;}
1498     }
1499   }
1500   /* Rebuild the point strata on the receiver */
1501   ierr = PetscCalloc1((*labelNew)->numStrata,&(*labelNew)->stratumSizes);CHKERRQ(ierr);
1502   ierr = PetscSectionGetChart(leafSection, &pStart, &pEnd);CHKERRQ(ierr);
1503   for (p=pStart; p<pEnd; p++) {
1504     ierr = PetscSectionGetDof(leafSection, p, &dof);CHKERRQ(ierr);
1505     ierr = PetscSectionGetOffset(leafSection, p, &offset);CHKERRQ(ierr);
1506     for (s=0; s<dof; s++) {
1507       (*labelNew)->stratumSizes[leafStrata[offset+s]]++;
1508     }
1509   }
1510   ierr = PetscCalloc1((*labelNew)->numStrata,&(*labelNew)->ht);CHKERRQ(ierr);
1511   ierr = PetscMalloc1((*labelNew)->numStrata,&(*labelNew)->points);CHKERRQ(ierr);
1512   ierr = PetscMalloc1((*labelNew)->numStrata,&points);CHKERRQ(ierr);
1513   for (s = 0; s < (*labelNew)->numStrata; ++s) {
1514     ierr = PetscHSetICreate(&(*labelNew)->ht[s]);CHKERRQ(ierr);
1515     ierr = PetscMalloc1((*labelNew)->stratumSizes[s], &(points[s]));CHKERRQ(ierr);
1516   }
1517   /* Insert points into new strata */
1518   ierr = PetscCalloc1((*labelNew)->numStrata, &strataIdx);CHKERRQ(ierr);
1519   ierr = PetscSectionGetChart(leafSection, &pStart, &pEnd);CHKERRQ(ierr);
1520   for (p=pStart; p<pEnd; p++) {
1521     ierr = PetscSectionGetDof(leafSection, p, &dof);CHKERRQ(ierr);
1522     ierr = PetscSectionGetOffset(leafSection, p, &offset);CHKERRQ(ierr);
1523     for (s=0; s<dof; s++) {
1524       stratum = leafStrata[offset+s];
1525       points[stratum][strataIdx[stratum]++] = p;
1526     }
1527   }
1528   for (s = 0; s < (*labelNew)->numStrata; s++) {
1529     ierr = ISCreateGeneral(PETSC_COMM_SELF,(*labelNew)->stratumSizes[s],&(points[s][0]),PETSC_OWN_POINTER,&((*labelNew)->points[s]));CHKERRQ(ierr);
1530     ierr = PetscObjectSetName((PetscObject)((*labelNew)->points[s]),"indices");CHKERRQ(ierr);
1531   }
1532   ierr = PetscFree(points);CHKERRQ(ierr);
1533   ierr = PetscHSetIDestroy(&stratumHash);CHKERRQ(ierr);
1534   ierr = PetscFree(leafStrata);CHKERRQ(ierr);
1535   ierr = PetscFree(strataIdx);CHKERRQ(ierr);
1536   ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
1537   PetscFunctionReturn(0);
1538 }
1539 
1540 /*@
1541   DMLabelGather - Gather all label values from leafs into roots
1542 
1543   Collective on sf
1544 
1545   Input Parameters:
1546 + label - the DMLabel
1547 - sf - the Star Forest point communication map
1548 
1549   Output Parameters:
1550 . labelNew - the new DMLabel with localised leaf values
1551 
1552   Level: developer
1553 
1554   Note: This is the inverse operation to DMLabelDistribute.
1555 
1556 .seealso: DMLabelDistribute()
1557 @*/
1558 PetscErrorCode DMLabelGather(DMLabel label, PetscSF sf, DMLabel *labelNew)
1559 {
1560   MPI_Comm       comm;
1561   PetscSection   rootSection;
1562   PetscSF        sfLabel;
1563   PetscSFNode   *rootPoints, *leafPoints;
1564   PetscInt       p, s, d, nroots, nleaves, nmultiroots, idx, dof, offset;
1565   const PetscInt *rootDegree, *ilocal;
1566   PetscInt       *rootStrata;
1567   const char    *lname;
1568   char          *name;
1569   PetscInt       nameSize;
1570   size_t         len = 0;
1571   PetscMPIInt    rank, size;
1572   PetscErrorCode ierr;
1573 
1574   PetscFunctionBegin;
1575   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1576   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
1577   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
1578   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1579   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
1580   /* Bcast name */
1581   if (!rank) {
1582     ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
1583     ierr = PetscStrlen(lname, &len);CHKERRQ(ierr);
1584   }
1585   nameSize = len;
1586   ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
1587   ierr = PetscMalloc1(nameSize+1, &name);CHKERRQ(ierr);
1588   if (!rank) {ierr = PetscArraycpy(name, lname, nameSize+1);CHKERRQ(ierr);}
1589   ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
1590   ierr = DMLabelCreate(PETSC_COMM_SELF, name, labelNew);CHKERRQ(ierr);
1591   ierr = PetscFree(name);CHKERRQ(ierr);
1592   /* Gather rank/index pairs of leaves into local roots to build
1593      an inverse, multi-rooted SF. Note that this ignores local leaf
1594      indexing due to the use of the multiSF in PetscSFGather. */
1595   ierr = PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, NULL);CHKERRQ(ierr);
1596   ierr = PetscMalloc1(nroots, &leafPoints);CHKERRQ(ierr);
1597   for (p = 0; p < nroots; ++p) leafPoints[p].rank = leafPoints[p].index = -1;
1598   for (p = 0; p < nleaves; p++) {
1599     PetscInt ilp = ilocal ? ilocal[p] : p;
1600 
1601     leafPoints[ilp].index = ilp;
1602     leafPoints[ilp].rank  = rank;
1603   }
1604   ierr = PetscSFComputeDegreeBegin(sf, &rootDegree);CHKERRQ(ierr);
1605   ierr = PetscSFComputeDegreeEnd(sf, &rootDegree);CHKERRQ(ierr);
1606   for (p = 0, nmultiroots = 0; p < nroots; ++p) nmultiroots += rootDegree[p];
1607   ierr = PetscMalloc1(nmultiroots, &rootPoints);CHKERRQ(ierr);
1608   ierr = PetscSFGatherBegin(sf, MPIU_2INT, leafPoints, rootPoints);CHKERRQ(ierr);
1609   ierr = PetscSFGatherEnd(sf, MPIU_2INT, leafPoints, rootPoints);CHKERRQ(ierr);
1610   ierr = PetscSFCreate(comm,& sfLabel);CHKERRQ(ierr);
1611   ierr = PetscSFSetGraph(sfLabel, nroots, nmultiroots, NULL, PETSC_OWN_POINTER, rootPoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
1612   /* Migrate label over inverted SF to pull stratum values at leaves into roots. */
1613   ierr = DMLabelDistribute_Internal(label, sfLabel, &rootSection, &rootStrata);CHKERRQ(ierr);
1614   /* Rebuild the point strata on the receiver */
1615   for (p = 0, idx = 0; p < nroots; p++) {
1616     for (d = 0; d < rootDegree[p]; d++) {
1617       ierr = PetscSectionGetDof(rootSection, idx+d, &dof);CHKERRQ(ierr);
1618       ierr = PetscSectionGetOffset(rootSection, idx+d, &offset);CHKERRQ(ierr);
1619       for (s = 0; s < dof; s++) {ierr = DMLabelSetValue(*labelNew, p, rootStrata[offset+s]);CHKERRQ(ierr);}
1620     }
1621     idx += rootDegree[p];
1622   }
1623   ierr = PetscFree(leafPoints);CHKERRQ(ierr);
1624   ierr = PetscFree(rootStrata);CHKERRQ(ierr);
1625   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
1626   ierr = PetscSFDestroy(&sfLabel);CHKERRQ(ierr);
1627   PetscFunctionReturn(0);
1628 }
1629 
1630 /*@
1631   DMLabelConvertToSection - Make a PetscSection/IS pair that encodes the label
1632 
1633   Not collective
1634 
1635   Input Parameter:
1636 . label - the DMLabel
1637 
1638   Output Parameters:
1639 + section - the section giving offsets for each stratum
1640 - is - An IS containing all the label points
1641 
1642   Level: developer
1643 
1644 .seealso: DMLabelDistribute()
1645 @*/
1646 PetscErrorCode DMLabelConvertToSection(DMLabel label, PetscSection *section, IS *is)
1647 {
1648   IS              vIS;
1649   const PetscInt *values;
1650   PetscInt       *points;
1651   PetscInt        nV, vS = 0, vE = 0, v, N;
1652   PetscErrorCode  ierr;
1653 
1654   PetscFunctionBegin;
1655   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1656   ierr = DMLabelGetNumValues(label, &nV);CHKERRQ(ierr);
1657   ierr = DMLabelGetValueIS(label, &vIS);CHKERRQ(ierr);
1658   ierr = ISGetIndices(vIS, &values);CHKERRQ(ierr);
1659   if (nV) {vS = values[0]; vE = values[0]+1;}
1660   for (v = 1; v < nV; ++v) {
1661     vS = PetscMin(vS, values[v]);
1662     vE = PetscMax(vE, values[v]+1);
1663   }
1664   ierr = PetscSectionCreate(PETSC_COMM_SELF, section);CHKERRQ(ierr);
1665   ierr = PetscSectionSetChart(*section, vS, vE);CHKERRQ(ierr);
1666   for (v = 0; v < nV; ++v) {
1667     PetscInt n;
1668 
1669     ierr = DMLabelGetStratumSize(label, values[v], &n);CHKERRQ(ierr);
1670     ierr = PetscSectionSetDof(*section, values[v], n);CHKERRQ(ierr);
1671   }
1672   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
1673   ierr = PetscSectionGetStorageSize(*section, &N);CHKERRQ(ierr);
1674   ierr = PetscMalloc1(N, &points);CHKERRQ(ierr);
1675   for (v = 0; v < nV; ++v) {
1676     IS              is;
1677     const PetscInt *spoints;
1678     PetscInt        dof, off, p;
1679 
1680     ierr = PetscSectionGetDof(*section, values[v], &dof);CHKERRQ(ierr);
1681     ierr = PetscSectionGetOffset(*section, values[v], &off);CHKERRQ(ierr);
1682     ierr = DMLabelGetStratumIS(label, values[v], &is);CHKERRQ(ierr);
1683     ierr = ISGetIndices(is, &spoints);CHKERRQ(ierr);
1684     for (p = 0; p < dof; ++p) points[off+p] = spoints[p];
1685     ierr = ISRestoreIndices(is, &spoints);CHKERRQ(ierr);
1686     ierr = ISDestroy(&is);CHKERRQ(ierr);
1687   }
1688   ierr = ISRestoreIndices(vIS, &values);CHKERRQ(ierr);
1689   ierr = ISDestroy(&vIS);CHKERRQ(ierr);
1690   ierr = ISCreateGeneral(PETSC_COMM_SELF, N, points, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
1691   PetscFunctionReturn(0);
1692 }
1693 
1694 /*@
1695   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
1696   the local section and an SF describing the section point overlap.
1697 
1698   Collective on sf
1699 
1700   Input Parameters:
1701   + s - The PetscSection for the local field layout
1702   . sf - The SF describing parallel layout of the section points
1703   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
1704   . label - The label specifying the points
1705   - labelValue - The label stratum specifying the points
1706 
1707   Output Parameter:
1708   . gsection - The PetscSection for the global field layout
1709 
1710   Note: This gives negative sizes and offsets to points not owned by this process
1711 
1712   Level: developer
1713 
1714 .seealso: PetscSectionCreate()
1715 @*/
1716 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
1717 {
1718   PetscInt      *neg = NULL, *tmpOff = NULL;
1719   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
1720   PetscErrorCode ierr;
1721 
1722   PetscFunctionBegin;
1723   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1724   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
1725   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
1726   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), gsection);CHKERRQ(ierr);
1727   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
1728   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
1729   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
1730   if (nroots >= 0) {
1731     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
1732     ierr = PetscCalloc1(nroots, &neg);CHKERRQ(ierr);
1733     if (nroots > pEnd-pStart) {
1734       ierr = PetscCalloc1(nroots, &tmpOff);CHKERRQ(ierr);
1735     } else {
1736       tmpOff = &(*gsection)->atlasDof[-pStart];
1737     }
1738   }
1739   /* Mark ghost points with negative dof */
1740   for (p = pStart; p < pEnd; ++p) {
1741     PetscInt value;
1742 
1743     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
1744     if (value != labelValue) continue;
1745     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
1746     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
1747     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
1748     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
1749     if (neg) neg[p] = -(dof+1);
1750   }
1751   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
1752   if (nroots >= 0) {
1753     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1754     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1755     if (nroots > pEnd-pStart) {
1756       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
1757     }
1758   }
1759   /* Calculate new sizes, get proccess offset, and calculate point offsets */
1760   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
1761     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
1762     (*gsection)->atlasOff[p] = off;
1763     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
1764   }
1765   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) s));CHKERRQ(ierr);
1766   globalOff -= off;
1767   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
1768     (*gsection)->atlasOff[p] += globalOff;
1769     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
1770   }
1771   /* Put in negative offsets for ghost points */
1772   if (nroots >= 0) {
1773     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1774     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1775     if (nroots > pEnd-pStart) {
1776       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
1777     }
1778   }
1779   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
1780   ierr = PetscFree(neg);CHKERRQ(ierr);
1781   PetscFunctionReturn(0);
1782 }
1783 
1784 typedef struct _n_PetscSectionSym_Label
1785 {
1786   DMLabel           label;
1787   PetscCopyMode     *modes;
1788   PetscInt          *sizes;
1789   const PetscInt    ***perms;
1790   const PetscScalar ***rots;
1791   PetscInt          (*minMaxOrients)[2];
1792   PetscInt          numStrata; /* numStrata is only increasing, functions as a state */
1793 } PetscSectionSym_Label;
1794 
1795 static PetscErrorCode PetscSectionSymLabelReset(PetscSectionSym sym)
1796 {
1797   PetscInt              i, j;
1798   PetscSectionSym_Label *sl = (PetscSectionSym_Label *) sym->data;
1799   PetscErrorCode        ierr;
1800 
1801   PetscFunctionBegin;
1802   for (i = 0; i <= sl->numStrata; i++) {
1803     if (sl->modes[i] == PETSC_OWN_POINTER || sl->modes[i] == PETSC_COPY_VALUES) {
1804       for (j = sl->minMaxOrients[i][0]; j < sl->minMaxOrients[i][1]; j++) {
1805         if (sl->perms[i]) {ierr = PetscFree(sl->perms[i][j]);CHKERRQ(ierr);}
1806         if (sl->rots[i]) {ierr = PetscFree(sl->rots[i][j]);CHKERRQ(ierr);}
1807       }
1808       if (sl->perms[i]) {
1809         const PetscInt **perms = &sl->perms[i][sl->minMaxOrients[i][0]];
1810 
1811         ierr = PetscFree(perms);CHKERRQ(ierr);
1812       }
1813       if (sl->rots[i]) {
1814         const PetscScalar **rots = &sl->rots[i][sl->minMaxOrients[i][0]];
1815 
1816         ierr = PetscFree(rots);CHKERRQ(ierr);
1817       }
1818     }
1819   }
1820   ierr = PetscFree5(sl->modes,sl->sizes,sl->perms,sl->rots,sl->minMaxOrients);CHKERRQ(ierr);
1821   ierr = DMLabelDestroy(&sl->label);CHKERRQ(ierr);
1822   sl->numStrata = 0;
1823   PetscFunctionReturn(0);
1824 }
1825 
1826 static PetscErrorCode PetscSectionSymDestroy_Label(PetscSectionSym sym)
1827 {
1828   PetscErrorCode ierr;
1829 
1830   PetscFunctionBegin;
1831   ierr = PetscSectionSymLabelReset(sym);CHKERRQ(ierr);
1832   ierr = PetscFree(sym->data);CHKERRQ(ierr);
1833   PetscFunctionReturn(0);
1834 }
1835 
1836 static PetscErrorCode PetscSectionSymView_Label(PetscSectionSym sym, PetscViewer viewer)
1837 {
1838   PetscSectionSym_Label *sl = (PetscSectionSym_Label *) sym->data;
1839   PetscBool             isAscii;
1840   DMLabel               label = sl->label;
1841   const char           *name;
1842   PetscErrorCode        ierr;
1843 
1844   PetscFunctionBegin;
1845   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isAscii);CHKERRQ(ierr);
1846   if (isAscii) {
1847     PetscInt          i, j, k;
1848     PetscViewerFormat format;
1849 
1850     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
1851     if (label) {
1852       ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
1853       if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1854         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1855         ierr = DMLabelView(label, viewer);CHKERRQ(ierr);
1856         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1857       } else {
1858         ierr = PetscObjectGetName((PetscObject) sl->label, &name);CHKERRQ(ierr);
1859         ierr = PetscViewerASCIIPrintf(viewer,"  Label '%s'\n",name);CHKERRQ(ierr);
1860       }
1861     } else {
1862       ierr = PetscViewerASCIIPrintf(viewer, "No label given\n");CHKERRQ(ierr);
1863     }
1864     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1865     for (i = 0; i <= sl->numStrata; i++) {
1866       PetscInt value = i < sl->numStrata ? label->stratumValues[i] : label->defaultValue;
1867 
1868       if (!(sl->perms[i] || sl->rots[i])) {
1869         ierr = PetscViewerASCIIPrintf(viewer, "Symmetry for stratum value %D (%D dofs per point): no symmetries\n", value, sl->sizes[i]);CHKERRQ(ierr);
1870       } else {
1871       ierr = PetscViewerASCIIPrintf(viewer, "Symmetry for stratum value %D (%D dofs per point):\n", value, sl->sizes[i]);CHKERRQ(ierr);
1872         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1873         ierr = PetscViewerASCIIPrintf(viewer, "Orientation range: [%D, %D)\n", sl->minMaxOrients[i][0], sl->minMaxOrients[i][1]);CHKERRQ(ierr);
1874         if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1875           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1876           for (j = sl->minMaxOrients[i][0]; j < sl->minMaxOrients[i][1]; j++) {
1877             if (!((sl->perms[i] && sl->perms[i][j]) || (sl->rots[i] && sl->rots[i][j]))) {
1878               ierr = PetscViewerASCIIPrintf(viewer, "Orientation %D: identity\n",j);CHKERRQ(ierr);
1879             } else {
1880               PetscInt tab;
1881 
1882               ierr = PetscViewerASCIIPrintf(viewer, "Orientation %D:\n",j);CHKERRQ(ierr);
1883               ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1884               ierr = PetscViewerASCIIGetTab(viewer,&tab);CHKERRQ(ierr);
1885               if (sl->perms[i] && sl->perms[i][j]) {
1886                 ierr = PetscViewerASCIIPrintf(viewer,"Permutation:");CHKERRQ(ierr);
1887                 ierr = PetscViewerASCIISetTab(viewer,0);CHKERRQ(ierr);
1888                 for (k = 0; k < sl->sizes[i]; k++) {ierr = PetscViewerASCIIPrintf(viewer," %D",sl->perms[i][j][k]);CHKERRQ(ierr);}
1889                 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
1890                 ierr = PetscViewerASCIISetTab(viewer,tab);CHKERRQ(ierr);
1891               }
1892               if (sl->rots[i] && sl->rots[i][j]) {
1893                 ierr = PetscViewerASCIIPrintf(viewer,"Rotations:  ");CHKERRQ(ierr);
1894                 ierr = PetscViewerASCIISetTab(viewer,0);CHKERRQ(ierr);
1895 #if defined(PETSC_USE_COMPLEX)
1896                 for (k = 0; k < sl->sizes[i]; k++) {ierr = PetscViewerASCIIPrintf(viewer," %+f+i*%+f",PetscRealPart(sl->rots[i][j][k]),PetscImaginaryPart(sl->rots[i][j][k]));CHKERRQ(ierr);}
1897 #else
1898                 for (k = 0; k < sl->sizes[i]; k++) {ierr = PetscViewerASCIIPrintf(viewer," %+f",sl->rots[i][j][k]);CHKERRQ(ierr);}
1899 #endif
1900                 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
1901                 ierr = PetscViewerASCIISetTab(viewer,tab);CHKERRQ(ierr);
1902               }
1903               ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1904             }
1905           }
1906           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1907         }
1908         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1909       }
1910     }
1911     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1912   }
1913   PetscFunctionReturn(0);
1914 }
1915 
1916 /*@
1917   PetscSectionSymLabelSetLabel - set the label whose strata will define the points that receive symmetries
1918 
1919   Logically collective on sym
1920 
1921   Input parameters:
1922 + sym - the section symmetries
1923 - label - the DMLabel describing the types of points
1924 
1925   Level: developer:
1926 
1927 .seealso: PetscSectionSymLabelSetStratum(), PetscSectionSymCreateLabel(), PetscSectionGetPointSyms()
1928 @*/
1929 PetscErrorCode PetscSectionSymLabelSetLabel(PetscSectionSym sym, DMLabel label)
1930 {
1931   PetscSectionSym_Label *sl;
1932   PetscErrorCode        ierr;
1933 
1934   PetscFunctionBegin;
1935   PetscValidHeaderSpecific(sym,PETSC_SECTION_SYM_CLASSID,1);
1936   sl = (PetscSectionSym_Label *) sym->data;
1937   if (sl->label && sl->label != label) {ierr = PetscSectionSymLabelReset(sym);CHKERRQ(ierr);}
1938   if (label) {
1939     sl->label = label;
1940     ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
1941     ierr = DMLabelGetNumValues(label,&sl->numStrata);CHKERRQ(ierr);
1942     ierr = PetscMalloc5(sl->numStrata+1,&sl->modes,sl->numStrata+1,&sl->sizes,sl->numStrata+1,&sl->perms,sl->numStrata+1,&sl->rots,sl->numStrata+1,&sl->minMaxOrients);CHKERRQ(ierr);
1943     ierr = PetscMemzero((void *) sl->modes,(sl->numStrata+1)*sizeof(PetscCopyMode));CHKERRQ(ierr);
1944     ierr = PetscMemzero((void *) sl->sizes,(sl->numStrata+1)*sizeof(PetscInt));CHKERRQ(ierr);
1945     ierr = PetscMemzero((void *) sl->perms,(sl->numStrata+1)*sizeof(const PetscInt **));CHKERRQ(ierr);
1946     ierr = PetscMemzero((void *) sl->rots,(sl->numStrata+1)*sizeof(const PetscScalar **));CHKERRQ(ierr);
1947     ierr = PetscMemzero((void *) sl->minMaxOrients,(sl->numStrata+1)*sizeof(PetscInt[2]));CHKERRQ(ierr);
1948   }
1949   PetscFunctionReturn(0);
1950 }
1951 
1952 /*@C
1953   PetscSectionSymLabelSetStratum - set the symmetries for the orientations of a stratum
1954 
1955   Logically collective on sym
1956 
1957   InputParameters:
1958 + sym       - the section symmetries
1959 . stratum   - the stratum value in the label that we are assigning symmetries for
1960 . size      - the number of dofs for points in the stratum of the label
1961 . minOrient - the smallest orientation for a point in this stratum
1962 . maxOrient - one greater than the largest orientation for a ppoint in this stratum (i.e., orientations are in the range [minOrient, maxOrient))
1963 . mode      - how sym should copy the perms and rots arrays
1964 . perms     - NULL if there are no permutations, or (maxOrient - minOrient) permutations, one for each orientation.  A NULL permutation is the identity
1965 - rots      - NULL if there are no rotations, or (maxOrient - minOrient) sets of rotations, one for each orientation.  A NULL set of orientations is the identity
1966 
1967   Level: developer
1968 
1969 .seealso: PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetPointSyms(), PetscSectionSymCreateLabel()
1970 @*/
1971 PetscErrorCode PetscSectionSymLabelSetStratum(PetscSectionSym sym, PetscInt stratum, PetscInt size, PetscInt minOrient, PetscInt maxOrient, PetscCopyMode mode, const PetscInt **perms, const PetscScalar **rots)
1972 {
1973   PetscSectionSym_Label *sl;
1974   const char            *name;
1975   PetscInt               i, j, k;
1976   PetscErrorCode         ierr;
1977 
1978   PetscFunctionBegin;
1979   PetscValidHeaderSpecific(sym,PETSC_SECTION_SYM_CLASSID,1);
1980   sl = (PetscSectionSym_Label *) sym->data;
1981   if (!sl->label) SETERRQ(PetscObjectComm((PetscObject)sym),PETSC_ERR_ARG_WRONGSTATE,"No label set yet");
1982   for (i = 0; i <= sl->numStrata; i++) {
1983     PetscInt value = (i < sl->numStrata) ? sl->label->stratumValues[i] : sl->label->defaultValue;
1984 
1985     if (stratum == value) break;
1986   }
1987   ierr = PetscObjectGetName((PetscObject) sl->label, &name);CHKERRQ(ierr);
1988   if (i > sl->numStrata) SETERRQ2(PetscObjectComm((PetscObject)sym),PETSC_ERR_ARG_OUTOFRANGE,"Stratum %D not found in label %s\n",stratum,name);
1989   sl->sizes[i] = size;
1990   sl->modes[i] = mode;
1991   sl->minMaxOrients[i][0] = minOrient;
1992   sl->minMaxOrients[i][1] = maxOrient;
1993   if (mode == PETSC_COPY_VALUES) {
1994     if (perms) {
1995       PetscInt    **ownPerms;
1996 
1997       ierr = PetscCalloc1(maxOrient - minOrient,&ownPerms);CHKERRQ(ierr);
1998       for (j = 0; j < maxOrient-minOrient; j++) {
1999         if (perms[j]) {
2000           ierr = PetscMalloc1(size,&ownPerms[j]);CHKERRQ(ierr);
2001           for (k = 0; k < size; k++) {ownPerms[j][k] = perms[j][k];}
2002         }
2003       }
2004       sl->perms[i] = (const PetscInt **) &ownPerms[-minOrient];
2005     }
2006     if (rots) {
2007       PetscScalar **ownRots;
2008 
2009       ierr = PetscCalloc1(maxOrient - minOrient,&ownRots);CHKERRQ(ierr);
2010       for (j = 0; j < maxOrient-minOrient; j++) {
2011         if (rots[j]) {
2012           ierr = PetscMalloc1(size,&ownRots[j]);CHKERRQ(ierr);
2013           for (k = 0; k < size; k++) {ownRots[j][k] = rots[j][k];}
2014         }
2015       }
2016       sl->rots[i] = (const PetscScalar **) &ownRots[-minOrient];
2017     }
2018   } else {
2019     sl->perms[i] = perms ? &perms[-minOrient] : NULL;
2020     sl->rots[i]  = rots ? &rots[-minOrient] : NULL;
2021   }
2022   PetscFunctionReturn(0);
2023 }
2024 
2025 static PetscErrorCode PetscSectionSymGetPoints_Label(PetscSectionSym sym, PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt **perms, const PetscScalar **rots)
2026 {
2027   PetscInt              i, j, numStrata;
2028   PetscSectionSym_Label *sl;
2029   DMLabel               label;
2030   PetscErrorCode        ierr;
2031 
2032   PetscFunctionBegin;
2033   sl = (PetscSectionSym_Label *) sym->data;
2034   numStrata = sl->numStrata;
2035   label     = sl->label;
2036   for (i = 0; i < numPoints; i++) {
2037     PetscInt point = points[2*i];
2038     PetscInt ornt  = points[2*i+1];
2039 
2040     for (j = 0; j < numStrata; j++) {
2041       if (label->validIS[j]) {
2042         PetscInt k;
2043 
2044         ierr = ISLocate(label->points[j],point,&k);CHKERRQ(ierr);
2045         if (k >= 0) break;
2046       } else {
2047         PetscBool has;
2048 
2049         ierr = PetscHSetIHas(label->ht[j], point, &has);CHKERRQ(ierr);
2050         if (has) break;
2051       }
2052     }
2053     if ((sl->minMaxOrients[j][1] > sl->minMaxOrients[j][0]) && (ornt < sl->minMaxOrients[j][0] || ornt >= sl->minMaxOrients[j][1])) SETERRQ5(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"point %D orientation %D not in range [%D, %D) for stratum %D",point,ornt,sl->minMaxOrients[j][0],sl->minMaxOrients[j][1],j < numStrata ? label->stratumValues[j] : label->defaultValue);
2054     if (perms) {perms[i] = sl->perms[j] ? sl->perms[j][ornt] : NULL;}
2055     if (rots) {rots[i]  = sl->rots[j] ? sl->rots[j][ornt] : NULL;}
2056   }
2057   PetscFunctionReturn(0);
2058 }
2059 
2060 PetscErrorCode PetscSectionSymCreate_Label(PetscSectionSym sym)
2061 {
2062   PetscSectionSym_Label *sl;
2063   PetscErrorCode        ierr;
2064 
2065   PetscFunctionBegin;
2066   ierr = PetscNewLog(sym,&sl);CHKERRQ(ierr);
2067   sym->ops->getpoints = PetscSectionSymGetPoints_Label;
2068   sym->ops->view      = PetscSectionSymView_Label;
2069   sym->ops->destroy   = PetscSectionSymDestroy_Label;
2070   sym->data           = (void *) sl;
2071   PetscFunctionReturn(0);
2072 }
2073 
2074 /*@
2075   PetscSectionSymCreateLabel - Create a section symmetry that assigns one symmetry to each stratum of a label
2076 
2077   Collective
2078 
2079   Input Parameters:
2080 + comm - the MPI communicator for the new symmetry
2081 - label - the label defining the strata
2082 
2083   Output Parameters:
2084 . sym - the section symmetries
2085 
2086   Level: developer
2087 
2088 .seealso: PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetSym(), PetscSectionSymLabelSetStratum(), PetscSectionGetPointSyms()
2089 @*/
2090 PetscErrorCode PetscSectionSymCreateLabel(MPI_Comm comm, DMLabel label, PetscSectionSym *sym)
2091 {
2092   PetscErrorCode        ierr;
2093 
2094   PetscFunctionBegin;
2095   ierr = DMInitializePackage();CHKERRQ(ierr);
2096   ierr = PetscSectionSymCreate(comm,sym);CHKERRQ(ierr);
2097   ierr = PetscSectionSymSetType(*sym,PETSCSECTIONSYMLABEL);CHKERRQ(ierr);
2098   ierr = PetscSectionSymLabelSetLabel(*sym,label);CHKERRQ(ierr);
2099   PetscFunctionReturn(0);
2100 }
2101