Actual source code: dmlabel.c

  1: #include <petscdm.h>
  2: #include <petsc/private/dmlabelimpl.h>
  3: #include <petsc/private/sectionimpl.h>
  4: #include <petscsf.h>
  5: #include <petscsection.h>

  7: PetscFunctionList DMLabelList              = NULL;
  8: PetscBool         DMLabelRegisterAllCalled = PETSC_FALSE;

 10: /*@
 11:   DMLabelCreate - Create a `DMLabel` object, which is a multimap

 13:   Collective

 15:   Input Parameters:
 16: + comm - The communicator, usually `PETSC_COMM_SELF`
 17: - name - The label name

 19:   Output Parameter:
 20: . label - The `DMLabel`

 22:   Level: beginner

 24:   Notes:
 25:   The label name is actually usually the `PetscObject` name.
 26:   One can get/set it with `PetscObjectGetName()`/`PetscObjectSetName()`.

 28: .seealso: `DMLabel`, `DM`, `DMLabelDestroy()`
 29: @*/
 30: PetscErrorCode DMLabelCreate(MPI_Comm comm, const char name[], DMLabel *label)
 31: {
 32:   PetscFunctionBegin;
 33:   PetscAssertPointer(label, 3);
 34:   PetscCall(DMInitializePackage());

 36:   PetscCall(PetscHeaderCreate(*label, DMLABEL_CLASSID, "DMLabel", "DMLabel", "DM", comm, DMLabelDestroy, DMLabelView));

 38:   (*label)->numStrata     = 0;
 39:   (*label)->defaultValue  = -1;
 40:   (*label)->stratumValues = NULL;
 41:   (*label)->validIS       = NULL;
 42:   (*label)->stratumSizes  = NULL;
 43:   (*label)->points        = NULL;
 44:   (*label)->ht            = NULL;
 45:   (*label)->pStart        = -1;
 46:   (*label)->pEnd          = -1;
 47:   (*label)->bt            = NULL;
 48:   PetscCall(PetscHMapICreate(&(*label)->hmap));
 49:   PetscCall(PetscObjectSetName((PetscObject)*label, name));
 50:   PetscCall(DMLabelSetType(*label, DMLABELCONCRETE));
 51:   PetscFunctionReturn(PETSC_SUCCESS);
 52: }

 54: /*@
 55:   DMLabelSetUp - SetUp a `DMLabel` object

 57:   Collective

 59:   Input Parameters:
 60: . label - The `DMLabel`

 62:   Level: intermediate

 64: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
 65: @*/
 66: PetscErrorCode DMLabelSetUp(DMLabel label)
 67: {
 68:   PetscFunctionBegin;
 70:   PetscTryTypeMethod(label, setup);
 71:   PetscFunctionReturn(PETSC_SUCCESS);
 72: }

 74: /*
 75:   DMLabelMakeValid_Private - Transfer stratum data from the hash format to the sorted list format

 77:   Not collective

 79:   Input parameter:
 80: + label - The `DMLabel`
 81: - v - The stratum value

 83:   Output parameter:
 84: . label - The `DMLabel` with stratum in sorted list format

 86:   Level: developer

 88: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`
 89: */
 90: static PetscErrorCode DMLabelMakeValid_Private(DMLabel label, PetscInt v)
 91: {
 92:   IS       is;
 93:   PetscInt off = 0, *pointArray, p;

 95:   PetscFunctionBegin;
 96:   if ((PetscLikely(v >= 0 && v < label->numStrata) && label->validIS[v]) || label->readonly) PetscFunctionReturn(PETSC_SUCCESS);
 97:   PetscCheck(v >= 0 && v < label->numStrata, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to access invalid stratum %" PetscInt_FMT " in DMLabelMakeValid_Private", v);
 98:   PetscCall(PetscHSetIGetSize(label->ht[v], &label->stratumSizes[v]));
 99:   PetscCall(PetscMalloc1(label->stratumSizes[v], &pointArray));
100:   PetscCall(PetscHSetIGetElems(label->ht[v], &off, pointArray));
101:   PetscCall(PetscHSetIClear(label->ht[v]));
102:   PetscCall(PetscSortInt(label->stratumSizes[v], pointArray));
103:   if (label->bt) {
104:     for (p = 0; p < label->stratumSizes[v]; ++p) {
105:       const PetscInt point = pointArray[p];
106:       PetscCheck(!(point < label->pStart) && !(point >= label->pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, label->pStart, label->pEnd);
107:       PetscCall(PetscBTSet(label->bt, point - label->pStart));
108:     }
109:   }
110:   if (label->stratumSizes[v] > 0 && pointArray[label->stratumSizes[v] - 1] == pointArray[0] + label->stratumSizes[v] - 1) {
111:     PetscCall(ISCreateStride(PETSC_COMM_SELF, label->stratumSizes[v], pointArray[0], 1, &is));
112:     PetscCall(PetscFree(pointArray));
113:   } else {
114:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, label->stratumSizes[v], pointArray, PETSC_OWN_POINTER, &is));
115:   }
116:   PetscCall(PetscObjectSetName((PetscObject)is, "indices"));
117:   label->points[v]  = is;
118:   label->validIS[v] = PETSC_TRUE;
119:   PetscCall(PetscObjectStateIncrease((PetscObject)label));
120:   PetscFunctionReturn(PETSC_SUCCESS);
121: }

123: /*
124:   DMLabelMakeAllValid_Private - Transfer all strata from the hash format to the sorted list format

126:   Not Collective

128:   Input parameter:
129: . label - The `DMLabel`

131:   Output parameter:
132: . label - The `DMLabel` with all strata in sorted list format

134:   Level: developer

136: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`
137: */
138: static PetscErrorCode DMLabelMakeAllValid_Private(DMLabel label)
139: {
140:   PetscInt v;

142:   PetscFunctionBegin;
143:   for (v = 0; v < label->numStrata; v++) PetscCall(DMLabelMakeValid_Private(label, v));
144:   PetscFunctionReturn(PETSC_SUCCESS);
145: }

147: /*
148:   DMLabelMakeInvalid_Private - Transfer stratum data from the sorted list format to the hash format

150:   Not Collective

152:   Input parameter:
153: + label - The `DMLabel`
154: - v - The stratum value

156:   Output parameter:
157: . label - The `DMLabel` with stratum in hash format

159:   Level: developer

161: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`
162: */
163: static PetscErrorCode DMLabelMakeInvalid_Private(DMLabel label, PetscInt v)
164: {
165:   PetscInt        p;
166:   const PetscInt *points;

168:   PetscFunctionBegin;
169:   if ((PetscLikely(v >= 0 && v < label->numStrata) && !label->validIS[v]) || label->readonly) PetscFunctionReturn(PETSC_SUCCESS);
170:   PetscCheck(v >= 0 && v < label->numStrata, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to access invalid stratum %" PetscInt_FMT " in DMLabelMakeInvalid_Private", v);
171:   if (label->points[v]) {
172:     PetscCall(ISGetIndices(label->points[v], &points));
173:     for (p = 0; p < label->stratumSizes[v]; ++p) PetscCall(PetscHSetIAdd(label->ht[v], points[p]));
174:     PetscCall(ISRestoreIndices(label->points[v], &points));
175:     PetscCall(ISDestroy(&label->points[v]));
176:   }
177:   label->validIS[v] = PETSC_FALSE;
178:   PetscFunctionReturn(PETSC_SUCCESS);
179: }

181: PetscErrorCode DMLabelMakeAllInvalid_Internal(DMLabel label)
182: {
183:   PetscInt v;

185:   PetscFunctionBegin;
186:   for (v = 0; v < label->numStrata; v++) PetscCall(DMLabelMakeInvalid_Private(label, v));
187:   PetscFunctionReturn(PETSC_SUCCESS);
188: }

190: #if !defined(DMLABEL_LOOKUP_THRESHOLD)
191:   #define DMLABEL_LOOKUP_THRESHOLD 16
192: #endif

194: PetscErrorCode DMLabelLookupStratum(DMLabel label, PetscInt value, PetscInt *index)
195: {
196:   PetscInt v;

198:   PetscFunctionBegin;
199:   *index = -1;
200:   if (label->numStrata <= DMLABEL_LOOKUP_THRESHOLD || label->readonly) {
201:     for (v = 0; v < label->numStrata; ++v)
202:       if (label->stratumValues[v] == value) {
203:         *index = v;
204:         break;
205:       }
206:   } else {
207:     PetscCall(PetscHMapIGet(label->hmap, value, index));
208:   }
209:   if (PetscDefined(USE_DEBUG) && !label->readonly) { /* Check strata hash map consistency */
210:     PetscInt len, loc = -1;
211:     PetscCall(PetscHMapIGetSize(label->hmap, &len));
212:     PetscCheck(len == label->numStrata, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent strata hash map size");
213:     if (label->numStrata <= DMLABEL_LOOKUP_THRESHOLD) {
214:       PetscCall(PetscHMapIGet(label->hmap, value, &loc));
215:     } else {
216:       for (v = 0; v < label->numStrata; ++v)
217:         if (label->stratumValues[v] == value) {
218:           loc = v;
219:           break;
220:         }
221:     }
222:     PetscCheck(loc == *index, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent strata hash map lookup");
223:   }
224:   PetscFunctionReturn(PETSC_SUCCESS);
225: }

227: static inline PetscErrorCode DMLabelNewStratum(DMLabel label, PetscInt value, PetscInt *index)
228: {
229:   PetscInt    v;
230:   PetscInt   *tmpV;
231:   PetscInt   *tmpS;
232:   PetscHSetI *tmpH, ht;
233:   IS         *tmpP, is;
234:   PetscBool  *tmpB;
235:   PetscHMapI  hmap = label->hmap;

237:   PetscFunctionBegin;
238:   v    = label->numStrata;
239:   tmpV = label->stratumValues;
240:   tmpS = label->stratumSizes;
241:   tmpH = label->ht;
242:   tmpP = label->points;
243:   tmpB = label->validIS;
244:   { /* TODO: PetscRealloc() is broken, use malloc+memcpy+free  */
245:     PetscInt   *oldV = tmpV;
246:     PetscInt   *oldS = tmpS;
247:     PetscHSetI *oldH = tmpH;
248:     IS         *oldP = tmpP;
249:     PetscBool  *oldB = tmpB;
250:     PetscCall(PetscMalloc((v + 1) * sizeof(*tmpV), &tmpV));
251:     PetscCall(PetscMalloc((v + 1) * sizeof(*tmpS), &tmpS));
252:     PetscCall(PetscCalloc((v + 1) * sizeof(*tmpH), &tmpH));
253:     PetscCall(PetscCalloc((v + 1) * sizeof(*tmpP), &tmpP));
254:     PetscCall(PetscMalloc((v + 1) * sizeof(*tmpB), &tmpB));
255:     PetscCall(PetscArraycpy(tmpV, oldV, v));
256:     PetscCall(PetscArraycpy(tmpS, oldS, v));
257:     PetscCall(PetscArraycpy(tmpH, oldH, v));
258:     PetscCall(PetscArraycpy(tmpP, oldP, v));
259:     PetscCall(PetscArraycpy(tmpB, oldB, v));
260:     PetscCall(PetscFree(oldV));
261:     PetscCall(PetscFree(oldS));
262:     PetscCall(PetscFree(oldH));
263:     PetscCall(PetscFree(oldP));
264:     PetscCall(PetscFree(oldB));
265:   }
266:   label->numStrata     = v + 1;
267:   label->stratumValues = tmpV;
268:   label->stratumSizes  = tmpS;
269:   label->ht            = tmpH;
270:   label->points        = tmpP;
271:   label->validIS       = tmpB;
272:   PetscCall(PetscHSetICreate(&ht));
273:   PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, &is));
274:   PetscCall(PetscHMapISet(hmap, value, v));
275:   tmpV[v] = value;
276:   tmpS[v] = 0;
277:   tmpH[v] = ht;
278:   tmpP[v] = is;
279:   tmpB[v] = PETSC_TRUE;
280:   PetscCall(PetscObjectStateIncrease((PetscObject)label));
281:   *index = v;
282:   PetscFunctionReturn(PETSC_SUCCESS);
283: }

285: static inline PetscErrorCode DMLabelLookupAddStratum(DMLabel label, PetscInt value, PetscInt *index)
286: {
287:   PetscFunctionBegin;
288:   PetscCall(DMLabelLookupStratum(label, value, index));
289:   if (*index < 0) PetscCall(DMLabelNewStratum(label, value, index));
290:   PetscFunctionReturn(PETSC_SUCCESS);
291: }

293: PetscErrorCode DMLabelGetStratumSize_Private(DMLabel label, PetscInt v, PetscInt *size)
294: {
295:   PetscFunctionBegin;
296:   *size = 0;
297:   if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
298:   if (label->readonly || label->validIS[v]) {
299:     *size = label->stratumSizes[v];
300:   } else {
301:     PetscCall(PetscHSetIGetSize(label->ht[v], size));
302:   }
303:   PetscFunctionReturn(PETSC_SUCCESS);
304: }

306: /*@
307:   DMLabelAddStratum - Adds a new stratum value in a `DMLabel`

309:   Input Parameters:
310: + label - The `DMLabel`
311: - value - The stratum value

313:   Level: beginner

315: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
316: @*/
317: PetscErrorCode DMLabelAddStratum(DMLabel label, PetscInt value)
318: {
319:   PetscInt v;

321:   PetscFunctionBegin;
323:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
324:   PetscCall(DMLabelLookupAddStratum(label, value, &v));
325:   PetscFunctionReturn(PETSC_SUCCESS);
326: }

328: /*@
329:   DMLabelAddStrata - Adds new stratum values in a `DMLabel`

331:   Not Collective

333:   Input Parameters:
334: + label         - The `DMLabel`
335: . numStrata     - The number of stratum values
336: - stratumValues - The stratum values

338:   Level: beginner

340: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
341: @*/
342: PetscErrorCode DMLabelAddStrata(DMLabel label, PetscInt numStrata, const PetscInt stratumValues[])
343: {
344:   PetscInt *values, v;

346:   PetscFunctionBegin;
348:   if (numStrata) PetscAssertPointer(stratumValues, 3);
349:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
350:   PetscCall(PetscMalloc1(numStrata, &values));
351:   PetscCall(PetscArraycpy(values, stratumValues, numStrata));
352:   PetscCall(PetscSortRemoveDupsInt(&numStrata, values));
353:   if (!label->numStrata) { /* Fast preallocation */
354:     PetscInt   *tmpV;
355:     PetscInt   *tmpS;
356:     PetscHSetI *tmpH, ht;
357:     IS         *tmpP, is;
358:     PetscBool  *tmpB;
359:     PetscHMapI  hmap = label->hmap;

361:     PetscCall(PetscMalloc1(numStrata, &tmpV));
362:     PetscCall(PetscMalloc1(numStrata, &tmpS));
363:     PetscCall(PetscCalloc1(numStrata, &tmpH));
364:     PetscCall(PetscCalloc1(numStrata, &tmpP));
365:     PetscCall(PetscMalloc1(numStrata, &tmpB));
366:     label->numStrata     = numStrata;
367:     label->stratumValues = tmpV;
368:     label->stratumSizes  = tmpS;
369:     label->ht            = tmpH;
370:     label->points        = tmpP;
371:     label->validIS       = tmpB;
372:     for (v = 0; v < numStrata; ++v) {
373:       PetscCall(PetscHSetICreate(&ht));
374:       PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, &is));
375:       PetscCall(PetscHMapISet(hmap, values[v], v));
376:       tmpV[v] = values[v];
377:       tmpS[v] = 0;
378:       tmpH[v] = ht;
379:       tmpP[v] = is;
380:       tmpB[v] = PETSC_TRUE;
381:     }
382:     PetscCall(PetscObjectStateIncrease((PetscObject)label));
383:   } else {
384:     for (v = 0; v < numStrata; ++v) PetscCall(DMLabelAddStratum(label, values[v]));
385:   }
386:   PetscCall(PetscFree(values));
387:   PetscFunctionReturn(PETSC_SUCCESS);
388: }

