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: /*@C
 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 usual PetscObject name.
 26:   One can get/set it with PetscObjectGetName()/PetscObjectSetName().

 28: .seealso: `DMLabelDestroy()`
 29: @*/
 30: PetscErrorCode DMLabelCreate(MPI_Comm comm, const char name[], DMLabel *label)
 31: {
 32:   PetscFunctionBegin;
 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: /*@C
 55:   DMLabelSetUp - SetUp a `DMLabel` object

 57:   Collective

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

 62:   Level: intermediate

 64: .seealso: `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: `DMLabelCreate()`
 89: */
 90: static PetscErrorCode DMLabelMakeValid_Private(DMLabel label, PetscInt v)
 91: {
 92:   IS       is;
 93:   PetscInt off = 0, *pointArray, p;

 95:   if ((PetscLikely(v >= 0 && v < label->numStrata) && label->validIS[v]) || label->readonly) return PETSC_SUCCESS;
 96:   PetscFunctionBegin;
 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: `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: `DMLabelCreate()`
162: */
163: static PetscErrorCode DMLabelMakeInvalid_Private(DMLabel label, PetscInt v)
164: {
165:   PetscInt        p;
166:   const PetscInt *points;

168:   if ((PetscLikely(v >= 0 && v < label->numStrata) && !label->validIS[v]) || label->readonly) return PETSC_SUCCESS;
169:   PetscFunctionBegin;
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: `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: `DMLabelCreate()`, `DMLabelDestroy()`
341: @*/
342: PetscErrorCode DMLabelAddStrata(DMLabel label, PetscInt numStrata, const PetscInt stratumValues[])
343: {
344:   PetscInt *values, v;

346:   PetscFunctionBegin;
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: `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: 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 on viewer

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

466:   Level: intermediate

468: .seealso: `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: `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:   label->stratumValues = NULL;
510:   label->stratumSizes  = NULL;
511:   label->ht            = NULL;
512:   label->points        = NULL;
513:   label->validIS       = NULL;
514:   PetscCall(PetscHMapIReset(label->hmap));
515:   label->pStart = -1;
516:   label->pEnd   = -1;
517:   PetscCall(PetscBTDestroy(&label->bt));
518:   PetscFunctionReturn(PETSC_SUCCESS);
519: }

521: /*@
522:   DMLabelDestroy - Destroys a DMLabel

524:   Collective on label

526:   Input Parameter:
527: . label - The DMLabel

529:   Level: beginner

531: .seealso: `DMLabelReset()`, `DMLabelCreate()`
532: @*/
533: PetscErrorCode DMLabelDestroy(DMLabel *label)
534: {
535:   PetscFunctionBegin;
536:   if (!*label) PetscFunctionReturn(PETSC_SUCCESS);
538:   if (--((PetscObject)(*label))->refct > 0) {
539:     *label = NULL;
540:     PetscFunctionReturn(PETSC_SUCCESS);
541:   }
542:   PetscCall(DMLabelReset(*label));
543:   PetscCall(PetscHMapIDestroy(&(*label)->hmap));
544:   PetscCall(PetscHeaderDestroy(label));
545:   PetscFunctionReturn(PETSC_SUCCESS);
546: }

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

561: /*@
562:   DMLabelDuplicate - Duplicates a DMLabel

564:   Collective on label

566:   Input Parameter:
567: . label - The DMLabel

569:   Output Parameter:
570: . labelnew - location to put new vector

572:   Level: intermediate

574: .seealso: `DMLabelCreate()`, `DMLabelDestroy()`
575: @*/
576: PetscErrorCode DMLabelDuplicate(DMLabel label, DMLabel *labelnew)
577: {
578:   const char *name;

580:   PetscFunctionBegin;
582:   PetscCall(DMLabelMakeAllValid_Private(label));
583:   PetscCall(PetscObjectGetName((PetscObject)label, &name));
584:   PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)label), name, labelnew));

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

605: /*@C
606:   DMLabelCompare - Compare two DMLabel objects

608:   Collective on comm

610:   Input Parameters:
611: + comm - Comm over which to compare labels
612: . l0 - First DMLabel
613: - l1 - Second DMLabel

615:   Output Parameters
616: + equal   - (Optional) Flag whether the two labels are equal
617: - message - (Optional) Message describing the difference

619:   Level: intermediate

621:   Notes:
622:   The output flag equal is the same on all processes.
623:   If it is passed as NULL and difference is found, an error is thrown on all processes.
624:   Make sure to pass NULL on all processes.

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

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

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

635:   Fortran Notes:
636:   This function is currently not available from Fortran.

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

647:   PetscFunctionBegin;
652:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
653:   PetscCall(PetscObjectGetName((PetscObject)l0, &name0));
654:   PetscCall(PetscObjectGetName((PetscObject)l1, &name1));
655:   {
656:     PetscInt v0, v1;

658:     PetscCall(DMLabelGetDefaultValue(l0, &v0));
659:     PetscCall(DMLabelGetDefaultValue(l1, &v1));
660:     eq = (PetscBool)(v0 == v1);
661:     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));
662:     PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
663:     if (!eq) goto finish;
664:   }
665:   {
666:     IS is0, is1;

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

680:     PetscCall(DMLabelGetNumValues(l0, &nValues));
681:     for (i = 0; i < nValues; i++) {
682:       const PetscInt v = l0->stratumValues[i];
683:       PetscInt       n;
684:       IS             is0, is1;

686:       PetscCall(DMLabelGetStratumSize_Private(l0, i, &n));
687:       if (!n) continue;
688:       PetscCall(DMLabelGetStratumIS(l0, v, &is0));
689:       PetscCall(DMLabelGetStratumIS(l1, v, &is1));
690:       PetscCall(ISEqualUnsorted(is0, is1, &eq));
691:       PetscCall(ISDestroy(&is0));
692:       PetscCall(ISDestroy(&is1));
693:       if (!eq) {
694:         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));
695:         break;
696:       }
697:     }
698:     PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
699:   }
700: finish:
701:   /* If message output arg not set, print to stderr */
702:   if (message) {
703:     *message = NULL;
704:     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
705:   } else {
706:     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
707:     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
708:   }
709:   /* If same output arg not ser and labels are not equal, throw error */
710:   if (equal) *equal = eq;
711:   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels l0 \"%s\" and l1 \"%s\" are not equal", name0, name1);
712:   PetscFunctionReturn(PETSC_SUCCESS);
713: }

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

718:   Not collective

720:   Input Parameter:
721: . label  - The DMLabel

723:   Level: intermediate

725: .seealso: `DMLabelHasPoint()`, `DMLabelCreateIndex()`, `DMLabelDestroyIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
726: @*/
727: PetscErrorCode DMLabelComputeIndex(DMLabel label)
728: {
729:   PetscInt pStart = PETSC_MAX_INT, pEnd = -1, v;

731:   PetscFunctionBegin;
733:   PetscCall(DMLabelMakeAllValid_Private(label));
734:   for (v = 0; v < label->numStrata; ++v) {
735:     const PetscInt *points;
736:     PetscInt        i;

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

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

753: /*@
754:   DMLabelCreateIndex - Create an index structure for membership determination

756:   Not collective

758:   Input Parameters:
759: + label  - The DMLabel
760: . pStart - The smallest point
761: - pEnd   - The largest point + 1

763:   Level: intermediate

765: .seealso: `DMLabelHasPoint()`, `DMLabelComputeIndex()`, `DMLabelDestroyIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
766: @*/
767: PetscErrorCode DMLabelCreateIndex(DMLabel label, PetscInt pStart, PetscInt pEnd)
768: {
769:   PetscInt v;

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

784:     PetscUseTypeMethod(label, getstratumis, v, &pointIS);
785:     PetscCall(ISGetIndices(pointIS, &points));
786:     for (i = 0; i < label->stratumSizes[v]; ++i) {
787:       const PetscInt point = points[i];

789:       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);
790:       PetscCall(PetscBTSet(label->bt, point - pStart));
791:     }
792:     PetscCall(ISRestoreIndices(label->points[v], &points));
793:     PetscCall(ISDestroy(&pointIS));
794:   }
795:   PetscFunctionReturn(PETSC_SUCCESS);
796: }

798: /*@
799:   DMLabelDestroyIndex - Destroy the index structure

801:   Not collective

803:   Input Parameter:
804: . label - the DMLabel

806:   Level: intermediate

808: .seealso: `DMLabelHasPoint()`, `DMLabelCreateIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
809: @*/
810: PetscErrorCode DMLabelDestroyIndex(DMLabel label)
811: {
812:   PetscFunctionBegin;
814:   label->pStart = -1;
815:   label->pEnd   = -1;
816:   PetscCall(PetscBTDestroy(&label->bt));
817:   PetscFunctionReturn(PETSC_SUCCESS);
818: }

820: /*@
821:   DMLabelGetBounds - Return the smallest and largest point in the label

823:   Not collective

825:   Input Parameter:
826: . label - the DMLabel

828:   Output Parameters:
829: + pStart - The smallest point
830: - pEnd   - The largest point + 1

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

834:   Level: intermediate

836: .seealso: `DMLabelHasPoint()`, `DMLabelCreateIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
837: @*/
838: PetscErrorCode DMLabelGetBounds(DMLabel label, PetscInt *pStart, PetscInt *pEnd)
839: {
840:   PetscFunctionBegin;
842:   if ((label->pStart == -1) && (label->pEnd == -1)) PetscCall(DMLabelComputeIndex(label));
843:   if (pStart) {
845:     *pStart = label->pStart;
846:   }
847:   if (pEnd) {
849:     *pEnd = label->pEnd;
850:   }
851:   PetscFunctionReturn(PETSC_SUCCESS);
852: }

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

857:   Not collective

859:   Input Parameters:
860: + label - the DMLabel
861: - value - the value

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

866:   Level: developer

868: .seealso: `DMLabelHasPoint()`, `DMLabelGetValue()`, `DMLabelSetValue()`
869: @*/
870: PetscErrorCode DMLabelHasValue(DMLabel label, PetscInt value, PetscBool *contains)
871: {
872:   PetscInt v;

874:   PetscFunctionBegin;
877:   PetscCall(DMLabelLookupStratum(label, value, &v));
878:   *contains = v < 0 ? PETSC_FALSE : PETSC_TRUE;
879:   PetscFunctionReturn(PETSC_SUCCESS);
880: }

882: /*@
883:   DMLabelHasPoint - Determine whether a label assigns a value to a point

885:   Not collective

887:   Input Parameters:
888: + label - the DMLabel
889: - point - the point

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

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

896:   Level: developer

898: .seealso: `DMLabelCreateIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
899: @*/
900: PetscErrorCode DMLabelHasPoint(DMLabel label, PetscInt point, PetscBool *contains)
901: {
902:   PetscFunctionBeginHot;
905:   PetscCall(DMLabelMakeAllValid_Private(label));
906:   if (PetscDefined(USE_DEBUG)) {
907:     PetscCheck(label->bt, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call DMLabelCreateIndex() before DMLabelHasPoint()");
908:     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);
909:   }
910:   *contains = PetscBTLookup(label->bt, point - label->pStart) ? PETSC_TRUE : PETSC_FALSE;
911:   PetscFunctionReturn(PETSC_SUCCESS);
912: }

914: /*@
915:   DMLabelStratumHasPoint - Return true if the stratum contains a point

917:   Not collective

919:   Input Parameters:
920: + label - the DMLabel
921: . value - the stratum value
922: - point - the point

924:   Output Parameter:
925: . contains - true if the stratum contains the point

927:   Level: intermediate

929: .seealso: `DMLabelCreate()`, `DMLabelSetValue()`, `DMLabelClearValue()`
930: @*/
931: PetscErrorCode DMLabelStratumHasPoint(DMLabel label, PetscInt value, PetscInt point, PetscBool *contains)
932: {
933:   PetscFunctionBeginHot;
936:   if (value == label->defaultValue) {
937:     PetscInt pointVal;

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

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

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

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

968:   Not collective

970:   Input parameter:
971: . label - a DMLabel object

973:   Output parameter:
974: . defaultValue - the default value

976:   Level: beginner

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

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

992:   Not collective

994:   Input parameter:
995: . label - a DMLabel object

997:   Output parameter:
998: . defaultValue - the default value

1000:   Level: beginner

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

1012: /*@
1013:   DMLabelGetValue - Return the value a label assigns to a point, or the label's default value (which is initially -1, and can be changed with DMLabelSetDefaultValue())

1015:   Not collective

1017:   Input Parameters:
1018: + label - the DMLabel
1019: - point - the point

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

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

1026:   Level: intermediate

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

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

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

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

1063: /*@
1064:   DMLabelSetValue - Set the value a label assigns to a point.  If the value is the same as the label's default value (which is initially -1, and can be changed with DMLabelSetDefaultValue() to something different), then this function will do nothing.

1066:   Not collective

1068:   Input Parameters:
1069: + label - the DMLabel
1070: . point - the point
1071: - value - The point value

1073:   Level: intermediate

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

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

1093: /*@
1094:   DMLabelClearValue - Clear the value a label assigns to a point

1096:   Not collective

1098:   Input Parameters:
1099: + label - the DMLabel
1100: . point - the point
1101: - value - The point value

1103:   Level: intermediate

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

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

1118:   if (label->bt) {
1119:     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);
1120:     PetscCall(PetscBTClear(label->bt, point - label->pStart));
1121:   }

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

1129: /*@
1130:   DMLabelInsertIS - Set all points in the IS to a value

1132:   Not collective

1134:   Input Parameters:
1135: + label - the DMLabel
1136: . is    - the point IS
1137: - value - The point value

1139:   Level: intermediate

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

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

1164: /*@
1165:   DMLabelGetNumValues - Get the number of values that the DMLabel takes

1167:   Not collective

1169:   Input Parameter:
1170: . label - the DMLabel

1172:   Output Parameter:
1173: . numValues - the number of values

1175:   Level: intermediate

1177: .seealso: `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1178: @*/
1179: PetscErrorCode DMLabelGetNumValues(DMLabel label, PetscInt *numValues)
1180: {
1181:   PetscFunctionBegin;
1184:   *numValues = label->numStrata;
1185:   PetscFunctionReturn(PETSC_SUCCESS);
1186: }

1188: /*@
1189:   DMLabelGetValueIS - Get an IS of all values that the DMlabel takes

1191:   Not collective

1193:   Input Parameter:
1194: . label - the DMLabel

1196:   Output Parameter:
1197: . is    - the value IS

1199:   Level: intermediate

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

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

1217: /*@
1218:   DMLabelGetNonEmptyStratumValuesIS - Get an IS of all values that the DMlabel takes

1220:   Not collective

1222:   Input Parameter:
1223: . label - the DMLabel

1225:   Output Parameter:
1226: . is    - the value IS

1228:   Level: intermediate

1230:   Notes:
1231:   The output IS should be destroyed when no longer needed.
1232:   This is similar to DMLabelGetValueIS() but counts only nonempty strata.

1234: .seealso: `DMLabelGetValueIS()`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1235: @*/
1236: PetscErrorCode DMLabelGetNonEmptyStratumValuesIS(DMLabel label, IS *values)
1237: {
1238:   PetscInt  i, j;
1239:   PetscInt *valuesArr;

1241:   PetscFunctionBegin;
1244:   PetscCall(PetscMalloc1(label->numStrata, &valuesArr));
1245:   for (i = 0, j = 0; i < label->numStrata; i++) {
1246:     PetscInt n;

1248:     PetscCall(DMLabelGetStratumSize_Private(label, i, &n));
1249:     if (n) valuesArr[j++] = label->stratumValues[i];
1250:   }
1251:   if (j == label->numStrata) {
1252:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, label->numStrata, label->stratumValues, PETSC_USE_POINTER, values));
1253:   } else {
1254:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, valuesArr, PETSC_COPY_VALUES, values));
1255:   }
1256:   PetscCall(PetscFree(valuesArr));
1257:   PetscFunctionReturn(PETSC_SUCCESS);
1258: }

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

1263:   Not collective

1265:   Input Parameters:
1266: + label - the DMLabel
1267: - value - the value

1269:   Output Parameter:
1270: . index - the index of value in the list of values

1272:   Level: intermediate

1274: .seealso: `DMLabelGetValueIS()`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1275: @*/
1276: PetscErrorCode DMLabelGetValueIndex(DMLabel label, PetscInt value, PetscInt *index)
1277: {
1278:   PetscInt v;

1280:   PetscFunctionBegin;
1283:   /* Do not assume they are sorted */
1284:   for (v = 0; v < label->numStrata; ++v)
1285:     if (label->stratumValues[v] == value) break;
1286:   if (v >= label->numStrata) *index = -1;
1287:   else *index = v;
1288:   PetscFunctionReturn(PETSC_SUCCESS);
1289: }

1291: /*@
1292:   DMLabelHasStratum - Determine whether points exist with the given value

1294:   Not collective

1296:   Input Parameters:
1297: + label - the DMLabel
1298: - value - the stratum value

1300:   Output Parameter:
1301: . exists - Flag saying whether points exist

1303:   Level: intermediate

1305: .seealso: `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1306: @*/
1307: PetscErrorCode DMLabelHasStratum(DMLabel label, PetscInt value, PetscBool *exists)
1308: {
1309:   PetscInt v;

1311:   PetscFunctionBegin;
1314:   PetscCall(DMLabelLookupStratum(label, value, &v));
1315:   *exists = v < 0 ? PETSC_FALSE : PETSC_TRUE;
1316:   PetscFunctionReturn(PETSC_SUCCESS);
1317: }

1319: /*@
1320:   DMLabelGetStratumSize - Get the size of a stratum

1322:   Not collective

1324:   Input Parameters:
1325: + label - the DMLabel
1326: - value - the stratum value

1328:   Output Parameter:
1329: . size - The number of points in the stratum

1331:   Level: intermediate

1333: .seealso: `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1334: @*/
1335: PetscErrorCode DMLabelGetStratumSize(DMLabel label, PetscInt value, PetscInt *size)
1336: {
1337:   PetscInt v;

1339:   PetscFunctionBegin;
1342:   PetscCall(DMLabelLookupStratum(label, value, &v));
1343:   PetscCall(DMLabelGetStratumSize_Private(label, v, size));
1344:   PetscFunctionReturn(PETSC_SUCCESS);
1345: }

1347: /*@
1348:   DMLabelGetStratumBounds - Get the largest and smallest point of a stratum

1350:   Not collective

1352:   Input Parameters:
1353: + label - the DMLabel
1354: - value - the stratum value

1356:   Output Parameters:
1357: + start - the smallest point in the stratum
1358: - end - the largest point in the stratum

1360:   Level: intermediate

1362: .seealso: `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1363: @*/
1364: PetscErrorCode DMLabelGetStratumBounds(DMLabel label, PetscInt value, PetscInt *start, PetscInt *end)
1365: {
1366:   IS       is;
1367:   PetscInt v, min, max;

1369:   PetscFunctionBegin;
1371:   if (start) {
1373:     *start = -1;
1374:   }
1375:   if (end) {
1377:     *end = -1;
1378:   }
1379:   PetscCall(DMLabelLookupStratum(label, value, &v));
1380:   if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1381:   PetscCall(DMLabelMakeValid_Private(label, v));
1382:   if (label->stratumSizes[v] <= 0) PetscFunctionReturn(PETSC_SUCCESS);
1383:   PetscUseTypeMethod(label, getstratumis, v, &is);
1384:   PetscCall(ISGetMinMax(is, &min, &max));
1385:   PetscCall(ISDestroy(&is));
1386:   if (start) *start = min;
1387:   if (end) *end = max + 1;
1388:   PetscFunctionReturn(PETSC_SUCCESS);
1389: }

1391: PetscErrorCode DMLabelGetStratumIS_Concrete(DMLabel label, PetscInt v, IS *pointIS)
1392: {
1393:   PetscFunctionBegin;
1394:   PetscCall(PetscObjectReference((PetscObject)label->points[v]));
1395:   *pointIS = label->points[v];
1396:   PetscFunctionReturn(PETSC_SUCCESS);
1397: }

1399: /*@
1400:   DMLabelGetStratumIS - Get an IS with the stratum points

1402:   Not collective

1404:   Input Parameters:
1405: + label - the DMLabel
1406: - value - the stratum value

1408:   Output Parameter:
1409: . points - The stratum points

1411:   Level: intermediate

1413:   Notes:
1414:   The output IS should be destroyed when no longer needed.
1415:   Returns NULL if the stratum is empty.

1417: .seealso: `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1418: @*/
1419: PetscErrorCode DMLabelGetStratumIS(DMLabel label, PetscInt value, IS *points)
1420: {
1421:   PetscInt v;

1423:   PetscFunctionBegin;
1426:   *points = NULL;
1427:   PetscCall(DMLabelLookupStratum(label, value, &v));
1428:   if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1429:   PetscCall(DMLabelMakeValid_Private(label, v));
1430:   PetscUseTypeMethod(label, getstratumis, v, points);
1431:   PetscFunctionReturn(PETSC_SUCCESS);
1432: }

1434: /*@
1435:   DMLabelSetStratumIS - Set the stratum points using an IS

1437:   Not collective

1439:   Input Parameters:
1440: + label - the DMLabel
1441: . value - the stratum value
1442: - points - The stratum points

1444:   Level: intermediate

1446: .seealso: `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1447: @*/
1448: PetscErrorCode DMLabelSetStratumIS(DMLabel label, PetscInt value, IS is)
1449: {
1450:   PetscInt v;

1452:   PetscFunctionBegin;
1455:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1456:   PetscCall(DMLabelLookupAddStratum(label, value, &v));
1457:   if (is == label->points[v]) PetscFunctionReturn(PETSC_SUCCESS);
1458:   PetscCall(DMLabelClearStratum(label, value));
1459:   PetscCall(ISGetLocalSize(is, &(label->stratumSizes[v])));
1460:   PetscCall(PetscObjectReference((PetscObject)is));
1461:   PetscCall(ISDestroy(&(label->points[v])));
1462:   label->points[v]  = is;
1463:   label->validIS[v] = PETSC_TRUE;
1464:   PetscCall(PetscObjectStateIncrease((PetscObject)label));
1465:   if (label->bt) {
1466:     const PetscInt *points;
1467:     PetscInt        p;

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

1473:       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);
1474:       PetscCall(PetscBTSet(label->bt, point - label->pStart));
1475:     }
1476:   }
1477:   PetscFunctionReturn(PETSC_SUCCESS);
1478: }

