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