390: /*@
391:   DMLabelAddStrataIS - Adds new stratum values in a `DMLabel`

393:   Not Collective

395:   Input Parameters:
396: + label   - The `DMLabel`
397: - valueIS - Index set with stratum values

399:   Level: beginner

401: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
402: @*/
403: PetscErrorCode DMLabelAddStrataIS(DMLabel label, IS valueIS)
404: {
405:   PetscInt        numStrata;
406:   const PetscInt *stratumValues;

408:   PetscFunctionBegin;
411:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
412:   PetscCall(ISGetLocalSize(valueIS, &numStrata));
413:   PetscCall(ISGetIndices(valueIS, &stratumValues));
414:   PetscCall(DMLabelAddStrata(label, numStrata, stratumValues));
415:   PetscFunctionReturn(PETSC_SUCCESS);
416: }

418: static PetscErrorCode DMLabelView_Concrete_Ascii(DMLabel label, PetscViewer viewer)
419: {
420:   PetscInt    v;
421:   PetscMPIInt rank;

423:   PetscFunctionBegin;
424:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
425:   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
426:   if (label) {
427:     const char *name;

429:     PetscCall(PetscObjectGetName((PetscObject)label, &name));
430:     PetscCall(PetscViewerASCIIPrintf(viewer, "Label '%s':\n", name));
431:     if (label->bt) PetscCall(PetscViewerASCIIPrintf(viewer, "  Index has been calculated in [%" PetscInt_FMT ", %" PetscInt_FMT ")\n", label->pStart, label->pEnd));
432:     for (v = 0; v < label->numStrata; ++v) {
433:       const PetscInt  value = label->stratumValues[v];
434:       const PetscInt *points;
435:       PetscInt        p;

437:       PetscCall(ISGetIndices(label->points[v], &points));
438:       for (p = 0; p < label->stratumSizes[v]; ++p) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, points[p], value));
439:       PetscCall(ISRestoreIndices(label->points[v], &points));
440:     }
441:   }
442:   PetscCall(PetscViewerFlush(viewer));
443:   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
444:   PetscFunctionReturn(PETSC_SUCCESS);
445: }

447: static PetscErrorCode DMLabelView_Concrete(DMLabel label, PetscViewer viewer)
448: {
449:   PetscBool iascii;

451:   PetscFunctionBegin;
452:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
453:   if (iascii) PetscCall(DMLabelView_Concrete_Ascii(label, viewer));
454:   PetscFunctionReturn(PETSC_SUCCESS);
455: }

457: /*@C
458:   DMLabelView - View the label

460:   Collective

462:   Input Parameters:
463: + label  - The `DMLabel`
464: - viewer - The `PetscViewer`

466:   Level: intermediate

468: .seealso: `DMLabel`, `PetscViewer`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
469: @*/
470: PetscErrorCode DMLabelView(DMLabel label, PetscViewer viewer)
471: {
472:   PetscFunctionBegin;
474:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)label), &viewer));
476:   PetscCall(DMLabelMakeAllValid_Private(label));
477:   PetscUseTypeMethod(label, view, viewer);
478:   PetscFunctionReturn(PETSC_SUCCESS);
479: }

481: /*@
482:   DMLabelReset - Destroys internal data structures in a `DMLabel`

484:   Not Collective

486:   Input Parameter:
487: . label - The `DMLabel`

489:   Level: beginner

491: .seealso: `DMLabel`, `DM`, `DMLabelDestroy()`, `DMLabelCreate()`
492: @*/
493: PetscErrorCode DMLabelReset(DMLabel label)
494: {
495:   PetscInt v;

497:   PetscFunctionBegin;
499:   for (v = 0; v < label->numStrata; ++v) {
500:     if (label->ht[v]) PetscCall(PetscHSetIDestroy(&label->ht[v]));
501:     PetscCall(ISDestroy(&label->points[v]));
502:   }
503:   label->numStrata = 0;
504:   PetscCall(PetscFree(label->stratumValues));
505:   PetscCall(PetscFree(label->stratumSizes));
506:   PetscCall(PetscFree(label->ht));
507:   PetscCall(PetscFree(label->points));
508:   PetscCall(PetscFree(label->validIS));
509:   PetscCall(PetscHMapIReset(label->hmap));
510:   label->pStart = -1;
511:   label->pEnd   = -1;
512:   PetscCall(PetscBTDestroy(&label->bt));
513:   PetscFunctionReturn(PETSC_SUCCESS);
514: }

516: /*@
517:   DMLabelDestroy - Destroys a `DMLabel`

519:   Collective

521:   Input Parameter:
522: . label - The `DMLabel`

524:   Level: beginner

526: .seealso: `DMLabel`, `DM`, `DMLabelReset()`, `DMLabelCreate()`
527: @*/
528: PetscErrorCode DMLabelDestroy(DMLabel *label)
529: {
530:   PetscFunctionBegin;
531:   if (!*label) PetscFunctionReturn(PETSC_SUCCESS);
533:   if (--((PetscObject)*label)->refct > 0) {
534:     *label = NULL;
535:     PetscFunctionReturn(PETSC_SUCCESS);
536:   }
537:   PetscCall(DMLabelReset(*label));
538:   PetscCall(PetscHMapIDestroy(&(*label)->hmap));
539:   PetscCall(PetscHeaderDestroy(label));
540:   PetscFunctionReturn(PETSC_SUCCESS);
541: }

543: static PetscErrorCode DMLabelDuplicate_Concrete(DMLabel label, DMLabel *labelnew)
544: {
545:   PetscFunctionBegin;
546:   for (PetscInt v = 0; v < label->numStrata; ++v) {
547:     PetscCall(PetscHSetICreate(&(*labelnew)->ht[v]));
548:     PetscCall(PetscObjectReference((PetscObject)label->points[v]));
549:     (*labelnew)->points[v] = label->points[v];
550:   }
551:   PetscCall(PetscHMapIDestroy(&(*labelnew)->hmap));
552:   PetscCall(PetscHMapIDuplicate(label->hmap, &(*labelnew)->hmap));
553:   PetscFunctionReturn(PETSC_SUCCESS);
554: }

556: /*@
557:   DMLabelDuplicate - Duplicates a `DMLabel`

559:   Collective

561:   Input Parameter:
562: . label - The `DMLabel`

564:   Output Parameter:
565: . labelnew - new label

567:   Level: intermediate

569: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
570: @*/
571: PetscErrorCode DMLabelDuplicate(DMLabel label, DMLabel *labelnew)
572: {
573:   const char *name;

575:   PetscFunctionBegin;
577:   PetscCall(DMLabelMakeAllValid_Private(label));
578:   PetscCall(PetscObjectGetName((PetscObject)label, &name));
579:   PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)label), name, labelnew));

581:   (*labelnew)->numStrata    = label->numStrata;
582:   (*labelnew)->defaultValue = label->defaultValue;
583:   (*labelnew)->readonly     = label->readonly;
584:   PetscCall(PetscMalloc1(label->numStrata, &(*labelnew)->stratumValues));
585:   PetscCall(PetscMalloc1(label->numStrata, &(*labelnew)->stratumSizes));
586:   PetscCall(PetscCalloc1(label->numStrata, &(*labelnew)->ht));
587:   PetscCall(PetscCalloc1(label->numStrata, &(*labelnew)->points));
588:   PetscCall(PetscMalloc1(label->numStrata, &(*labelnew)->validIS));
589:   for (PetscInt v = 0; v < label->numStrata; ++v) {
590:     (*labelnew)->stratumValues[v] = label->stratumValues[v];
591:     (*labelnew)->stratumSizes[v]  = label->stratumSizes[v];
592:     (*labelnew)->validIS[v]       = PETSC_TRUE;
593:   }
594:   (*labelnew)->pStart = -1;
595:   (*labelnew)->pEnd   = -1;
596:   (*labelnew)->bt     = NULL;
597:   PetscUseTypeMethod(label, duplicate, labelnew);
598:   PetscFunctionReturn(PETSC_SUCCESS);
599: }

601: /*@C
602:   DMLabelCompare - Compare two `DMLabel` objects

604:   Collective; No Fortran Support

606:   Input Parameters:
607: + comm - Comm over which to compare labels
608: . l0   - First `DMLabel`
609: - l1   - Second `DMLabel`

611:   Output Parameters:
612: + equal   - (Optional) Flag whether the two labels are equal
613: - message - (Optional) Message describing the difference

615:   Level: intermediate

617:   Notes:
618:   The output flag equal is the same on all processes.
619:   If it is passed as `NULL` and difference is found, an error is thrown on all processes.
620:   Make sure to pass `NULL` on all processes.

622:   The output message is set independently on each rank.
623:   It is set to `NULL` if no difference was found on the current rank. It must be freed by user.
624:   If message is passed as `NULL` and difference is found, the difference description is printed to stderr in synchronized manner.
625:   Make sure to pass `NULL` on all processes.

627:   For the comparison, we ignore the order of stratum values, and strata with no points.

629:   The communicator needs to be specified because currently `DMLabel` can live on `PETSC_COMM_SELF` even if the underlying `DM` is parallel.

631:   Developer Note:
632:   Fortran stub cannot be generated automatically because `message` must be freed with `PetscFree()`

634: .seealso: `DMLabel`, `DM`, `DMCompareLabels()`, `DMLabelGetNumValues()`, `DMLabelGetDefaultValue()`, `DMLabelGetNonEmptyStratumValuesIS()`, `DMLabelGetStratumIS()`
635: @*/
636: PetscErrorCode DMLabelCompare(MPI_Comm comm, DMLabel l0, DMLabel l1, PetscBool *equal, char **message)
637: {
638:   const char *name0, *name1;
639:   char        msg[PETSC_MAX_PATH_LEN] = "";
640:   PetscBool   eq;
641:   PetscMPIInt rank;

643:   PetscFunctionBegin;
646:   if (equal) PetscAssertPointer(equal, 4);
647:   if (message) PetscAssertPointer(message, 5);
648:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
649:   PetscCall(PetscObjectGetName((PetscObject)l0, &name0));
650:   PetscCall(PetscObjectGetName((PetscObject)l1, &name1));
651:   {
652:     PetscInt v0, v1;

654:     PetscCall(DMLabelGetDefaultValue(l0, &v0));
655:     PetscCall(DMLabelGetDefaultValue(l1, &v1));
656:     eq = (PetscBool)(v0 == v1);
657:     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Default value of DMLabel l0 \"%s\" = %" PetscInt_FMT " != %" PetscInt_FMT " = Default value of DMLabel l1 \"%s\"", name0, v0, v1, name1));
658:     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
659:     if (!eq) goto finish;
660:   }
661:   {
662:     IS is0, is1;

664:     PetscCall(DMLabelGetNonEmptyStratumValuesIS(l0, &is0));
665:     PetscCall(DMLabelGetNonEmptyStratumValuesIS(l1, &is1));
666:     PetscCall(ISEqual(is0, is1, &eq));
667:     PetscCall(ISDestroy(&is0));
668:     PetscCall(ISDestroy(&is1));
669:     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Stratum values in DMLabel l0 \"%s\" are different than in DMLabel l1 \"%s\"", name0, name1));
670:     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
671:     if (!eq) goto finish;
672:   }
673:   {
674:     PetscInt i, nValues;

676:     PetscCall(DMLabelGetNumValues(l0, &nValues));
677:     for (i = 0; i < nValues; i++) {
678:       const PetscInt v = l0->stratumValues[i];
679:       PetscInt       n;
680:       IS             is0, is1;

682:       PetscCall(DMLabelGetStratumSize_Private(l0, i, &n));
683:       if (!n) continue;
684:       PetscCall(DMLabelGetStratumIS(l0, v, &is0));
685:       PetscCall(DMLabelGetStratumIS(l1, v, &is1));
686:       PetscCall(ISEqualUnsorted(is0, is1, &eq));
687:       PetscCall(ISDestroy(&is0));
688:       PetscCall(ISDestroy(&is1));
689:       if (!eq) {
690:         PetscCall(PetscSNPrintf(msg, sizeof(msg), "Stratum #%" PetscInt_FMT " with value %" PetscInt_FMT " contains different points in DMLabel l0 \"%s\" and DMLabel l1 \"%s\"", i, v, name0, name1));
691:         break;
692:       }
693:     }
694:     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
695:   }
696: finish:
697:   /* If message output arg not set, print to stderr */
698:   if (message) {
699:     *message = NULL;
700:     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
701:   } else {
702:     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
703:     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
704:   }
705:   /* If same output arg not ser and labels are not equal, throw error */
706:   if (equal) *equal = eq;
707:   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels l0 \"%s\" and l1 \"%s\" are not equal", name0, name1);
708:   PetscFunctionReturn(PETSC_SUCCESS);
709: }

711: /*@
712:   DMLabelComputeIndex - Create an index structure for membership determination, automatically determining the bounds

714:   Not Collective

716:   Input Parameter:
717: . label - The `DMLabel`

719:   Level: intermediate

721: .seealso: `DMLabel`, `DM`, `DMLabelHasPoint()`, `DMLabelCreateIndex()`, `DMLabelDestroyIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
722: @*/
723: PetscErrorCode DMLabelComputeIndex(DMLabel label)
724: {
725:   PetscInt pStart = PETSC_MAX_INT, pEnd = -1, v;

727:   PetscFunctionBegin;
729:   PetscCall(DMLabelMakeAllValid_Private(label));
730:   for (v = 0; v < label->numStrata; ++v) {
731:     const PetscInt *points;
732:     PetscInt        i;

734:     PetscCall(ISGetIndices(label->points[v], &points));
735:     for (i = 0; i < label->stratumSizes[v]; ++i) {
736:       const PetscInt point = points[i];

738:       pStart = PetscMin(point, pStart);
739:       pEnd   = PetscMax(point + 1, pEnd);
740:     }
741:     PetscCall(ISRestoreIndices(label->points[v], &points));
742:   }
743:   label->pStart = pStart == PETSC_MAX_INT ? -1 : pStart;
744:   label->pEnd   = pEnd;
745:   PetscCall(DMLabelCreateIndex(label, label->pStart, label->pEnd));
746:   PetscFunctionReturn(PETSC_SUCCESS);
747: }

