xref: /petsc/src/dm/label/dmlabel.c (revision 4fc747eaadbeca11629f314a99edccbc2ed7b3d3)
1 #include <petsc/private/dmlabelimpl.h>   /*I      "petscdmlabel.h"   I*/
2 #include <petsc/private/isimpl.h>        /*I      "petscis.h"        I*/
3 #include <petscsf.h>
4 
5 #undef __FUNCT__
6 #define __FUNCT__ "DMLabelCreate"
7 /*@C
8   DMLabelCreate - Create a DMLabel object, which is a multimap
9 
10   Input parameter:
11 . name - The label name
12 
13   Output parameter:
14 . label - The DMLabel
15 
16   Level: beginner
17 
18 .seealso: DMLabelDestroy()
19 @*/
20 PetscErrorCode DMLabelCreate(const char name[], DMLabel *label)
21 {
22   PetscErrorCode ierr;
23 
24   PetscFunctionBegin;
25   ierr = PetscNew(label);CHKERRQ(ierr);
26   ierr = PetscStrallocpy(name, &(*label)->name);CHKERRQ(ierr);
27 
28   (*label)->refct          = 1;
29   (*label)->state          = -1;
30   (*label)->numStrata      = 0;
31   (*label)->defaultValue   = -1;
32   (*label)->stratumValues  = NULL;
33   (*label)->arrayValid     = NULL;
34   (*label)->stratumSizes   = NULL;
35   (*label)->points         = NULL;
36   (*label)->ht             = NULL;
37   (*label)->pStart         = -1;
38   (*label)->pEnd           = -1;
39   (*label)->bt             = NULL;
40   PetscFunctionReturn(0);
41 }
42 
43 #undef __FUNCT__
44 #define __FUNCT__ "DMLabelMakeValid_Private"
45 /*
46   DMLabelMakeValid_Private - Transfer stratum data from the hash format to the sorted list format
47 
48   Input parameter:
49 + label - The DMLabel
50 - v - The stratum value
51 
52   Output parameter:
53 . label - The DMLabel with stratum in sorted list format
54 
55   Level: developer
56 
57 .seealso: DMLabelCreate()
58 */
59 static PetscErrorCode DMLabelMakeValid_Private(DMLabel label, PetscInt v)
60 {
61   PetscInt       off;
62   PetscErrorCode ierr;
63 
64   if (label->arrayValid[v]) return 0;
65   if (v >= label->numStrata) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to access invalid stratum %D in DMLabelMakeValid_Private\n", v);
66   PetscFunctionBegin;
67   PetscHashISize(label->ht[v], label->stratumSizes[v]);
68 
69   ierr = PetscMalloc1(label->stratumSizes[v], &label->points[v]);CHKERRQ(ierr);
70   off = 0;
71   ierr = PetscHashIGetKeys(label->ht[v], &off, &(label->points[v][0]));CHKERRQ(ierr);
72   if (off != label->stratumSizes[v]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid number of contributed points %D from value %D should be %D", off, label->stratumValues[v], label->stratumSizes[v]);
73   PetscHashIClear(label->ht[v]);
74   ierr = PetscSortInt(label->stratumSizes[v], label->points[v]);CHKERRQ(ierr);
75   if (label->bt) {
76     PetscInt p;
77 
78     for (p = 0; p < label->stratumSizes[v]; ++p) {
79       const PetscInt point = label->points[v][p];
80 
81       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);
82       ierr = PetscBTSet(label->bt, point - label->pStart);CHKERRQ(ierr);
83     }
84   }
85   label->arrayValid[v] = PETSC_TRUE;
86   ++label->state;
87   PetscFunctionReturn(0);
88 }
89 
90 #undef __FUNCT__
91 #define __FUNCT__ "DMLabelMakeAllValid_Private"
92 /*
93   DMLabelMakeAllValid_Private - Transfer all strata from the hash format to the sorted list format
94 
95   Input parameter:
96 . label - The DMLabel
97 
98   Output parameter:
99 . label - The DMLabel with all strata in sorted list format
100 
101   Level: developer
102 
103 .seealso: DMLabelCreate()
104 */
105 static PetscErrorCode DMLabelMakeAllValid_Private(DMLabel label)
106 {
107   PetscInt       v;
108   PetscErrorCode ierr;
109 
110   PetscFunctionBegin;
111   for (v = 0; v < label->numStrata; v++){
112     ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
113   }
114   PetscFunctionReturn(0);
115 }
116 
117 #undef __FUNCT__
118 #define __FUNCT__ "DMLabelMakeInvalid_Private"
119 /*
120   DMLabelMakeInvalid_Private - Transfer stratum data from the sorted list format to the hash format
121 
122   Input parameter:
123 + label - The DMLabel
124 - v - The stratum value
125 
126   Output parameter:
127 . label - The DMLabel with stratum in hash format
128 
129   Level: developer
130 
131 .seealso: DMLabelCreate()
132 */
133 static PetscErrorCode DMLabelMakeInvalid_Private(DMLabel label, PetscInt v)
134 {
135   PETSC_UNUSED PetscHashIIter ret, iter;
136   PetscInt                    p;
137   PetscErrorCode ierr;
138 
139   PetscFunctionBegin;
140   if (!label->arrayValid[v]) PetscFunctionReturn(0);
141   for (p = 0; p < label->stratumSizes[v]; ++p) PetscHashIPut(label->ht[v], label->points[v][p], ret, iter);
142   ierr = PetscFree(label->points[v]);CHKERRQ(ierr);
143   label->arrayValid[v] = PETSC_FALSE;
144   PetscFunctionReturn(0);
145 }
146 
147 #undef __FUNCT__
148 #define __FUNCT__ "DMLabelGetState"
149 PetscErrorCode DMLabelGetState(DMLabel label, PetscObjectState *state)
150 {
151   PetscFunctionBegin;
152   PetscValidPointer(state, 2);
153   *state = label->state;
154   PetscFunctionReturn(0);
155 }
156 
157 #undef __FUNCT__
158 #define __FUNCT__ "DMLabelAddStratum"
159 PetscErrorCode DMLabelAddStratum(DMLabel label, PetscInt value)
160 {
161   PetscInt    v, *tmpV, *tmpS, **tmpP;
162   PetscHashI *tmpH;
163   PetscBool  *tmpB;
164   PetscErrorCode ierr;
165 
166   PetscFunctionBegin;
167 
168   ierr = PetscMalloc1((label->numStrata+1), &tmpV);CHKERRQ(ierr);
169   ierr = PetscMalloc1((label->numStrata+1), &tmpS);CHKERRQ(ierr);
170   ierr = PetscMalloc1((label->numStrata+1), &tmpH);CHKERRQ(ierr);
171   ierr = PetscMalloc1((label->numStrata+1), &tmpP);CHKERRQ(ierr);
172   ierr = PetscMalloc1((label->numStrata+1), &tmpB);CHKERRQ(ierr);
173   for (v = 0; v < label->numStrata; ++v) {
174     tmpV[v] = label->stratumValues[v];
175     tmpS[v] = label->stratumSizes[v];
176     tmpH[v] = label->ht[v];
177     tmpP[v] = label->points[v];
178     tmpB[v] = label->arrayValid[v];
179   }
180   tmpV[v] = value;
181   tmpS[v] = 0;
182   PetscHashICreate(tmpH[v]);
183   tmpP[v] = NULL;
184   tmpB[v] = PETSC_TRUE;
185   ++label->numStrata;
186   ierr = PetscFree(label->stratumValues);CHKERRQ(ierr);
187   ierr = PetscFree(label->stratumSizes);CHKERRQ(ierr);
188   ierr = PetscFree(label->ht);CHKERRQ(ierr);
189   ierr = PetscFree(label->points);CHKERRQ(ierr);
190   ierr = PetscFree(label->arrayValid);CHKERRQ(ierr);
191   label->stratumValues = tmpV;
192   label->stratumSizes  = tmpS;
193   label->ht            = tmpH;
194   label->points        = tmpP;
195   label->arrayValid    = tmpB;
196 
197   PetscFunctionReturn(0);
198 }
199 
200 #undef __FUNCT__
201 #define __FUNCT__ "DMLabelGetName"
202 /*@C
203   DMLabelGetName - Return the name of a DMLabel object
204 
205   Input parameter:
206 . label - The DMLabel
207 
208   Output parameter:
209 . name - The label name
210 
211   Level: beginner
212 
213 .seealso: DMLabelCreate()
214 @*/
215 PetscErrorCode DMLabelGetName(DMLabel label, const char **name)
216 {
217   PetscFunctionBegin;
218   PetscValidPointer(name, 2);
219   *name = label->name;
220   PetscFunctionReturn(0);
221 }
222 
223 #undef __FUNCT__
224 #define __FUNCT__ "DMLabelView_Ascii"
225 static PetscErrorCode DMLabelView_Ascii(DMLabel label, PetscViewer viewer)
226 {
227   PetscInt       v;
228   PetscMPIInt    rank;
229   PetscErrorCode ierr;
230 
231   PetscFunctionBegin;
232   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank);CHKERRQ(ierr);
233   ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
234   if (label) {
235     ierr = PetscViewerASCIIPrintf(viewer, "Label '%s':\n", label->name);CHKERRQ(ierr);
236     if (label->bt) {ierr = PetscViewerASCIIPrintf(viewer, "  Index has been calculated in [%D, %D)\n", label->pStart, label->pEnd);CHKERRQ(ierr);}
237     for (v = 0; v < label->numStrata; ++v) {
238       const PetscInt value = label->stratumValues[v];
239       PetscInt       p;
240 
241       for (p = 0; p < label->stratumSizes[v]; ++p) {
242         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D (%D)\n", rank, label->points[v][p], value);CHKERRQ(ierr);
243       }
244     }
245   }
246   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
247   ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
248   PetscFunctionReturn(0);
249 }
250 
251 #undef __FUNCT__
252 #define __FUNCT__ "DMLabelView"
253 /*@C
254   DMLabelView - View the label
255 
256   Input Parameters:
257 + label - The DMLabel
258 - viewer - The PetscViewer
259 
260   Level: intermediate
261 
262 .seealso: DMLabelCreate(), DMLabelDestroy()
263 @*/
264 PetscErrorCode DMLabelView(DMLabel label, PetscViewer viewer)
265 {
266   PetscBool      iascii;
267   PetscErrorCode ierr;
268 
269   PetscFunctionBegin;
270   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
271   if (label) {ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);}
272   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
273   if (iascii) {
274     ierr = DMLabelView_Ascii(label, viewer);CHKERRQ(ierr);
275   }
276   PetscFunctionReturn(0);
277 }
278 
279 #undef __FUNCT__
280 #define __FUNCT__ "DMLabelDestroy"
281 PetscErrorCode DMLabelDestroy(DMLabel *label)
282 {
283   PetscInt       v;
284   PetscErrorCode ierr;
285 
286   PetscFunctionBegin;
287   if (!(*label)) PetscFunctionReturn(0);
288   if (--(*label)->refct > 0) PetscFunctionReturn(0);
289   ierr = PetscFree((*label)->name);CHKERRQ(ierr);
290   ierr = PetscFree((*label)->stratumValues);CHKERRQ(ierr);
291   ierr = PetscFree((*label)->stratumSizes);CHKERRQ(ierr);
292   for (v = 0; v < (*label)->numStrata; ++v) {ierr = PetscFree((*label)->points[v]);CHKERRQ(ierr);}
293   ierr = PetscFree((*label)->points);CHKERRQ(ierr);
294   ierr = PetscFree((*label)->arrayValid);CHKERRQ(ierr);
295   if ((*label)->ht) {
296     for (v = 0; v < (*label)->numStrata; ++v) {PetscHashIDestroy((*label)->ht[v]);}
297     ierr = PetscFree((*label)->ht);CHKERRQ(ierr);
298   }
299   ierr = PetscBTDestroy(&(*label)->bt);CHKERRQ(ierr);
300   ierr = PetscFree(*label);CHKERRQ(ierr);
301   PetscFunctionReturn(0);
302 }
303 
304 #undef __FUNCT__
305 #define __FUNCT__ "DMLabelDuplicate"
306 PetscErrorCode DMLabelDuplicate(DMLabel label, DMLabel *labelnew)
307 {
308   PetscInt       v, q;
309   PetscErrorCode ierr;
310 
311   PetscFunctionBegin;
312   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
313   ierr = PetscNew(labelnew);CHKERRQ(ierr);
314   ierr = PetscStrallocpy(label->name, &(*labelnew)->name);CHKERRQ(ierr);
315 
316   (*labelnew)->refct        = 1;
317   (*labelnew)->numStrata    = label->numStrata;
318   (*labelnew)->defaultValue = label->defaultValue;
319   if (label->numStrata) {
320     ierr = PetscMalloc1(label->numStrata, &(*labelnew)->stratumValues);CHKERRQ(ierr);
321     ierr = PetscMalloc1(label->numStrata, &(*labelnew)->stratumSizes);CHKERRQ(ierr);
322     ierr = PetscMalloc1(label->numStrata, &(*labelnew)->ht);CHKERRQ(ierr);
323     ierr = PetscMalloc1(label->numStrata, &(*labelnew)->points);CHKERRQ(ierr);
324     ierr = PetscMalloc1(label->numStrata, &(*labelnew)->arrayValid);CHKERRQ(ierr);
325     /* Could eliminate unused space here */
326     for (v = 0; v < label->numStrata; ++v) {
327       ierr = PetscMalloc1(label->stratumSizes[v], &(*labelnew)->points[v]);CHKERRQ(ierr);
328       PetscHashICreate((*labelnew)->ht[v]);
329       (*labelnew)->arrayValid[v]     = PETSC_TRUE;
330       (*labelnew)->stratumValues[v]  = label->stratumValues[v];
331       (*labelnew)->stratumSizes[v]   = label->stratumSizes[v];
332       for (q = 0; q < label->stratumSizes[v]; ++q) {
333         (*labelnew)->points[v][q] = label->points[v][q];
334       }
335     }
336   }
337   (*labelnew)->pStart = -1;
338   (*labelnew)->pEnd   = -1;
339   (*labelnew)->bt     = NULL;
340   PetscFunctionReturn(0);
341 }
342 
343 #undef __FUNCT__
344 #define __FUNCT__ "DMLabelCreateIndex"
345 /* This can be hooked into SetValue(),  ClearValue(), etc. for updating */
346 PetscErrorCode DMLabelCreateIndex(DMLabel label, PetscInt pStart, PetscInt pEnd)
347 {
348   PetscInt       v;
349   PetscErrorCode ierr;
350 
351   PetscFunctionBegin;
352   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
353   if (label->bt) {ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);}
354   label->pStart = pStart;
355   label->pEnd   = pEnd;
356   ierr = PetscBTCreate(pEnd - pStart, &label->bt);CHKERRQ(ierr);
357   ierr = PetscBTMemzero(pEnd - pStart, label->bt);CHKERRQ(ierr);
358   for (v = 0; v < label->numStrata; ++v) {
359     PetscInt i;
360 
361     for (i = 0; i < label->stratumSizes[v]; ++i) {
362       const PetscInt point = label->points[v][i];
363 
364       if ((point < pStart) || (point >= pEnd)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %D is not in [%D, %D)", point, pStart, pEnd);
365       ierr = PetscBTSet(label->bt, point - pStart);CHKERRQ(ierr);
366     }
367   }
368   PetscFunctionReturn(0);
369 }
370 
371 #undef __FUNCT__
372 #define __FUNCT__ "DMLabelDestroyIndex"
373 PetscErrorCode DMLabelDestroyIndex(DMLabel label)
374 {
375   PetscErrorCode ierr;
376 
377   PetscFunctionBegin;
378   label->pStart = -1;
379   label->pEnd   = -1;
380   if (label->bt) {ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);}
381   PetscFunctionReturn(0);
382 }
383 
384 #undef __FUNCT__
385 #define __FUNCT__ "DMLabelHasValue"
386 /*@
387   DMLabelHasValue - Determine whether a label assigns the value to any point
388 
389   Input Parameters:
390 + label - the DMLabel
391 - value - the value
392 
393   Output Parameter:
394 . contains - Flag indicating whether the label maps this value to any point
395 
396   Level: developer
397 
398 .seealso: DMLabelHasPoint(), DMLabelGetValue(), DMLabelSetValue()
399 @*/
400 PetscErrorCode DMLabelHasValue(DMLabel label, PetscInt value, PetscBool *contains)
401 {
402   PetscInt v;
403 
404   PetscFunctionBegin;
405   PetscValidPointer(contains, 3);
406   for (v = 0; v < label->numStrata; ++v) {
407     if (value == label->stratumValues[v]) break;
408   }
409   *contains = (v < label->numStrata ? PETSC_TRUE : PETSC_FALSE);
410   PetscFunctionReturn(0);
411 }
412 
413 #undef __FUNCT__
414 #define __FUNCT__ "DMLabelHasPoint"
415 /*@
416   DMLabelHasPoint - Determine whether a label assigns a value to a point
417 
418   Input Parameters:
419 + label - the DMLabel
420 - point - the point
421 
422   Output Parameter:
423 . contains - Flag indicating whether the label maps this point to a value
424 
425   Note: The user must call DMLabelCreateIndex() before this function.
426 
427   Level: developer
428 
429 .seealso: DMLabelCreateIndex(), DMLabelGetValue(), DMLabelSetValue()
430 @*/
431 PetscErrorCode DMLabelHasPoint(DMLabel label, PetscInt point, PetscBool *contains)
432 {
433   PetscErrorCode ierr;
434 
435   PetscFunctionBeginHot;
436   PetscValidPointer(contains, 3);
437   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
438 #if defined(PETSC_USE_DEBUG)
439   if (!label->bt) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call DMLabelCreateIndex() before DMLabelHasPoint()");
440   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);
441 #endif
442   *contains = PetscBTLookup(label->bt, point - label->pStart) ? PETSC_TRUE : PETSC_FALSE;
443   PetscFunctionReturn(0);
444 }
445 
446 #undef __FUNCT__
447 #define __FUNCT__ "DMLabelStratumHasPoint"
448 /*@
449   DMLabelStratumHasPoint - Return true if the stratum contains a point
450 
451   Input Parameters:
452 + label - the DMLabel
453 . value - the stratum value
454 - point - the point
455 
456   Output Parameter:
457 . contains - true if the stratum contains the point
458 
459   Level: intermediate
460 
461 .seealso: DMLabelCreate(), DMLabelSetValue(), DMLabelClearValue()
462 @*/
463 PetscErrorCode DMLabelStratumHasPoint(DMLabel label, PetscInt value, PetscInt point, PetscBool *contains)
464 {
465   PetscInt       v;
466   PetscErrorCode ierr;
467 
468   PetscFunctionBegin;
469   PetscValidPointer(contains, 4);
470   *contains = PETSC_FALSE;
471   for (v = 0; v < label->numStrata; ++v) {
472     if (label->stratumValues[v] == value) {
473       if (label->arrayValid[v]) {
474         PetscInt i;
475 
476         ierr = PetscFindInt(point, label->stratumSizes[v], &label->points[v][0], &i);CHKERRQ(ierr);
477         if (i >= 0) {
478           *contains = PETSC_TRUE;
479           break;
480         }
481       } else {
482         PetscBool has;
483 
484         PetscHashIHasKey(label->ht[v], point, has);
485         if (has) {
486           *contains = PETSC_TRUE;
487           break;
488         }
489       }
490     }
491   }
492   PetscFunctionReturn(0);
493 }
494 
495 #undef __FUNCT__
496 #define __FUNCT__ "DMLabelGetDefaultValue"
497 /*
498   DMLabelGetDefaultValue - Get the default value returned by DMLabelGetValue() if a point has not been explicitly given a value.
499   When a label is created, it is initialized to -1.
500 
501   Input parameter:
502 . label - a DMLabel object
503 
504   Output parameter:
505 . defaultValue - the default value
506 
507   Level: beginner
508 
509 .seealso: DMLabelSetDefaultValue(), DMLabelGetValue(), DMLabelSetValue()
510 */
511 PetscErrorCode DMLabelGetDefaultValue(DMLabel label, PetscInt *defaultValue)
512 {
513   PetscFunctionBegin;
514   *defaultValue = label->defaultValue;
515   PetscFunctionReturn(0);
516 }
517 
518 #undef __FUNCT__
519 #define __FUNCT__ "DMLabelSetDefaultValue"
520 /*
521   DMLabelSetDefaultValue - Set the default value returned by DMLabelGetValue() if a point has not been explicitly given a value.
522   When a label is created, it is initialized to -1.
523 
524   Input parameter:
525 . label - a DMLabel object
526 
527   Output parameter:
528 . defaultValue - the default value
529 
530   Level: beginner
531 
532 .seealso: DMLabelGetDefaultValue(), DMLabelGetValue(), DMLabelSetValue()
533 */
534 PetscErrorCode DMLabelSetDefaultValue(DMLabel label, PetscInt defaultValue)
535 {
536   PetscFunctionBegin;
537   label->defaultValue = defaultValue;
538   PetscFunctionReturn(0);
539 }
540 
541 #undef __FUNCT__
542 #define __FUNCT__ "DMLabelGetValue"
543 /*@
544   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())
545 
546   Input Parameters:
547 + label - the DMLabel
548 - point - the point
549 
550   Output Parameter:
551 . value - The point value, or -1
552 
553   Level: intermediate
554 
555 .seealso: DMLabelCreate(), DMLabelSetValue(), DMLabelClearValue(), DMLabelGetDefaultValue(), DMLabelSetDefaultValue()
556 @*/
557 PetscErrorCode DMLabelGetValue(DMLabel label, PetscInt point, PetscInt *value)
558 {
559   PetscInt       v;
560   PetscErrorCode ierr;
561 
562   PetscFunctionBegin;
563   PetscValidPointer(value, 3);
564   *value = label->defaultValue;
565   for (v = 0; v < label->numStrata; ++v) {
566     if (label->arrayValid[v]) {
567       PetscInt i;
568 
569       ierr = PetscFindInt(point, label->stratumSizes[v], &label->points[v][0], &i);CHKERRQ(ierr);
570       if (i >= 0) {
571         *value = label->stratumValues[v];
572         break;
573       }
574     } else {
575       PetscBool has;
576 
577       PetscHashIHasKey(label->ht[v], point, has);
578       if (has) {
579         *value = label->stratumValues[v];
580         break;
581       }
582     }
583   }
584   PetscFunctionReturn(0);
585 }
586 
587 #undef __FUNCT__
588 #define __FUNCT__ "DMLabelSetValue"
589 /*@
590   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 somethingg different), then this function will do nothing.
591 
592   Input Parameters:
593 + label - the DMLabel
594 . point - the point
595 - value - The point value
596 
597   Level: intermediate
598 
599 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelClearValue(), DMLabelGetDefaultValue(), DMLabelSetDefaultValue()
600 @*/
601 PetscErrorCode DMLabelSetValue(DMLabel label, PetscInt point, PetscInt value)
602 {
603   PETSC_UNUSED PetscHashIIter iter, ret;
604   PetscInt                    v;
605   PetscErrorCode              ierr;
606 
607   PetscFunctionBegin;
608   /* Find, or add, label value */
609   if (value == label->defaultValue) PetscFunctionReturn(0);
610   for (v = 0; v < label->numStrata; ++v) {
611     if (label->stratumValues[v] == value) break;
612   }
613   /* Create new table */
614   if (v >= label->numStrata) {ierr = DMLabelAddStratum(label, value);CHKERRQ(ierr);}
615   ierr = DMLabelMakeInvalid_Private(label, v);CHKERRQ(ierr);
616   /* Set key */
617   PetscHashIPut(label->ht[v], point, ret, iter);
618   PetscFunctionReturn(0);
619 }
620 
621 #undef __FUNCT__
622 #define __FUNCT__ "DMLabelClearValue"
623 /*@
624   DMLabelClearValue - Clear the value a label assigns to a point
625 
626   Input Parameters:
627 + label - the DMLabel
628 . point - the point
629 - value - The point value
630 
631   Level: intermediate
632 
633 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue()
634 @*/
635 PetscErrorCode DMLabelClearValue(DMLabel label, PetscInt point, PetscInt value)
636 {
637   PetscInt       v, p;
638   PetscErrorCode ierr;
639 
640   PetscFunctionBegin;
641   /* Find label value */
642   for (v = 0; v < label->numStrata; ++v) {
643     if (label->stratumValues[v] == value) break;
644   }
645   if (v >= label->numStrata) PetscFunctionReturn(0);
646   if (label->arrayValid[v]) {
647     /* Check whether point exists */
648     ierr = PetscFindInt(point, label->stratumSizes[v], &label->points[v][0], &p);CHKERRQ(ierr);
649     if (p >= 0) {
650       ierr = PetscMemmove(&label->points[v][p], &label->points[v][p+1], (label->stratumSizes[v]-p-1) * sizeof(PetscInt));CHKERRQ(ierr);
651       --label->stratumSizes[v];
652       if (label->bt) {
653         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);
654         ierr = PetscBTClear(label->bt, point - label->pStart);CHKERRQ(ierr);
655       }
656     }
657   } else {
658     ierr = PetscHashIDelKey(label->ht[v], point);CHKERRQ(ierr);
659   }
660   PetscFunctionReturn(0);
661 }
662 
663 #undef __FUNCT__
664 #define __FUNCT__ "DMLabelInsertIS"
665 /*@
666   DMLabelInsertIS - Set all points in the IS to a value
667 
668   Input Parameters:
669 + label - the DMLabel
670 . is    - the point IS
671 - value - The point value
672 
673   Level: intermediate
674 
675 .seealso: DMLabelCreate(), DMLabelGetValue(), DMLabelSetValue(), DMLabelClearValue()
676 @*/
677 PetscErrorCode DMLabelInsertIS(DMLabel label, IS is, PetscInt value)
678 {
679   const PetscInt *points;
680   PetscInt        n, p;
681   PetscErrorCode  ierr;
682 
683   PetscFunctionBegin;
684   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
685   ierr = ISGetLocalSize(is, &n);CHKERRQ(ierr);
686   ierr = ISGetIndices(is, &points);CHKERRQ(ierr);
687   for (p = 0; p < n; ++p) {ierr = DMLabelSetValue(label, points[p], value);CHKERRQ(ierr);}
688   ierr = ISRestoreIndices(is, &points);CHKERRQ(ierr);
689   PetscFunctionReturn(0);
690 }
691 
692 #undef __FUNCT__
693 #define __FUNCT__ "DMLabelGetNumValues"
694 PetscErrorCode DMLabelGetNumValues(DMLabel label, PetscInt *numValues)
695 {
696   PetscFunctionBegin;
697   PetscValidPointer(numValues, 2);
698   *numValues = label->numStrata;
699   PetscFunctionReturn(0);
700 }
701 
702 #undef __FUNCT__
703 #define __FUNCT__ "DMLabelGetValueIS"
704 PetscErrorCode DMLabelGetValueIS(DMLabel label, IS *values)
705 {
706   PetscErrorCode ierr;
707 
708   PetscFunctionBegin;
709   PetscValidPointer(values, 2);
710   ierr = ISCreateGeneral(PETSC_COMM_SELF, label->numStrata, label->stratumValues, PETSC_USE_POINTER, values);CHKERRQ(ierr);
711   PetscFunctionReturn(0);
712 }
713 
714 #undef __FUNCT__
715 #define __FUNCT__ "DMLabelHasStratum"
716 PetscErrorCode DMLabelHasStratum(DMLabel label, PetscInt value, PetscBool *exists)
717 {
718   PetscInt v;
719 
720   PetscFunctionBegin;
721   PetscValidPointer(exists, 3);
722   *exists = PETSC_FALSE;
723   for (v = 0; v < label->numStrata; ++v) {
724     if (label->stratumValues[v] == value) {
725       *exists = PETSC_TRUE;
726       break;
727     }
728   }
729   PetscFunctionReturn(0);
730 }
731 
732 #undef __FUNCT__
733 #define __FUNCT__ "DMLabelGetStratumSize"
734 PetscErrorCode DMLabelGetStratumSize(DMLabel label, PetscInt value, PetscInt *size)
735 {
736   PetscInt       v;
737   PetscErrorCode ierr;
738 
739   PetscFunctionBegin;
740   PetscValidPointer(size, 3);
741   *size = 0;
742   for (v = 0; v < label->numStrata; ++v) {
743     if (label->stratumValues[v] == value) {
744       ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
745       *size = label->stratumSizes[v];
746       break;
747     }
748   }
749   PetscFunctionReturn(0);
750 }
751 
752 #undef __FUNCT__
753 #define __FUNCT__ "DMLabelGetStratumBounds"
754 PetscErrorCode DMLabelGetStratumBounds(DMLabel label, PetscInt value, PetscInt *start, PetscInt *end)
755 {
756   PetscInt       v;
757   PetscErrorCode ierr;
758 
759   PetscFunctionBegin;
760   if (start) {PetscValidPointer(start, 3); *start = 0;}
761   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
762   for (v = 0; v < label->numStrata; ++v) {
763     if (label->stratumValues[v] != value) continue;
764     ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
765     if (label->stratumSizes[v]  <= 0)     break;
766     if (start) *start = label->points[v][0];
767     if (end)   *end   = label->points[v][label->stratumSizes[v]-1]+1;
768     break;
769   }
770   PetscFunctionReturn(0);
771 }
772 
773 #undef __FUNCT__
774 #define __FUNCT__ "DMLabelGetStratumIS"
775 PetscErrorCode DMLabelGetStratumIS(DMLabel label, PetscInt value, IS *points)
776 {
777   PetscInt       v;
778   PetscErrorCode ierr;
779 
780   PetscFunctionBegin;
781   PetscValidPointer(points, 3);
782   *points = NULL;
783   for (v = 0; v < label->numStrata; ++v) {
784     if (label->stratumValues[v] == value) {
785       ierr = DMLabelMakeValid_Private(label, v);CHKERRQ(ierr);
786       if (label->arrayValid[v]) {
787         ierr = ISCreateGeneral(PETSC_COMM_SELF, label->stratumSizes[v], &label->points[v][0], PETSC_COPY_VALUES, points);CHKERRQ(ierr);
788         ierr = PetscObjectSetName((PetscObject) *points, "indices");CHKERRQ(ierr);
789       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Need to implement this to speedup Stratify");
790       break;
791     }
792   }
793   PetscFunctionReturn(0);
794 }
795 
796 #undef __FUNCT__
797 #define __FUNCT__ "DMLabelClearStratum"
798 PetscErrorCode DMLabelClearStratum(DMLabel label, PetscInt value)
799 {
800   PetscInt       v;
801   PetscErrorCode ierr;
802 
803   PetscFunctionBegin;
804   for (v = 0; v < label->numStrata; ++v) {
805     if (label->stratumValues[v] == value) break;
806   }
807   if (v >= label->numStrata) PetscFunctionReturn(0);
808   if (label->bt) {
809     PetscInt i;
810 
811     for (i = 0; i < label->stratumSizes[v]; ++i) {
812       const PetscInt point = label->points[v][i];
813 
814       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);
815       ierr = PetscBTClear(label->bt, point - label->pStart);CHKERRQ(ierr);
816     }
817   }
818   if (label->arrayValid[v]) {
819     label->stratumSizes[v] = 0;
820   } else {
821     PetscHashIClear(label->ht[v]);
822   }
823   PetscFunctionReturn(0);
824 }
825 
826 #undef __FUNCT__
827 #define __FUNCT__ "DMLabelFilter"
828 PetscErrorCode DMLabelFilter(DMLabel label, PetscInt start, PetscInt end)
829 {
830   PetscInt       v;
831   PetscErrorCode ierr;
832 
833   PetscFunctionBegin;
834   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
835   label->pStart = start;
836   label->pEnd   = end;
837   if (label->bt) {ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);}
838   /* Could squish offsets, but would only make sense if I reallocate the storage */
839   for (v = 0; v < label->numStrata; ++v) {
840     PetscInt off, q;
841 
842     for (off = 0, q = 0; q < label->stratumSizes[v]; ++q) {
843       const PetscInt point = label->points[v][q];
844 
845       if ((point < start) || (point >= end)) continue;
846       label->points[v][off++] = point;
847     }
848     label->stratumSizes[v] = off;
849   }
850   ierr = DMLabelCreateIndex(label, start, end);CHKERRQ(ierr);
851   PetscFunctionReturn(0);
852 }
853 
854 #undef __FUNCT__
855 #define __FUNCT__ "DMLabelPermute"
856 PetscErrorCode DMLabelPermute(DMLabel label, IS permutation, DMLabel *labelNew)
857 {
858   const PetscInt *perm;
859   PetscInt        numValues, numPoints, v, q;
860   PetscErrorCode  ierr;
861 
862   PetscFunctionBegin;
863   ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);
864   ierr = DMLabelDuplicate(label, labelNew);CHKERRQ(ierr);
865   ierr = DMLabelGetNumValues(*labelNew, &numValues);CHKERRQ(ierr);
866   ierr = ISGetLocalSize(permutation, &numPoints);CHKERRQ(ierr);
867   ierr = ISGetIndices(permutation, &perm);CHKERRQ(ierr);
868   for (v = 0; v < numValues; ++v) {
869     const PetscInt size   = (*labelNew)->stratumSizes[v];
870 
871     for (q = 0; q < size; ++q) {
872       const PetscInt point = (*labelNew)->points[v][q];
873 
874       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);
875       (*labelNew)->points[v][q] = perm[point];
876     }
877     ierr = PetscSortInt(size, &(*labelNew)->points[v][0]);CHKERRQ(ierr);
878   }
879   ierr = ISRestoreIndices(permutation, &perm);CHKERRQ(ierr);
880   if (label->bt) {
881     ierr = PetscBTDestroy(&label->bt);CHKERRQ(ierr);
882     ierr = DMLabelCreateIndex(label, label->pStart, label->pEnd);CHKERRQ(ierr);
883   }
884   PetscFunctionReturn(0);
885 }
886 
887 #undef __FUNCT__
888 #define __FUNCT__ "DMLabelDistribute_Internal"
889 PetscErrorCode DMLabelDistribute_Internal(DMLabel label, PetscSF sf, PetscSection *leafSection, PetscInt **leafStrata)
890 {
891   MPI_Comm       comm;
892   PetscInt       s, l, nroots, nleaves, dof, offset, size;
893   PetscInt      *remoteOffsets, *rootStrata, *rootIdx;
894   PetscSection   rootSection;
895   PetscSF        labelSF;
896   PetscErrorCode ierr;
897 
898   PetscFunctionBegin;
899   if (label) {ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);}
900   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
901   /* Build a section of stratum values per point, generate the according SF
902      and distribute point-wise stratum values to leaves. */
903   ierr = PetscSFGetGraph(sf, &nroots, &nleaves, NULL, NULL);CHKERRQ(ierr);
904   ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr);
905   ierr = PetscSectionSetChart(rootSection, 0, nroots);CHKERRQ(ierr);
906   if (label) {
907     for (s = 0; s < label->numStrata; ++s) {
908       for (l = 0; l < label->stratumSizes[s]; l++) {
909         ierr = PetscSectionGetDof(rootSection, label->points[s][l], &dof);CHKERRQ(ierr);
910         ierr = PetscSectionSetDof(rootSection, label->points[s][l], dof+1);CHKERRQ(ierr);
911       }
912     }
913   }
914   ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
915   /* Create a point-wise array of stratum values */
916   ierr = PetscSectionGetStorageSize(rootSection, &size);CHKERRQ(ierr);
917   ierr = PetscMalloc1(size, &rootStrata);CHKERRQ(ierr);
918   ierr = PetscCalloc1(nroots, &rootIdx);CHKERRQ(ierr);
919   if (label) {
920     for (s = 0; s < label->numStrata; ++s) {
921       for (l = 0; l < label->stratumSizes[s]; l++) {
922         const PetscInt p = label->points[s][l];
923         ierr = PetscSectionGetOffset(rootSection, p, &offset);CHKERRQ(ierr);
924         rootStrata[offset+rootIdx[p]++] = label->stratumValues[s];
925       }
926     }
927   }
928   /* Build SF that maps label points to remote processes */
929   ierr = PetscSectionCreate(comm, leafSection);CHKERRQ(ierr);
930   ierr = PetscSFDistributeSection(sf, rootSection, &remoteOffsets, *leafSection);CHKERRQ(ierr);
931   ierr = PetscSFCreateSectionSF(sf, rootSection, remoteOffsets, *leafSection, &labelSF);CHKERRQ(ierr);
932   ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
933   /* Send the strata for each point over the derived SF */
934   ierr = PetscSectionGetStorageSize(*leafSection, &size);CHKERRQ(ierr);
935   ierr = PetscMalloc1(size, leafStrata);CHKERRQ(ierr);
936   ierr = PetscSFBcastBegin(labelSF, MPIU_INT, rootStrata, *leafStrata);CHKERRQ(ierr);
937   ierr = PetscSFBcastEnd(labelSF, MPIU_INT, rootStrata, *leafStrata);CHKERRQ(ierr);
938   /* Clean up */
939   ierr = PetscFree(rootStrata);CHKERRQ(ierr);
940   ierr = PetscFree(rootIdx);CHKERRQ(ierr);
941   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
942   ierr = PetscSFDestroy(&labelSF);CHKERRQ(ierr);
943   PetscFunctionReturn(0);
944 }
945 
946 #undef __FUNCT__
947 #define __FUNCT__ "DMLabelDistribute"
948 PetscErrorCode DMLabelDistribute(DMLabel label, PetscSF sf, DMLabel *labelNew)
949 {
950   MPI_Comm       comm;
951   PetscSection   leafSection;
952   PetscInt       p, pStart, pEnd, s, size, dof, offset, stratum;
953   PetscInt      *leafStrata, *strataIdx;
954   char          *name;
955   PetscInt       nameSize;
956   PetscHashI     stratumHash;
957   PETSC_UNUSED   PetscHashIIter ret, iter;
958   size_t         len = 0;
959   PetscMPIInt    rank;
960   PetscErrorCode ierr;
961 
962   PetscFunctionBegin;
963   if (label) {ierr = DMLabelMakeAllValid_Private(label);CHKERRQ(ierr);}
964   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
965   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
966   /* Bcast name */
967   if (!rank) {ierr = PetscStrlen(label->name, &len);CHKERRQ(ierr);}
968   nameSize = len;
969   ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
970   ierr = PetscMalloc1(nameSize+1, &name);CHKERRQ(ierr);
971   if (!rank) {ierr = PetscMemcpy(name, label->name, nameSize+1);CHKERRQ(ierr);}
972   ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
973   ierr = DMLabelCreate(name, labelNew);CHKERRQ(ierr);
974   ierr = PetscFree(name);CHKERRQ(ierr);
975   /* Bcast defaultValue */
976   if (!rank) (*labelNew)->defaultValue = label->defaultValue;
977   ierr = MPI_Bcast(&(*labelNew)->defaultValue, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
978   /* Distribute stratum values over the SF and get the point mapping on the receiver */
979   ierr = DMLabelDistribute_Internal(label, sf, &leafSection, &leafStrata);CHKERRQ(ierr);
980   /* Determine received stratum values and initialise new label*/
981   PetscHashICreate(stratumHash);
982   ierr = PetscSectionGetStorageSize(leafSection, &size);CHKERRQ(ierr);
983   for (p = 0; p < size; ++p) PetscHashIPut(stratumHash, leafStrata[p], ret, iter);
984   PetscHashISize(stratumHash, (*labelNew)->numStrata);
985   ierr = PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->arrayValid);CHKERRQ(ierr);
986   for (s = 0; s < (*labelNew)->numStrata; ++s) (*labelNew)->arrayValid[s] = PETSC_TRUE;
987   ierr = PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->stratumValues);CHKERRQ(ierr);
988   /* Turn leafStrata into indices rather than stratum values */
989   offset = 0;
990   ierr = PetscHashIGetKeys(stratumHash, &offset, (*labelNew)->stratumValues);CHKERRQ(ierr);
991   for (p = 0; p < size; ++p) {
992     for (s = 0; s < (*labelNew)->numStrata; ++s) {
993       if (leafStrata[p] == (*labelNew)->stratumValues[s]) {leafStrata[p] = s; break;}
994     }
995   }
996   /* Rebuild the point strata on the receiver */
997   ierr = PetscCalloc1((*labelNew)->numStrata,&(*labelNew)->stratumSizes);CHKERRQ(ierr);
998   ierr = PetscSectionGetChart(leafSection, &pStart, &pEnd);CHKERRQ(ierr);
999   for (p=pStart; p<pEnd; p++) {
1000     ierr = PetscSectionGetDof(leafSection, p, &dof);CHKERRQ(ierr);
1001     ierr = PetscSectionGetOffset(leafSection, p, &offset);CHKERRQ(ierr);
1002     for (s=0; s<dof; s++) {
1003       (*labelNew)->stratumSizes[leafStrata[offset+s]]++;
1004     }
1005   }
1006   ierr = PetscCalloc1((*labelNew)->numStrata,&(*labelNew)->ht);CHKERRQ(ierr);
1007   ierr = PetscMalloc1((*labelNew)->numStrata,&(*labelNew)->points);CHKERRQ(ierr);
1008   for (s = 0; s < (*labelNew)->numStrata; ++s) {
1009     PetscHashICreate((*labelNew)->ht[s]);
1010     ierr = PetscMalloc1((*labelNew)->stratumSizes[s], &(*labelNew)->points[s]);CHKERRQ(ierr);
1011   }
1012   /* Insert points into new strata */
1013   ierr = PetscCalloc1((*labelNew)->numStrata, &strataIdx);CHKERRQ(ierr);
1014   ierr = PetscSectionGetChart(leafSection, &pStart, &pEnd);CHKERRQ(ierr);
1015   for (p=pStart; p<pEnd; p++) {
1016     ierr = PetscSectionGetDof(leafSection, p, &dof);CHKERRQ(ierr);
1017     ierr = PetscSectionGetOffset(leafSection, p, &offset);CHKERRQ(ierr);
1018     for (s=0; s<dof; s++) {
1019       stratum = leafStrata[offset+s];
1020       (*labelNew)->points[stratum][strataIdx[stratum]++] = p;
1021     }
1022   }
1023   PetscHashIDestroy(stratumHash);
1024   ierr = PetscFree(leafStrata);CHKERRQ(ierr);
1025   ierr = PetscFree(strataIdx);CHKERRQ(ierr);
1026   ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
1027   PetscFunctionReturn(0);
1028 }
1029 
1030 #undef __FUNCT__
1031 #define __FUNCT__ "DMLabelGather"
1032 /*@
1033   DMLabelGather - Gather all label values from leafs into roots
1034 
1035   Input Parameters:
1036 + label - the DMLabel
1037 . point - the Star Forest point communication map
1038 
1039   Input Parameters:
1040 + label - the new DMLabel with localised leaf values
1041 
1042   Level: developer
1043 
1044   Note: This is the inverse operation to DMLabelDistribute.
1045 
1046 .seealso: DMLabelDistribute()
1047 @*/
1048 PetscErrorCode DMLabelGather(DMLabel label, PetscSF sf, DMLabel *labelNew)
1049 {
1050   MPI_Comm       comm;
1051   PetscSection   rootSection;
1052   PetscSF        sfLabel;
1053   PetscSFNode   *rootPoints, *leafPoints;
1054   PetscInt       p, s, d, nroots, nleaves, nmultiroots, idx, dof, offset;
1055   const PetscInt *rootDegree, *ilocal;
1056   PetscInt       *rootStrata;
1057   char          *name;
1058   PetscInt       nameSize;
1059   size_t         len = 0;
1060   PetscMPIInt    rank, numProcs;
1061   PetscErrorCode ierr;
1062 
1063   PetscFunctionBegin;
1064   ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr);
1065   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1066   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
1067   /* Bcast name */
1068   if (!rank) {ierr = PetscStrlen(label->name, &len);CHKERRQ(ierr);}
1069   nameSize = len;
1070   ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
1071   ierr = PetscMalloc1(nameSize+1, &name);CHKERRQ(ierr);
1072   if (!rank) {ierr = PetscMemcpy(name, label->name, nameSize+1);CHKERRQ(ierr);}
1073   ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
1074   ierr = DMLabelCreate(name, labelNew);CHKERRQ(ierr);
1075   ierr = PetscFree(name);CHKERRQ(ierr);
1076   /* Gather rank/index pairs of leaves into local roots to build
1077      an inverse, multi-rooted SF. Note that this ignores local leaf
1078      indexing due to the use of the multiSF in PetscSFGather. */
1079   ierr = PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, NULL);CHKERRQ(ierr);
1080   ierr = PetscMalloc1(nroots, &leafPoints);CHKERRQ(ierr);
1081   for (p = 0; p < nroots; ++p) leafPoints[p].rank = leafPoints[p].index = -1;
1082   for (p = 0; p < nleaves; p++) {
1083     leafPoints[ilocal[p]].index = ilocal[p];
1084     leafPoints[ilocal[p]].rank  = rank;
1085   }
1086   ierr = PetscSFComputeDegreeBegin(sf, &rootDegree);CHKERRQ(ierr);
1087   ierr = PetscSFComputeDegreeEnd(sf, &rootDegree);CHKERRQ(ierr);
1088   for (p = 0, nmultiroots = 0; p < nroots; ++p) nmultiroots += rootDegree[p];
1089   ierr = PetscMalloc1(nmultiroots, &rootPoints);CHKERRQ(ierr);
1090   ierr = PetscSFGatherBegin(sf, MPIU_2INT, leafPoints, rootPoints);CHKERRQ(ierr);
1091   ierr = PetscSFGatherEnd(sf, MPIU_2INT, leafPoints, rootPoints);CHKERRQ(ierr);
1092   ierr = PetscSFCreate(comm,& sfLabel);CHKERRQ(ierr);
1093   ierr = PetscSFSetGraph(sfLabel, nroots, nmultiroots, NULL, PETSC_OWN_POINTER, rootPoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
1094   /* Migrate label over inverted SF to pull stratum values at leaves into roots. */
1095   ierr = DMLabelDistribute_Internal(label, sfLabel, &rootSection, &rootStrata);CHKERRQ(ierr);
1096   /* Rebuild the point strata on the receiver */
1097   for (p = 0, idx = 0; p < nroots; p++) {
1098     for (d = 0; d < rootDegree[p]; d++) {
1099       ierr = PetscSectionGetDof(rootSection, idx+d, &dof);CHKERRQ(ierr);
1100       ierr = PetscSectionGetOffset(rootSection, idx+d, &offset);CHKERRQ(ierr);
1101       for (s = 0; s < dof; s++) {ierr = DMLabelSetValue(*labelNew, p, rootStrata[offset+s]);CHKERRQ(ierr);}
1102     }
1103     idx += rootDegree[p];
1104   }
1105   ierr = PetscFree(leafPoints);CHKERRQ(ierr);
1106   ierr = PetscFree(rootStrata);CHKERRQ(ierr);
1107   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
1108   ierr = PetscSFDestroy(&sfLabel);CHKERRQ(ierr);
1109   PetscFunctionReturn(0);
1110 }
1111 
1112 #undef __FUNCT__
1113 #define __FUNCT__ "DMLabelConvertToSection"
1114 PetscErrorCode DMLabelConvertToSection(DMLabel label, PetscSection *section, IS *is)
1115 {
1116   IS              vIS;
1117   const PetscInt *values;
1118   PetscInt       *points;
1119   PetscInt        nV, vS = 0, vE = 0, v, N;
1120   PetscErrorCode  ierr;
1121 
1122   PetscFunctionBegin;
1123   ierr = DMLabelGetNumValues(label, &nV);CHKERRQ(ierr);
1124   ierr = DMLabelGetValueIS(label, &vIS);CHKERRQ(ierr);
1125   ierr = ISGetIndices(vIS, &values);CHKERRQ(ierr);
1126   if (nV) {vS = values[0]; vE = values[0]+1;}
1127   for (v = 1; v < nV; ++v) {
1128     vS = PetscMin(vS, values[v]);
1129     vE = PetscMax(vE, values[v]+1);
1130   }
1131   ierr = PetscSectionCreate(PETSC_COMM_SELF, section);CHKERRQ(ierr);
1132   ierr = PetscSectionSetChart(*section, vS, vE);CHKERRQ(ierr);
1133   for (v = 0; v < nV; ++v) {
1134     PetscInt n;
1135 
1136     ierr = DMLabelGetStratumSize(label, values[v], &n);CHKERRQ(ierr);
1137     ierr = PetscSectionSetDof(*section, values[v], n);CHKERRQ(ierr);
1138   }
1139   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
1140   ierr = PetscSectionGetStorageSize(*section, &N);CHKERRQ(ierr);
1141   ierr = PetscMalloc1(N, &points);CHKERRQ(ierr);
1142   for (v = 0; v < nV; ++v) {
1143     IS              is;
1144     const PetscInt *spoints;
1145     PetscInt        dof, off, p;
1146 
1147     ierr = PetscSectionGetDof(*section, values[v], &dof);CHKERRQ(ierr);
1148     ierr = PetscSectionGetOffset(*section, values[v], &off);CHKERRQ(ierr);
1149     ierr = DMLabelGetStratumIS(label, values[v], &is);CHKERRQ(ierr);
1150     ierr = ISGetIndices(is, &spoints);CHKERRQ(ierr);
1151     for (p = 0; p < dof; ++p) points[off+p] = spoints[p];
1152     ierr = ISRestoreIndices(is, &spoints);CHKERRQ(ierr);
1153     ierr = ISDestroy(&is);CHKERRQ(ierr);
1154   }
1155   ierr = ISRestoreIndices(vIS, &values);CHKERRQ(ierr);
1156   ierr = ISDestroy(&vIS);CHKERRQ(ierr);
1157   ierr = ISCreateGeneral(PETSC_COMM_SELF, N, points, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
1158   PetscFunctionReturn(0);
1159 }
1160 
1161 #undef __FUNCT__
1162 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
1163 /*@C
1164   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
1165   the local section and an SF describing the section point overlap.
1166 
1167   Input Parameters:
1168   + s - The PetscSection for the local field layout
1169   . sf - The SF describing parallel layout of the section points
1170   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
1171   . label - The label specifying the points
1172   - labelValue - The label stratum specifying the points
1173 
1174   Output Parameter:
1175   . gsection - The PetscSection for the global field layout
1176 
1177   Note: This gives negative sizes and offsets to points not owned by this process
1178 
1179   Level: developer
1180 
1181 .seealso: PetscSectionCreate()
1182 @*/
1183 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
1184 {
1185   PetscInt      *neg = NULL, *tmpOff = NULL;
1186   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
1187   PetscErrorCode ierr;
1188 
1189   PetscFunctionBegin;
1190   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), gsection);CHKERRQ(ierr);
1191   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
1192   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
1193   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
1194   if (nroots >= 0) {
1195     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
1196     ierr = PetscCalloc1(nroots, &neg);CHKERRQ(ierr);
1197     if (nroots > pEnd-pStart) {
1198       ierr = PetscCalloc1(nroots, &tmpOff);CHKERRQ(ierr);
1199     } else {
1200       tmpOff = &(*gsection)->atlasDof[-pStart];
1201     }
1202   }
1203   /* Mark ghost points with negative dof */
1204   for (p = pStart; p < pEnd; ++p) {
1205     PetscInt value;
1206 
1207     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
1208     if (value != labelValue) continue;
1209     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
1210     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
1211     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
1212     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
1213     if (neg) neg[p] = -(dof+1);
1214   }
1215   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
1216   if (nroots >= 0) {
1217     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1218     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1219     if (nroots > pEnd-pStart) {
1220       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
1221     }
1222   }
1223   /* Calculate new sizes, get proccess offset, and calculate point offsets */
1224   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
1225     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
1226     (*gsection)->atlasOff[p] = off;
1227     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
1228   }
1229   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) s));CHKERRQ(ierr);
1230   globalOff -= off;
1231   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
1232     (*gsection)->atlasOff[p] += globalOff;
1233     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
1234   }
1235   /* Put in negative offsets for ghost points */
1236   if (nroots >= 0) {
1237     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1238     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
1239     if (nroots > pEnd-pStart) {
1240       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
1241     }
1242   }
1243   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
1244   ierr = PetscFree(neg);CHKERRQ(ierr);
1245   PetscFunctionReturn(0);
1246 }
1247 
1248