1480: /*@
1481:   DMLabelClearStratum - Remove a stratum

1483:   Not collective

1485:   Input Parameters:
1486: + label - the DMLabel
1487: - value - the stratum value

1489:   Level: intermediate

1491: .seealso: `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1492: @*/
1493: PetscErrorCode DMLabelClearStratum(DMLabel label, PetscInt value)
1494: {
1495:   PetscInt v;

1497:   PetscFunctionBegin;
1499:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1500:   PetscCall(DMLabelLookupStratum(label, value, &v));
1501:   if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1502:   if (label->validIS[v]) {
1503:     if (label->bt) {
1504:       PetscInt        i;
1505:       const PetscInt *points;

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

1511:         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);
1512:         PetscCall(PetscBTClear(label->bt, point - label->pStart));
1513:       }
1514:       PetscCall(ISRestoreIndices(label->points[v], &points));
1515:     }
1516:     label->stratumSizes[v] = 0;
1517:     PetscCall(ISDestroy(&label->points[v]));
1518:     PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, &label->points[v]));
1519:     PetscCall(PetscObjectSetName((PetscObject)label->points[v], "indices"));
1520:     PetscCall(PetscObjectStateIncrease((PetscObject)label));
1521:   } else {
1522:     PetscCall(PetscHSetIClear(label->ht[v]));
1523:   }
1524:   PetscFunctionReturn(PETSC_SUCCESS);
1525: }

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