749: /*@
750:   DMLabelCreateIndex - Create an index structure for membership determination

752:   Not Collective

754:   Input Parameters:
755: + label  - The `DMLabel`
756: . pStart - The smallest point
757: - pEnd   - The largest point + 1

759:   Level: intermediate

761: .seealso: `DMLabel`, `DM`, `DMLabelHasPoint()`, `DMLabelComputeIndex()`, `DMLabelDestroyIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
762: @*/
763: PetscErrorCode DMLabelCreateIndex(DMLabel label, PetscInt pStart, PetscInt pEnd)
764: {
765:   PetscInt v;

767:   PetscFunctionBegin;
769:   PetscCall(DMLabelDestroyIndex(label));
770:   PetscCall(DMLabelMakeAllValid_Private(label));
771:   label->pStart = pStart;
772:   label->pEnd   = pEnd;
773:   /* This can be hooked into SetValue(),  ClearValue(), etc. for updating */
774:   PetscCall(PetscBTCreate(pEnd - pStart, &label->bt));
775:   for (v = 0; v < label->numStrata; ++v) {
776:     IS              pointIS;
777:     const PetscInt *points;
778:     PetscInt        i;

780:     PetscUseTypeMethod(label, getstratumis, v, &pointIS);
781:     PetscCall(ISGetIndices(pointIS, &points));
782:     for (i = 0; i < label->stratumSizes[v]; ++i) {
783:       const PetscInt point = points[i];

785:       PetscCheck(!(point < pStart) && !(point >= pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %" PetscInt_FMT " in stratum %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, label->stratumValues[v], pStart, pEnd);
786:       PetscCall(PetscBTSet(label->bt, point - pStart));
787:     }
788:     PetscCall(ISRestoreIndices(label->points[v], &points));
789:     PetscCall(ISDestroy(&pointIS));
790:   }
791:   PetscFunctionReturn(PETSC_SUCCESS);
792: }

794: /*@
795:   DMLabelDestroyIndex - Destroy the index structure

797:   Not Collective

799:   Input Parameter:
800: . label - the `DMLabel`

802:   Level: intermediate

804: .seealso: `DMLabel`, `DM`, `DMLabelHasPoint()`, `DMLabelCreateIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
805: @*/
806: PetscErrorCode DMLabelDestroyIndex(DMLabel label)
807: {
808:   PetscFunctionBegin;
810:   label->pStart = -1;
811:   label->pEnd   = -1;
812:   PetscCall(PetscBTDestroy(&label->bt));
813:   PetscFunctionReturn(PETSC_SUCCESS);
814: }

816: /*@
817:   DMLabelGetBounds - Return the smallest and largest point in the label

819:   Not Collective

821:   Input Parameter:
822: . label - the `DMLabel`

824:   Output Parameters:
825: + pStart - The smallest point
826: - pEnd   - The largest point + 1

828:   Level: intermediate

830:   Note:
831:   This will compute an index for the label if one does not exist.

833: .seealso: `DMLabel`, `DM`, `DMLabelHasPoint()`, `DMLabelCreateIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
834: @*/
835: PetscErrorCode DMLabelGetBounds(DMLabel label, PetscInt *pStart, PetscInt *pEnd)
836: {
837:   PetscFunctionBegin;
839:   if ((label->pStart == -1) && (label->pEnd == -1)) PetscCall(DMLabelComputeIndex(label));
840:   if (pStart) {
841:     PetscAssertPointer(pStart, 2);
842:     *pStart = label->pStart;
843:   }
844:   if (pEnd) {
845:     PetscAssertPointer(pEnd, 3);
846:     *pEnd = label->pEnd;
847:   }
848:   PetscFunctionReturn(PETSC_SUCCESS);
849: }

851: /*@
852:   DMLabelHasValue - Determine whether a label assigns the value to any point

854:   Not Collective

856:   Input Parameters:
857: + label - the `DMLabel`
858: - value - the value

860:   Output Parameter:
861: . contains - Flag indicating whether the label maps this value to any point

863:   Level: developer

865: .seealso: `DMLabel`, `DM`, `DMLabelHasPoint()`, `DMLabelGetValue()`, `DMLabelSetValue()`
866: @*/
867: PetscErrorCode DMLabelHasValue(DMLabel label, PetscInt value, PetscBool *contains)
868: {
869:   PetscInt v;

871:   PetscFunctionBegin;
873:   PetscAssertPointer(contains, 3);
874:   PetscCall(DMLabelLookupStratum(label, value, &v));
875:   *contains = v < 0 ? PETSC_FALSE : PETSC_TRUE;
876:   PetscFunctionReturn(PETSC_SUCCESS);
877: }

879: /*@
880:   DMLabelHasPoint - Determine whether a label assigns a value to a point

882:   Not Collective

884:   Input Parameters:
885: + label - the `DMLabel`
886: - point - the point

888:   Output Parameter:
889: . contains - Flag indicating whether the label maps this point to a value

891:   Level: developer

893:   Note:
894:   The user must call `DMLabelCreateIndex()` before this function.

896: .seealso: `DMLabel`, `DM`, `DMLabelCreateIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
897: @*/
898: PetscErrorCode DMLabelHasPoint(DMLabel label, PetscInt point, PetscBool *contains)
899: {
900:   PetscFunctionBeginHot;
902:   PetscAssertPointer(contains, 3);
903:   PetscCall(DMLabelMakeAllValid_Private(label));
904:   if (PetscDefined(USE_DEBUG)) {
905:     PetscCheck(label->bt, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call DMLabelCreateIndex() before DMLabelHasPoint()");
906:     PetscCheck(!(point < label->pStart) && !(point >= label->pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, label->pStart, label->pEnd);
907:   }
908:   *contains = PetscBTLookup(label->bt, point - label->pStart) ? PETSC_TRUE : PETSC_FALSE;
909:   PetscFunctionReturn(PETSC_SUCCESS);
910: }

912: /*@
913:   DMLabelStratumHasPoint - Return true if the stratum contains a point

915:   Not Collective

917:   Input Parameters:
918: + label - the `DMLabel`
919: . value - the stratum value
920: - point - the point

922:   Output Parameter:
923: . contains - true if the stratum contains the point

925:   Level: intermediate

927: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelSetValue()`, `DMLabelClearValue()`
928: @*/
929: PetscErrorCode DMLabelStratumHasPoint(DMLabel label, PetscInt value, PetscInt point, PetscBool *contains)
930: {
931:   PetscFunctionBeginHot;
933:   PetscAssertPointer(contains, 4);
934:   if (value == label->defaultValue) {
935:     PetscInt pointVal;

937:     PetscCall(DMLabelGetValue(label, point, &pointVal));
938:     *contains = (PetscBool)(pointVal == value);
939:   } else {
940:     PetscInt v;

942:     PetscCall(DMLabelLookupStratum(label, value, &v));
943:     if (v >= 0) {
944:       if (label->validIS[v] || label->readonly) {
945:         IS       is;
946:         PetscInt i;

948:         PetscUseTypeMethod(label, getstratumis, v, &is);
949:         PetscCall(ISLocate(is, point, &i));
950:         PetscCall(ISDestroy(&is));
951:         *contains = (PetscBool)(i >= 0);
952:       } else {
953:         PetscCall(PetscHSetIHas(label->ht[v], point, contains));
954:       }
955:     } else { // value is not present
956:       *contains = PETSC_FALSE;
957:     }
958:   }
959:   PetscFunctionReturn(PETSC_SUCCESS);
960: }

962: /*@
963:   DMLabelGetDefaultValue - Get the default value returned by `DMLabelGetValue()` if a point has not been explicitly given a value.
964:   When a label is created, it is initialized to -1.

966:   Not Collective

968:   Input Parameter:
969: . label - a `DMLabel` object

971:   Output Parameter:
972: . defaultValue - the default value

974:   Level: beginner

976: .seealso: `DMLabel`, `DM`, `DMLabelSetDefaultValue()`, `DMLabelGetValue()`, `DMLabelSetValue()`
977: @*/
978: PetscErrorCode DMLabelGetDefaultValue(DMLabel label, PetscInt *defaultValue)
979: {
980:   PetscFunctionBegin;
982:   *defaultValue = label->defaultValue;
983:   PetscFunctionReturn(PETSC_SUCCESS);
984: }

986: /*@
987:   DMLabelSetDefaultValue - Set the default value returned by `DMLabelGetValue()` if a point has not been explicitly given a value.
988:   When a label is created, it is initialized to -1.

990:   Not Collective

992:   Input Parameter:
993: . label - a `DMLabel` object

995:   Output Parameter:
996: . defaultValue - the default value

998:   Level: beginner

1000: .seealso: `DMLabel`, `DM`, `DMLabelGetDefaultValue()`, `DMLabelGetValue()`, `DMLabelSetValue()`
1001: @*/
1002: PetscErrorCode DMLabelSetDefaultValue(DMLabel label, PetscInt defaultValue)
1003: {
1004:   PetscFunctionBegin;
1006:   label->defaultValue = defaultValue;
1007:   PetscFunctionReturn(PETSC_SUCCESS);
1008: }

1010: /*@
1011:   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
1012:   `DMLabelSetDefaultValue()`)

1014:   Not Collective

1016:   Input Parameters:
1017: + label - the `DMLabel`
1018: - point - the point

1020:   Output Parameter:
1021: . value - The point value, or the default value (-1 by default)

1023:   Level: intermediate

1025:   Note:
1026:   A label may assign multiple values to a point.  No guarantees are made about which value is returned in that case.
1027:   Use `DMLabelStratumHasPoint()` to check for inclusion in a specific value stratum.

1029: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelSetValue()`, `DMLabelClearValue()`, `DMLabelGetDefaultValue()`, `DMLabelSetDefaultValue()`
1030: @*/
1031: PetscErrorCode DMLabelGetValue(DMLabel label, PetscInt point, PetscInt *value)
1032: {
1033:   PetscInt v;

1035:   PetscFunctionBeginHot;
1037:   PetscAssertPointer(value, 3);
1038:   *value = label->defaultValue;
1039:   for (v = 0; v < label->numStrata; ++v) {
1040:     if (label->validIS[v] || label->readonly) {
1041:       IS       is;
1042:       PetscInt i;

1044:       PetscUseTypeMethod(label, getstratumis, v, &is);
1045:       PetscCall(ISLocate(label->points[v], point, &i));
1046:       PetscCall(ISDestroy(&is));
1047:       if (i >= 0) {
1048:         *value = label->stratumValues[v];
1049:         break;
1050:       }
1051:     } else {
1052:       PetscBool has;

1054:       PetscCall(PetscHSetIHas(label->ht[v], point, &has));
1055:       if (has) {
1056:         *value = label->stratumValues[v];
1057:         break;
1058:       }
1059:     }
1060:   }
1061:   PetscFunctionReturn(PETSC_SUCCESS);
1062: }

1064: /*@
1065:   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
1066:   be changed with `DMLabelSetDefaultValue()` to something different), then this function will do nothing.

1068:   Not Collective

1070:   Input Parameters:
1071: + label - the `DMLabel`
1072: . point - the point
1073: - value - The point value

1075:   Level: intermediate

1077: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelClearValue()`, `DMLabelGetDefaultValue()`, `DMLabelSetDefaultValue()`
1078: @*/
1079: PetscErrorCode DMLabelSetValue(DMLabel label, PetscInt point, PetscInt value)
1080: {
1081:   PetscInt v;

1083:   PetscFunctionBegin;
1085:   /* Find label value, add new entry if needed */
1086:   if (value == label->defaultValue) PetscFunctionReturn(PETSC_SUCCESS);
1087:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1088:   PetscCall(DMLabelLookupAddStratum(label, value, &v));
1089:   /* Set key */
1090:   PetscCall(DMLabelMakeInvalid_Private(label, v));
1091:   PetscCall(PetscHSetIAdd(label->ht[v], point));
1092:   PetscFunctionReturn(PETSC_SUCCESS);
1093: }

1095: /*@
1096:   DMLabelClearValue - Clear the value a label assigns to a point

1098:   Not Collective

1100:   Input Parameters:
1101: + label - the `DMLabel`
1102: . point - the point
1103: - value - The point value

1105:   Level: intermediate

1107: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`
1108: @*/
1109: PetscErrorCode DMLabelClearValue(DMLabel label, PetscInt point, PetscInt value)
1110: {
1111:   PetscInt v;

1113:   PetscFunctionBegin;
1115:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1116:   /* Find label value */
1117:   PetscCall(DMLabelLookupStratum(label, value, &v));
1118:   if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);

1120:   if (label->bt) {
1121:     PetscCheck(!(point < label->pStart) && !(point >= label->pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, label->pStart, label->pEnd);
1122:     PetscCall(PetscBTClear(label->bt, point - label->pStart));
1123:   }

1125:   /* Delete key */
1126:   PetscCall(DMLabelMakeInvalid_Private(label, v));
1127:   PetscCall(PetscHSetIDel(label->ht[v], point));
1128:   PetscFunctionReturn(PETSC_SUCCESS);
1129: }

1131: /*@
1132:   DMLabelInsertIS - Set all points in the `IS` to a value

1134:   Not Collective

1136:   Input Parameters:
1137: + label - the `DMLabel`
1138: . is    - the point `IS`
1139: - value - The point value

1141:   Level: intermediate

1143: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1144: @*/
1145: PetscErrorCode DMLabelInsertIS(DMLabel label, IS is, PetscInt value)
1146: {
1147:   PetscInt        v, n, p;
1148:   const PetscInt *points;

1150:   PetscFunctionBegin;
1153:   /* Find label value, add new entry if needed */
1154:   if (value == label->defaultValue) PetscFunctionReturn(PETSC_SUCCESS);
1155:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1156:   PetscCall(DMLabelLookupAddStratum(label, value, &v));
1157:   /* Set keys */
1158:   PetscCall(DMLabelMakeInvalid_Private(label, v));
1159:   PetscCall(ISGetLocalSize(is, &n));
1160:   PetscCall(ISGetIndices(is, &points));
1161:   for (p = 0; p < n; ++p) PetscCall(PetscHSetIAdd(label->ht[v], points[p]));
1162:   PetscCall(ISRestoreIndices(is, &points));
1163:   PetscFunctionReturn(PETSC_SUCCESS);
1164: }

1166: /*@
1167:   DMLabelGetNumValues - Get the number of values that the `DMLabel` takes

1169:   Not Collective

1171:   Input Parameter:
1172: . label - the `DMLabel`

1174:   Output Parameter:
1175: . numValues - the number of values

1177:   Level: intermediate

1179: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1180: @*/
1181: PetscErrorCode DMLabelGetNumValues(DMLabel label, PetscInt *numValues)
1182: {
1183:   PetscFunctionBegin;
1185:   PetscAssertPointer(numValues, 2);
1186:   *numValues = label->numStrata;
1187:   PetscFunctionReturn(PETSC_SUCCESS);
1188: }

1190: /*@
1191:   DMLabelGetValueIS - Get an `IS` of all values that the `DMlabel` takes

1193:   Not Collective

1195:   Input Parameter:
1196: . label - the `DMLabel`

1198:   Output Parameter:
1199: . values - the value `IS`

1201:   Level: intermediate

1203:   Notes:
1204:   The output `IS` should be destroyed when no longer needed.
1205:   Strata which are allocated but empty [`DMLabelGetStratumSize()` yields 0] are counted.
1206:   If you need to count only nonempty strata, use `DMLabelGetNonEmptyStratumValuesIS()`.

1208: .seealso: `DMLabel`, `DM`, `DMLabelGetNonEmptyStratumValuesIS()`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1209: @*/
1210: PetscErrorCode DMLabelGetValueIS(DMLabel label, IS *values)
1211: {
1212:   PetscFunctionBegin;
1214:   PetscAssertPointer(values, 2);
1215:   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, label->numStrata, label->stratumValues, PETSC_USE_POINTER, values));
1216:   PetscFunctionReturn(PETSC_SUCCESS);
1217: }

1219: /*@
1220:   DMLabelGetValueBounds - Return the smallest and largest value in the label

1222:   Not Collective

1224:   Input Parameter:
1225: . label - the `DMLabel`

1227:   Output Parameters:
1228: + minValue - The smallest value
1229: - maxValue - The largest value

1231:   Level: intermediate

1233: .seealso: `DMLabel`, `DM`, `DMLabelGetBounds()`, `DMLabelGetValue()`, `DMLabelSetValue()`
1234: @*/
1235: PetscErrorCode DMLabelGetValueBounds(DMLabel label, PetscInt *minValue, PetscInt *maxValue)
1236: {
1237:   PetscInt min = PETSC_MAX_INT, max = PETSC_MIN_INT;

1239:   PetscFunctionBegin;
1241:   for (PetscInt v = 0; v < label->numStrata; ++v) {
1242:     min = PetscMin(min, label->stratumValues[v]);
1243:     max = PetscMax(max, label->stratumValues[v]);
1244:   }
1245:   if (minValue) {
1246:     PetscAssertPointer(minValue, 2);
1247:     *minValue = min;
1248:   }
1249:   if (maxValue) {
1250:     PetscAssertPointer(maxValue, 3);
1251:     *maxValue = max;
1252:   }
1253:   PetscFunctionReturn(PETSC_SUCCESS);
1254: }

1256: /*@
1257:   DMLabelGetNonEmptyStratumValuesIS - Get an `IS` of all values that the `DMlabel` takes

1259:   Not Collective

1261:   Input Parameter:
1262: . label - the `DMLabel`

1264:   Output Parameter:
1265: . values - the value `IS`

1267:   Level: intermediate

1269:   Notes:
1270:   The output `IS` should be destroyed when no longer needed.
1271:   This is similar to `DMLabelGetValueIS()` but counts only nonempty strata.

1273: .seealso: `DMLabel`, `DM`, `DMLabelGetValueIS()`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1274: @*/
1275: PetscErrorCode DMLabelGetNonEmptyStratumValuesIS(DMLabel label, IS *values)
1276: {
1277:   PetscInt  i, j;
1278:   PetscInt *valuesArr;

1280:   PetscFunctionBegin;
1282:   PetscAssertPointer(values, 2);
1283:   PetscCall(PetscMalloc1(label->numStrata, &valuesArr));
1284:   for (i = 0, j = 0; i < label->numStrata; i++) {
1285:     PetscInt n;

1287:     PetscCall(DMLabelGetStratumSize_Private(label, i, &n));
1288:     if (n) valuesArr[j++] = label->stratumValues[i];
1289:   }
1290:   if (j == label->numStrata) {
1291:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, label->numStrata, label->stratumValues, PETSC_USE_POINTER, values));
1292:   } else {
1293:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, valuesArr, PETSC_COPY_VALUES, values));
1294:   }
1295:   PetscCall(PetscFree(valuesArr));
1296:   PetscFunctionReturn(PETSC_SUCCESS);
1297: }

