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