1530:   Not collective

1532:   Input Parameters:
1533: + label  - The DMLabel
1534: . value  - The label value for all points
1535: . pStart - The first point
1536: - pEnd   - A point beyond all marked points

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

1540:   Level: intermediate

1542: .seealso: `DMLabelCreate()`, `DMLabelSetStratumIS()`, `DMLabelGetStratumIS()`
1543: @*/
1544: PetscErrorCode DMLabelSetStratumBounds(DMLabel label, PetscInt value, PetscInt pStart, PetscInt pEnd)
1545: {
1546:   IS pIS;

1548:   PetscFunctionBegin;
1549:   PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &pIS));
1550:   PetscCall(DMLabelSetStratumIS(label, value, pIS));
1551:   PetscCall(ISDestroy(&pIS));
1552:   PetscFunctionReturn(PETSC_SUCCESS);
1553: }

1555: /*@
1556:   DMLabelGetStratumPointIndex - Get the index of a point in a given stratum

1558:   Not collective

1560:   Input Parameters:
1561: + label  - The DMLabel
1562: . value  - The label value
1563: - p      - A point with this value

1565:   Output Parameter:
1566: . 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

1568:   Level: intermediate

1570: .seealso: `DMLabelGetValueIndex()`, `DMLabelGetStratumIS()`, `DMLabelCreate()`
1571: @*/
1572: PetscErrorCode DMLabelGetStratumPointIndex(DMLabel label, PetscInt value, PetscInt p, PetscInt *index)
1573: {
1574:   IS              pointIS;
1575:   const PetscInt *indices;
1576:   PetscInt        v;

1578:   PetscFunctionBegin;
1581:   *index = -1;
1582:   PetscCall(DMLabelLookupStratum(label, value, &v));
1583:   if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1584:   PetscCall(DMLabelMakeValid_Private(label, v));
1585:   PetscUseTypeMethod(label, getstratumis, v, &pointIS);
1586:   PetscCall(ISGetIndices(pointIS, &indices));
1587:   PetscCall(PetscFindInt(p, label->stratumSizes[v], indices, index));
1588:   PetscCall(ISRestoreIndices(pointIS, &indices));
1589:   PetscCall(ISDestroy(&pointIS));
1590:   PetscFunctionReturn(PETSC_SUCCESS);
1591: }

1593: /*@
1594:   DMLabelFilter - Remove all points outside of [start, end)

1596:   Not collective

1598:   Input Parameters:
1599: + label - the DMLabel
1600: . start - the first point kept
1601: - end - one more than the last point kept

1603:   Level: intermediate

1605: .seealso: `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1606: @*/
1607: PetscErrorCode DMLabelFilter(DMLabel label, PetscInt start, PetscInt end)
1608: {
1609:   PetscInt v;

1611:   PetscFunctionBegin;
1613:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1614:   PetscCall(DMLabelDestroyIndex(label));
1615:   PetscCall(DMLabelMakeAllValid_Private(label));
1616:   for (v = 0; v < label->numStrata; ++v) {
1617:     PetscCall(ISGeneralFilter(label->points[v], start, end));
1618:     PetscCall(ISGetLocalSize(label->points[v], &label->stratumSizes[v]));
1619:   }
1620:   PetscCall(DMLabelCreateIndex(label, start, end));
1621:   PetscFunctionReturn(PETSC_SUCCESS);
1622: }

1624: /*@
1625:   DMLabelPermute - Create a new label with permuted points

1627:   Not collective

1629:   Input Parameters:
1630: + label - the DMLabel
1631: - permutation - the point permutation

1633:   Output Parameter:
1634: . labelnew - the new label containing the permuted points

1636:   Level: intermediate

1638: .seealso: `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1639: @*/
1640: PetscErrorCode DMLabelPermute(DMLabel label, IS permutation, DMLabel *labelNew)
1641: {
1642:   const PetscInt *perm;
1643:   PetscInt        numValues, numPoints, v, q;

1645:   PetscFunctionBegin;
1648:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1649:   PetscCall(DMLabelMakeAllValid_Private(label));
1650:   PetscCall(DMLabelDuplicate(label, labelNew));
1651:   PetscCall(DMLabelGetNumValues(*labelNew, &numValues));
1652:   PetscCall(ISGetLocalSize(permutation, &numPoints));
1653:   PetscCall(ISGetIndices(permutation, &perm));
1654:   for (v = 0; v < numValues; ++v) {
1655:     const PetscInt  size = (*labelNew)->stratumSizes[v];
1656:     const PetscInt *points;
1657:     PetscInt       *pointsNew;

1659:     PetscCall(ISGetIndices((*labelNew)->points[v], &points));
1660:     PetscCall(PetscCalloc1(size, &pointsNew));
1661:     for (q = 0; q < size; ++q) {
1662:       const PetscInt point = points[q];

1664:       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);
1665:       pointsNew[q] = perm[point];
1666:     }
1667:     PetscCall(ISRestoreIndices((*labelNew)->points[v], &points));
1668:     PetscCall(PetscSortInt(size, pointsNew));
1669:     PetscCall(ISDestroy(&((*labelNew)->points[v])));
1670:     if (size > 0 && pointsNew[size - 1] == pointsNew[0] + size - 1) {
1671:       PetscCall(ISCreateStride(PETSC_COMM_SELF, size, pointsNew[0], 1, &((*labelNew)->points[v])));
1672:       PetscCall(PetscFree(pointsNew));
1673:     } else {
1674:       PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, pointsNew, PETSC_OWN_POINTER, &((*labelNew)->points[v])));
1675:     }
1676:     PetscCall(PetscObjectSetName((PetscObject)((*labelNew)->points[v]), "indices"));
1677:   }
1678:   PetscCall(ISRestoreIndices(permutation, &perm));
1679:   if (label->bt) {
1680:     PetscCall(PetscBTDestroy(&label->bt));
1681:     PetscCall(DMLabelCreateIndex(label, label->pStart, label->pEnd));
1682:   }
1683:   PetscFunctionReturn(PETSC_SUCCESS);
1684: }