1299: /*@
1300:   DMLabelGetValueIndex - Get the index of a given value in the list of values for the `DMlabel`, or -1 if it is not present

1302:   Not Collective

1304:   Input Parameters:
1305: + label - the `DMLabel`
1306: - value - the value

1308:   Output Parameter:
1309: . index - the index of value in the list of values

1311:   Level: intermediate

1313: .seealso: `DMLabel`, `DM`, `DMLabelGetValueIS()`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1314: @*/
1315: PetscErrorCode DMLabelGetValueIndex(DMLabel label, PetscInt value, PetscInt *index)
1316: {
1317:   PetscInt v;

1319:   PetscFunctionBegin;
1321:   PetscAssertPointer(index, 3);
1322:   /* Do not assume they are sorted */
1323:   for (v = 0; v < label->numStrata; ++v)
1324:     if (label->stratumValues[v] == value) break;
1325:   if (v >= label->numStrata) *index = -1;
1326:   else *index = v;
1327:   PetscFunctionReturn(PETSC_SUCCESS);
1328: }

1330: /*@
1331:   DMLabelHasStratum - Determine whether points exist with the given value

1333:   Not Collective

1335:   Input Parameters:
1336: + label - the `DMLabel`
1337: - value - the stratum value

1339:   Output Parameter:
1340: . exists - Flag saying whether points exist

1342:   Level: intermediate

1344: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1345: @*/
1346: PetscErrorCode DMLabelHasStratum(DMLabel label, PetscInt value, PetscBool *exists)
1347: {
1348:   PetscInt v;

1350:   PetscFunctionBegin;
1352:   PetscAssertPointer(exists, 3);
1353:   PetscCall(DMLabelLookupStratum(label, value, &v));
1354:   *exists = v < 0 ? PETSC_FALSE : PETSC_TRUE;
1355:   PetscFunctionReturn(PETSC_SUCCESS);
1356: }

1358: /*@
1359:   DMLabelGetStratumSize - Get the size of a stratum

1361:   Not Collective

1363:   Input Parameters:
1364: + label - the `DMLabel`
1365: - value - the stratum value

1367:   Output Parameter:
1368: . size - The number of points in the stratum

1370:   Level: intermediate

1372: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1373: @*/
1374: PetscErrorCode DMLabelGetStratumSize(DMLabel label, PetscInt value, PetscInt *size)
1375: {
1376:   PetscInt v;

1378:   PetscFunctionBegin;
1380:   PetscAssertPointer(size, 3);
1381:   PetscCall(DMLabelLookupStratum(label, value, &v));
1382:   PetscCall(DMLabelGetStratumSize_Private(label, v, size));
1383:   PetscFunctionReturn(PETSC_SUCCESS);
1384: }

1386: /*@
1387:   DMLabelGetStratumBounds - Get the largest and smallest point of a stratum

1389:   Not Collective

1391:   Input Parameters:
1392: + label - the `DMLabel`
1393: - value - the stratum value

1395:   Output Parameters:
1396: + start - the smallest point in the stratum
1397: - end   - the largest point in the stratum

1399:   Level: intermediate

1401: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1402: @*/
1403: PetscErrorCode DMLabelGetStratumBounds(DMLabel label, PetscInt value, PetscInt *start, PetscInt *end)
1404: {
1405:   IS       is;
1406:   PetscInt v, min, max;

1408:   PetscFunctionBegin;
1410:   if (start) {
1411:     PetscAssertPointer(start, 3);
1412:     *start = -1;
1413:   }
1414:   if (end) {
1415:     PetscAssertPointer(end, 4);
1416:     *end = -1;
1417:   }
1418:   PetscCall(DMLabelLookupStratum(label, value, &v));
1419:   if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1420:   PetscCall(DMLabelMakeValid_Private(label, v));
1421:   if (label->stratumSizes[v] <= 0) PetscFunctionReturn(PETSC_SUCCESS);
1422:   PetscUseTypeMethod(label, getstratumis, v, &is);
1423:   PetscCall(ISGetMinMax(is, &min, &max));
1424:   PetscCall(ISDestroy(&is));
1425:   if (start) *start = min;
1426:   if (end) *end = max + 1;
1427:   PetscFunctionReturn(PETSC_SUCCESS);
1428: }

1430: static PetscErrorCode DMLabelGetStratumIS_Concrete(DMLabel label, PetscInt v, IS *pointIS)
1431: {
1432:   PetscFunctionBegin;
1433:   PetscCall(PetscObjectReference((PetscObject)label->points[v]));
1434:   *pointIS = label->points[v];
1435:   PetscFunctionReturn(PETSC_SUCCESS);
1436: }

1438: /*@
1439:   DMLabelGetStratumIS - Get an `IS` with the stratum points

1441:   Not Collective

1443:   Input Parameters:
1444: + label - the `DMLabel`
1445: - value - the stratum value

1447:   Output Parameter:
1448: . points - The stratum points

1450:   Level: intermediate

1452:   Notes:
1453:   The output `IS` should be destroyed when no longer needed.
1454:   Returns `NULL` if the stratum is empty.

1456: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1457: @*/
1458: PetscErrorCode DMLabelGetStratumIS(DMLabel label, PetscInt value, IS *points)
1459: {
1460:   PetscInt v;

1462:   PetscFunctionBegin;
1464:   PetscAssertPointer(points, 3);
1465:   *points = NULL;
1466:   PetscCall(DMLabelLookupStratum(label, value, &v));
1467:   if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1468:   PetscCall(DMLabelMakeValid_Private(label, v));
1469:   PetscUseTypeMethod(label, getstratumis, v, points);
1470:   PetscFunctionReturn(PETSC_SUCCESS);
1471: }

1473: /*@
1474:   DMLabelSetStratumIS - Set the stratum points using an `IS`

1476:   Not Collective

1478:   Input Parameters:
1479: + label - the `DMLabel`
1480: . value - the stratum value
1481: - is    - The stratum points

1483:   Level: intermediate

1485: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1486: @*/
1487: PetscErrorCode DMLabelSetStratumIS(DMLabel label, PetscInt value, IS is)
1488: {
1489:   PetscInt v;

1491:   PetscFunctionBegin;
1494:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1495:   PetscCall(DMLabelLookupAddStratum(label, value, &v));
1496:   if (is == label->points[v]) PetscFunctionReturn(PETSC_SUCCESS);
1497:   PetscCall(DMLabelClearStratum(label, value));
1498:   PetscCall(ISGetLocalSize(is, &label->stratumSizes[v]));
1499:   PetscCall(PetscObjectReference((PetscObject)is));
1500:   PetscCall(ISDestroy(&label->points[v]));
1501:   label->points[v]  = is;
1502:   label->validIS[v] = PETSC_TRUE;
1503:   PetscCall(PetscObjectStateIncrease((PetscObject)label));
1504:   if (label->bt) {
1505:     const PetscInt *points;
1506:     PetscInt        p;

1508:     PetscCall(ISGetIndices(is, &points));
1509:     for (p = 0; p < label->stratumSizes[v]; ++p) {
1510:       const PetscInt point = points[p];

1512:       PetscCheck(!(point < label->pStart) && !(point >= label->pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, label->pStart, label->pEnd);
1513:       PetscCall(PetscBTSet(label->bt, point - label->pStart));
1514:     }
1515:   }
1516:   PetscFunctionReturn(PETSC_SUCCESS);
1517: }

1519: /*@
1520:   DMLabelClearStratum - Remove a stratum

1522:   Not Collective

1524:   Input Parameters:
1525: + label - the `DMLabel`
1526: - value - the stratum value

1528:   Level: intermediate

1530: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1531: @*/
1532: PetscErrorCode DMLabelClearStratum(DMLabel label, PetscInt value)
1533: {
1534:   PetscInt v;

1536:   PetscFunctionBegin;
1538:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1539:   PetscCall(DMLabelLookupStratum(label, value, &v));
1540:   if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1541:   if (label->validIS[v]) {
1542:     if (label->bt) {
1543:       PetscInt        i;
1544:       const PetscInt *points;

1546:       PetscCall(ISGetIndices(label->points[v], &points));
1547:       for (i = 0; i < label->stratumSizes[v]; ++i) {
1548:         const PetscInt point = points[i];

1550:         PetscCheck(!(point < label->pStart) && !(point >= label->pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %" PetscInt_FMT " is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, label->pStart, label->pEnd);
1551:         PetscCall(PetscBTClear(label->bt, point - label->pStart));
1552:       }
1553:       PetscCall(ISRestoreIndices(label->points[v], &points));
1554:     }
1555:     label->stratumSizes[v] = 0;
1556:     PetscCall(ISDestroy(&label->points[v]));
1557:     PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, &label->points[v]));
1558:     PetscCall(PetscObjectSetName((PetscObject)label->points[v], "indices"));
1559:     PetscCall(PetscObjectStateIncrease((PetscObject)label));
1560:   } else {
1561:     PetscCall(PetscHSetIClear(label->ht[v]));
1562:   }
1563:   PetscFunctionReturn(PETSC_SUCCESS);
1564: }

1566: /*@
1567:   DMLabelSetStratumBounds - Efficiently give a contiguous set of points a given label value

1569:   Not Collective

1571:   Input Parameters:
1572: + label  - The `DMLabel`
1573: . value  - The label value for all points
1574: . pStart - The first point
1575: - pEnd   - A point beyond all marked points

1577:   Level: intermediate

1579:   Note:
1580:   The marks points are [`pStart`, `pEnd`), and only the bounds are stored.

1582: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelSetStratumIS()`, `DMLabelGetStratumIS()`
1583: @*/
1584: PetscErrorCode DMLabelSetStratumBounds(DMLabel label, PetscInt value, PetscInt pStart, PetscInt pEnd)
1585: {
1586:   IS pIS;

1588:   PetscFunctionBegin;
1589:   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &pIS));
1590:   PetscCall(DMLabelSetStratumIS(label, value, pIS));
1591:   PetscCall(ISDestroy(&pIS));
1592:   PetscFunctionReturn(PETSC_SUCCESS);
1593: }

1595: /*@
1596:   DMLabelGetStratumPointIndex - Get the index of a point in a given stratum

1598:   Not Collective

1600:   Input Parameters:
1601: + label - The `DMLabel`
1602: . value - The label value
1603: - p     - A point with this value

1605:   Output Parameter:
1606: . index - The index of this point in the stratum, or -1 if the point is not in the stratum or the stratum does not exist

1608:   Level: intermediate

1610: .seealso: `DMLabel`, `DM`, `DMLabelGetValueIndex()`, `DMLabelGetStratumIS()`, `DMLabelCreate()`
1611: @*/
1612: PetscErrorCode DMLabelGetStratumPointIndex(DMLabel label, PetscInt value, PetscInt p, PetscInt *index)
1613: {
1614:   IS              pointIS;
1615:   const PetscInt *indices;
1616:   PetscInt        v;

1618:   PetscFunctionBegin;
1620:   PetscAssertPointer(index, 4);
1621:   *index = -1;
1622:   PetscCall(DMLabelLookupStratum(label, value, &v));
1623:   if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1624:   PetscCall(DMLabelMakeValid_Private(label, v));
1625:   PetscUseTypeMethod(label, getstratumis, v, &pointIS);
1626:   PetscCall(ISGetIndices(pointIS, &indices));
1627:   PetscCall(PetscFindInt(p, label->stratumSizes[v], indices, index));
1628:   PetscCall(ISRestoreIndices(pointIS, &indices));
1629:   PetscCall(ISDestroy(&pointIS));
1630:   PetscFunctionReturn(PETSC_SUCCESS);
1631: }

