xref: /petsc/src/dm/label/dmlabel.c (revision c771d45aecabfae9acb9d61b056a28d9ce9991da)
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 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1152 @*/
1153 PetscErrorCode DMLabelGetStratumIS(DMLabel label, PetscInt value, IS *points)
1154 {
1155   PetscInt       v;
1156   PetscErrorCode ierr;
1157 
1158   PetscFunctionBegin;
1159   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1160   PetscValidPointer(points, 3);
1161   *points = NULL;
1162   ierr = DMLabelLookupStratum(label, value, &v);CHKERRQ(ierr);
1163   if (v < 0) PetscFunctionReturn(0);
1164   ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
1165   ierr = PetscObjectReference((PetscObject) label->points[v]);CHKERRQ(ierr);
1166   *points = label->points[v];
1167   PetscFunctionReturn(0);
1168 }
1169 
1170 /*@
1171   DMLabelSetStratumIS - Set the stratum points using an IS
1172 
1173   Not collective
1174 
1175   Input Parameters:
1176 + label - the DMLabel
1177 . value - the stratum value
1178 - points - The stratum points
1179 
1180   Level: intermediate
1181 
1182 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1183 @*/
1184 PetscErrorCode DMLabelSetStratumIS(DMLabel label, PetscInt value, IS is)
1185 {
1186   PetscInt       v;
1187   PetscErrorCode ierr;
1188 
1189   PetscFunctionBegin;
1190   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1191   PetscValidHeaderSpecific(is, IS_CLASSID, 3);
1192   ierr = DMLabelLookupAddStratum(label, value, &v);CHKERRQ(ierr);
1193   if (is == label->points[v]) PetscFunctionReturn(0);
1194   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
1195   ierr = ISGetLocalSize(is, &(label->stratumSizes[v]));CHKERRQ(ierr);
1196   ierr = PetscObjectReference((PetscObject)is);CHKERRQ(ierr);
1197   ierr = ISDestroy(&(label->points[v]));CHKERRQ(ierr);
1198   label->points[v]  = is;
1199   label->validIS[v] = PETSC_TRUE;
1200   ierr = PetscObjectStateIncrease((PetscObject) label);CHKERRQ(ierr);
1201   if (label->bt) {
1202     const PetscInt *points;
1203     PetscInt p;
1204 
1205     ierr = ISGetIndices(is,&points);CHKERRQ(ierr);
1206     for (p = 0; p < label->stratumSizes[v]; ++p) {
1207       const PetscInt point = points[p];
1208 
1209       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);
1210       ierr = PetscBTSet(label->bt, point - label->pStart);CHKERRQ(ierr);
1211     }
1212   }
1213   PetscFunctionReturn(0);
1214 }
1215 
1216 /*@
1217   DMLabelClearStratum - Remove a stratum
1218 
1219   Not collective
1220 
1221   Input Parameters:
1222 + label - the DMLabel
1223 - value - the stratum value
1224 
1225   Level: intermediate
1226 
1227 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1228 @*/
1229 PetscErrorCode DMLabelClearStratum(DMLabel label, PetscInt value)
1230 {
1231   PetscInt       v;
1232   PetscErrorCode ierr;
1233 
1234   PetscFunctionBegin;
1235   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1236   ierr = DMLabelLookupStratum(label, value, &v);CHKERRQ(ierr);
1237   if (v < 0) PetscFunctionReturn(0);
1238   if (label->validIS[v]) {
1239     if (label->bt) {
1240       PetscInt       i;
1241       const PetscInt *points;
1242 
1243       ierr = ISGetIndices(label->points[v], &points);CHKERRQ(ierr);
1244       for (i = 0; i < label->stratumSizes[v]; ++i) {
1245         const PetscInt point = points[i];
1246 
1247         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);
1248         ierr = PetscBTClear(label->bt, point - label->pStart);CHKERRQ(ierr);
1249       }
1250       ierr = ISRestoreIndices(label->points[v], &points);CHKERRQ(ierr);
1251     }
1252     label->stratumSizes[v] = 0;
1253     ierr = ISDestroy(&label->points[v]);CHKERRQ(ierr);
1254     ierr = ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, &label->points[v]);CHKERRQ(ierr);
1255     ierr = PetscObjectSetName((PetscObject) label->points[v], "indices");CHKERRQ(ierr);
1256     ierr = PetscObjectStateIncrease((PetscObject) label);CHKERRQ(ierr);
1257   } else {
1258     ierr = PetscHSetIClear(label->ht[v]);CHKERRQ(ierr);
1259   }
1260   PetscFunctionReturn(0);
1261 }
1262 
1263 /*@
1264   DMLabelFilter - Remove all points outside of [start, end)
1265 
1266   Not collective
1267 
1268   Input Parameters:
1269 + label - the DMLabel
1270 . start - the first point kept
1271 - end - one more than the last point kept
1272 
1273   Level: intermediate
1274 
1275 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1276 @*/
1277 PetscErrorCode DMLabelFilter(DMLabel label, PetscInt start, PetscInt end)
1278 {
1279   PetscInt       v;
1280   PetscErrorCode ierr;
1281 
1282   PetscFunctionBegin;
1283   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1284   ierr = DMLabelDestroyIndex(label);CHKERRQ(ierr);
1285   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
1286   for (v = 0; v < label->numStrata; ++v) {
1287     ierr = ISGeneralFilter(label->points[v], start, end);CHKERRQ(ierr);
1288   }
1289   ierr = DMLabelCreateIndex(label, start, end);CHKERRQ(ierr);
1290   PetscFunctionReturn(0);
1291 }
1292 
1293 /*@
1294   DMLabelPermute - Create a new label with permuted points
1295 
1296   Not collective
1297 
1298   Input Parameters:
1299 + label - the DMLabel
1300 - permutation - the point permutation
1301 
1302   Output Parameter:
1303 . labelnew - the new label containing the permuted points
1304 
1305   Level: intermediate
1306 
1307 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1308 @*/
1309 PetscErrorCode DMLabelPermute(DMLabel label, IS permutation, DMLabel *labelNew)
1310 {
1311   const PetscInt *perm;
1312   PetscInt        numValues, numPoints, v, q;
1313   PetscErrorCode  ierr;
1314 
1315   PetscFunctionBegin;
1316   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1317   PetscValidHeaderSpecific(permutation, IS_CLASSID, 2);
1318   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
1319   ierr = DMLabelDuplicate(label, labelNew);CHKERRQ(ierr);
1320   ierr = DMLabelGetNumValues(*labelNew, &numValues);CHKERRQ(ierr);
1321   ierr = ISGetLocalSize(permutation, &numPoints);CHKERRQ(ierr);
1322   ierr = ISGetIndices(permutation, &perm);CHKERRQ(ierr);
1323   for (v = 0; v < numValues; ++v) {
1324     const PetscInt size   = (*labelNew)->stratumSizes[v];
1325     const PetscInt *points;
1326     PetscInt *pointsNew;
1327 
1328     ierr = ISGetIndices((*labelNew)->points[v],&points);CHKERRQ(ierr);
1329     ierr = PetscMalloc1(size,&pointsNew);CHKERRQ(ierr);
1330     for (q = 0; q < size; ++q) {
1331       const PetscInt point = points[q];
1332 
1333       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);
1334       pointsNew[q] = perm[point];
1335     }
1336     ierr = ISRestoreIndices((*labelNew)->points[v],&points);CHKERRQ(ierr);
1337     ierr = PetscSortInt(size, pointsNew);CHKERRQ(ierr);
1338     ierr = ISDestroy(&((*labelNew)->points[v]));CHKERRQ(ierr);
1339     if (size > 0 && pointsNew[size - 1] == pointsNew[0] + size - 1) {
1340       ierr = ISCreateStride(PETSC_COMM_SELF,size,pointsNew[0],1,&((*labelNew)->points[v]));CHKERRQ(ierr);
1341       ierr = PetscFree(pointsNew);CHKERRQ(ierr);
1342     } else {
1343       ierr = ISCreateGeneral(PETSC_COMM_SELF,size,pointsNew,PETSC_OWN_POINTER,&((*labelNew)->points[v]));CHKERRQ(ierr);
1344     }
1345     ierr = PetscObjectSetName((PetscObject) ((*labelNew)->points[v]), "indices");CHKERRQ(ierr);
1346   }
1347   ierr = ISRestoreIndices(permutation, &perm);CHKERRQ(ierr);
1348   if (label->bt) {
1349     ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);
1350     ierr = DMLabelCreateIndex(label, label->pStart, label->pEnd);CHKERRQ(ierr);
1351   }
1352   PetscFunctionReturn(0);
1353 }
1354 
1355 PetscErrorCode DMLabelDistribute_Internal(DMLabel label, PetscSF sf, PetscSection *leafSection, PetscInt **leafStrata)
1356 {
1357   MPI_Comm       comm;
1358   PetscInt       s, l, nroots, nleaves, dof, offset, size;
1359   PetscInt      *remoteOffsets, *rootStrata, *rootIdx;
1360   PetscSection   rootSection;
1361   PetscSF        labelSF;
1362   PetscErrorCode ierr;
1363 
1364   PetscFunctionBegin;
1365   if (label) {ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);}
1366   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
1367   /* Build a section of stratum values per point, generate the according SF
1368      and distribute point-wise stratum values to leaves. */
1369   ierr = PetscSFGetGraph(sf, &nroots, &nleaves, NULL, NULL);CHKERRQ(ierr);
1370   ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr);
1371   ierr = PetscSectionSetChart(rootSection, 0, nroots);CHKERRQ(ierr);
1372   if (label) {
1373     for (s = 0; s < label->numStrata; ++s) {
1374       const PetscInt *points;
1375 
1376       ierr = ISGetIndices(label->points[s], &points);CHKERRQ(ierr);
1377       for (l = 0; l < label->stratumSizes[s]; l++) {
1378         ierr = PetscSectionGetDof(rootSection, points[l], &dof);CHKERRQ(ierr);
1379         ierr = PetscSectionSetDof(rootSection, points[l], dof+1);CHKERRQ(ierr);
1380       }
1381       ierr = ISRestoreIndices(label->points[s], &points);CHKERRQ(ierr);
1382     }
1383   }
1384   ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
1385   /* Create a point-wise array of stratum values */
1386   ierr = PetscSectionGetStorageSize(rootSection, &size);CHKERRQ(ierr);
1387   ierr = PetscMalloc1(size, &rootStrata);CHKERRQ(ierr);
1388   ierr = PetscCalloc1(nroots, &rootIdx);CHKERRQ(ierr);
1389   if (label) {
1390     for (s = 0; s < label->numStrata; ++s) {
1391       const PetscInt *points;
1392 
1393       ierr = ISGetIndices(label->points[s], &points);CHKERRQ(ierr);
1394       for (l = 0; l < label->stratumSizes[s]; l++) {
1395         const PetscInt p = points[l];
1396         ierr = PetscSectionGetOffset(rootSection, p, &offset);CHKERRQ(ierr);
1397         rootStrata[offset+rootIdx[p]++] = label->stratumValues[s];
1398       }
1399       ierr = ISRestoreIndices(label->points[s], &points);CHKERRQ(ierr);
1400     }
1401   }
1402   /* Build SF that maps label points to remote processes */
1403   ierr = PetscSectionCreate(comm, leafSection);CHKERRQ(ierr);
1404   ierr = PetscSFDistributeSection(sf, rootSection, &remoteOffsets, *leafSection);CHKERRQ(ierr);
1405   ierr = PetscSFCreateSectionSF(sf, rootSection, remoteOffsets, *leafSection, &labelSF);CHKERRQ(ierr);
1406   ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
1407   /* Send the strata for each point over the derived SF */
1408   ierr = PetscSectionGetStorageSize(*leafSection, &size);CHKERRQ(ierr);
1409   ierr = PetscMalloc1(size, leafStrata);CHKERRQ(ierr);
1410   ierr = PetscSFBcastBegin(labelSF, MPIU_INT, rootStrata, *leafStrata);CHKERRQ(ierr);
1411   ierr = PetscSFBcastEnd(labelSF, MPIU_INT, rootStrata, *leafStrata);CHKERRQ(ierr);
1412   /* Clean up */
1413   ierr = PetscFree(rootStrata);CHKERRQ(ierr);
1414   ierr = PetscFree(rootIdx);CHKERRQ(ierr);
1415   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
1416   ierr = PetscSFDestroy(&labelSF);CHKERRQ(ierr);
1417   PetscFunctionReturn(0);
1418 }
1419 
1420 /*@
1421   DMLabelDistribute - Create a new label pushed forward over the PetscSF
1422 
1423   Collective on sf
1424 
1425   Input Parameters:
1426 + label - the DMLabel
1427 - sf    - the map from old to new distribution
1428 
1429   Output Parameter:
1430 . labelnew - the new redistributed label
1431 
1432   Level: intermediate
1433 
1434 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
1435 @*/
1436 PetscErrorCode DMLabelDistribute(DMLabel label, PetscSF sf, DMLabel *labelNew)
1437 {
1438   MPI_Comm       comm;
1439   PetscSection   leafSection;
1440   PetscInt       p, pStart, pEnd, s, size, dof, offset, stratum;
1441   PetscInt      *leafStrata, *strataIdx;
1442   PetscInt     **points;
1443   const char    *lname = NULL;
1444   char          *name;
1445   PetscInt       nameSize;
1446   PetscHSetI     stratumHash;
1447   size_t         len = 0;
1448   PetscMPIInt    rank;
1449   PetscErrorCode ierr;
1450 
1451   PetscFunctionBegin;
1452   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
1453   if (label) {
1454     PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1455     ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
1456   }
1457   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
1458   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1459   /* Bcast name */
1460   if (!rank) {
1461     ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
1462     ierr = PetscStrlen(lname, &len);CHKERRQ(ierr);
1463   }
1464   nameSize = len;
1465   ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
1466   ierr = PetscMalloc1(nameSize+1, &name);CHKERRQ(ierr);
1467   if (!rank) {ierr = PetscArraycpy(name, lname, nameSize+1);CHKERRQ(ierr);}
1468   ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
1469   ierr = DMLabelCreate(PETSC_COMM_SELF, name, labelNew);CHKERRQ(ierr);
1470   ierr = PetscFree(name);CHKERRQ(ierr);
1471   /* Bcast defaultValue */
1472   if (!rank) (*labelNew)->defaultValue = label->defaultValue;
1473   ierr = MPI_Bcast(&(*labelNew)->defaultValue, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
1474   /* Distribute stratum values over the SF and get the point mapping on the receiver */
1475   ierr = DMLabelDistribute_Internal(label, sf, &leafSection, &leafStrata);CHKERRQ(ierr);
1476   /* Determine received stratum values and initialise new label*/
1477   ierr = PetscHSetICreate(&stratumHash);CHKERRQ(ierr);
1478   ierr = PetscSectionGetStorageSize(leafSection, &size);CHKERRQ(ierr);
1479   for (p = 0; p < size; ++p) {ierr = PetscHSetIAdd(stratumHash, leafStrata[p]);CHKERRQ(ierr);}
1480   ierr = PetscHSetIGetSize(stratumHash, &(*labelNew)->numStrata);CHKERRQ(ierr);
1481   ierr = PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->validIS);CHKERRQ(ierr);
1482   for (s = 0; s < (*labelNew)->numStrata; ++s) (*labelNew)->validIS[s] = PETSC_TRUE;
1483   ierr = PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->stratumValues);CHKERRQ(ierr);
1484   /* Turn leafStrata into indices rather than stratum values */
1485   offset = 0;
1486   ierr = PetscHSetIGetElems(stratumHash, &offset, (*labelNew)->stratumValues);CHKERRQ(ierr);
1487   ierr = PetscSortInt((*labelNew)->numStrata,(*labelNew)->stratumValues);CHKERRQ(ierr);
1488   for (s = 0; s < (*labelNew)->numStrata; ++s) {
1489     ierr = PetscHMapISet((*labelNew)->hmap, (*labelNew)->stratumValues[s], s);CHKERRQ(ierr);
1490   }
1491   for (p = 0; p < size; ++p) {
1492     for (s = 0; s < (*labelNew)->numStrata; ++s) {
1493       if (leafStrata[p] == (*labelNew)->stratumValues[s]) {leafStrata[p] = s; break;}
1494     }
1495   }
1496   /* Rebuild the point strata on the receiver */
1497   ierr = PetscCalloc1((*labelNew)->numStrata,&(*labelNew)->stratumSizes);CHKERRQ(ierr);
1498   ierr = PetscSectionGetChart(leafSection, &pStart, &pEnd);CHKERRQ(ierr);
1499   for (p=pStart; p<pEnd; p++) {
1500     ierr = PetscSectionGetDof(leafSection, p, &dof);CHKERRQ(ierr);
1501     ierr = PetscSectionGetOffset(leafSection, p, &offset);CHKERRQ(ierr);
1502     for (s=0; s<dof; s++) {
1503       (*labelNew)->stratumSizes[leafStrata[offset+s]]++;
1504     }
1505   }
1506   ierr = PetscCalloc1((*labelNew)->numStrata,&(*labelNew)->ht);CHKERRQ(ierr);
1507   ierr = PetscMalloc1((*labelNew)->numStrata,&(*labelNew)->points);CHKERRQ(ierr);
1508   ierr = PetscMalloc1((*labelNew)->numStrata,&points);CHKERRQ(ierr);
1509   for (s = 0; s < (*labelNew)->numStrata; ++s) {
1510     ierr = PetscHSetICreate(&(*labelNew)->ht[s]);CHKERRQ(ierr);
1511     ierr = PetscMalloc1((*labelNew)->stratumSizes[s], &(points[s]));CHKERRQ(ierr);
1512   }
1513   /* Insert points into new strata */
1514   ierr = PetscCalloc1((*labelNew)->numStrata, &strataIdx);CHKERRQ(ierr);
1515   ierr = PetscSectionGetChart(leafSection, &pStart, &pEnd);CHKERRQ(ierr);
1516   for (p=pStart; p<pEnd; p++) {
1517     ierr = PetscSectionGetDof(leafSection, p, &dof);CHKERRQ(ierr);
1518     ierr = PetscSectionGetOffset(leafSection, p, &offset);CHKERRQ(ierr);
1519     for (s=0; s<dof; s++) {
1520       stratum = leafStrata[offset+s];
1521       points[stratum][strataIdx[stratum]++] = p;
1522     }
1523   }
1524   for (s = 0; s < (*labelNew)->numStrata; s++) {
1525     ierr = ISCreateGeneral(PETSC_COMM_SELF,(*labelNew)->stratumSizes[s],&(points[s][0]),PETSC_OWN_POINTER,&((*labelNew)->points[s]));CHKERRQ(ierr);
1526     ierr = PetscObjectSetName((PetscObject)((*labelNew)->points[s]),"indices");CHKERRQ(ierr);
1527   }
1528   ierr = PetscFree(points);CHKERRQ(ierr);
1529   ierr = PetscHSetIDestroy(&stratumHash);CHKERRQ(ierr);
1530   ierr = PetscFree(leafStrata);CHKERRQ(ierr);
1531   ierr = PetscFree(strataIdx);CHKERRQ(ierr);
1532   ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
1533   PetscFunctionReturn(0);
1534 }
1535 
1536 /*@
1537   DMLabelGather - Gather all label values from leafs into roots
1538 
1539   Collective on sf
1540 
1541   Input Parameters:
1542 + label - the DMLabel
1543 - sf - the Star Forest point communication map
1544 
1545   Output Parameters:
1546 . labelNew - the new DMLabel with localised leaf values
1547 
1548   Level: developer
1549 
1550   Note: This is the inverse operation to DMLabelDistribute.
1551 
1552 .seealso: DMLabelDistribute()
1553 @*/
1554 PetscErrorCode DMLabelGather(DMLabel label, PetscSF sf, DMLabel *labelNew)
1555 {
1556   MPI_Comm       comm;
1557   PetscSection   rootSection;
1558   PetscSF        sfLabel;
1559   PetscSFNode   *rootPoints, *leafPoints;
1560   PetscInt       p, s, d, nroots, nleaves, nmultiroots, idx, dof, offset;
1561   const PetscInt *rootDegree, *ilocal;
1562   PetscInt       *rootStrata;
1563   const char    *lname;
1564   char          *name;
1565   PetscInt       nameSize;
1566   size_t         len = 0;
1567   PetscMPIInt    rank, size;
1568   PetscErrorCode ierr;
1569 
1570   PetscFunctionBegin;
1571   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1572   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
1573   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
1574   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1575   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
1576   /* Bcast name */
1577   if (!rank) {
1578     ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
1579     ierr = PetscStrlen(lname, &len);CHKERRQ(ierr);
1580   }
1581   nameSize = len;
1582   ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
1583   ierr = PetscMalloc1(nameSize+1, &name);CHKERRQ(ierr);
1584   if (!rank) {ierr = PetscArraycpy(name, lname, nameSize+1);CHKERRQ(ierr);}
1585   ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
1586   ierr = DMLabelCreate(PETSC_COMM_SELF, name, labelNew);CHKERRQ(ierr);
1587   ierr = PetscFree(name);CHKERRQ(ierr);
1588   /* Gather rank/index pairs of leaves into local roots to build
1589      an inverse, multi-rooted SF. Note that this ignores local leaf
1590      indexing due to the use of the multiSF in PetscSFGather. */
1591   ierr = PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, NULL);CHKERRQ(ierr);
1592   ierr = PetscMalloc1(nroots, &leafPoints);CHKERRQ(ierr);
1593   for (p = 0; p < nroots; ++p) leafPoints[p].rank = leafPoints[p].index = -1;
1594   for (p = 0; p < nleaves; p++) {
1595     PetscInt ilp = ilocal ? ilocal[p] : p;
1596 
1597     leafPoints[ilp].index = ilp;
1598     leafPoints[ilp].rank  = rank;
1599   }
1600   ierr = PetscSFComputeDegreeBegin(sf, &rootDegree);CHKERRQ(ierr);
1601   ierr = PetscSFComputeDegreeEnd(sf, &rootDegree);CHKERRQ(ierr);
1602   for (p = 0, nmultiroots = 0; p < nroots; ++p) nmultiroots += rootDegree[p];
1603   ierr = PetscMalloc1(nmultiroots, &rootPoints);CHKERRQ(ierr);
1604   ierr = PetscSFGatherBegin(sf, MPIU_2INT, leafPoints, rootPoints);CHKERRQ(ierr);
1605   ierr = PetscSFGatherEnd(sf, MPIU_2INT, leafPoints, rootPoints);CHKERRQ(ierr);
1606   ierr = PetscSFCreate(comm,& sfLabel);CHKERRQ(ierr);
1607   ierr = PetscSFSetGraph(sfLabel, nroots, nmultiroots, NULL, PETSC_OWN_POINTER, rootPoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
1608   /* Migrate label over inverted SF to pull stratum values at leaves into roots. */
1609   ierr = DMLabelDistribute_Internal(label, sfLabel, &rootSection, &rootStrata);CHKERRQ(ierr);
1610   /* Rebuild the point strata on the receiver */
1611   for (p = 0, idx = 0; p < nroots; p++) {
1612     for (d = 0; d < rootDegree[p]; d++) {
1613       ierr = PetscSectionGetDof(rootSection, idx+d, &dof);CHKERRQ(ierr);
1614       ierr = PetscSectionGetOffset(rootSection, idx+d, &offset);CHKERRQ(ierr);
1615       for (s = 0; s < dof; s++) {ierr = DMLabelSetValue(*labelNew, p, rootStrata[offset+s]);CHKERRQ(ierr);}
1616     }
1617     idx += rootDegree[p];
1618   }
1619   ierr = PetscFree(leafPoints);CHKERRQ(ierr);
1620   ierr = PetscFree(rootStrata);CHKERRQ(ierr);
1621   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
1622   ierr = PetscSFDestroy(&sfLabel);CHKERRQ(ierr);
1623   PetscFunctionReturn(0);
1624 }
1625 
1626 /*@
1627   DMLabelConvertToSection - Make a PetscSection/IS pair that encodes the label
1628 
1629   Not collective
1630 
1631   Input Parameter:
1632 . label - the DMLabel
1633 
1634   Output Parameters:
1635 + section - the section giving offsets for each stratum
1636 - is - An IS containing all the label points
1637 
1638   Level: developer
1639 
1640 .seealso: DMLabelDistribute()
1641 @*/
1642 PetscErrorCode DMLabelConvertToSection(DMLabel label, PetscSection *section, IS *is)
1643 {
1644   IS              vIS;
1645   const PetscInt *values;
1646   PetscInt       *points;
1647   PetscInt        nV, vS = 0, vE = 0, v, N;
1648   PetscErrorCode  ierr;
1649 
1650   PetscFunctionBegin;
1651   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1652   ierr = DMLabelGetNumValues(label, &nV);CHKERRQ(ierr);
1653   ierr = DMLabelGetValueIS(label, &vIS);CHKERRQ(ierr);
1654   ierr = ISGetIndices(vIS, &values);CHKERRQ(ierr);
1655   if (nV) {vS = values[0]; vE = values[0]+1;}
1656   for (v = 1; v < nV; ++v) {
1657     vS = PetscMin(vS, values[v]);
1658     vE = PetscMax(vE, values[v]+1);
1659   }
1660   ierr = PetscSectionCreate(PETSC_COMM_SELF, section);CHKERRQ(ierr);
1661   ierr = PetscSectionSetChart(*section, vS, vE);CHKERRQ(ierr);
1662   for (v = 0; v < nV; ++v) {
1663     PetscInt n;
1664 
1665     ierr = DMLabelGetStratumSize(label, values[v], &n);CHKERRQ(ierr);
1666     ierr = PetscSectionSetDof(*section, values[v], n);CHKERRQ(ierr);
1667   }
1668   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
1669   ierr = PetscSectionGetStorageSize(*section, &N);CHKERRQ(ierr);
1670   ierr = PetscMalloc1(N, &points);CHKERRQ(ierr);
1671   for (v = 0; v < nV; ++v) {
1672     IS              is;
1673     const PetscInt *spoints;
1674     PetscInt        dof, off, p;
1675 
1676     ierr = PetscSectionGetDof(*section, values[v], &dof);CHKERRQ(ierr);
1677     ierr = PetscSectionGetOffset(*section, values[v], &off);CHKERRQ(ierr);
1678     ierr = DMLabelGetStratumIS(label, values[v], &is);CHKERRQ(ierr);
1679     ierr = ISGetIndices(is, &spoints);CHKERRQ(ierr);
1680     for (p = 0; p < dof; ++p) points[off+p] = spoints[p];
1681     ierr = ISRestoreIndices(is, &spoints);CHKERRQ(ierr);
1682     ierr = ISDestroy(&is);CHKERRQ(ierr);
1683   }
1684   ierr = ISRestoreIndices(vIS, &values);CHKERRQ(ierr);
1685   ierr = ISDestroy(&vIS);CHKERRQ(ierr);
1686   ierr = ISCreateGeneral(PETSC_COMM_SELF, N, points, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
1687   PetscFunctionReturn(0);
1688 }
1689 
1690 /*@
1691   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
1692   the local section and an SF describing the section point overlap.
1693 
1694   Collective on sf
1695 
1696   Input Parameters:
1697   + s - The PetscSection for the local field layout
1698   . sf - The SF describing parallel layout of the section points
1699   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
1700   . label - The label specifying the points
1701   - labelValue - The label stratum specifying the points
1702 
1703   Output Parameter:
1704   . gsection - The PetscSection for the global field layout
1705 
1706   Note: This gives negative sizes and offsets to points not owned by this process
1707 
1708   Level: developer
1709 
1710 .seealso: PetscSectionCreate()
1711 @*/
1712 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
1713 {
1714   PetscInt      *neg = NULL, *tmpOff = NULL;
1715   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
1716   PetscErrorCode ierr;
1717 
1718   PetscFunctionBegin;
1719   PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
1720   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
1721   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
1722   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), gsection);CHKERRQ(ierr);
1723   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
1724   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
1725   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
1726   if (nroots >= 0) {
1727     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
1728     ierr = PetscCalloc1(nroots, &neg);CHKERRQ(ierr);
1729     if (nroots > pEnd-pStart) {
1730       ierr = PetscCalloc1(nroots, &tmpOff);CHKERRQ(ierr);
1731     } else {
1732       tmpOff = &(*gsection)->atlasDof[-pStart];
1733     }
1734   }
1735   /* Mark ghost points with negative dof */
1736   for (p = pStart; p < pEnd; ++p) {
1737     PetscInt value;
1738 
1739     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
1740     if (value != labelValue) continue;
1741     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
1742     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
1743     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
1744     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
1745     if (neg) neg[p] = -(dof+1);
1746   }
1747   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
1748   if (nroots >= 0) {
1749     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1750     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1751     if (nroots > pEnd-pStart) {
1752       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
1753     }
1754   }
1755   /* Calculate new sizes, get proccess offset, and calculate point offsets */
1756   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
1757     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
1758     (*gsection)->atlasOff[p] = off;
1759     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
1760   }
1761   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) s));CHKERRQ(ierr);
1762   globalOff -= off;
1763   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
1764     (*gsection)->atlasOff[p] += globalOff;
1765     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
1766   }
1767   /* Put in negative offsets for ghost points */
1768   if (nroots >= 0) {
1769     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1770     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1771     if (nroots > pEnd-pStart) {
1772       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
1773     }
1774   }
1775   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
1776   ierr = PetscFree(neg);CHKERRQ(ierr);
1777   PetscFunctionReturn(0);
1778 }
1779 
1780 typedef struct _n_PetscSectionSym_Label
1781 {
1782   DMLabel           label;
1783   PetscCopyMode     *modes;
1784   PetscInt          *sizes;
1785   const PetscInt    ***perms;
1786   const PetscScalar ***rots;
1787   PetscInt          (*minMaxOrients)[2];
1788   PetscInt          numStrata; /* numStrata is only increasing, functions as a state */
1789 } PetscSectionSym_Label;
1790 
1791 static PetscErrorCode PetscSectionSymLabelReset(PetscSectionSym sym)
1792 {
1793   PetscInt              i, j;
1794   PetscSectionSym_Label *sl = (PetscSectionSym_Label *) sym->data;
1795   PetscErrorCode        ierr;
1796 
1797   PetscFunctionBegin;
1798   for (i = 0; i <= sl->numStrata; i++) {
1799     if (sl->modes[i] == PETSC_OWN_POINTER || sl->modes[i] == PETSC_COPY_VALUES) {
1800       for (j = sl->minMaxOrients[i][0]; j < sl->minMaxOrients[i][1]; j++) {
1801         if (sl->perms[i]) {ierr = PetscFree(sl->perms[i][j]);CHKERRQ(ierr);}
1802         if (sl->rots[i]) {ierr = PetscFree(sl->rots[i][j]);CHKERRQ(ierr);}
1803       }
1804       if (sl->perms[i]) {
1805         const PetscInt **perms = &sl->perms[i][sl->minMaxOrients[i][0]];
1806 
1807         ierr = PetscFree(perms);CHKERRQ(ierr);
1808       }
1809       if (sl->rots[i]) {
1810         const PetscScalar **rots = &sl->rots[i][sl->minMaxOrients[i][0]];
1811 
1812         ierr = PetscFree(rots);CHKERRQ(ierr);
1813       }
1814     }
1815   }
1816   ierr = PetscFree5(sl->modes,sl->sizes,sl->perms,sl->rots,sl->minMaxOrients);CHKERRQ(ierr);
1817   ierr = DMLabelDestroy(&sl->label);CHKERRQ(ierr);
1818   sl->numStrata = 0;
1819   PetscFunctionReturn(0);
1820 }
1821 
1822 static PetscErrorCode PetscSectionSymDestroy_Label(PetscSectionSym sym)
1823 {
1824   PetscErrorCode ierr;
1825 
1826   PetscFunctionBegin;
1827   ierr = PetscSectionSymLabelReset(sym);CHKERRQ(ierr);
1828   ierr = PetscFree(sym->data);CHKERRQ(ierr);
1829   PetscFunctionReturn(0);
1830 }
1831 
1832 static PetscErrorCode PetscSectionSymView_Label(PetscSectionSym sym, PetscViewer viewer)
1833 {
1834   PetscSectionSym_Label *sl = (PetscSectionSym_Label *) sym->data;
1835   PetscBool             isAscii;
1836   DMLabel               label = sl->label;
1837   const char           *name;
1838   PetscErrorCode        ierr;
1839 
1840   PetscFunctionBegin;
1841   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isAscii);CHKERRQ(ierr);
1842   if (isAscii) {
1843     PetscInt          i, j, k;
1844     PetscViewerFormat format;
1845 
1846     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
1847     if (label) {
1848       ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
1849       if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1850         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1851         ierr = DMLabelView(label, viewer);CHKERRQ(ierr);
1852         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1853       } else {
1854         ierr = PetscObjectGetName((PetscObject) sl->label, &name);CHKERRQ(ierr);
1855         ierr = PetscViewerASCIIPrintf(viewer,"  Label '%s'\n",name);CHKERRQ(ierr);
1856       }
1857     } else {
1858       ierr = PetscViewerASCIIPrintf(viewer, "No label given\n");CHKERRQ(ierr);
1859     }
1860     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1861     for (i = 0; i <= sl->numStrata; i++) {
1862       PetscInt value = i < sl->numStrata ? label->stratumValues[i] : label->defaultValue;
1863 
1864       if (!(sl->perms[i] || sl->rots[i])) {
1865         ierr = PetscViewerASCIIPrintf(viewer, "Symmetry for stratum value %D (%D dofs per point): no symmetries\n", value, sl->sizes[i]);CHKERRQ(ierr);
1866       } else {
1867       ierr = PetscViewerASCIIPrintf(viewer, "Symmetry for stratum value %D (%D dofs per point):\n", value, sl->sizes[i]);CHKERRQ(ierr);
1868         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1869         ierr = PetscViewerASCIIPrintf(viewer, "Orientation range: [%D, %D)\n", sl->minMaxOrients[i][0], sl->minMaxOrients[i][1]);CHKERRQ(ierr);
1870         if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1871           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1872           for (j = sl->minMaxOrients[i][0]; j < sl->minMaxOrients[i][1]; j++) {
1873             if (!((sl->perms[i] && sl->perms[i][j]) || (sl->rots[i] && sl->rots[i][j]))) {
1874               ierr = PetscViewerASCIIPrintf(viewer, "Orientation %D: identity\n",j);CHKERRQ(ierr);
1875             } else {
1876               PetscInt tab;
1877 
1878               ierr = PetscViewerASCIIPrintf(viewer, "Orientation %D:\n",j);CHKERRQ(ierr);
1879               ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1880               ierr = PetscViewerASCIIGetTab(viewer,&tab);CHKERRQ(ierr);
1881               if (sl->perms[i] && sl->perms[i][j]) {
1882                 ierr = PetscViewerASCIIPrintf(viewer,"Permutation:");CHKERRQ(ierr);
1883                 ierr = PetscViewerASCIISetTab(viewer,0);CHKERRQ(ierr);
1884                 for (k = 0; k < sl->sizes[i]; k++) {ierr = PetscViewerASCIIPrintf(viewer," %D",sl->perms[i][j][k]);CHKERRQ(ierr);}
1885                 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
1886                 ierr = PetscViewerASCIISetTab(viewer,tab);CHKERRQ(ierr);
1887               }
1888               if (sl->rots[i] && sl->rots[i][j]) {
1889                 ierr = PetscViewerASCIIPrintf(viewer,"Rotations:  ");CHKERRQ(ierr);
1890                 ierr = PetscViewerASCIISetTab(viewer,0);CHKERRQ(ierr);
1891 #if defined(PETSC_USE_COMPLEX)
1892                 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);}
1893 #else
1894                 for (k = 0; k < sl->sizes[i]; k++) {ierr = PetscViewerASCIIPrintf(viewer," %+f",sl->rots[i][j][k]);CHKERRQ(ierr);}
1895 #endif
1896                 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
1897                 ierr = PetscViewerASCIISetTab(viewer,tab);CHKERRQ(ierr);
1898               }
1899               ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1900             }
1901           }
1902           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1903         }
1904         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1905       }
1906     }
1907     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1908   }
1909   PetscFunctionReturn(0);
1910 }
1911 
1912 /*@
1913   PetscSectionSymLabelSetLabel - set the label whose strata will define the points that receive symmetries
1914 
1915   Logically collective on sym
1916 
1917   Input parameters:
1918 + sym - the section symmetries
1919 - label - the DMLabel describing the types of points
1920 
1921   Level: developer:
1922 
1923 .seealso: PetscSectionSymLabelSetStratum(), PetscSectionSymCreateLabel(), PetscSectionGetPointSyms()
1924 @*/
1925 PetscErrorCode PetscSectionSymLabelSetLabel(PetscSectionSym sym, DMLabel label)
1926 {
1927   PetscSectionSym_Label *sl;
1928   PetscErrorCode        ierr;
1929 
1930   PetscFunctionBegin;
1931   PetscValidHeaderSpecific(sym,PETSC_SECTION_SYM_CLASSID,1);
1932   sl = (PetscSectionSym_Label *) sym->data;
1933   if (sl->label && sl->label != label) {ierr = PetscSectionSymLabelReset(sym);CHKERRQ(ierr);}
1934   if (label) {
1935     sl->label = label;
1936     ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
1937     ierr = DMLabelGetNumValues(label,&sl->numStrata);CHKERRQ(ierr);
1938     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);
1939     ierr = PetscMemzero((void *) sl->modes,(sl->numStrata+1)*sizeof(PetscCopyMode));CHKERRQ(ierr);
1940     ierr = PetscMemzero((void *) sl->sizes,(sl->numStrata+1)*sizeof(PetscInt));CHKERRQ(ierr);
1941     ierr = PetscMemzero((void *) sl->perms,(sl->numStrata+1)*sizeof(const PetscInt **));CHKERRQ(ierr);
1942     ierr = PetscMemzero((void *) sl->rots,(sl->numStrata+1)*sizeof(const PetscScalar **));CHKERRQ(ierr);
1943     ierr = PetscMemzero((void *) sl->minMaxOrients,(sl->numStrata+1)*sizeof(PetscInt[2]));CHKERRQ(ierr);
1944   }
1945   PetscFunctionReturn(0);
1946 }
1947 
1948 /*@C
1949   PetscSectionSymLabelSetStratum - set the symmetries for the orientations of a stratum
1950 
1951   Logically collective on sym
1952 
1953   InputParameters:
1954 + sym       - the section symmetries
1955 . stratum   - the stratum value in the label that we are assigning symmetries for
1956 . size      - the number of dofs for points in the stratum of the label
1957 . minOrient - the smallest orientation for a point in this stratum
1958 . maxOrient - one greater than the largest orientation for a ppoint in this stratum (i.e., orientations are in the range [minOrient, maxOrient))
1959 . mode      - how sym should copy the perms and rots arrays
1960 . perms     - NULL if there are no permutations, or (maxOrient - minOrient) permutations, one for each orientation.  A NULL permutation is the identity
1961 - 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
1962 
1963   Level: developer
1964 
1965 .seealso: PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetPointSyms(), PetscSectionSymCreateLabel()
1966 @*/
1967 PetscErrorCode PetscSectionSymLabelSetStratum(PetscSectionSym sym, PetscInt stratum, PetscInt size, PetscInt minOrient, PetscInt maxOrient, PetscCopyMode mode, const PetscInt **perms, const PetscScalar **rots)
1968 {
1969   PetscSectionSym_Label *sl;
1970   const char            *name;
1971   PetscInt               i, j, k;
1972   PetscErrorCode         ierr;
1973 
1974   PetscFunctionBegin;
1975   PetscValidHeaderSpecific(sym,PETSC_SECTION_SYM_CLASSID,1);
1976   sl = (PetscSectionSym_Label *) sym->data;
1977   if (!sl->label) SETERRQ(PetscObjectComm((PetscObject)sym),PETSC_ERR_ARG_WRONGSTATE,"No label set yet");
1978   for (i = 0; i <= sl->numStrata; i++) {
1979     PetscInt value = (i < sl->numStrata) ? sl->label->stratumValues[i] : sl->label->defaultValue;
1980 
1981     if (stratum == value) break;
1982   }
1983   ierr = PetscObjectGetName((PetscObject) sl->label, &name);CHKERRQ(ierr);
1984   if (i > sl->numStrata) SETERRQ2(PetscObjectComm((PetscObject)sym),PETSC_ERR_ARG_OUTOFRANGE,"Stratum %D not found in label %s\n",stratum,name);
1985   sl->sizes[i] = size;
1986   sl->modes[i] = mode;
1987   sl->minMaxOrients[i][0] = minOrient;
1988   sl->minMaxOrients[i][1] = maxOrient;
1989   if (mode == PETSC_COPY_VALUES) {
1990     if (perms) {
1991       PetscInt    **ownPerms;
1992 
1993       ierr = PetscCalloc1(maxOrient - minOrient,&ownPerms);CHKERRQ(ierr);
1994       for (j = 0; j < maxOrient-minOrient; j++) {
1995         if (perms[j]) {
1996           ierr = PetscMalloc1(size,&ownPerms[j]);CHKERRQ(ierr);
1997           for (k = 0; k < size; k++) {ownPerms[j][k] = perms[j][k];}
1998         }
1999       }
2000       sl->perms[i] = (const PetscInt **) &ownPerms[-minOrient];
2001     }
2002     if (rots) {
2003       PetscScalar **ownRots;
2004 
2005       ierr = PetscCalloc1(maxOrient - minOrient,&ownRots);CHKERRQ(ierr);
2006       for (j = 0; j < maxOrient-minOrient; j++) {
2007         if (rots[j]) {
2008           ierr = PetscMalloc1(size,&ownRots[j]);CHKERRQ(ierr);
2009           for (k = 0; k < size; k++) {ownRots[j][k] = rots[j][k];}
2010         }
2011       }
2012       sl->rots[i] = (const PetscScalar **) &ownRots[-minOrient];
2013     }
2014   } else {
2015     sl->perms[i] = perms ? &perms[-minOrient] : NULL;
2016     sl->rots[i]  = rots ? &rots[-minOrient] : NULL;
2017   }
2018   PetscFunctionReturn(0);
2019 }
2020 
2021 static PetscErrorCode PetscSectionSymGetPoints_Label(PetscSectionSym sym, PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt **perms, const PetscScalar **rots)
2022 {
2023   PetscInt              i, j, numStrata;
2024   PetscSectionSym_Label *sl;
2025   DMLabel               label;
2026   PetscErrorCode        ierr;
2027 
2028   PetscFunctionBegin;
2029   sl = (PetscSectionSym_Label *) sym->data;
2030   numStrata = sl->numStrata;
2031   label     = sl->label;
2032   for (i = 0; i < numPoints; i++) {
2033     PetscInt point = points[2*i];
2034     PetscInt ornt  = points[2*i+1];
2035 
2036     for (j = 0; j < numStrata; j++) {
2037       if (label->validIS[j]) {
2038         PetscInt k;
2039 
2040         ierr = ISLocate(label->points[j],point,&k);CHKERRQ(ierr);
2041         if (k >= 0) break;
2042       } else {
2043         PetscBool has;
2044 
2045         ierr = PetscHSetIHas(label->ht[j], point, &has);CHKERRQ(ierr);
2046         if (has) break;
2047       }
2048     }
2049     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);
2050     if (perms) {perms[i] = sl->perms[j] ? sl->perms[j][ornt] : NULL;}
2051     if (rots) {rots[i]  = sl->rots[j] ? sl->rots[j][ornt] : NULL;}
2052   }
2053   PetscFunctionReturn(0);
2054 }
2055 
2056 PetscErrorCode PetscSectionSymCreate_Label(PetscSectionSym sym)
2057 {
2058   PetscSectionSym_Label *sl;
2059   PetscErrorCode        ierr;
2060 
2061   PetscFunctionBegin;
2062   ierr = PetscNewLog(sym,&sl);CHKERRQ(ierr);
2063   sym->ops->getpoints = PetscSectionSymGetPoints_Label;
2064   sym->ops->view      = PetscSectionSymView_Label;
2065   sym->ops->destroy   = PetscSectionSymDestroy_Label;
2066   sym->data           = (void *) sl;
2067   PetscFunctionReturn(0);
2068 }
2069 
2070 /*@
2071   PetscSectionSymCreateLabel - Create a section symmetry that assigns one symmetry to each stratum of a label
2072 
2073   Collective
2074 
2075   Input Parameters:
2076 + comm - the MPI communicator for the new symmetry
2077 - label - the label defining the strata
2078 
2079   Output Parameters:
2080 . sym - the section symmetries
2081 
2082   Level: developer
2083 
2084 .seealso: PetscSectionSymCreate(), PetscSectionSetSym(), PetscSectionGetSym(), PetscSectionSymLabelSetStratum(), PetscSectionGetPointSyms()
2085 @*/
2086 PetscErrorCode PetscSectionSymCreateLabel(MPI_Comm comm, DMLabel label, PetscSectionSym *sym)
2087 {
2088   PetscErrorCode        ierr;
2089 
2090   PetscFunctionBegin;
2091   ierr = DMInitializePackage();CHKERRQ(ierr);
2092   ierr = PetscSectionSymCreate(comm,sym);CHKERRQ(ierr);
2093   ierr = PetscSectionSymSetType(*sym,PETSCSECTIONSYMLABEL);CHKERRQ(ierr);
2094   ierr = PetscSectionSymLabelSetLabel(*sym,label);CHKERRQ(ierr);
2095   PetscFunctionReturn(0);
2096 }
2097