1686: PetscErrorCode DMLabelDistribute_Internal(DMLabel label, PetscSF sf, PetscSection *leafSection, PetscInt **leafStrata)
1687: {
1688:   MPI_Comm     comm;
1689:   PetscInt     s, l, nroots, nleaves, offset, size;
1690:   PetscInt    *remoteOffsets, *rootStrata, *rootIdx;
1691:   PetscSection rootSection;
1692:   PetscSF      labelSF;

1694:   PetscFunctionBegin;
1695:   if (label) PetscCall(DMLabelMakeAllValid_Private(label));
1696:   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
1697:   /* Build a section of stratum values per point, generate the according SF
1698:      and distribute point-wise stratum values to leaves. */
1699:   PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, NULL, NULL));
1700:   PetscCall(PetscSectionCreate(comm, &rootSection));
1701:   PetscCall(PetscSectionSetChart(rootSection, 0, nroots));
1702:   if (label) {
1703:     for (s = 0; s < label->numStrata; ++s) {
1704:       const PetscInt *points;

1706:       PetscCall(ISGetIndices(label->points[s], &points));
1707:       for (l = 0; l < label->stratumSizes[s]; l++) PetscCall(PetscSectionAddDof(rootSection, points[l], 1));
1708:       PetscCall(ISRestoreIndices(label->points[s], &points));
1709:     }
1710:   }
1711:   PetscCall(PetscSectionSetUp(rootSection));
1712:   /* Create a point-wise array of stratum values */
1713:   PetscCall(PetscSectionGetStorageSize(rootSection, &size));
1714:   PetscCall(PetscMalloc1(size, &rootStrata));
1715:   PetscCall(PetscCalloc1(nroots, &rootIdx));
1716:   if (label) {
1717:     for (s = 0; s < label->numStrata; ++s) {
1718:       const PetscInt *points;

1720:       PetscCall(ISGetIndices(label->points[s], &points));
1721:       for (l = 0; l < label->stratumSizes[s]; l++) {
1722:         const PetscInt p = points[l];
1723:         PetscCall(PetscSectionGetOffset(rootSection, p, &offset));
1724:         rootStrata[offset + rootIdx[p]++] = label->stratumValues[s];
1725:       }
1726:       PetscCall(ISRestoreIndices(label->points[s], &points));
1727:     }
1728:   }
1729:   /* Build SF that maps label points to remote processes */
1730:   PetscCall(PetscSectionCreate(comm, leafSection));
1731:   PetscCall(PetscSFDistributeSection(sf, rootSection, &remoteOffsets, *leafSection));
1732:   PetscCall(PetscSFCreateSectionSF(sf, rootSection, remoteOffsets, *leafSection, &labelSF));
1733:   PetscCall(PetscFree(remoteOffsets));
1734:   /* Send the strata for each point over the derived SF */
1735:   PetscCall(PetscSectionGetStorageSize(*leafSection, &size));
1736:   PetscCall(PetscMalloc1(size, leafStrata));
1737:   PetscCall(PetscSFBcastBegin(labelSF, MPIU_INT, rootStrata, *leafStrata, MPI_REPLACE));
1738:   PetscCall(PetscSFBcastEnd(labelSF, MPIU_INT, rootStrata, *leafStrata, MPI_REPLACE));
1739:   /* Clean up */
1740:   PetscCall(PetscFree(rootStrata));
1741:   PetscCall(PetscFree(rootIdx));
1742:   PetscCall(PetscSectionDestroy(&rootSection));
1743:   PetscCall(PetscSFDestroy(&labelSF));
1744:   PetscFunctionReturn(PETSC_SUCCESS);
1745: }

1747: /*@
1748:   DMLabelDistribute - Create a new label pushed forward over the PetscSF

1750:   Collective on sf

1752:   Input Parameters:
1753: + label - the DMLabel
1754: - sf    - the map from old to new distribution

1756:   Output Parameter:
1757: . labelnew - the new redistributed label

1759:   Level: intermediate

1761: .seealso: `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1762: @*/
1763: PetscErrorCode DMLabelDistribute(DMLabel label, PetscSF sf, DMLabel *labelNew)
1764: {
1765:   MPI_Comm     comm;
1766:   PetscSection leafSection;
1767:   PetscInt     p, pStart, pEnd, s, size, dof, offset, stratum;
1768:   PetscInt    *leafStrata, *strataIdx;
1769:   PetscInt   **points;
1770:   const char  *lname = NULL;
1771:   char        *name;
1772:   PetscInt     nameSize;
1773:   PetscHSetI   stratumHash;
1774:   size_t       len = 0;
1775:   PetscMPIInt  rank;

1777:   PetscFunctionBegin;
1779:   if (label) {
1781:     PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1782:     PetscCall(DMLabelMakeAllValid_Private(label));
1783:   }
1784:   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
1785:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1786:   /* Bcast name */
1787:   if (rank == 0) {
1788:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
1789:     PetscCall(PetscStrlen(lname, &len));
1790:   }
1791:   nameSize = len;
1792:   PetscCallMPI(MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm));
1793:   PetscCall(PetscMalloc1(nameSize + 1, &name));
1794:   if (rank == 0) PetscCall(PetscArraycpy(name, lname, nameSize + 1));
1795:   PetscCallMPI(MPI_Bcast(name, nameSize + 1, MPI_CHAR, 0, comm));
1796:   PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, labelNew));
1797:   PetscCall(PetscFree(name));
1798:   /* Bcast defaultValue */
1799:   if (rank == 0) (*labelNew)->defaultValue = label->defaultValue;
1800:   PetscCallMPI(MPI_Bcast(&(*labelNew)->defaultValue, 1, MPIU_INT, 0, comm));
1801:   /* Distribute stratum values over the SF and get the point mapping on the receiver */
1802:   PetscCall(DMLabelDistribute_Internal(label, sf, &leafSection, &leafStrata));
1803:   /* Determine received stratum values and initialise new label*/
1804:   PetscCall(PetscHSetICreate(&stratumHash));
1805:   PetscCall(PetscSectionGetStorageSize(leafSection, &size));
1806:   for (p = 0; p < size; ++p) PetscCall(PetscHSetIAdd(stratumHash, leafStrata[p]));
1807:   PetscCall(PetscHSetIGetSize(stratumHash, &(*labelNew)->numStrata));
1808:   PetscCall(PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->validIS));
1809:   for (s = 0; s < (*labelNew)->numStrata; ++s) (*labelNew)->validIS[s] = PETSC_TRUE;
1810:   PetscCall(PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->stratumValues));
1811:   /* Turn leafStrata into indices rather than stratum values */
1812:   offset = 0;
1813:   PetscCall(PetscHSetIGetElems(stratumHash, &offset, (*labelNew)->stratumValues));
1814:   PetscCall(PetscSortInt((*labelNew)->numStrata, (*labelNew)->stratumValues));
1815:   for (s = 0; s < (*labelNew)->numStrata; ++s) PetscCall(PetscHMapISet((*labelNew)->hmap, (*labelNew)->stratumValues[s], s));
1816:   for (p = 0; p < size; ++p) {
1817:     for (s = 0; s < (*labelNew)->numStrata; ++s) {
1818:       if (leafStrata[p] == (*labelNew)->stratumValues[s]) {
1819:         leafStrata[p] = s;
1820:         break;
1821:       }
1822:     }
1823:   }
1824:   /* Rebuild the point strata on the receiver */
1825:   PetscCall(PetscCalloc1((*labelNew)->numStrata, &(*labelNew)->stratumSizes));
1826:   PetscCall(PetscSectionGetChart(leafSection, &pStart, &pEnd));
1827:   for (p = pStart; p < pEnd; p++) {
1828:     PetscCall(PetscSectionGetDof(leafSection, p, &dof));
1829:     PetscCall(PetscSectionGetOffset(leafSection, p, &offset));
1830:     for (s = 0; s < dof; s++) (*labelNew)->stratumSizes[leafStrata[offset + s]]++;
1831:   }
1832:   PetscCall(PetscCalloc1((*labelNew)->numStrata, &(*labelNew)->ht));
1833:   PetscCall(PetscCalloc1((*labelNew)->numStrata, &(*labelNew)->points));
1834:   PetscCall(PetscCalloc1((*labelNew)->numStrata, &points));
1835:   for (s = 0; s < (*labelNew)->numStrata; ++s) {
1836:     PetscCall(PetscHSetICreate(&(*labelNew)->ht[s]));
1837:     PetscCall(PetscMalloc1((*labelNew)->stratumSizes[s], &(points[s])));
1838:   }
1839:   /* Insert points into new strata */
1840:   PetscCall(PetscCalloc1((*labelNew)->numStrata, &strataIdx));
1841:   PetscCall(PetscSectionGetChart(leafSection, &pStart, &pEnd));
1842:   for (p = pStart; p < pEnd; p++) {
1843:     PetscCall(PetscSectionGetDof(leafSection, p, &dof));
1844:     PetscCall(PetscSectionGetOffset(leafSection, p, &offset));
1845:     for (s = 0; s < dof; s++) {
1846:       stratum                               = leafStrata[offset + s];
1847:       points[stratum][strataIdx[stratum]++] = p;
1848:     }
1849:   }
1850:   for (s = 0; s < (*labelNew)->numStrata; s++) {
1851:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, (*labelNew)->stratumSizes[s], &(points[s][0]), PETSC_OWN_POINTER, &((*labelNew)->points[s])));
1852:     PetscCall(PetscObjectSetName((PetscObject)((*labelNew)->points[s]), "indices"));
1853:   }
1854:   PetscCall(PetscFree(points));
1855:   PetscCall(PetscHSetIDestroy(&stratumHash));
1856:   PetscCall(PetscFree(leafStrata));
1857:   PetscCall(PetscFree(strataIdx));
1858:   PetscCall(PetscSectionDestroy(&leafSection));
1859:   PetscFunctionReturn(PETSC_SUCCESS);
1860: }