1633: /*@
1634:   DMLabelFilter - Remove all points outside of [`start`, `end`)

1636:   Not Collective

1638:   Input Parameters:
1639: + label - the `DMLabel`
1640: . start - the first point kept
1641: - end   - one more than the last point kept

1643:   Level: intermediate

1645: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1646: @*/
1647: PetscErrorCode DMLabelFilter(DMLabel label, PetscInt start, PetscInt end)
1648: {
1649:   PetscInt v;

1651:   PetscFunctionBegin;
1653:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1654:   PetscCall(DMLabelDestroyIndex(label));
1655:   PetscCall(DMLabelMakeAllValid_Private(label));
1656:   for (v = 0; v < label->numStrata; ++v) {
1657:     PetscCall(ISGeneralFilter(label->points[v], start, end));
1658:     PetscCall(ISGetLocalSize(label->points[v], &label->stratumSizes[v]));
1659:   }
1660:   PetscCall(DMLabelCreateIndex(label, start, end));
1661:   PetscFunctionReturn(PETSC_SUCCESS);
1662: }

1664: /*@
1665:   DMLabelPermute - Create a new label with permuted points

1667:   Not Collective

1669:   Input Parameters:
1670: + label       - the `DMLabel`
1671: - permutation - the point permutation

1673:   Output Parameter:
1674: . labelNew - the new label containing the permuted points

1676:   Level: intermediate

1678: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1679: @*/
1680: PetscErrorCode DMLabelPermute(DMLabel label, IS permutation, DMLabel *labelNew)
1681: {
1682:   const PetscInt *perm;
1683:   PetscInt        numValues, numPoints, v, q;

1685:   PetscFunctionBegin;
1688:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1689:   PetscCall(DMLabelMakeAllValid_Private(label));
1690:   PetscCall(DMLabelDuplicate(label, labelNew));
1691:   PetscCall(DMLabelGetNumValues(*labelNew, &numValues));
1692:   PetscCall(ISGetLocalSize(permutation, &numPoints));
1693:   PetscCall(ISGetIndices(permutation, &perm));
1694:   for (v = 0; v < numValues; ++v) {
1695:     const PetscInt  size = (*labelNew)->stratumSizes[v];
1696:     const PetscInt *points;
1697:     PetscInt       *pointsNew;

1699:     PetscCall(ISGetIndices((*labelNew)->points[v], &points));
1700:     PetscCall(PetscCalloc1(size, &pointsNew));
1701:     for (q = 0; q < size; ++q) {
1702:       const PetscInt point = points[q];

1704:       PetscCheck(!(point < 0) && !(point >= numPoints), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label point %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ") for the remapping", point, numPoints);
1705:       pointsNew[q] = perm[point];
1706:     }
1707:     PetscCall(ISRestoreIndices((*labelNew)->points[v], &points));
1708:     PetscCall(PetscSortInt(size, pointsNew));
1709:     PetscCall(ISDestroy(&((*labelNew)->points[v])));
1710:     if (size > 0 && pointsNew[size - 1] == pointsNew[0] + size - 1) {
1711:       PetscCall(ISCreateStride(PETSC_COMM_SELF, size, pointsNew[0], 1, &((*labelNew)->points[v])));
1712:       PetscCall(PetscFree(pointsNew));
1713:     } else {
1714:       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, pointsNew, PETSC_OWN_POINTER, &((*labelNew)->points[v])));
1715:     }
1716:     PetscCall(PetscObjectSetName((PetscObject)((*labelNew)->points[v]), "indices"));
1717:   }
1718:   PetscCall(ISRestoreIndices(permutation, &perm));
1719:   if (label->bt) {
1720:     PetscCall(PetscBTDestroy(&label->bt));
1721:     PetscCall(DMLabelCreateIndex(label, label->pStart, label->pEnd));
1722:   }
1723:   PetscFunctionReturn(PETSC_SUCCESS);
1724: }

1726: static PetscErrorCode DMLabelDistribute_Internal(DMLabel label, PetscSF sf, PetscSection *leafSection, PetscInt **leafStrata)
1727: {
1728:   MPI_Comm     comm;
1729:   PetscInt     s, l, nroots, nleaves, offset, size;
1730:   PetscInt    *remoteOffsets, *rootStrata, *rootIdx;
1731:   PetscSection rootSection;
1732:   PetscSF      labelSF;

1734:   PetscFunctionBegin;
1735:   if (label) PetscCall(DMLabelMakeAllValid_Private(label));
1736:   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
1737:   /* Build a section of stratum values per point, generate the according SF
1738:      and distribute point-wise stratum values to leaves. */
1739:   PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, NULL, NULL));
1740:   PetscCall(PetscSectionCreate(comm, &rootSection));
1741:   PetscCall(PetscSectionSetChart(rootSection, 0, nroots));
1742:   if (label) {
1743:     for (s = 0; s < label->numStrata; ++s) {
1744:       const PetscInt *points;

1746:       PetscCall(ISGetIndices(label->points[s], &points));
1747:       for (l = 0; l < label->stratumSizes[s]; l++) PetscCall(PetscSectionAddDof(rootSection, points[l], 1));
1748:       PetscCall(ISRestoreIndices(label->points[s], &points));
1749:     }
1750:   }
1751:   PetscCall(PetscSectionSetUp(rootSection));
1752:   /* Create a point-wise array of stratum values */
1753:   PetscCall(PetscSectionGetStorageSize(rootSection, &size));
1754:   PetscCall(PetscMalloc1(size, &rootStrata));
1755:   PetscCall(PetscCalloc1(nroots, &rootIdx));
1756:   if (label) {
1757:     for (s = 0; s < label->numStrata; ++s) {
1758:       const PetscInt *points;

1760:       PetscCall(ISGetIndices(label->points[s], &points));
1761:       for (l = 0; l < label->stratumSizes[s]; l++) {
1762:         const PetscInt p = points[l];
1763:         PetscCall(PetscSectionGetOffset(rootSection, p, &offset));
1764:         rootStrata[offset + rootIdx[p]++] = label->stratumValues[s];
1765:       }
1766:       PetscCall(ISRestoreIndices(label->points[s], &points));
1767:     }
1768:   }
1769:   /* Build SF that maps label points to remote processes */
1770:   PetscCall(PetscSectionCreate(comm, leafSection));
1771:   PetscCall(PetscSFDistributeSection(sf, rootSection, &remoteOffsets, *leafSection));
1772:   PetscCall(PetscSFCreateSectionSF(sf, rootSection, remoteOffsets, *leafSection, &labelSF));
1773:   PetscCall(PetscFree(remoteOffsets));
1774:   /* Send the strata for each point over the derived SF */
1775:   PetscCall(PetscSectionGetStorageSize(*leafSection, &size));
1776:   PetscCall(PetscMalloc1(size, leafStrata));
1777:   PetscCall(PetscSFBcastBegin(labelSF, MPIU_INT, rootStrata, *leafStrata, MPI_REPLACE));
1778:   PetscCall(PetscSFBcastEnd(labelSF, MPIU_INT, rootStrata, *leafStrata, MPI_REPLACE));
1779:   /* Clean up */
1780:   PetscCall(PetscFree(rootStrata));
1781:   PetscCall(PetscFree(rootIdx));
1782:   PetscCall(PetscSectionDestroy(&rootSection));
1783:   PetscCall(PetscSFDestroy(&labelSF));
1784:   PetscFunctionReturn(PETSC_SUCCESS);
1785: }

1787: /*@
1788:   DMLabelDistribute - Create a new label pushed forward over the `PetscSF`

1790:   Collective

1792:   Input Parameters:
1793: + label - the `DMLabel`
1794: - sf    - the map from old to new distribution

1796:   Output Parameter:
1797: . labelNew - the new redistributed label

1799:   Level: intermediate

1801: .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1802: @*/
1803: PetscErrorCode DMLabelDistribute(DMLabel label, PetscSF sf, DMLabel *labelNew)
1804: {
1805:   MPI_Comm     comm;
1806:   PetscSection leafSection;
1807:   PetscInt     p, pStart, pEnd, s, size, dof, offset, stratum;
1808:   PetscInt    *leafStrata, *strataIdx;
1809:   PetscInt   **points;
1810:   const char  *lname = NULL;
1811:   char        *name;
1812:   PetscInt     nameSize;
1813:   PetscHSetI   stratumHash;
1814:   size_t       len = 0;
1815:   PetscMPIInt  rank;

1817:   PetscFunctionBegin;
1819:   if (label) {
1821:     PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1822:     PetscCall(DMLabelMakeAllValid_Private(label));
1823:   }
1824:   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
1825:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1826:   /* Bcast name */
1827:   if (rank == 0) {
1828:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
1829:     PetscCall(PetscStrlen(lname, &len));
1830:   }
1831:   nameSize = len;
1832:   PetscCallMPI(MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm));
1833:   PetscCall(PetscMalloc1(nameSize + 1, &name));
1834:   if (rank == 0) PetscCall(PetscArraycpy(name, lname, nameSize + 1));
1835:   PetscCallMPI(MPI_Bcast(name, nameSize + 1, MPI_CHAR, 0, comm));
1836:   PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, labelNew));
1837:   PetscCall(PetscFree(name));
1838:   /* Bcast defaultValue */
1839:   if (rank == 0) (*labelNew)->defaultValue = label->defaultValue;
1840:   PetscCallMPI(MPI_Bcast(&(*labelNew)->defaultValue, 1, MPIU_INT, 0, comm));
1841:   /* Distribute stratum values over the SF and get the point mapping on the receiver */
1842:   PetscCall(DMLabelDistribute_Internal(label, sf, &leafSection, &leafStrata));
1843:   /* Determine received stratum values and initialise new label*/
1844:   PetscCall(PetscHSetICreate(&stratumHash));
1845:   PetscCall(PetscSectionGetStorageSize(leafSection, &size));
1846:   for (p = 0; p < size; ++p) PetscCall(PetscHSetIAdd(stratumHash, leafStrata[p]));
1847:   PetscCall(PetscHSetIGetSize(stratumHash, &(*labelNew)->numStrata));
1848:   PetscCall(PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->validIS));
1849:   for (s = 0; s < (*labelNew)->numStrata; ++s) (*labelNew)->validIS[s] = PETSC_TRUE;
1850:   PetscCall(PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->stratumValues));
1851:   /* Turn leafStrata into indices rather than stratum values */
1852:   offset = 0;
1853:   PetscCall(PetscHSetIGetElems(stratumHash, &offset, (*labelNew)->stratumValues));
1854:   PetscCall(PetscSortInt((*labelNew)->numStrata, (*labelNew)->stratumValues));
1855:   for (s = 0; s < (*labelNew)->numStrata; ++s) PetscCall(PetscHMapISet((*labelNew)->hmap, (*labelNew)->stratumValues[s], s));
1856:   for (p = 0; p < size; ++p) {
1857:     for (s = 0; s < (*labelNew)->numStrata; ++s) {
1858:       if (leafStrata[p] == (*labelNew)->stratumValues[s]) {
1859:         leafStrata[p] = s;
1860:         break;
1861:       }
1862:     }
1863:   }
1864:   /* Rebuild the point strata on the receiver */
1865:   PetscCall(PetscCalloc1((*labelNew)->numStrata, &(*labelNew)->stratumSizes));
1866:   PetscCall(PetscSectionGetChart(leafSection, &pStart, &pEnd));
1867:   for (p = pStart; p < pEnd; p++) {
1868:     PetscCall(PetscSectionGetDof(leafSection, p, &dof));
1869:     PetscCall(PetscSectionGetOffset(leafSection, p, &offset));
1870:     for (s = 0; s < dof; s++) (*labelNew)->stratumSizes[leafStrata[offset + s]]++;
1871:   }
1872:   PetscCall(PetscCalloc1((*labelNew)->numStrata, &(*labelNew)->ht));
1873:   PetscCall(PetscCalloc1((*labelNew)->numStrata, &(*labelNew)->points));
1874:   PetscCall(PetscCalloc1((*labelNew)->numStrata, &points));
1875:   for (s = 0; s < (*labelNew)->numStrata; ++s) {
1876:     PetscCall(PetscHSetICreate(&(*labelNew)->ht[s]));
1877:     PetscCall(PetscMalloc1((*labelNew)->stratumSizes[s], &points[s]));
1878:   }
1879:   /* Insert points into new strata */
1880:   PetscCall(PetscCalloc1((*labelNew)->numStrata, &strataIdx));
1881:   PetscCall(PetscSectionGetChart(leafSection, &pStart, &pEnd));
1882:   for (p = pStart; p < pEnd; p++) {
1883:     PetscCall(PetscSectionGetDof(leafSection, p, &dof));
1884:     PetscCall(PetscSectionGetOffset(leafSection, p, &offset));
1885:     for (s = 0; s < dof; s++) {
1886:       stratum                               = leafStrata[offset + s];
1887:       points[stratum][strataIdx[stratum]++] = p;
1888:     }
1889:   }
1890:   for (s = 0; s < (*labelNew)->numStrata; s++) {
1891:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, (*labelNew)->stratumSizes[s], &points[s][0], PETSC_OWN_POINTER, &((*labelNew)->points[s])));
1892:     PetscCall(PetscObjectSetName((PetscObject)((*labelNew)->points[s]), "indices"));
1893:   }
1894:   PetscCall(PetscFree(points));
1895:   PetscCall(PetscHSetIDestroy(&stratumHash));
1896:   PetscCall(PetscFree(leafStrata));
1897:   PetscCall(PetscFree(strataIdx));
1898:   PetscCall(PetscSectionDestroy(&leafSection));
1899:   PetscFunctionReturn(PETSC_SUCCESS);
1900: }

1902: /*@
1903:   DMLabelGather - Gather all label values from leafs into roots

1905:   Collective

1907:   Input Parameters:
1908: + label - the `DMLabel`
1909: - sf    - the `PetscSF` communication map

1911:   Output Parameter:
1912: . labelNew - the new `DMLabel` with localised leaf values

1914:   Level: developer

1916:   Note:
1917:   This is the inverse operation to `DMLabelDistribute()`.

1919: .seealso: `DMLabel`, `DM`, `DMLabelDistribute()`
1920: @*/
1921: PetscErrorCode DMLabelGather(DMLabel label, PetscSF sf, DMLabel *labelNew)
1922: {
1923:   MPI_Comm        comm;
1924:   PetscSection    rootSection;
1925:   PetscSF         sfLabel;
1926:   PetscSFNode    *rootPoints, *leafPoints;
1927:   PetscInt        p, s, d, nroots, nleaves, nmultiroots, idx, dof, offset;
1928:   const PetscInt *rootDegree, *ilocal;
1929:   PetscInt       *rootStrata;
1930:   const char     *lname;
1931:   char           *name;
1932:   PetscInt        nameSize;
1933:   size_t          len = 0;
1934:   PetscMPIInt     rank, size;

1936:   PetscFunctionBegin;
1939:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1940:   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
1941:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1942:   PetscCallMPI(MPI_Comm_size(comm, &size));
1943:   /* Bcast name */
1944:   if (rank == 0) {
1945:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
1946:     PetscCall(PetscStrlen(lname, &len));
1947:   }
1948:   nameSize = len;
1949:   PetscCallMPI(MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm));
1950:   PetscCall(PetscMalloc1(nameSize + 1, &name));
1951:   if (rank == 0) PetscCall(PetscArraycpy(name, lname, nameSize + 1));
1952:   PetscCallMPI(MPI_Bcast(name, nameSize + 1, MPI_CHAR, 0, comm));
1953:   PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, labelNew));
1954:   PetscCall(PetscFree(name));
1955:   /* Gather rank/index pairs of leaves into local roots to build
1956:      an inverse, multi-rooted SF. Note that this ignores local leaf
1957:      indexing due to the use of the multiSF in PetscSFGather. */
1958:   PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, NULL));
1959:   PetscCall(PetscMalloc1(nroots, &leafPoints));
1960:   for (p = 0; p < nroots; ++p) leafPoints[p].rank = leafPoints[p].index = -1;
1961:   for (p = 0; p < nleaves; p++) {
1962:     PetscInt ilp = ilocal ? ilocal[p] : p;

1964:     leafPoints[ilp].index = ilp;
1965:     leafPoints[ilp].rank  = rank;
1966:   }
1967:   PetscCall(PetscSFComputeDegreeBegin(sf, &rootDegree));
1968:   PetscCall(PetscSFComputeDegreeEnd(sf, &rootDegree));
1969:   for (p = 0, nmultiroots = 0; p < nroots; ++p) nmultiroots += rootDegree[p];
1970:   PetscCall(PetscMalloc1(nmultiroots, &rootPoints));
1971:   PetscCall(PetscSFGatherBegin(sf, MPIU_2INT, leafPoints, rootPoints));
1972:   PetscCall(PetscSFGatherEnd(sf, MPIU_2INT, leafPoints, rootPoints));
1973:   PetscCall(PetscSFCreate(comm, &sfLabel));
1974:   PetscCall(PetscSFSetGraph(sfLabel, nroots, nmultiroots, NULL, PETSC_OWN_POINTER, rootPoints, PETSC_OWN_POINTER));
1975:   /* Migrate label over inverted SF to pull stratum values at leaves into roots. */
1976:   PetscCall(DMLabelDistribute_Internal(label, sfLabel, &rootSection, &rootStrata));
1977:   /* Rebuild the point strata on the receiver */
1978:   for (p = 0, idx = 0; p < nroots; p++) {
1979:     for (d = 0; d < rootDegree[p]; d++) {
1980:       PetscCall(PetscSectionGetDof(rootSection, idx + d, &dof));
1981:       PetscCall(PetscSectionGetOffset(rootSection, idx + d, &offset));
1982:       for (s = 0; s < dof; s++) PetscCall(DMLabelSetValue(*labelNew, p, rootStrata[offset + s]));
1983:     }
1984:     idx += rootDegree[p];
1985:   }
1986:   PetscCall(PetscFree(leafPoints));
1987:   PetscCall(PetscFree(rootStrata));
1988:   PetscCall(PetscSectionDestroy(&rootSection));
1989:   PetscCall(PetscSFDestroy(&sfLabel));
1990:   PetscFunctionReturn(PETSC_SUCCESS);
1991: }

1993: static PetscErrorCode DMLabelPropagateInit_Internal(DMLabel label, PetscSF pointSF, PetscInt valArray[])
1994: {
1995:   const PetscInt *degree;
1996:   const PetscInt *points;
1997:   PetscInt        Nr, r, Nl, l, val, defVal;

1999:   PetscFunctionBegin;
2000:   PetscCall(DMLabelGetDefaultValue(label, &defVal));
2001:   /* Add in leaves */
2002:   PetscCall(PetscSFGetGraph(pointSF, &Nr, &Nl, &points, NULL));
2003:   for (l = 0; l < Nl; ++l) {
2004:     PetscCall(DMLabelGetValue(label, points[l], &val));
2005:     if (val != defVal) valArray[points[l]] = val;
2006:   }
2007:   /* Add in shared roots */
2008:   PetscCall(PetscSFComputeDegreeBegin(pointSF, &degree));
2009:   PetscCall(PetscSFComputeDegreeEnd(pointSF, &degree));
2010:   for (r = 0; r < Nr; ++r) {
2011:     if (degree[r]) {
2012:       PetscCall(DMLabelGetValue(label, r, &val));
2013:       if (val != defVal) valArray[r] = val;
2014:     }
2015:   }
2016:   PetscFunctionReturn(PETSC_SUCCESS);
2017: }

2019: static PetscErrorCode DMLabelPropagateFini_Internal(DMLabel label, PetscSF pointSF, PetscInt valArray[], PetscErrorCode (*markPoint)(DMLabel, PetscInt, PetscInt, void *), void *ctx)
2020: {
2021:   const PetscInt *degree;
2022:   const PetscInt *points;
2023:   PetscInt        Nr, r, Nl, l, val, defVal;

2025:   PetscFunctionBegin;
2026:   PetscCall(DMLabelGetDefaultValue(label, &defVal));
2027:   /* Read out leaves */
2028:   PetscCall(PetscSFGetGraph(pointSF, &Nr, &Nl, &points, NULL));
2029:   for (l = 0; l < Nl; ++l) {
2030:     const PetscInt p    = points[l];
2031:     const PetscInt cval = valArray[p];

2033:     if (cval != defVal) {
2034:       PetscCall(DMLabelGetValue(label, p, &val));
2035:       if (val == defVal) {
2036:         PetscCall(DMLabelSetValue(label, p, cval));
2037:         if (markPoint) PetscCall((*markPoint)(label, p, cval, ctx));
2038:       }
2039:     }
2040:   }
2041:   /* Read out shared roots */
2042:   PetscCall(PetscSFComputeDegreeBegin(pointSF, &degree));
2043:   PetscCall(PetscSFComputeDegreeEnd(pointSF, &degree));
2044:   for (r = 0; r < Nr; ++r) {
2045:     if (degree[r]) {
2046:       const PetscInt cval = valArray[r];

2048:       if (cval != defVal) {
2049:         PetscCall(DMLabelGetValue(label, r, &val));
2050:         if (val == defVal) {
2051:           PetscCall(DMLabelSetValue(label, r, cval));
2052:           if (markPoint) PetscCall((*markPoint)(label, r, cval, ctx));
2053:         }
2054:       }
2055:     }
2056:   }
2057:   PetscFunctionReturn(PETSC_SUCCESS);
2058: }

2060: /*@
2061:   DMLabelPropagateBegin - Setup a cycle of label propagation

2063:   Collective

2065:   Input Parameters:
2066: + label - The `DMLabel` to propagate across processes
2067: - sf    - The `PetscSF` describing parallel layout of the label points

2069:   Level: intermediate

2071: .seealso: `DMLabel`, `DM`, `DMLabelPropagateEnd()`, `DMLabelPropagatePush()`
2072: @*/
2073: PetscErrorCode DMLabelPropagateBegin(DMLabel label, PetscSF sf)
2074: {
2075:   PetscInt    Nr, r, defVal;
2076:   PetscMPIInt size;

2078:   PetscFunctionBegin;
2079:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
2080:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)sf), &size));
2081:   if (size > 1) {
2082:     PetscCall(DMLabelGetDefaultValue(label, &defVal));
2083:     PetscCall(PetscSFGetGraph(sf, &Nr, NULL, NULL, NULL));
2084:     if (Nr >= 0) PetscCall(PetscMalloc1(Nr, &label->propArray));
2085:     for (r = 0; r < Nr; ++r) label->propArray[r] = defVal;
2086:   }
2087:   PetscFunctionReturn(PETSC_SUCCESS);
2088: }

2090: /*@
2091:   DMLabelPropagateEnd - Tear down a cycle of label propagation

2093:   Collective

2095:   Input Parameters:
2096: + label   - The `DMLabel` to propagate across processes
2097: - pointSF - The `PetscSF` describing parallel layout of the label points

2099:   Level: intermediate

2101: .seealso: `DMLabel`, `DM`, `DMLabelPropagateBegin()`, `DMLabelPropagatePush()`
2102: @*/
2103: PetscErrorCode DMLabelPropagateEnd(DMLabel label, PetscSF pointSF)
2104: {
2105:   PetscFunctionBegin;
2106:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
2107:   PetscCall(PetscFree(label->propArray));
2108:   label->propArray = NULL;
2109:   PetscFunctionReturn(PETSC_SUCCESS);
2110: }

2112: /*@C
2113:   DMLabelPropagatePush - Tear down a cycle of label propagation

2115:   Collective

2117:   Input Parameters:
2118: + label     - The `DMLabel` to propagate across processes
2119: . pointSF   - The `PetscSF` describing parallel layout of the label points
2120: . markPoint - An optional callback that is called when a point is marked, or `NULL`
2121: - ctx       - An optional user context for the callback, or `NULL`

2123:   Calling sequence of `markPoint`:
2124: + label - The `DMLabel`
2125: . p     - The point being marked
2126: . val   - The label value for `p`
2127: - ctx   - An optional user context

2129:   Level: intermediate

2131: .seealso: `DMLabel`, `DM`, `DMLabelPropagateBegin()`, `DMLabelPropagateEnd()`
2132: @*/
2133: PetscErrorCode DMLabelPropagatePush(DMLabel label, PetscSF pointSF, PetscErrorCode (*markPoint)(DMLabel label, PetscInt p, PetscInt val, void *ctx), void *ctx)
2134: {
2135:   PetscInt   *valArray = label->propArray, Nr;
2136:   PetscMPIInt size;

2138:   PetscFunctionBegin;
2139:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
2140:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pointSF), &size));
2141:   PetscCall(PetscSFGetGraph(pointSF, &Nr, NULL, NULL, NULL));
2142:   if (size > 1 && Nr >= 0) {
2143:     /* Communicate marked edges
2144:        The current implementation allocates an array the size of the number of root. We put the label values into the
2145:        array, and then call PetscSFReduce()+PetscSFBcast() to make the marks consistent.

2147:        TODO: We could use in-place communication with a different SF
2148:        We use MPI_SUM for the Reduce, and check the result against the rootdegree. If sum >= rootdegree+1, then the edge has
2149:        already been marked. If not, it might have been handled on the process in this round, but we add it anyway.

2151:        In order to update the queue with the new edges from the label communication, we use BcastAnOp(MPI_SUM), so that new
2152:        values will have 1+0=1 and old values will have 1+1=2. Loop over these, resetting the values to 1, and adding any new
2153:        edge to the queue.
2154:     */
2155:     PetscCall(DMLabelPropagateInit_Internal(label, pointSF, valArray));
2156:     PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, valArray, valArray, MPI_MAX));
2157:     PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, valArray, valArray, MPI_MAX));
2158:     PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, valArray, valArray, MPI_REPLACE));
2159:     PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, valArray, valArray, MPI_REPLACE));
2160:     PetscCall(DMLabelPropagateFini_Internal(label, pointSF, valArray, markPoint, ctx));
2161:   }
2162:   PetscFunctionReturn(PETSC_SUCCESS);
2163: }

2165: /*@
2166:   DMLabelConvertToSection - Make a `PetscSection`/`IS` pair that encodes the label

2168:   Not Collective

2170:   Input Parameter:
2171: . label - the `DMLabel`

2173:   Output Parameters:
2174: + section - the section giving offsets for each stratum
2175: - is      - An `IS` containing all the label points

2177:   Level: developer

2179: .seealso: `DMLabel`, `DM`, `DMLabelDistribute()`
2180: @*/
2181: PetscErrorCode DMLabelConvertToSection(DMLabel label, PetscSection *section, IS *is)
2182: {
2183:   IS              vIS;
2184:   const PetscInt *values;
2185:   PetscInt       *points;
2186:   PetscInt        nV, vS = 0, vE = 0, v, N;

2188:   PetscFunctionBegin;
2190:   PetscCall(DMLabelGetNumValues(label, &nV));
2191:   PetscCall(DMLabelGetValueIS(label, &vIS));
2192:   PetscCall(ISGetIndices(vIS, &values));
2193:   if (nV) {
2194:     vS = values[0];
2195:     vE = values[0] + 1;
2196:   }
2197:   for (v = 1; v < nV; ++v) {
2198:     vS = PetscMin(vS, values[v]);
2199:     vE = PetscMax(vE, values[v] + 1);
2200:   }
2201:   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, section));
2202:   PetscCall(PetscSectionSetChart(*section, vS, vE));
2203:   for (v = 0; v < nV; ++v) {
2204:     PetscInt n;

2206:     PetscCall(DMLabelGetStratumSize(label, values[v], &n));
2207:     PetscCall(PetscSectionSetDof(*section, values[v], n));
2208:   }
2209:   PetscCall(PetscSectionSetUp(*section));
2210:   PetscCall(PetscSectionGetStorageSize(*section, &N));
2211:   PetscCall(PetscMalloc1(N, &points));
2212:   for (v = 0; v < nV; ++v) {
2213:     IS              is;
2214:     const PetscInt *spoints;
2215:     PetscInt        dof, off, p;

2217:     PetscCall(PetscSectionGetDof(*section, values[v], &dof));
2218:     PetscCall(PetscSectionGetOffset(*section, values[v], &off));
2219:     PetscCall(DMLabelGetStratumIS(label, values[v], &is));
2220:     PetscCall(ISGetIndices(is, &spoints));
2221:     for (p = 0; p < dof; ++p) points[off + p] = spoints[p];
2222:     PetscCall(ISRestoreIndices(is, &spoints));
2223:     PetscCall(ISDestroy(&is));
2224:   }
2225:   PetscCall(ISRestoreIndices(vIS, &values));
2226:   PetscCall(ISDestroy(&vIS));
2227:   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, N, points, PETSC_OWN_POINTER, is));
2228:   PetscFunctionReturn(PETSC_SUCCESS);
2229: }

2231: /*@C
2232:   DMLabelRegister - Adds a new label component implementation

2234:   Not Collective

2236:   Input Parameters:
2237: + name        - The name of a new user-defined creation routine
2238: - create_func - The creation routine itself

2240:   Notes:
2241:   `DMLabelRegister()` may be called multiple times to add several user-defined labels

2243:   Example Usage:
2244: .vb
2245:   DMLabelRegister("my_label", MyLabelCreate);
2246: .ve

2248:   Then, your label type can be chosen with the procedural interface via
2249: .vb
2250:   DMLabelCreate(MPI_Comm, DMLabel *);
2251:   DMLabelSetType(DMLabel, "my_label");
2252: .ve
2253:   or at runtime via the option
2254: .vb
2255:   -dm_label_type my_label
2256: .ve

2258:   Level: advanced

2260: .seealso: `DMLabel`, `DM`, `DMLabelType`, `DMLabelRegisterAll()`, `DMLabelRegisterDestroy()`
2261: @*/
2262: PetscErrorCode DMLabelRegister(const char name[], PetscErrorCode (*create_func)(DMLabel))
2263: {
2264:   PetscFunctionBegin;
2265:   PetscCall(DMInitializePackage());
2266:   PetscCall(PetscFunctionListAdd(&DMLabelList, name, create_func));
2267:   PetscFunctionReturn(PETSC_SUCCESS);
2268: }