1862: /*@
1863:   DMLabelGather - Gather all label values from leafs into roots

1865:   Collective on sf

1867:   Input Parameters:
1868: + label - the DMLabel
1869: - sf - the Star Forest point communication map

1871:   Output Parameters:
1872: . labelNew - the new DMLabel with localised leaf values

1874:   Level: developer

1876:   Note: This is the inverse operation to DMLabelDistribute.

1878: .seealso: `DMLabelDistribute()`
1879: @*/
1880: PetscErrorCode DMLabelGather(DMLabel label, PetscSF sf, DMLabel *labelNew)
1881: {
1882:   MPI_Comm        comm;
1883:   PetscSection    rootSection;
1884:   PetscSF         sfLabel;
1885:   PetscSFNode    *rootPoints, *leafPoints;
1886:   PetscInt        p, s, d, nroots, nleaves, nmultiroots, idx, dof, offset;
1887:   const PetscInt *rootDegree, *ilocal;
1888:   PetscInt       *rootStrata;
1889:   const char     *lname;
1890:   char           *name;
1891:   PetscInt        nameSize;
1892:   size_t          len = 0;
1893:   PetscMPIInt     rank, size;

1895:   PetscFunctionBegin;
1898:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1899:   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
1900:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1901:   PetscCallMPI(MPI_Comm_size(comm, &size));
1902:   /* Bcast name */
1903:   if (rank == 0) {
1904:     PetscCall(PetscObjectGetName((PetscObject)label, &lname));
1905:     PetscCall(PetscStrlen(lname, &len));
1906:   }
1907:   nameSize = len;
1908:   PetscCallMPI(MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm));
1909:   PetscCall(PetscMalloc1(nameSize + 1, &name));
1910:   if (rank == 0) PetscCall(PetscArraycpy(name, lname, nameSize + 1));
1911:   PetscCallMPI(MPI_Bcast(name, nameSize + 1, MPI_CHAR, 0, comm));
1912:   PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, labelNew));
1913:   PetscCall(PetscFree(name));
1914:   /* Gather rank/index pairs of leaves into local roots to build
1915:      an inverse, multi-rooted SF. Note that this ignores local leaf
1916:      indexing due to the use of the multiSF in PetscSFGather. */
1917:   PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, NULL));
1918:   PetscCall(PetscMalloc1(nroots, &leafPoints));
1919:   for (p = 0; p < nroots; ++p) leafPoints[p].rank = leafPoints[p].index = -1;
1920:   for (p = 0; p < nleaves; p++) {
1921:     PetscInt ilp = ilocal ? ilocal[p] : p;

1923:     leafPoints[ilp].index = ilp;
1924:     leafPoints[ilp].rank  = rank;
1925:   }
1926:   PetscCall(PetscSFComputeDegreeBegin(sf, &rootDegree));
1927:   PetscCall(PetscSFComputeDegreeEnd(sf, &rootDegree));
1928:   for (p = 0, nmultiroots = 0; p < nroots; ++p) nmultiroots += rootDegree[p];
1929:   PetscCall(PetscMalloc1(nmultiroots, &rootPoints));
1930:   PetscCall(PetscSFGatherBegin(sf, MPIU_2INT, leafPoints, rootPoints));
1931:   PetscCall(PetscSFGatherEnd(sf, MPIU_2INT, leafPoints, rootPoints));
1932:   PetscCall(PetscSFCreate(comm, &sfLabel));
1933:   PetscCall(PetscSFSetGraph(sfLabel, nroots, nmultiroots, NULL, PETSC_OWN_POINTER, rootPoints, PETSC_OWN_POINTER));
1934:   /* Migrate label over inverted SF to pull stratum values at leaves into roots. */
1935:   PetscCall(DMLabelDistribute_Internal(label, sfLabel, &rootSection, &rootStrata));
1936:   /* Rebuild the point strata on the receiver */
1937:   for (p = 0, idx = 0; p < nroots; p++) {
1938:     for (d = 0; d < rootDegree[p]; d++) {
1939:       PetscCall(PetscSectionGetDof(rootSection, idx + d, &dof));
1940:       PetscCall(PetscSectionGetOffset(rootSection, idx + d, &offset));
1941:       for (s = 0; s < dof; s++) PetscCall(DMLabelSetValue(*labelNew, p, rootStrata[offset + s]));
1942:     }
1943:     idx += rootDegree[p];
1944:   }
1945:   PetscCall(PetscFree(leafPoints));
1946:   PetscCall(PetscFree(rootStrata));
1947:   PetscCall(PetscSectionDestroy(&rootSection));
1948:   PetscCall(PetscSFDestroy(&sfLabel));
1949:   PetscFunctionReturn(PETSC_SUCCESS);
1950: }

1952: static PetscErrorCode DMLabelPropagateInit_Internal(DMLabel label, PetscSF pointSF, PetscInt valArray[])
1953: {
1954:   const PetscInt *degree;
1955:   const PetscInt *points;
1956:   PetscInt        Nr, r, Nl, l, val, defVal;

1958:   PetscFunctionBegin;
1959:   PetscCall(DMLabelGetDefaultValue(label, &defVal));
1960:   /* Add in leaves */
1961:   PetscCall(PetscSFGetGraph(pointSF, &Nr, &Nl, &points, NULL));
1962:   for (l = 0; l < Nl; ++l) {
1963:     PetscCall(DMLabelGetValue(label, points[l], &val));
1964:     if (val != defVal) valArray[points[l]] = val;
1965:   }
1966:   /* Add in shared roots */
1967:   PetscCall(PetscSFComputeDegreeBegin(pointSF, &degree));
1968:   PetscCall(PetscSFComputeDegreeEnd(pointSF, &degree));
1969:   for (r = 0; r < Nr; ++r) {
1970:     if (degree[r]) {
1971:       PetscCall(DMLabelGetValue(label, r, &val));
1972:       if (val != defVal) valArray[r] = val;
1973:     }
1974:   }
1975:   PetscFunctionReturn(PETSC_SUCCESS);
1976: }

1978: static PetscErrorCode DMLabelPropagateFini_Internal(DMLabel label, PetscSF pointSF, PetscInt valArray[], PetscErrorCode (*markPoint)(DMLabel, PetscInt, PetscInt, void *), void *ctx)
1979: {
1980:   const PetscInt *degree;
1981:   const PetscInt *points;
1982:   PetscInt        Nr, r, Nl, l, val, defVal;

1984:   PetscFunctionBegin;
1985:   PetscCall(DMLabelGetDefaultValue(label, &defVal));
1986:   /* Read out leaves */
1987:   PetscCall(PetscSFGetGraph(pointSF, &Nr, &Nl, &points, NULL));
1988:   for (l = 0; l < Nl; ++l) {
1989:     const PetscInt p    = points[l];
1990:     const PetscInt cval = valArray[p];

1992:     if (cval != defVal) {
1993:       PetscCall(DMLabelGetValue(label, p, &val));
1994:       if (val == defVal) {
1995:         PetscCall(DMLabelSetValue(label, p, cval));
1996:         if (markPoint) PetscCall((*markPoint)(label, p, cval, ctx));
1997:       }
1998:     }
1999:   }
2000:   /* Read out shared roots */
2001:   PetscCall(PetscSFComputeDegreeBegin(pointSF, &degree));
2002:   PetscCall(PetscSFComputeDegreeEnd(pointSF, &degree));
2003:   for (r = 0; r < Nr; ++r) {
2004:     if (degree[r]) {
2005:       const PetscInt cval = valArray[r];

2007:       if (cval != defVal) {
2008:         PetscCall(DMLabelGetValue(label, r, &val));
2009:         if (val == defVal) {
2010:           PetscCall(DMLabelSetValue(label, r, cval));
2011:           if (markPoint) PetscCall((*markPoint)(label, r, cval, ctx));
2012:         }
2013:       }
2014:     }
2015:   }
2016:   PetscFunctionReturn(PETSC_SUCCESS);
2017: }

2019: /*@
2020:   DMLabelPropagateBegin - Setup a cycle of label propagation

2022:   Collective on sf

2024:   Input Parameters:
2025: + label - The DMLabel to propagate across processes
2026: - sf    - The SF describing parallel layout of the label points

2028:   Level: intermediate

2030: .seealso: `DMLabelPropagateEnd()`, `DMLabelPropagatePush()`
2031: @*/
2032: PetscErrorCode DMLabelPropagateBegin(DMLabel label, PetscSF sf)
2033: {
2034:   PetscInt    Nr, r, defVal;
2035:   PetscMPIInt size;

2037:   PetscFunctionBegin;
2038:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
2039:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)sf), &size));
2040:   if (size > 1) {
2041:     PetscCall(DMLabelGetDefaultValue(label, &defVal));
2042:     PetscCall(PetscSFGetGraph(sf, &Nr, NULL, NULL, NULL));
2043:     if (Nr >= 0) PetscCall(PetscMalloc1(Nr, &label->propArray));
2044:     for (r = 0; r < Nr; ++r) label->propArray[r] = defVal;
2045:   }
2046:   PetscFunctionReturn(PETSC_SUCCESS);
2047: }

2049: /*@
2050:   DMLabelPropagateEnd - Tear down a cycle of label propagation

2052:   Collective on sf

2054:   Input Parameters:
2055: + label - The DMLabel to propagate across processes
2056: - sf    - The SF describing parallel layout of the label points

2058:   Level: intermediate

2060: .seealso: `DMLabelPropagateBegin()`, `DMLabelPropagatePush()`
2061: @*/
2062: PetscErrorCode DMLabelPropagateEnd(DMLabel label, PetscSF pointSF)
2063: {
2064:   PetscFunctionBegin;
2065:   PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
2066:   PetscCall(PetscFree(label->propArray));
2067:   label->propArray = NULL;
2068:   PetscFunctionReturn(PETSC_SUCCESS);
2069: }

2071: /*@C
2072:   DMLabelPropagatePush - Tear down a cycle of label propagation

2074:   Collective on sf

2076:   Input Parameters:
2077: + label     - The DMLabel to propagate across processes
2078: . sf        - The SF describing parallel layout of the label points
2079: . markPoint - An optional callback that is called when a point is marked, or NULL
2080: - ctx       - An optional user context for the callback, or NULL

2082:   Calling sequence of markPoint:
2083: $ markPoint(DMLabel label, PetscInt p, PetscInt val, void *ctx);

2085: + label - The DMLabel
2086: . p     - The point being marked
2087: . val   - The label value for p
2088: - ctx   - An optional user context

2090:   Level: intermediate

2092: .seealso: `DMLabelPropagateBegin()`, `DMLabelPropagateEnd()`
2093: @*/
2094: PetscErrorCode DMLabelPropagatePush(DMLabel label, PetscSF pointSF, PetscErrorCode (*markPoint)(DMLabel, PetscInt, PetscInt, void *), void *ctx)
2095: {
2096:   PetscInt   *valArray = label->propArray, Nr;
2097:   PetscMPIInt size;

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

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

2112:        In order to update the queue with the new edges from the label communication, we use BcastAnOp(MPI_SUM), so that new
2113:        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
2114:        edge to the queue.
2115:     */
2116:     PetscCall(DMLabelPropagateInit_Internal(label, pointSF, valArray));
2117:     PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, valArray, valArray, MPI_MAX));
2118:     PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, valArray, valArray, MPI_MAX));
2119:     PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, valArray, valArray, MPI_REPLACE));
2120:     PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, valArray, valArray, MPI_REPLACE));
2121:     PetscCall(DMLabelPropagateFini_Internal(label, pointSF, valArray, markPoint, ctx));
2122:   }
2123:   PetscFunctionReturn(PETSC_SUCCESS);
2124: }