2270: PETSC_EXTERN PetscErrorCode DMLabelCreate_Concrete(DMLabel);
2271: PETSC_EXTERN PetscErrorCode DMLabelCreate_Ephemeral(DMLabel);

2273: /*@C
2274:   DMLabelRegisterAll - Registers all of the `DMLabel` implementations in the `DM` package.

2276:   Not Collective

2278:   Level: advanced

2280: .seealso: `DMLabel`, `DM`, `DMRegisterAll()`, `DMLabelRegisterDestroy()`
2281: @*/
2282: PetscErrorCode DMLabelRegisterAll(void)
2283: {
2284:   PetscFunctionBegin;
2285:   if (DMLabelRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
2286:   DMLabelRegisterAllCalled = PETSC_TRUE;

2288:   PetscCall(DMLabelRegister(DMLABELCONCRETE, DMLabelCreate_Concrete));
2289:   PetscCall(DMLabelRegister(DMLABELEPHEMERAL, DMLabelCreate_Ephemeral));
2290:   PetscFunctionReturn(PETSC_SUCCESS);
2291: }

2293: /*@C
2294:   DMLabelRegisterDestroy - This function destroys the `DMLabel` registry. It is called from `PetscFinalize()`.

2296:   Level: developer

2298: .seealso: `DMLabel`, `DM`, `PetscInitialize()`
2299: @*/
2300: PetscErrorCode DMLabelRegisterDestroy(void)
2301: {
2302:   PetscFunctionBegin;
2303:   PetscCall(PetscFunctionListDestroy(&DMLabelList));
2304:   DMLabelRegisterAllCalled = PETSC_FALSE;
2305:   PetscFunctionReturn(PETSC_SUCCESS);
2306: }

2308: /*@
2309:   DMLabelSetType - Sets the particular implementation for a label.

2311:   Collective

2313:   Input Parameters:
2314: + label  - The label
2315: - method - The name of the label type

2317:   Options Database Key:
2318: . -dm_label_type <type> - Sets the label type; use -help for a list of available types or see `DMLabelType`

2320:   Level: intermediate

2322: .seealso: `DMLabel`, `DM`, `DMLabelGetType()`, `DMLabelCreate()`
2323: @*/
2324: PetscErrorCode DMLabelSetType(DMLabel label, DMLabelType method)
2325: {
2326:   PetscErrorCode (*r)(DMLabel);
2327:   PetscBool match;

2329:   PetscFunctionBegin;
2331:   PetscCall(PetscObjectTypeCompare((PetscObject)label, method, &match));
2332:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

2334:   PetscCall(DMLabelRegisterAll());
2335:   PetscCall(PetscFunctionListFind(DMLabelList, method, &r));
2336:   PetscCheck(r, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DMLabel type: %s", method);

2338:   PetscTryTypeMethod(label, destroy);
2339:   PetscCall(PetscMemzero(label->ops, sizeof(*label->ops)));
2340:   PetscCall(PetscObjectChangeTypeName((PetscObject)label, method));
2341:   PetscCall((*r)(label));
2342:   PetscFunctionReturn(PETSC_SUCCESS);
2343: }

2345: /*@
2346:   DMLabelGetType - Gets the type name (as a string) from the label.

2348:   Not Collective

2350:   Input Parameter:
2351: . label - The `DMLabel`

2353:   Output Parameter:
2354: . type - The `DMLabel` type name

2356:   Level: intermediate

2358: .seealso: `DMLabel`, `DM`, `DMLabelSetType()`, `DMLabelCreate()`
2359: @*/
2360: PetscErrorCode DMLabelGetType(DMLabel label, DMLabelType *type)
2361: {
2362:   PetscFunctionBegin;
2364:   PetscAssertPointer(type, 2);
2365:   PetscCall(DMLabelRegisterAll());
2366:   *type = ((PetscObject)label)->type_name;
2367:   PetscFunctionReturn(PETSC_SUCCESS);
2368: }

2370: static PetscErrorCode DMLabelInitialize_Concrete(DMLabel label)
2371: {
2372:   PetscFunctionBegin;
2373:   label->ops->view         = DMLabelView_Concrete;
2374:   label->ops->setup        = NULL;
2375:   label->ops->duplicate    = DMLabelDuplicate_Concrete;
2376:   label->ops->getstratumis = DMLabelGetStratumIS_Concrete;
2377:   PetscFunctionReturn(PETSC_SUCCESS);
2378: }

2380: PETSC_EXTERN PetscErrorCode DMLabelCreate_Concrete(DMLabel label)
2381: {
2382:   PetscFunctionBegin;
2384:   PetscCall(DMLabelInitialize_Concrete(label));
2385:   PetscFunctionReturn(PETSC_SUCCESS);
2386: }

2388: /*@
2389:   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
2390:   the local section and an `PetscSF` describing the section point overlap.

2392:   Collective

2394:   Input Parameters:
2395: + s                  - The `PetscSection` for the local field layout
2396: . sf                 - The `PetscSF` describing parallel layout of the section points
2397: . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global field vector will not possess constrained dofs
2398: . label              - The label specifying the points
2399: - labelValue         - The label stratum specifying the points

2401:   Output Parameter:
2402: . gsection - The `PetscSection` for the global field layout

2404:   Level: developer

2406:   Note:
2407:   This gives negative sizes and offsets to points not owned by this process

2409: .seealso: `DMLabel`, `DM`, `PetscSectionCreate()`
2410: @*/
2411: PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
2412: {
2413:   PetscInt *neg = NULL, *tmpOff = NULL;
2414:   PetscInt  pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;

2416:   PetscFunctionBegin;
2420:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), gsection));
2421:   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2422:   PetscCall(PetscSectionSetChart(*gsection, pStart, pEnd));
2423:   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
2424:   if (nroots >= 0) {
2425:     PetscCheck(nroots >= pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %" PetscInt_FMT " < %" PetscInt_FMT " section size", nroots, pEnd - pStart);
2426:     PetscCall(PetscCalloc1(nroots, &neg));
2427:     if (nroots > pEnd - pStart) {
2428:       PetscCall(PetscCalloc1(nroots, &tmpOff));
2429:     } else {
2430:       tmpOff = &(*gsection)->atlasDof[-pStart];
2431:     }
2432:   }
2433:   /* Mark ghost points with negative dof */
2434:   for (p = pStart; p < pEnd; ++p) {
2435:     PetscInt value;

2437:     PetscCall(DMLabelGetValue(label, p, &value));
2438:     if (value != labelValue) continue;
2439:     PetscCall(PetscSectionGetDof(s, p, &dof));
2440:     PetscCall(PetscSectionSetDof(*gsection, p, dof));
2441:     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2442:     if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(*gsection, p, cdof));
2443:     if (neg) neg[p] = -(dof + 1);
2444:   }
2445:   PetscCall(PetscSectionSetUpBC(*gsection));
2446:   if (nroots >= 0) {
2447:     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2448:     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2449:     if (nroots > pEnd - pStart) {
2450:       for (p = pStart; p < pEnd; ++p) {
2451:         if (tmpOff[p] < 0) (*gsection)->atlasDof[p - pStart] = tmpOff[p];
2452:       }
2453:     }
2454:   }
2455:   /* Calculate new sizes, get process offset, and calculate point offsets */
2456:   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
2457:     cdof                     = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
2458:     (*gsection)->atlasOff[p] = off;
2459:     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p] - cdof : 0;
2460:   }
2461:   PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s)));
2462:   globalOff -= off;
2463:   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
2464:     (*gsection)->atlasOff[p] += globalOff;
2465:     if (neg) neg[p] = -((*gsection)->atlasOff[p] + 1);
2466:   }
2467:   /* Put in negative offsets for ghost points */
2468:   if (nroots >= 0) {
2469:     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2470:     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2471:     if (nroots > pEnd - pStart) {
2472:       for (p = pStart; p < pEnd; ++p) {
2473:         if (tmpOff[p] < 0) (*gsection)->atlasOff[p - pStart] = tmpOff[p];
2474:       }
2475:     }
2476:   }
2477:   if (nroots >= 0 && nroots > pEnd - pStart) PetscCall(PetscFree(tmpOff));
2478:   PetscCall(PetscFree(neg));
2479:   PetscFunctionReturn(PETSC_SUCCESS);
2480: }

2482: typedef struct _n_PetscSectionSym_Label {
2483:   DMLabel              label;
2484:   PetscCopyMode       *modes;
2485:   PetscInt            *sizes;
2486:   const PetscInt    ***perms;
2487:   const PetscScalar ***rots;
2488:   PetscInt (*minMaxOrients)[2];
2489:   PetscInt numStrata; /* numStrata is only increasing, functions as a state */
2490: } PetscSectionSym_Label;

2492: static PetscErrorCode PetscSectionSymLabelReset(PetscSectionSym sym)
2493: {
2494:   PetscInt               i, j;
2495:   PetscSectionSym_Label *sl = (PetscSectionSym_Label *)sym->data;

2497:   PetscFunctionBegin;
2498:   for (i = 0; i <= sl->numStrata; i++) {
2499:     if (sl->modes[i] == PETSC_OWN_POINTER || sl->modes[i] == PETSC_COPY_VALUES) {
2500:       for (j = sl->minMaxOrients[i][0]; j < sl->minMaxOrients[i][1]; j++) {
2501:         if (sl->perms[i]) PetscCall(PetscFree(sl->perms[i][j]));
2502:         if (sl->rots[i]) PetscCall(PetscFree(sl->rots[i][j]));
2503:       }
2504:       if (sl->perms[i]) {
2505:         const PetscInt **perms = &sl->perms[i][sl->minMaxOrients[i][0]];

2507:         PetscCall(PetscFree(perms));
2508:       }
2509:       if (sl->rots[i]) {
2510:         const PetscScalar **rots = &sl->rots[i][sl->minMaxOrients[i][0]];

2512:         PetscCall(PetscFree(rots));
2513:       }
2514:     }
2515:   }
2516:   PetscCall(PetscFree5(sl->modes, sl->sizes, sl->perms, sl->rots, sl->minMaxOrients));
2517:   PetscCall(DMLabelDestroy(&sl->label));
2518:   sl->numStrata = 0;
2519:   PetscFunctionReturn(PETSC_SUCCESS);
2520: }

2522: static PetscErrorCode PetscSectionSymDestroy_Label(PetscSectionSym sym)
2523: {
2524:   PetscFunctionBegin;
2525:   PetscCall(PetscSectionSymLabelReset(sym));
2526:   PetscCall(PetscFree(sym->data));
2527:   PetscFunctionReturn(PETSC_SUCCESS);
2528: }

2530: static PetscErrorCode PetscSectionSymView_Label(PetscSectionSym sym, PetscViewer viewer)
2531: {
2532:   PetscSectionSym_Label *sl = (PetscSectionSym_Label *)sym->data;
2533:   PetscBool              isAscii;
2534:   DMLabel                label = sl->label;
2535:   const char            *name;

2537:   PetscFunctionBegin;
2538:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isAscii));
2539:   if (isAscii) {
2540:     PetscInt          i, j, k;
2541:     PetscViewerFormat format;

2543:     PetscCall(PetscViewerGetFormat(viewer, &format));
2544:     if (label) {
2545:       PetscCall(PetscViewerGetFormat(viewer, &format));
2546:       if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
2547:         PetscCall(PetscViewerASCIIPushTab(viewer));
2548:         PetscCall(DMLabelView(label, viewer));
2549:         PetscCall(PetscViewerASCIIPopTab(viewer));
2550:       } else {
2551:         PetscCall(PetscObjectGetName((PetscObject)sl->label, &name));
2552:         PetscCall(PetscViewerASCIIPrintf(viewer, "  Label '%s'\n", name));
2553:       }
2554:     } else {
2555:       PetscCall(PetscViewerASCIIPrintf(viewer, "No label given\n"));
2556:     }
2557:     PetscCall(PetscViewerASCIIPushTab(viewer));
2558:     for (i = 0; i <= sl->numStrata; i++) {
2559:       PetscInt value = i < sl->numStrata ? label->stratumValues[i] : label->defaultValue;

2561:       if (!(sl->perms[i] || sl->rots[i])) {
2562:         PetscCall(PetscViewerASCIIPrintf(viewer, "Symmetry for stratum value %" PetscInt_FMT " (%" PetscInt_FMT " dofs per point): no symmetries\n", value, sl->sizes[i]));
2563:       } else {
2564:         PetscCall(PetscViewerASCIIPrintf(viewer, "Symmetry for stratum value %" PetscInt_FMT " (%" PetscInt_FMT " dofs per point):\n", value, sl->sizes[i]));
2565:         PetscCall(PetscViewerASCIIPushTab(viewer));
2566:         PetscCall(PetscViewerASCIIPrintf(viewer, "Orientation range: [%" PetscInt_FMT ", %" PetscInt_FMT ")\n", sl->minMaxOrients[i][0], sl->minMaxOrients[i][1]));
2567:         if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
2568:           PetscCall(PetscViewerASCIIPushTab(viewer));
2569:           for (j = sl->minMaxOrients[i][0]; j < sl->minMaxOrients[i][1]; j++) {
2570:             if (!((sl->perms[i] && sl->perms[i][j]) || (sl->rots[i] && sl->rots[i][j]))) {
2571:               PetscCall(PetscViewerASCIIPrintf(viewer, "Orientation %" PetscInt_FMT ": identity\n", j));
2572:             } else {
2573:               PetscInt tab;

2575:               PetscCall(PetscViewerASCIIPrintf(viewer, "Orientation %" PetscInt_FMT ":\n", j));
2576:               PetscCall(PetscViewerASCIIPushTab(viewer));
2577:               PetscCall(PetscViewerASCIIGetTab(viewer, &tab));
2578:               if (sl->perms[i] && sl->perms[i][j]) {
2579:                 PetscCall(PetscViewerASCIIPrintf(viewer, "Permutation:"));
2580:                 PetscCall(PetscViewerASCIISetTab(viewer, 0));
2581:                 for (k = 0; k < sl->sizes[i]; k++) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sl->perms[i][j][k]));
2582:                 PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
2583:                 PetscCall(PetscViewerASCIISetTab(viewer, tab));
2584:               }
2585:               if (sl->rots[i] && sl->rots[i][j]) {
2586:                 PetscCall(PetscViewerASCIIPrintf(viewer, "Rotations:  "));
2587:                 PetscCall(PetscViewerASCIISetTab(viewer, 0));
2588: #if defined(PETSC_USE_COMPLEX)
2589:                 for (k = 0; k < sl->sizes[i]; k++) PetscCall(PetscViewerASCIIPrintf(viewer, " %+g+i*%+g", (double)PetscRealPart(sl->rots[i][j][k]), (double)PetscImaginaryPart(sl->rots[i][j][k])));
2590: #else
2591:                 for (k = 0; k < sl->sizes[i]; k++) PetscCall(PetscViewerASCIIPrintf(viewer, " %+g", (double)sl->rots[i][j][k]));
2592: #endif
2593:                 PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
2594:                 PetscCall(PetscViewerASCIISetTab(viewer, tab));
2595:               }
2596:               PetscCall(PetscViewerASCIIPopTab(viewer));
2597:             }
2598:           }
2599:           PetscCall(PetscViewerASCIIPopTab(viewer));
2600:         }
2601:         PetscCall(PetscViewerASCIIPopTab(viewer));
2602:       }
2603:     }
2604:     PetscCall(PetscViewerASCIIPopTab(viewer));
2605:   }
2606:   PetscFunctionReturn(PETSC_SUCCESS);
2607: }