2126: /*@
2127:   DMLabelConvertToSection - Make a PetscSection/IS pair that encodes the label

2129:   Not collective

2131:   Input Parameter:
2132: . label - the DMLabel

2134:   Output Parameters:
2135: + section - the section giving offsets for each stratum
2136: - is - An IS containing all the label points

2138:   Level: developer

2140: .seealso: `DMLabelDistribute()`
2141: @*/
2142: PetscErrorCode DMLabelConvertToSection(DMLabel label, PetscSection *section, IS *is)
2143: {
2144:   IS              vIS;
2145:   const PetscInt *values;
2146:   PetscInt       *points;
2147:   PetscInt        nV, vS = 0, vE = 0, v, N;

2149:   PetscFunctionBegin;
2151:   PetscCall(DMLabelGetNumValues(label, &nV));
2152:   PetscCall(DMLabelGetValueIS(label, &vIS));
2153:   PetscCall(ISGetIndices(vIS, &values));
2154:   if (nV) {
2155:     vS = values[0];
2156:     vE = values[0] + 1;
2157:   }
2158:   for (v = 1; v < nV; ++v) {
2159:     vS = PetscMin(vS, values[v]);
2160:     vE = PetscMax(vE, values[v] + 1);
2161:   }
2162:   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, section));
2163:   PetscCall(PetscSectionSetChart(*section, vS, vE));
2164:   for (v = 0; v < nV; ++v) {
2165:     PetscInt n;

2167:     PetscCall(DMLabelGetStratumSize(label, values[v], &n));
2168:     PetscCall(PetscSectionSetDof(*section, values[v], n));
2169:   }
2170:   PetscCall(PetscSectionSetUp(*section));
2171:   PetscCall(PetscSectionGetStorageSize(*section, &N));
2172:   PetscCall(PetscMalloc1(N, &points));
2173:   for (v = 0; v < nV; ++v) {
2174:     IS              is;
2175:     const PetscInt *spoints;
2176:     PetscInt        dof, off, p;

2178:     PetscCall(PetscSectionGetDof(*section, values[v], &dof));
2179:     PetscCall(PetscSectionGetOffset(*section, values[v], &off));
2180:     PetscCall(DMLabelGetStratumIS(label, values[v], &is));
2181:     PetscCall(ISGetIndices(is, &spoints));
2182:     for (p = 0; p < dof; ++p) points[off + p] = spoints[p];
2183:     PetscCall(ISRestoreIndices(is, &spoints));
2184:     PetscCall(ISDestroy(&is));
2185:   }
2186:   PetscCall(ISRestoreIndices(vIS, &values));
2187:   PetscCall(ISDestroy(&vIS));
2188:   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, N, points, PETSC_OWN_POINTER, is));
2189:   PetscFunctionReturn(PETSC_SUCCESS);
2190: }

2192: /*@C
2193:   DMLabelRegister - Adds a new label component implementation

2195:   Not Collective

2197:   Input Parameters:
2198: + name        - The name of a new user-defined creation routine
2199: - create_func - The creation routine itself

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

2204:   Sample usage:
2205: .vb
2206:   DMLabelRegister("my_label", MyLabelCreate);
2207: .ve

2209:   Then, your label type can be chosen with the procedural interface via
2210: .vb
2211:   DMLabelCreate(MPI_Comm, DMLabel *);
2212:   DMLabelSetType(DMLabel, "my_label");
2213: .ve
2214:   or at runtime via the option
2215: .vb
2216:   -dm_label_type my_label
2217: .ve

2219:   Level: advanced

2221: .seealso: `DMLabel`, `DMLabelType`, `DMLabelRegisterAll()`, `DMLabelRegisterDestroy()`
2222: @*/
2223: PetscErrorCode DMLabelRegister(const char name[], PetscErrorCode (*create_func)(DMLabel))
2224: {
2225:   PetscFunctionBegin;
2226:   PetscCall(DMInitializePackage());
2227:   PetscCall(PetscFunctionListAdd(&DMLabelList, name, create_func));
2228:   PetscFunctionReturn(PETSC_SUCCESS);
2229: }

2231: PETSC_EXTERN PetscErrorCode DMLabelCreate_Concrete(DMLabel);
2232: PETSC_EXTERN PetscErrorCode DMLabelCreate_Ephemeral(DMLabel);

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

2237:   Not Collective

2239:   Level: advanced

2241: .seealso: `DMRegisterAll()`, `DMLabelRegisterDestroy()`
2242: @*/
2243: PetscErrorCode DMLabelRegisterAll(void)
2244: {
2245:   PetscFunctionBegin;
2246:   if (DMLabelRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
2247:   DMLabelRegisterAllCalled = PETSC_TRUE;

2249:   PetscCall(DMLabelRegister(DMLABELCONCRETE, DMLabelCreate_Concrete));
2250:   PetscCall(DMLabelRegister(DMLABELEPHEMERAL, DMLabelCreate_Ephemeral));
2251:   PetscFunctionReturn(PETSC_SUCCESS);
2252: }

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

2257:   Level: developer

2259: .seealso: `PetscInitialize()`
2260: @*/
2261: PetscErrorCode DMLabelRegisterDestroy(void)
2262: {
2263:   PetscFunctionBegin;
2264:   PetscCall(PetscFunctionListDestroy(&DMLabelList));
2265:   DMLabelRegisterAllCalled = PETSC_FALSE;
2266:   PetscFunctionReturn(PETSC_SUCCESS);
2267: }

2269: /*@C
2270:   DMLabelSetType - Sets the particular implementation for a label.

2272:   Collective on tr

2274:   Input Parameters:
2275: + label  - The label
2276: - method - The name of the label type

2278:   Options Database Key:
2279: . -dm_label_type <type> - Sets the label type; use -help for a list of available types

2281:   Notes:
2282:   See "petsc/include/petscdmlabel.h" for available label types

2284:   Level: intermediate

2286: .seealso: `DMLabelGetType()`, `DMLabelCreate()`
2287: @*/
2288: PetscErrorCode DMLabelSetType(DMLabel label, DMLabelType method)
2289: {
2290:   PetscErrorCode (*r)(DMLabel);
2291:   PetscBool match;

2293:   PetscFunctionBegin;
2295:   PetscCall(PetscObjectTypeCompare((PetscObject)label, method, &match));
2296:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

2298:   PetscCall(DMLabelRegisterAll());
2299:   PetscCall(PetscFunctionListFind(DMLabelList, method, &r));
2300:   PetscCheck(r, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DMLabel type: %s", method);

2302:   PetscTryTypeMethod(label, destroy);
2303:   PetscCall(PetscMemzero(label->ops, sizeof(*label->ops)));
2304:   PetscCall(PetscObjectChangeTypeName((PetscObject)label, method));
2305:   PetscCall((*r)(label));
2306:   PetscFunctionReturn(PETSC_SUCCESS);
2307: }

2309: /*@C
2310:   DMLabelGetType - Gets the type name (as a string) from the label.

2312:   Not Collective

2314:   Input Parameter:
2315: . label  - The DMLabel

2317:   Output Parameter:
2318: . type - The DMLabel type name

2320:   Level: intermediate

2322: .seealso: `DMLabelSetType()`, `DMLabelCreate()`
2323: @*/
2324: PetscErrorCode DMLabelGetType(DMLabel label, DMLabelType *type)
2325: {
2326:   PetscFunctionBegin;
2329:   PetscCall(DMLabelRegisterAll());
2330:   *type = ((PetscObject)label)->type_name;
2331:   PetscFunctionReturn(PETSC_SUCCESS);
2332: }

2334: static PetscErrorCode DMLabelInitialize_Concrete(DMLabel label)
2335: {
2336:   PetscFunctionBegin;
2337:   label->ops->view         = DMLabelView_Concrete;
2338:   label->ops->setup        = NULL;
2339:   label->ops->duplicate    = DMLabelDuplicate_Concrete;
2340:   label->ops->getstratumis = DMLabelGetStratumIS_Concrete;
2341:   PetscFunctionReturn(PETSC_SUCCESS);
2342: }

2344: PETSC_EXTERN PetscErrorCode DMLabelCreate_Concrete(DMLabel label)
2345: {
2346:   PetscFunctionBegin;
2348:   PetscCall(DMLabelInitialize_Concrete(label));
2349:   PetscFunctionReturn(PETSC_SUCCESS);
2350: }

2352: /*@
2353:   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
2354:   the local section and an SF describing the section point overlap.

2356:   Collective on sf

2358:   Input Parameters:
2359: + s - The PetscSection for the local field layout
2360: . sf - The SF describing parallel layout of the section points
2361: . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
2362: . label - The label specifying the points
2363: - labelValue - The label stratum specifying the points

2365:   Output Parameter:
2366: . gsection - The PetscSection for the global field layout

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

2370:   Level: developer

2372: .seealso: `PetscSectionCreate()`
2373: @*/
2374: PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
2375: {
2376:   PetscInt *neg = NULL, *tmpOff = NULL;
2377:   PetscInt  pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;

2379:   PetscFunctionBegin;
2383:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), gsection));
2384:   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2385:   PetscCall(PetscSectionSetChart(*gsection, pStart, pEnd));
2386:   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
2387:   if (nroots >= 0) {
2388:     PetscCheck(nroots >= pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %" PetscInt_FMT " < %" PetscInt_FMT " section size", nroots, pEnd - pStart);
2389:     PetscCall(PetscCalloc1(nroots, &neg));
2390:     if (nroots > pEnd - pStart) {
2391:       PetscCall(PetscCalloc1(nroots, &tmpOff));
2392:     } else {
2393:       tmpOff = &(*gsection)->atlasDof[-pStart];
2394:     }
2395:   }
2396:   /* Mark ghost points with negative dof */
2397:   for (p = pStart; p < pEnd; ++p) {
2398:     PetscInt value;

2400:     PetscCall(DMLabelGetValue(label, p, &value));
2401:     if (value != labelValue) continue;
2402:     PetscCall(PetscSectionGetDof(s, p, &dof));
2403:     PetscCall(PetscSectionSetDof(*gsection, p, dof));
2404:     PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2405:     if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(*gsection, p, cdof));
2406:     if (neg) neg[p] = -(dof + 1);
2407:   }
2408:   PetscCall(PetscSectionSetUpBC(*gsection));
2409:   if (nroots >= 0) {
2410:     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2411:     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2412:     if (nroots > pEnd - pStart) {
2413:       for (p = pStart; p < pEnd; ++p) {
2414:         if (tmpOff[p] < 0) (*gsection)->atlasDof[p - pStart] = tmpOff[p];
2415:       }
2416:     }
2417:   }
2418:   /* Calculate new sizes, get process offset, and calculate point offsets */
2419:   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
2420:     cdof                     = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
2421:     (*gsection)->atlasOff[p] = off;
2422:     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p] - cdof : 0;
2423:   }
2424:   PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s)));
2425:   globalOff -= off;
2426:   for (p = 0, off = 0; p < pEnd - pStart; ++p) {
2427:     (*gsection)->atlasOff[p] += globalOff;
2428:     if (neg) neg[p] = -((*gsection)->atlasOff[p] + 1);
2429:   }
2430:   /* Put in negative offsets for ghost points */
2431:   if (nroots >= 0) {
2432:     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2433:     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2434:     if (nroots > pEnd - pStart) {
2435:       for (p = pStart; p < pEnd; ++p) {
2436:         if (tmpOff[p] < 0) (*gsection)->atlasOff[p - pStart] = tmpOff[p];
2437:       }
2438:     }
2439:   }
2440:   if (nroots >= 0 && nroots > pEnd - pStart) PetscCall(PetscFree(tmpOff));
2441:   PetscCall(PetscFree(neg));
2442:   PetscFunctionReturn(PETSC_SUCCESS);
2443: }

2445: typedef struct _n_PetscSectionSym_Label {
2446:   DMLabel              label;
2447:   PetscCopyMode       *modes;
2448:   PetscInt            *sizes;
2449:   const PetscInt    ***perms;
2450:   const PetscScalar ***rots;
2451:   PetscInt (*minMaxOrients)[2];
2452:   PetscInt numStrata; /* numStrata is only increasing, functions as a state */
2453: } PetscSectionSym_Label;

2455: static PetscErrorCode PetscSectionSymLabelReset(PetscSectionSym sym)
2456: {
2457:   PetscInt               i, j;
2458:   PetscSectionSym_Label *sl = (PetscSectionSym_Label *)sym->data;

2460:   PetscFunctionBegin;
2461:   for (i = 0; i <= sl->numStrata; i++) {
2462:     if (sl->modes[i] == PETSC_OWN_POINTER || sl->modes[i] == PETSC_COPY_VALUES) {
2463:       for (j = sl->minMaxOrients[i][0]; j < sl->minMaxOrients[i][1]; j++) {
2464:         if (sl->perms[i]) PetscCall(PetscFree(sl->perms[i][j]));
2465:         if (sl->rots[i]) PetscCall(PetscFree(sl->rots[i][j]));
2466:       }
2467:       if (sl->perms[i]) {
2468:         const PetscInt **perms = &sl->perms[i][sl->minMaxOrients[i][0]];

2470:         PetscCall(PetscFree(perms));
2471:       }
2472:       if (sl->rots[i]) {
2473:         const PetscScalar **rots = &sl->rots[i][sl->minMaxOrients[i][0]];

2475:         PetscCall(PetscFree(rots));
2476:       }
2477:     }
2478:   }
2479:   PetscCall(PetscFree5(sl->modes, sl->sizes, sl->perms, sl->rots, sl->minMaxOrients));
2480:   PetscCall(DMLabelDestroy(&sl->label));
2481:   sl->numStrata = 0;
2482:   PetscFunctionReturn(PETSC_SUCCESS);
2483: }

2485: static PetscErrorCode PetscSectionSymDestroy_Label(PetscSectionSym sym)
2486: {
2487:   PetscFunctionBegin;
2488:   PetscCall(PetscSectionSymLabelReset(sym));
2489:   PetscCall(PetscFree(sym->data));
2490:   PetscFunctionReturn(PETSC_SUCCESS);
2491: }

2493: static PetscErrorCode PetscSectionSymView_Label(PetscSectionSym sym, PetscViewer viewer)
2494: {
2495:   PetscSectionSym_Label *sl = (PetscSectionSym_Label *)sym->data;
2496:   PetscBool              isAscii;
2497:   DMLabel                label = sl->label;
2498:   const char            *name;

2500:   PetscFunctionBegin;
2501:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isAscii));
2502:   if (isAscii) {
2503:     PetscInt          i, j, k;
2504:     PetscViewerFormat format;

2506:     PetscCall(PetscViewerGetFormat(viewer, &format));
2507:     if (label) {
2508:       PetscCall(PetscViewerGetFormat(viewer, &format));
2509:       if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
2510:         PetscCall(PetscViewerASCIIPushTab(viewer));
2511:         PetscCall(DMLabelView(label, viewer));
2512:         PetscCall(PetscViewerASCIIPopTab(viewer));
2513:       } else {
2514:         PetscCall(PetscObjectGetName((PetscObject)sl->label, &name));
2515:         PetscCall(PetscViewerASCIIPrintf(viewer, "  Label '%s'\n", name));
2516:       }
2517:     } else {
2518:       PetscCall(PetscViewerASCIIPrintf(viewer, "No label given\n"));
2519:     }
2520:     PetscCall(PetscViewerASCIIPushTab(viewer));
2521:     for (i = 0; i <= sl->numStrata; i++) {
2522:       PetscInt value = i < sl->numStrata ? label->stratumValues[i] : label->defaultValue;

2524:       if (!(sl->perms[i] || sl->rots[i])) {
2525:         PetscCall(PetscViewerASCIIPrintf(viewer, "Symmetry for stratum value %" PetscInt_FMT " (%" PetscInt_FMT " dofs per point): no symmetries\n", value, sl->sizes[i]));
2526:       } else {
2527:         PetscCall(PetscViewerASCIIPrintf(viewer, "Symmetry for stratum value %" PetscInt_FMT " (%" PetscInt_FMT " dofs per point):\n", value, sl->sizes[i]));
2528:         PetscCall(PetscViewerASCIIPushTab(viewer));
2529:         PetscCall(PetscViewerASCIIPrintf(viewer, "Orientation range: [%" PetscInt_FMT ", %" PetscInt_FMT ")\n", sl->minMaxOrients[i][0], sl->minMaxOrients[i][1]));
2530:         if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
2531:           PetscCall(PetscViewerASCIIPushTab(viewer));
2532:           for (j = sl->minMaxOrients[i][0]; j < sl->minMaxOrients[i][1]; j++) {
2533:             if (!((sl->perms[i] && sl->perms[i][j]) || (sl->rots[i] && sl->rots[i][j]))) {
2534:               PetscCall(PetscViewerASCIIPrintf(viewer, "Orientation %" PetscInt_FMT ": identity\n", j));
2535:             } else {
2536:               PetscInt tab;

2538:               PetscCall(PetscViewerASCIIPrintf(viewer, "Orientation %" PetscInt_FMT ":\n", j));
2539:               PetscCall(PetscViewerASCIIPushTab(viewer));
2540:               PetscCall(PetscViewerASCIIGetTab(viewer, &tab));
2541:               if (sl->perms[i] && sl->perms[i][j]) {
2542:                 PetscCall(PetscViewerASCIIPrintf(viewer, "Permutation:"));
2543:                 PetscCall(PetscViewerASCIISetTab(viewer, 0));
2544:                 for (k = 0; k < sl->sizes[i]; k++) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sl->perms[i][j][k]));
2545:                 PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
2546:                 PetscCall(PetscViewerASCIISetTab(viewer, tab));
2547:               }
2548:               if (sl->rots[i] && sl->rots[i][j]) {
2549:                 PetscCall(PetscViewerASCIIPrintf(viewer, "Rotations:  "));
2550:                 PetscCall(PetscViewerASCIISetTab(viewer, 0));
2551: #if defined(PETSC_USE_COMPLEX)
2552:                 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])));
2553: #else
2554:                 for (k = 0; k < sl->sizes[i]; k++) PetscCall(PetscViewerASCIIPrintf(viewer, " %+g", (double)sl->rots[i][j][k]));
2555: #endif
2556:                 PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
2557:                 PetscCall(PetscViewerASCIISetTab(viewer, tab));
2558:               }
2559:               PetscCall(PetscViewerASCIIPopTab(viewer));
2560:             }
2561:           }
2562:           PetscCall(PetscViewerASCIIPopTab(viewer));
2563:         }
2564:         PetscCall(PetscViewerASCIIPopTab(viewer));
2565:       }
2566:     }
2567:     PetscCall(PetscViewerASCIIPopTab(viewer));
2568:   }
2569:   PetscFunctionReturn(PETSC_SUCCESS);
2570: }

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

2575:   Logically collective on sym

2577:   Input parameters:
2578: + sym - the section symmetries
2579: - label - the DMLabel describing the types of points

2581:   Level: developer:

2583: .seealso: `PetscSectionSymLabelSetStratum()`, `PetscSectionSymCreateLabel()`, `PetscSectionGetPointSyms()`
2584: @*/
2585: PetscErrorCode PetscSectionSymLabelSetLabel(PetscSectionSym sym, DMLabel label)
2586: {
2587:   PetscSectionSym_Label *sl;

2589:   PetscFunctionBegin;
2591:   sl = (PetscSectionSym_Label *)sym->data;
2592:   if (sl->label && sl->label != label) PetscCall(PetscSectionSymLabelReset(sym));
2593:   if (label) {
2594:     sl->label = label;
2595:     PetscCall(PetscObjectReference((PetscObject)label));
2596:     PetscCall(DMLabelGetNumValues(label, &sl->numStrata));
2597:     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));
2598:     PetscCall(PetscMemzero((void *)sl->modes, (sl->numStrata + 1) * sizeof(PetscCopyMode)));
2599:     PetscCall(PetscMemzero((void *)sl->sizes, (sl->numStrata + 1) * sizeof(PetscInt)));
2600:     PetscCall(PetscMemzero((void *)sl->perms, (sl->numStrata + 1) * sizeof(const PetscInt **)));
2601:     PetscCall(PetscMemzero((void *)sl->rots, (sl->numStrata + 1) * sizeof(const PetscScalar **)));
2602:     PetscCall(PetscMemzero((void *)sl->minMaxOrients, (sl->numStrata + 1) * sizeof(PetscInt[2])));
2603:   }
2604:   PetscFunctionReturn(PETSC_SUCCESS);
2605: }