2609: /*@
2610:   PetscSectionSymLabelSetLabel - set the label whose strata will define the points that receive symmetries

2612:   Logically

2614:   Input Parameters:
2615: + sym   - the section symmetries
2616: - label - the `DMLabel` describing the types of points

2618:   Level: developer:

2620: .seealso: `DMLabel`, `DM`, `PetscSectionSymLabelSetStratum()`, `PetscSectionSymCreateLabel()`, `PetscSectionGetPointSyms()`
2621: @*/
2622: PetscErrorCode PetscSectionSymLabelSetLabel(PetscSectionSym sym, DMLabel label)
2623: {
2624:   PetscSectionSym_Label *sl;

2626:   PetscFunctionBegin;
2628:   sl = (PetscSectionSym_Label *)sym->data;
2629:   if (sl->label && sl->label != label) PetscCall(PetscSectionSymLabelReset(sym));
2630:   if (label) {
2631:     sl->label = label;
2632:     PetscCall(PetscObjectReference((PetscObject)label));
2633:     PetscCall(DMLabelGetNumValues(label, &sl->numStrata));
2634:     PetscCall(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));
2635:     PetscCall(PetscMemzero((void *)sl->modes, (sl->numStrata + 1) * sizeof(PetscCopyMode)));
2636:     PetscCall(PetscMemzero((void *)sl->sizes, (sl->numStrata + 1) * sizeof(PetscInt)));
2637:     PetscCall(PetscMemzero((void *)sl->perms, (sl->numStrata + 1) * sizeof(const PetscInt **)));
2638:     PetscCall(PetscMemzero((void *)sl->rots, (sl->numStrata + 1) * sizeof(const PetscScalar **)));
2639:     PetscCall(PetscMemzero((void *)sl->minMaxOrients, (sl->numStrata + 1) * sizeof(PetscInt[2])));
2640:   }
2641:   PetscFunctionReturn(PETSC_SUCCESS);
2642: }

2644: /*@C
2645:   PetscSectionSymLabelGetStratum - get the symmetries for the orientations of a stratum

2647:   Logically Collective

2649:   Input Parameters:
2650: + sym     - the section symmetries
2651: - stratum - the stratum value in the label that we are assigning symmetries for

2653:   Output Parameters:
2654: + size      - the number of dofs for points in the `stratum` of the label
2655: . minOrient - the smallest orientation for a point in this `stratum`
2656: . maxOrient - one greater than the largest orientation for a ppoint in this `stratum` (i.e., orientations are in the range [`minOrient`, `maxOrient`))
2657: . perms     - `NULL` if there are no permutations, or (`maxOrient` - `minOrient`) permutations, one for each orientation.  A `NULL` permutation is the identity
2658: - 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

2660:   Level: developer

2662: .seealso: `DMLabel`, `DM`, `PetscSectionSymLabelSetStratum()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreateLabel()`
2663: @*/
2664: PetscErrorCode PetscSectionSymLabelGetStratum(PetscSectionSym sym, PetscInt stratum, PetscInt *size, PetscInt *minOrient, PetscInt *maxOrient, const PetscInt ***perms, const PetscScalar ***rots)
2665: {
2666:   PetscSectionSym_Label *sl;
2667:   const char            *name;
2668:   PetscInt               i;

2670:   PetscFunctionBegin;
2672:   sl = (PetscSectionSym_Label *)sym->data;
2673:   PetscCheck(sl->label, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_WRONGSTATE, "No label set yet");
2674:   for (i = 0; i <= sl->numStrata; i++) {
2675:     PetscInt value = (i < sl->numStrata) ? sl->label->stratumValues[i] : sl->label->defaultValue;

2677:     if (stratum == value) break;
2678:   }
2679:   PetscCall(PetscObjectGetName((PetscObject)sl->label, &name));
2680:   PetscCheck(i <= sl->numStrata, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_OUTOFRANGE, "Stratum %" PetscInt_FMT " not found in label %s", stratum, name);
2681:   if (size) {
2682:     PetscAssertPointer(size, 3);
2683:     *size = sl->sizes[i];
2684:   }
2685:   if (minOrient) {
2686:     PetscAssertPointer(minOrient, 4);
2687:     *minOrient = sl->minMaxOrients[i][0];
2688:   }
2689:   if (maxOrient) {
2690:     PetscAssertPointer(maxOrient, 5);
2691:     *maxOrient = sl->minMaxOrients[i][1];
2692:   }
2693:   if (perms) {
2694:     PetscAssertPointer(perms, 6);
2695:     *perms = PetscSafePointerPlusOffset(sl->perms[i], sl->minMaxOrients[i][0]);
2696:   }
2697:   if (rots) {
2698:     PetscAssertPointer(rots, 7);
2699:     *rots = PetscSafePointerPlusOffset(sl->rots[i], sl->minMaxOrients[i][0]);
2700:   }
2701:   PetscFunctionReturn(PETSC_SUCCESS);
2702: }

2704: /*@C
2705:   PetscSectionSymLabelSetStratum - set the symmetries for the orientations of a stratum

2707:   Logically

2709:   Input Parameters:
2710: + sym       - the section symmetries
2711: . stratum   - the stratum value in the label that we are assigning symmetries for
2712: . size      - the number of dofs for points in the `stratum` of the label
2713: . minOrient - the smallest orientation for a point in this `stratum`
2714: . maxOrient - one greater than the largest orientation for a point in this `stratum` (i.e., orientations are in the range [`minOrient`, `maxOrient`))
2715: . mode      - how `sym` should copy the `perms` and `rots` arrays
2716: . perms     - `NULL` if there are no permutations, or (`maxOrient` - `minOrient`) permutations, one for each orientation.  A `NULL` permutation is the identity
2717: - 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

2719:   Level: developer

2721: .seealso: `DMLabel`, `DM`, `PetscSectionSymLabelGetStratum()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreateLabel()`
2722: @*/
2723: PetscErrorCode PetscSectionSymLabelSetStratum(PetscSectionSym sym, PetscInt stratum, PetscInt size, PetscInt minOrient, PetscInt maxOrient, PetscCopyMode mode, const PetscInt **perms, const PetscScalar **rots)
2724: {
2725:   PetscSectionSym_Label *sl;
2726:   const char            *name;
2727:   PetscInt               i, j, k;

2729:   PetscFunctionBegin;
2731:   sl = (PetscSectionSym_Label *)sym->data;
2732:   PetscCheck(sl->label, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_WRONGSTATE, "No label set yet");
2733:   for (i = 0; i <= sl->numStrata; i++) {
2734:     PetscInt value = (i < sl->numStrata) ? sl->label->stratumValues[i] : sl->label->defaultValue;

2736:     if (stratum == value) break;
2737:   }
2738:   PetscCall(PetscObjectGetName((PetscObject)sl->label, &name));
2739:   PetscCheck(i <= sl->numStrata, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_OUTOFRANGE, "Stratum %" PetscInt_FMT " not found in label %s", stratum, name);
2740:   sl->sizes[i]            = size;
2741:   sl->modes[i]            = mode;
2742:   sl->minMaxOrients[i][0] = minOrient;
2743:   sl->minMaxOrients[i][1] = maxOrient;
2744:   if (mode == PETSC_COPY_VALUES) {
2745:     if (perms) {
2746:       PetscInt **ownPerms;

2748:       PetscCall(PetscCalloc1(maxOrient - minOrient, &ownPerms));
2749:       for (j = 0; j < maxOrient - minOrient; j++) {
2750:         if (perms[j]) {
2751:           PetscCall(PetscMalloc1(size, &ownPerms[j]));
2752:           for (k = 0; k < size; k++) ownPerms[j][k] = perms[j][k];
2753:         }
2754:       }
2755:       sl->perms[i] = (const PetscInt **)&ownPerms[-minOrient];
2756:     }
2757:     if (rots) {
2758:       PetscScalar **ownRots;

2760:       PetscCall(PetscCalloc1(maxOrient - minOrient, &ownRots));
2761:       for (j = 0; j < maxOrient - minOrient; j++) {
2762:         if (rots[j]) {
2763:           PetscCall(PetscMalloc1(size, &ownRots[j]));
2764:           for (k = 0; k < size; k++) ownRots[j][k] = rots[j][k];
2765:         }
2766:       }
2767:       sl->rots[i] = (const PetscScalar **)&ownRots[-minOrient];
2768:     }
2769:   } else {
2770:     sl->perms[i] = PetscSafePointerPlusOffset(perms, -minOrient);
2771:     sl->rots[i]  = PetscSafePointerPlusOffset(rots, -minOrient);
2772:   }
2773:   PetscFunctionReturn(PETSC_SUCCESS);
2774: }

2776: static PetscErrorCode PetscSectionSymGetPoints_Label(PetscSectionSym sym, PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt **perms, const PetscScalar **rots)
2777: {
2778:   PetscInt               i, j, numStrata;
2779:   PetscSectionSym_Label *sl;
2780:   DMLabel                label;

2782:   PetscFunctionBegin;
2783:   sl        = (PetscSectionSym_Label *)sym->data;
2784:   numStrata = sl->numStrata;
2785:   label     = sl->label;
2786:   for (i = 0; i < numPoints; i++) {
2787:     PetscInt point = points[2 * i];
2788:     PetscInt ornt  = points[2 * i + 1];

2790:     for (j = 0; j < numStrata; j++) {
2791:       if (label->validIS[j]) {
2792:         PetscInt k;

2794:         PetscCall(ISLocate(label->points[j], point, &k));
2795:         if (k >= 0) break;
2796:       } else {
2797:         PetscBool has;

2799:         PetscCall(PetscHSetIHas(label->ht[j], point, &has));
2800:         if (has) break;
2801:       }
2802:     }
2803:     PetscCheck(!(sl->minMaxOrients[j][1] > sl->minMaxOrients[j][0]) || !(ornt < sl->minMaxOrients[j][0] || ornt >= sl->minMaxOrients[j][1]), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "point %" PetscInt_FMT " orientation %" PetscInt_FMT " not in range [%" PetscInt_FMT ", %" PetscInt_FMT ") for stratum %" PetscInt_FMT, point, ornt, sl->minMaxOrients[j][0], sl->minMaxOrients[j][1],
2804:                j < numStrata ? label->stratumValues[j] : label->defaultValue);
2805:     if (perms) perms[i] = sl->perms[j] ? sl->perms[j][ornt] : NULL;
2806:     if (rots) rots[i] = sl->rots[j] ? sl->rots[j][ornt] : NULL;
2807:   }
2808:   PetscFunctionReturn(PETSC_SUCCESS);
2809: }

2811: static PetscErrorCode PetscSectionSymCopy_Label(PetscSectionSym sym, PetscSectionSym nsym)
2812: {
2813:   PetscSectionSym_Label *sl = (PetscSectionSym_Label *)nsym->data;
2814:   IS                     valIS;
2815:   const PetscInt        *values;
2816:   PetscInt               Nv, v;

2818:   PetscFunctionBegin;
2819:   PetscCall(DMLabelGetNumValues(sl->label, &Nv));
2820:   PetscCall(DMLabelGetValueIS(sl->label, &valIS));
2821:   PetscCall(ISGetIndices(valIS, &values));
2822:   for (v = 0; v < Nv; ++v) {
2823:     const PetscInt      val = values[v];
2824:     PetscInt            size, minOrient, maxOrient;
2825:     const PetscInt    **perms;
2826:     const PetscScalar **rots;

2828:     PetscCall(PetscSectionSymLabelGetStratum(sym, val, &size, &minOrient, &maxOrient, &perms, &rots));
2829:     PetscCall(PetscSectionSymLabelSetStratum(nsym, val, size, minOrient, maxOrient, PETSC_COPY_VALUES, perms, rots));
2830:   }
2831:   PetscCall(ISDestroy(&valIS));
2832:   PetscFunctionReturn(PETSC_SUCCESS);
2833: }

2835: static PetscErrorCode PetscSectionSymDistribute_Label(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym)
2836: {
2837:   PetscSectionSym_Label *sl = (PetscSectionSym_Label *)sym->data;
2838:   DMLabel                dlabel;

2840:   PetscFunctionBegin;
2841:   PetscCall(DMLabelDistribute(sl->label, migrationSF, &dlabel));
2842:   PetscCall(PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)sym), dlabel, dsym));
2843:   PetscCall(DMLabelDestroy(&dlabel));
2844:   PetscCall(PetscSectionSymCopy(sym, *dsym));
2845:   PetscFunctionReturn(PETSC_SUCCESS);
2846: }

2848: PetscErrorCode PetscSectionSymCreate_Label(PetscSectionSym sym)
2849: {
2850:   PetscSectionSym_Label *sl;

2852:   PetscFunctionBegin;
2853:   PetscCall(PetscNew(&sl));
2854:   sym->ops->getpoints  = PetscSectionSymGetPoints_Label;
2855:   sym->ops->distribute = PetscSectionSymDistribute_Label;
2856:   sym->ops->copy       = PetscSectionSymCopy_Label;
2857:   sym->ops->view       = PetscSectionSymView_Label;
2858:   sym->ops->destroy    = PetscSectionSymDestroy_Label;
2859:   sym->data            = (void *)sl;
2860:   PetscFunctionReturn(PETSC_SUCCESS);
2861: }

2863: /*@
2864:   PetscSectionSymCreateLabel - Create a section symmetry that assigns one symmetry to each stratum of a label

2866:   Collective

2868:   Input Parameters:
2869: + comm  - the MPI communicator for the new symmetry
2870: - label - the label defining the strata

2872:   Output Parameter:
2873: . sym - the section symmetries

2875:   Level: developer

2877: .seealso: `DMLabel`, `DM`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()`
2878: @*/
2879: PetscErrorCode PetscSectionSymCreateLabel(MPI_Comm comm, DMLabel label, PetscSectionSym *sym)
2880: {
2881:   PetscFunctionBegin;
2882:   PetscCall(DMInitializePackage());
2883:   PetscCall(PetscSectionSymCreate(comm, sym));
2884:   PetscCall(PetscSectionSymSetType(*sym, PETSCSECTIONSYMLABEL));
2885:   PetscCall(PetscSectionSymLabelSetLabel(*sym, label));
2886:   PetscFunctionReturn(PETSC_SUCCESS);
2887: }