2607: /*@C
2608:   PetscSectionSymLabelGetStratum - get the symmetries for the orientations of a stratum

2610:   Logically collective on sym

2612:   Input Parameters:
2613: + sym       - the section symmetries
2614: - stratum   - the stratum value in the label that we are assigning symmetries for

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

2623:   Level: developer

2625: .seealso: `PetscSectionSymLabelSetStratum()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreateLabel()`
2626: @*/
2627: PetscErrorCode PetscSectionSymLabelGetStratum(PetscSectionSym sym, PetscInt stratum, PetscInt *size, PetscInt *minOrient, PetscInt *maxOrient, const PetscInt ***perms, const PetscScalar ***rots)
2628: {
2629:   PetscSectionSym_Label *sl;
2630:   const char            *name;
2631:   PetscInt               i;

2633:   PetscFunctionBegin;
2635:   sl = (PetscSectionSym_Label *)sym->data;
2636:   PetscCheck(sl->label, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_WRONGSTATE, "No label set yet");
2637:   for (i = 0; i <= sl->numStrata; i++) {
2638:     PetscInt value = (i < sl->numStrata) ? sl->label->stratumValues[i] : sl->label->defaultValue;

2640:     if (stratum == value) break;
2641:   }
2642:   PetscCall(PetscObjectGetName((PetscObject)sl->label, &name));
2643:   PetscCheck(i <= sl->numStrata, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_OUTOFRANGE, "Stratum %" PetscInt_FMT " not found in label %s", stratum, name);
2644:   if (size) {
2646:     *size = sl->sizes[i];
2647:   }
2648:   if (minOrient) {
2650:     *minOrient = sl->minMaxOrients[i][0];
2651:   }
2652:   if (maxOrient) {
2654:     *maxOrient = sl->minMaxOrients[i][1];
2655:   }
2656:   if (perms) {
2658:     *perms = sl->perms[i] ? &sl->perms[i][sl->minMaxOrients[i][0]] : NULL;
2659:   }
2660:   if (rots) {
2662:     *rots = sl->rots[i] ? &sl->rots[i][sl->minMaxOrients[i][0]] : NULL;
2663:   }
2664:   PetscFunctionReturn(PETSC_SUCCESS);
2665: }

2667: /*@C
2668:   PetscSectionSymLabelSetStratum - set the symmetries for the orientations of a stratum

2670:   Logically collective on sym

2672:   InputParameters:
2673: + sym       - the section symmetries
2674: . stratum   - the stratum value in the label that we are assigning symmetries for
2675: . size      - the number of dofs for points in the stratum of the label
2676: . minOrient - the smallest orientation for a point in this stratum
2677: . maxOrient - one greater than the largest orientation for a ppoint in this stratum (i.e., orientations are in the range [minOrient, maxOrient))
2678: . mode      - how sym should copy the perms and rots arrays
2679: . perms     - NULL if there are no permutations, or (maxOrient - minOrient) permutations, one for each orientation.  A NULL permutation is the identity
2680: - 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

2682:   Level: developer

2684: .seealso: `PetscSectionSymLabelGetStratum()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreateLabel()`
2685: @*/
2686: PetscErrorCode PetscSectionSymLabelSetStratum(PetscSectionSym sym, PetscInt stratum, PetscInt size, PetscInt minOrient, PetscInt maxOrient, PetscCopyMode mode, const PetscInt **perms, const PetscScalar **rots)
2687: {
2688:   PetscSectionSym_Label *sl;
2689:   const char            *name;
2690:   PetscInt               i, j, k;

2692:   PetscFunctionBegin;
2694:   sl = (PetscSectionSym_Label *)sym->data;
2695:   PetscCheck(sl->label, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_WRONGSTATE, "No label set yet");
2696:   for (i = 0; i <= sl->numStrata; i++) {
2697:     PetscInt value = (i < sl->numStrata) ? sl->label->stratumValues[i] : sl->label->defaultValue;

2699:     if (stratum == value) break;
2700:   }
2701:   PetscCall(PetscObjectGetName((PetscObject)sl->label, &name));
2702:   PetscCheck(i <= sl->numStrata, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_OUTOFRANGE, "Stratum %" PetscInt_FMT " not found in label %s", stratum, name);
2703:   sl->sizes[i]            = size;
2704:   sl->modes[i]            = mode;
2705:   sl->minMaxOrients[i][0] = minOrient;
2706:   sl->minMaxOrients[i][1] = maxOrient;
2707:   if (mode == PETSC_COPY_VALUES) {
2708:     if (perms) {
2709:       PetscInt **ownPerms;

2711:       PetscCall(PetscCalloc1(maxOrient - minOrient, &ownPerms));
2712:       for (j = 0; j < maxOrient - minOrient; j++) {
2713:         if (perms[j]) {
2714:           PetscCall(PetscMalloc1(size, &ownPerms[j]));
2715:           for (k = 0; k < size; k++) ownPerms[j][k] = perms[j][k];
2716:         }
2717:       }
2718:       sl->perms[i] = (const PetscInt **)&ownPerms[-minOrient];
2719:     }
2720:     if (rots) {
2721:       PetscScalar **ownRots;

2723:       PetscCall(PetscCalloc1(maxOrient - minOrient, &ownRots));
2724:       for (j = 0; j < maxOrient - minOrient; j++) {
2725:         if (rots[j]) {
2726:           PetscCall(PetscMalloc1(size, &ownRots[j]));
2727:           for (k = 0; k < size; k++) ownRots[j][k] = rots[j][k];
2728:         }
2729:       }
2730:       sl->rots[i] = (const PetscScalar **)&ownRots[-minOrient];
2731:     }
2732:   } else {
2733:     sl->perms[i] = perms ? &perms[-minOrient] : NULL;
2734:     sl->rots[i]  = rots ? &rots[-minOrient] : NULL;
2735:   }
2736:   PetscFunctionReturn(PETSC_SUCCESS);
2737: }

2739: static PetscErrorCode PetscSectionSymGetPoints_Label(PetscSectionSym sym, PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt **perms, const PetscScalar **rots)
2740: {
2741:   PetscInt               i, j, numStrata;
2742:   PetscSectionSym_Label *sl;
2743:   DMLabel                label;

2745:   PetscFunctionBegin;
2746:   sl        = (PetscSectionSym_Label *)sym->data;
2747:   numStrata = sl->numStrata;
2748:   label     = sl->label;
2749:   for (i = 0; i < numPoints; i++) {
2750:     PetscInt point = points[2 * i];
2751:     PetscInt ornt  = points[2 * i + 1];

2753:     for (j = 0; j < numStrata; j++) {
2754:       if (label->validIS[j]) {
2755:         PetscInt k;

2757:         PetscCall(ISLocate(label->points[j], point, &k));
2758:         if (k >= 0) break;
2759:       } else {
2760:         PetscBool has;

2762:         PetscCall(PetscHSetIHas(label->ht[j], point, &has));
2763:         if (has) break;
2764:       }
2765:     }
2766:     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],
2767:                j < numStrata ? label->stratumValues[j] : label->defaultValue);
2768:     if (perms) perms[i] = sl->perms[j] ? sl->perms[j][ornt] : NULL;
2769:     if (rots) rots[i] = sl->rots[j] ? sl->rots[j][ornt] : NULL;
2770:   }
2771:   PetscFunctionReturn(PETSC_SUCCESS);
2772: }

2774: static PetscErrorCode PetscSectionSymCopy_Label(PetscSectionSym sym, PetscSectionSym nsym)
2775: {
2776:   PetscSectionSym_Label *sl = (PetscSectionSym_Label *)nsym->data;
2777:   IS                     valIS;
2778:   const PetscInt        *values;
2779:   PetscInt               Nv, v;

2781:   PetscFunctionBegin;
2782:   PetscCall(DMLabelGetNumValues(sl->label, &Nv));
2783:   PetscCall(DMLabelGetValueIS(sl->label, &valIS));
2784:   PetscCall(ISGetIndices(valIS, &values));
2785:   for (v = 0; v < Nv; ++v) {
2786:     const PetscInt      val = values[v];
2787:     PetscInt            size, minOrient, maxOrient;
2788:     const PetscInt    **perms;
2789:     const PetscScalar **rots;

2791:     PetscCall(PetscSectionSymLabelGetStratum(sym, val, &size, &minOrient, &maxOrient, &perms, &rots));
2792:     PetscCall(PetscSectionSymLabelSetStratum(nsym, val, size, minOrient, maxOrient, PETSC_COPY_VALUES, perms, rots));
2793:   }
2794:   PetscCall(ISDestroy(&valIS));
2795:   PetscFunctionReturn(PETSC_SUCCESS);
2796: }

2798: static PetscErrorCode PetscSectionSymDistribute_Label(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym)
2799: {
2800:   PetscSectionSym_Label *sl = (PetscSectionSym_Label *)sym->data;
2801:   DMLabel                dlabel;

2803:   PetscFunctionBegin;
2804:   PetscCall(DMLabelDistribute(sl->label, migrationSF, &dlabel));
2805:   PetscCall(PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)sym), dlabel, dsym));
2806:   PetscCall(DMLabelDestroy(&dlabel));
2807:   PetscCall(PetscSectionSymCopy(sym, *dsym));
2808:   PetscFunctionReturn(PETSC_SUCCESS);
2809: }

2811: PetscErrorCode PetscSectionSymCreate_Label(PetscSectionSym sym)
2812: {
2813:   PetscSectionSym_Label *sl;

2815:   PetscFunctionBegin;
2816:   PetscCall(PetscNew(&sl));
2817:   sym->ops->getpoints  = PetscSectionSymGetPoints_Label;
2818:   sym->ops->distribute = PetscSectionSymDistribute_Label;
2819:   sym->ops->copy       = PetscSectionSymCopy_Label;
2820:   sym->ops->view       = PetscSectionSymView_Label;
2821:   sym->ops->destroy    = PetscSectionSymDestroy_Label;
2822:   sym->data            = (void *)sl;
2823:   PetscFunctionReturn(PETSC_SUCCESS);
2824: }

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

2829:   Collective

2831:   Input Parameters:
2832: + comm - the MPI communicator for the new symmetry
2833: - label - the label defining the strata

2835:   Output Parameters:
2836: . sym - the section symmetries

2838:   Level: developer

2840: .seealso: `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()`
2841: @*/
2842: PetscErrorCode PetscSectionSymCreateLabel(MPI_Comm comm, DMLabel label, PetscSectionSym *sym)
2843: {
2844:   PetscFunctionBegin;
2845:   PetscCall(DMInitializePackage());
2846:   PetscCall(PetscSectionSymCreate(comm, sym));
2847:   PetscCall(PetscSectionSymSetType(*sym, PETSCSECTIONSYMLABEL));
2848:   PetscCall(PetscSectionSymLabelSetLabel(*sym, label));
2849:   PetscFunctionReturn(PETSC_SUCCESS);
2850: }