1 #include <petscdm.h>
2 #include <petsc/private/dmlabelimpl.h> /*I "petscdmlabel.h" I*/
3 #include <petsc/private/sectionimpl.h> /*I "petscsection.h" I*/
4 #include <petscsf.h>
5 #include <petscsection.h>
6
7 PetscFunctionList DMLabelList = NULL;
8 PetscBool DMLabelRegisterAllCalled = PETSC_FALSE;
9
10 /*@
11 DMLabelCreate - Create a `DMLabel` object, which is a multimap
12
13 Collective
14
15 Input Parameters:
16 + comm - The communicator, usually `PETSC_COMM_SELF`
17 - name - The label name
18
19 Output Parameter:
20 . label - The `DMLabel`
21
22 Level: beginner
23
24 Notes:
25 The label name is actually usually the `PetscObject` name.
26 One can get/set it with `PetscObjectGetName()`/`PetscObjectSetName()`.
27
28 .seealso: `DMLabel`, `DM`, `DMLabelDestroy()`
29 @*/
DMLabelCreate(MPI_Comm comm,const char name[],DMLabel * label)30 PetscErrorCode DMLabelCreate(MPI_Comm comm, const char name[], DMLabel *label)
31 {
32 PetscFunctionBegin;
33 PetscAssertPointer(label, 3);
34 PetscCall(DMInitializePackage());
35
36 PetscCall(PetscHeaderCreate(*label, DMLABEL_CLASSID, "DMLabel", "DMLabel", "DM", comm, DMLabelDestroy, DMLabelView));
37 (*label)->numStrata = 0;
38 (*label)->defaultValue = -1;
39 (*label)->stratumValues = NULL;
40 (*label)->validIS = NULL;
41 (*label)->stratumSizes = NULL;
42 (*label)->points = NULL;
43 (*label)->ht = NULL;
44 (*label)->pStart = -1;
45 (*label)->pEnd = -1;
46 (*label)->bt = NULL;
47 PetscCall(PetscHMapICreate(&(*label)->hmap));
48 PetscCall(PetscObjectSetName((PetscObject)*label, name));
49 PetscCall(DMLabelSetType(*label, DMLABELCONCRETE));
50 PetscFunctionReturn(PETSC_SUCCESS);
51 }
52
53 /*@
54 DMLabelSetUp - SetUp a `DMLabel` object
55
56 Collective
57
58 Input Parameters:
59 . label - The `DMLabel`
60
61 Level: intermediate
62
63 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
64 @*/
DMLabelSetUp(DMLabel label)65 PetscErrorCode DMLabelSetUp(DMLabel label)
66 {
67 PetscFunctionBegin;
68 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
69 PetscTryTypeMethod(label, setup);
70 PetscFunctionReturn(PETSC_SUCCESS);
71 }
72
73 /*
74 DMLabelMakeValid_Private - Transfer stratum data from the hash format to the sorted list format
75
76 Not collective
77
78 Input parameter:
79 + label - The `DMLabel`
80 - v - The stratum value
81
82 Output parameter:
83 . label - The `DMLabel` with stratum in sorted list format
84
85 Level: developer
86
87 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`
88 */
DMLabelMakeValid_Private(DMLabel label,PetscInt v)89 static PetscErrorCode DMLabelMakeValid_Private(DMLabel label, PetscInt v)
90 {
91 IS is;
92 PetscInt off = 0, *pointArray, p;
93
94 PetscFunctionBegin;
95 if ((PetscLikely(v >= 0 && v < label->numStrata) && label->validIS[v]) || label->readonly) PetscFunctionReturn(PETSC_SUCCESS);
96 PetscCheck(v >= 0 && v < label->numStrata, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to access invalid stratum %" PetscInt_FMT " in DMLabelMakeValid_Private", v);
97 PetscCall(PetscHSetIGetSize(label->ht[v], &label->stratumSizes[v]));
98 PetscCall(PetscMalloc1(label->stratumSizes[v], &pointArray));
99 PetscCall(PetscHSetIGetElems(label->ht[v], &off, pointArray));
100 PetscCall(PetscHSetIClear(label->ht[v]));
101 PetscCall(PetscSortInt(label->stratumSizes[v], pointArray));
102 if (label->bt) {
103 for (p = 0; p < label->stratumSizes[v]; ++p) {
104 const PetscInt point = pointArray[p];
105 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);
106 PetscCall(PetscBTSet(label->bt, point - label->pStart));
107 }
108 }
109 if (label->stratumSizes[v] > 0 && pointArray[label->stratumSizes[v] - 1] == pointArray[0] + label->stratumSizes[v] - 1) {
110 PetscCall(ISCreateStride(PETSC_COMM_SELF, label->stratumSizes[v], pointArray[0], 1, &is));
111 PetscCall(PetscFree(pointArray));
112 } else {
113 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, label->stratumSizes[v], pointArray, PETSC_OWN_POINTER, &is));
114 }
115 PetscCall(ISSetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, PETSC_TRUE));
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 }
122
123 /*
124 DMLabelMakeAllValid_Private - Transfer all strata from the hash format to the sorted list format
125
126 Not Collective
127
128 Input parameter:
129 . label - The `DMLabel`
130
131 Output parameter:
132 . label - The `DMLabel` with all strata in sorted list format
133
134 Level: developer
135
136 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`
137 */
DMLabelMakeAllValid_Private(DMLabel label)138 static PetscErrorCode DMLabelMakeAllValid_Private(DMLabel label)
139 {
140 PetscInt v;
141
142 PetscFunctionBegin;
143 for (v = 0; v < label->numStrata; v++) PetscCall(DMLabelMakeValid_Private(label, v));
144 PetscFunctionReturn(PETSC_SUCCESS);
145 }
146
147 /*
148 DMLabelMakeInvalid_Private - Transfer stratum data from the sorted list format to the hash format
149
150 Not Collective
151
152 Input parameter:
153 + label - The `DMLabel`
154 - v - The stratum value
155
156 Output parameter:
157 . label - The `DMLabel` with stratum in hash format
158
159 Level: developer
160
161 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`
162 */
DMLabelMakeInvalid_Private(DMLabel label,PetscInt v)163 static PetscErrorCode DMLabelMakeInvalid_Private(DMLabel label, PetscInt v)
164 {
165 PetscInt p;
166 const PetscInt *points;
167
168 PetscFunctionBegin;
169 if ((PetscLikely(v >= 0 && v < label->numStrata) && !label->validIS[v]) || label->readonly) PetscFunctionReturn(PETSC_SUCCESS);
170 PetscCheck(v >= 0 && v < label->numStrata, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Trying to access invalid stratum %" PetscInt_FMT " in DMLabelMakeInvalid_Private", v);
171 if (label->points[v]) {
172 PetscCall(ISGetIndices(label->points[v], &points));
173 for (p = 0; p < label->stratumSizes[v]; ++p) PetscCall(PetscHSetIAdd(label->ht[v], points[p]));
174 PetscCall(ISRestoreIndices(label->points[v], &points));
175 PetscCall(ISDestroy(&label->points[v]));
176 }
177 label->validIS[v] = PETSC_FALSE;
178 PetscFunctionReturn(PETSC_SUCCESS);
179 }
180
DMLabelMakeAllInvalid_Internal(DMLabel label)181 PetscErrorCode DMLabelMakeAllInvalid_Internal(DMLabel label)
182 {
183 PetscInt v;
184
185 PetscFunctionBegin;
186 for (v = 0; v < label->numStrata; v++) PetscCall(DMLabelMakeInvalid_Private(label, v));
187 PetscFunctionReturn(PETSC_SUCCESS);
188 }
189
190 #if !defined(DMLABEL_LOOKUP_THRESHOLD)
191 #define DMLABEL_LOOKUP_THRESHOLD 16
192 #endif
193
DMLabelLookupStratum(DMLabel label,PetscInt value,PetscInt * index)194 PetscErrorCode DMLabelLookupStratum(DMLabel label, PetscInt value, PetscInt *index)
195 {
196 PetscInt v;
197
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 }
226
DMLabelNewStratum(DMLabel label,PetscInt value,PetscInt * index)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;
236
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 }
284
DMLabelLookupAddStratum(DMLabel label,PetscInt value,PetscInt * index)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 }
292
DMLabelGetStratumSize_Private(DMLabel label,PetscInt v,PetscInt * size)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 }
305
306 /*@
307 DMLabelAddStratum - Adds a new stratum value in a `DMLabel`
308
309 Input Parameters:
310 + label - The `DMLabel`
311 - value - The stratum value
312
313 Level: beginner
314
315 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
316 @*/
DMLabelAddStratum(DMLabel label,PetscInt value)317 PetscErrorCode DMLabelAddStratum(DMLabel label, PetscInt value)
318 {
319 PetscInt v;
320
321 PetscFunctionBegin;
322 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
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 }
327
328 /*@
329 DMLabelAddStrata - Adds new stratum values in a `DMLabel`
330
331 Not Collective
332
333 Input Parameters:
334 + label - The `DMLabel`
335 . numStrata - The number of stratum values
336 - stratumValues - The stratum values
337
338 Level: beginner
339
340 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
341 @*/
DMLabelAddStrata(DMLabel label,PetscInt numStrata,const PetscInt stratumValues[])342 PetscErrorCode DMLabelAddStrata(DMLabel label, PetscInt numStrata, const PetscInt stratumValues[])
343 {
344 PetscInt *values, v;
345
346 PetscFunctionBegin;
347 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
348 if (numStrata) PetscAssertPointer(stratumValues, 3);
349 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
350 PetscCall(PetscMalloc1(numStrata, &values));
351 PetscCall(PetscArraycpy(values, stratumValues, numStrata));
352 PetscCall(PetscSortRemoveDupsInt(&numStrata, values));
353 if (!label->numStrata) { /* Fast preallocation */
354 PetscInt *tmpV;
355 PetscInt *tmpS;
356 PetscHSetI *tmpH, ht;
357 IS *tmpP, is;
358 PetscBool *tmpB;
359 PetscHMapI hmap = label->hmap;
360
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 }
389
390 /*@
391 DMLabelAddStrataIS - Adds new stratum values in a `DMLabel`
392
393 Not Collective
394
395 Input Parameters:
396 + label - The `DMLabel`
397 - valueIS - Index set with stratum values
398
399 Level: beginner
400
401 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
402 @*/
DMLabelAddStrataIS(DMLabel label,IS valueIS)403 PetscErrorCode DMLabelAddStrataIS(DMLabel label, IS valueIS)
404 {
405 PetscInt numStrata;
406 const PetscInt *stratumValues;
407
408 PetscFunctionBegin;
409 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
410 PetscValidHeaderSpecific(valueIS, IS_CLASSID, 2);
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 }
417
DMLabelView_Concrete_Ascii(DMLabel label,PetscViewer viewer)418 static PetscErrorCode DMLabelView_Concrete_Ascii(DMLabel label, PetscViewer viewer)
419 {
420 PetscInt v;
421 PetscMPIInt rank;
422
423 PetscFunctionBegin;
424 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
425 PetscCall(PetscViewerASCIIPushSynchronized(viewer));
426 if (label) {
427 const char *name;
428
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;
436
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 }
446
DMLabelView_Concrete(DMLabel label,PetscViewer viewer)447 static PetscErrorCode DMLabelView_Concrete(DMLabel label, PetscViewer viewer)
448 {
449 PetscBool isascii;
450
451 PetscFunctionBegin;
452 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
453 if (isascii) PetscCall(DMLabelView_Concrete_Ascii(label, viewer));
454 PetscFunctionReturn(PETSC_SUCCESS);
455 }
456
457 /*@
458 DMLabelView - View the label
459
460 Collective
461
462 Input Parameters:
463 + label - The `DMLabel`
464 - viewer - The `PetscViewer`
465
466 Level: intermediate
467
468 .seealso: `DMLabel`, `PetscViewer`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
469 @*/
DMLabelView(DMLabel label,PetscViewer viewer)470 PetscErrorCode DMLabelView(DMLabel label, PetscViewer viewer)
471 {
472 PetscFunctionBegin;
473 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
474 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)label), &viewer));
475 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
476 PetscCall(DMLabelMakeAllValid_Private(label));
477 PetscUseTypeMethod(label, view, viewer);
478 PetscFunctionReturn(PETSC_SUCCESS);
479 }
480
481 /*@
482 DMLabelViewFromOptions - View a `DMLabel` in a particular way based on a request in the options database
483
484 Collective
485
486 Input Parameters:
487 + label - the `DMLabel` object
488 . obj - optional object that provides the prefix for the options database (if `NULL` then the prefix in `obj` is used)
489 - name - option string that is used to activate viewing
490
491 Level: intermediate
492
493 Note:
494 See `PetscObjectViewFromOptions()` for a list of values that can be provided in the options database to determine how the `DMLabel` is viewed
495
496 .seealso: [](ch_dmbase), `DMLabel`, `DMLabelView()`, `PetscObjectViewFromOptions()`, `DMLabelCreate()`
497 @*/
DMLabelViewFromOptions(DMLabel label,PeOp PetscObject obj,const char name[])498 PetscErrorCode DMLabelViewFromOptions(DMLabel label, PeOp PetscObject obj, const char name[])
499 {
500 PetscFunctionBegin;
501 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
502 PetscCall(PetscObjectViewFromOptions((PetscObject)label, obj, name));
503 PetscFunctionReturn(PETSC_SUCCESS);
504 }
505
506 /*@
507 DMLabelReset - Destroys internal data structures in a `DMLabel`
508
509 Not Collective
510
511 Input Parameter:
512 . label - The `DMLabel`
513
514 Level: beginner
515
516 .seealso: `DMLabel`, `DM`, `DMLabelDestroy()`, `DMLabelCreate()`
517 @*/
DMLabelReset(DMLabel label)518 PetscErrorCode DMLabelReset(DMLabel label)
519 {
520 PetscInt v;
521
522 PetscFunctionBegin;
523 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
524 for (v = 0; v < label->numStrata; ++v) {
525 if (label->ht[v]) PetscCall(PetscHSetIDestroy(&label->ht[v]));
526 PetscCall(ISDestroy(&label->points[v]));
527 }
528 label->numStrata = 0;
529 PetscCall(PetscFree(label->stratumValues));
530 PetscCall(PetscFree(label->stratumSizes));
531 PetscCall(PetscFree(label->ht));
532 PetscCall(PetscFree(label->points));
533 PetscCall(PetscFree(label->validIS));
534 PetscCall(PetscHMapIReset(label->hmap));
535 label->pStart = -1;
536 label->pEnd = -1;
537 PetscCall(PetscBTDestroy(&label->bt));
538 PetscFunctionReturn(PETSC_SUCCESS);
539 }
540
541 /*@
542 DMLabelDestroy - Destroys a `DMLabel`
543
544 Collective
545
546 Input Parameter:
547 . label - The `DMLabel`
548
549 Level: beginner
550
551 .seealso: `DMLabel`, `DM`, `DMLabelReset()`, `DMLabelCreate()`
552 @*/
DMLabelDestroy(DMLabel * label)553 PetscErrorCode DMLabelDestroy(DMLabel *label)
554 {
555 PetscFunctionBegin;
556 if (!*label) PetscFunctionReturn(PETSC_SUCCESS);
557 PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 1);
558 if (--((PetscObject)*label)->refct > 0) {
559 *label = NULL;
560 PetscFunctionReturn(PETSC_SUCCESS);
561 }
562 PetscCall(DMLabelReset(*label));
563 PetscCall(PetscHMapIDestroy(&(*label)->hmap));
564 PetscCall(PetscHeaderDestroy(label));
565 PetscFunctionReturn(PETSC_SUCCESS);
566 }
567
DMLabelDuplicate_Concrete(DMLabel label,DMLabel * labelnew)568 static PetscErrorCode DMLabelDuplicate_Concrete(DMLabel label, DMLabel *labelnew)
569 {
570 PetscFunctionBegin;
571 for (PetscInt v = 0; v < label->numStrata; ++v) {
572 PetscCall(PetscHSetICreate(&(*labelnew)->ht[v]));
573 PetscCall(PetscObjectReference((PetscObject)label->points[v]));
574 (*labelnew)->points[v] = label->points[v];
575 }
576 PetscCall(PetscHMapIDestroy(&(*labelnew)->hmap));
577 PetscCall(PetscHMapIDuplicate(label->hmap, &(*labelnew)->hmap));
578 PetscFunctionReturn(PETSC_SUCCESS);
579 }
580
581 /*@
582 DMLabelDuplicate - Duplicates a `DMLabel`
583
584 Collective
585
586 Input Parameter:
587 . label - The `DMLabel`
588
589 Output Parameter:
590 . labelnew - new label
591
592 Level: intermediate
593
594 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelDestroy()`
595 @*/
DMLabelDuplicate(DMLabel label,DMLabel * labelnew)596 PetscErrorCode DMLabelDuplicate(DMLabel label, DMLabel *labelnew)
597 {
598 const char *name;
599
600 PetscFunctionBegin;
601 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
602 PetscCall(DMLabelMakeAllValid_Private(label));
603 PetscCall(PetscObjectGetName((PetscObject)label, &name));
604 PetscCall(DMLabelCreate(PetscObjectComm((PetscObject)label), name, labelnew));
605
606 (*labelnew)->numStrata = label->numStrata;
607 (*labelnew)->defaultValue = label->defaultValue;
608 (*labelnew)->readonly = label->readonly;
609 PetscCall(PetscMalloc1(label->numStrata, &(*labelnew)->stratumValues));
610 PetscCall(PetscMalloc1(label->numStrata, &(*labelnew)->stratumSizes));
611 PetscCall(PetscCalloc1(label->numStrata, &(*labelnew)->ht));
612 PetscCall(PetscCalloc1(label->numStrata, &(*labelnew)->points));
613 PetscCall(PetscMalloc1(label->numStrata, &(*labelnew)->validIS));
614 for (PetscInt v = 0; v < label->numStrata; ++v) {
615 (*labelnew)->stratumValues[v] = label->stratumValues[v];
616 (*labelnew)->stratumSizes[v] = label->stratumSizes[v];
617 (*labelnew)->validIS[v] = PETSC_TRUE;
618 }
619 (*labelnew)->pStart = -1;
620 (*labelnew)->pEnd = -1;
621 (*labelnew)->bt = NULL;
622 PetscUseTypeMethod(label, duplicate, labelnew);
623 PetscFunctionReturn(PETSC_SUCCESS);
624 }
625
626 /*@C
627 DMLabelCompare - Compare two `DMLabel` objects
628
629 Collective; No Fortran Support
630
631 Input Parameters:
632 + comm - Comm over which to compare labels
633 . l0 - First `DMLabel`
634 - l1 - Second `DMLabel`
635
636 Output Parameters:
637 + equal - (Optional) Flag whether the two labels are equal
638 - message - (Optional) Message describing the difference
639
640 Level: intermediate
641
642 Notes:
643 The output flag equal is the same on all processes.
644 If it is passed as `NULL` and difference is found, an error is thrown on all processes.
645 Make sure to pass `NULL` on all processes.
646
647 The output message is set independently on each rank.
648 It is set to `NULL` if no difference was found on the current rank. It must be freed by user.
649 If message is passed as `NULL` and difference is found, the difference description is printed to stderr in synchronized manner.
650 Make sure to pass `NULL` on all processes.
651
652 For the comparison, we ignore the order of stratum values, and strata with no points.
653
654 The communicator needs to be specified because currently `DMLabel` can live on `PETSC_COMM_SELF` even if the underlying `DM` is parallel.
655
656 Developer Note:
657 Fortran stub cannot be generated automatically because `message` must be freed with `PetscFree()`
658
659 .seealso: `DMLabel`, `DM`, `DMCompareLabels()`, `DMLabelGetNumValues()`, `DMLabelGetDefaultValue()`, `DMLabelGetNonEmptyStratumValuesIS()`, `DMLabelGetStratumIS()`
660 @*/
DMLabelCompare(MPI_Comm comm,DMLabel l0,DMLabel l1,PetscBool * equal,char ** message)661 PetscErrorCode DMLabelCompare(MPI_Comm comm, DMLabel l0, DMLabel l1, PetscBool *equal, char **message)
662 {
663 const char *name0, *name1;
664 char msg[PETSC_MAX_PATH_LEN] = "";
665 PetscBool eq;
666 PetscMPIInt rank;
667
668 PetscFunctionBegin;
669 PetscValidHeaderSpecific(l0, DMLABEL_CLASSID, 2);
670 PetscValidHeaderSpecific(l1, DMLABEL_CLASSID, 3);
671 if (equal) PetscAssertPointer(equal, 4);
672 if (message) PetscAssertPointer(message, 5);
673 PetscCallMPI(MPI_Comm_rank(comm, &rank));
674 PetscCall(PetscObjectGetName((PetscObject)l0, &name0));
675 PetscCall(PetscObjectGetName((PetscObject)l1, &name1));
676 {
677 PetscInt v0, v1;
678
679 PetscCall(DMLabelGetDefaultValue(l0, &v0));
680 PetscCall(DMLabelGetDefaultValue(l1, &v1));
681 eq = (PetscBool)(v0 == v1);
682 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));
683 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPI_C_BOOL, MPI_LAND, comm));
684 if (!eq) goto finish;
685 }
686 {
687 IS is0, is1;
688
689 PetscCall(DMLabelGetNonEmptyStratumValuesIS(l0, &is0));
690 PetscCall(DMLabelGetNonEmptyStratumValuesIS(l1, &is1));
691 PetscCall(ISEqual(is0, is1, &eq));
692 PetscCall(ISDestroy(&is0));
693 PetscCall(ISDestroy(&is1));
694 if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Stratum values in DMLabel l0 \"%s\" are different than in DMLabel l1 \"%s\"", name0, name1));
695 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPI_C_BOOL, MPI_LAND, comm));
696 if (!eq) goto finish;
697 }
698 {
699 PetscInt i, nValues;
700
701 PetscCall(DMLabelGetNumValues(l0, &nValues));
702 for (i = 0; i < nValues; i++) {
703 const PetscInt v = l0->stratumValues[i];
704 PetscInt n;
705 IS is0, is1;
706
707 PetscCall(DMLabelGetStratumSize_Private(l0, i, &n));
708 if (!n) continue;
709 PetscCall(DMLabelGetStratumIS(l0, v, &is0));
710 PetscCall(DMLabelGetStratumIS(l1, v, &is1));
711 PetscCall(ISEqualUnsorted(is0, is1, &eq));
712 PetscCall(ISDestroy(&is0));
713 PetscCall(ISDestroy(&is1));
714 if (!eq) {
715 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));
716 break;
717 }
718 }
719 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPI_C_BOOL, MPI_LAND, comm));
720 }
721 finish:
722 /* If message output arg not set, print to stderr */
723 if (message) {
724 *message = NULL;
725 if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
726 } else {
727 if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
728 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
729 }
730 /* If same output arg not ser and labels are not equal, throw error */
731 if (equal) *equal = eq;
732 else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels l0 \"%s\" and l1 \"%s\" are not equal", name0, name1);
733 PetscFunctionReturn(PETSC_SUCCESS);
734 }
735
736 /*@
737 DMLabelComputeIndex - Create an index structure for membership determination, automatically determining the bounds
738
739 Not Collective
740
741 Input Parameter:
742 . label - The `DMLabel`
743
744 Level: intermediate
745
746 .seealso: `DMLabel`, `DM`, `DMLabelHasPoint()`, `DMLabelCreateIndex()`, `DMLabelDestroyIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
747 @*/
DMLabelComputeIndex(DMLabel label)748 PetscErrorCode DMLabelComputeIndex(DMLabel label)
749 {
750 PetscInt pStart = PETSC_INT_MAX, pEnd = -1, v;
751
752 PetscFunctionBegin;
753 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
754 PetscCall(DMLabelMakeAllValid_Private(label));
755 for (v = 0; v < label->numStrata; ++v) {
756 const PetscInt *points;
757 PetscInt i;
758
759 PetscCall(ISGetIndices(label->points[v], &points));
760 for (i = 0; i < label->stratumSizes[v]; ++i) {
761 const PetscInt point = points[i];
762
763 pStart = PetscMin(point, pStart);
764 pEnd = PetscMax(point + 1, pEnd);
765 }
766 PetscCall(ISRestoreIndices(label->points[v], &points));
767 }
768 label->pStart = pStart == PETSC_INT_MAX ? -1 : pStart;
769 label->pEnd = pEnd;
770 PetscCall(DMLabelCreateIndex(label, label->pStart, label->pEnd));
771 PetscFunctionReturn(PETSC_SUCCESS);
772 }
773
774 /*@
775 DMLabelCreateIndex - Create an index structure for membership determination
776
777 Not Collective
778
779 Input Parameters:
780 + label - The `DMLabel`
781 . pStart - The smallest point
782 - pEnd - The largest point + 1
783
784 Level: intermediate
785
786 .seealso: `DMLabel`, `DM`, `DMLabelHasPoint()`, `DMLabelComputeIndex()`, `DMLabelDestroyIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
787 @*/
DMLabelCreateIndex(DMLabel label,PetscInt pStart,PetscInt pEnd)788 PetscErrorCode DMLabelCreateIndex(DMLabel label, PetscInt pStart, PetscInt pEnd)
789 {
790 PetscInt v;
791
792 PetscFunctionBegin;
793 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
794 PetscCall(DMLabelDestroyIndex(label));
795 PetscCall(DMLabelMakeAllValid_Private(label));
796 label->pStart = pStart;
797 label->pEnd = pEnd;
798 /* This can be hooked into SetValue(), ClearValue(), etc. for updating */
799 PetscCall(PetscBTCreate(pEnd - pStart, &label->bt));
800 for (v = 0; v < label->numStrata; ++v) {
801 IS pointIS;
802 const PetscInt *points;
803 PetscInt i;
804
805 PetscUseTypeMethod(label, getstratumis, v, &pointIS);
806 PetscCall(ISGetIndices(pointIS, &points));
807 for (i = 0; i < label->stratumSizes[v]; ++i) {
808 const PetscInt point = points[i];
809
810 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);
811 PetscCall(PetscBTSet(label->bt, point - pStart));
812 }
813 PetscCall(ISRestoreIndices(label->points[v], &points));
814 PetscCall(ISDestroy(&pointIS));
815 }
816 PetscFunctionReturn(PETSC_SUCCESS);
817 }
818
819 /*@
820 DMLabelDestroyIndex - Destroy the index structure
821
822 Not Collective
823
824 Input Parameter:
825 . label - the `DMLabel`
826
827 Level: intermediate
828
829 .seealso: `DMLabel`, `DM`, `DMLabelHasPoint()`, `DMLabelCreateIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
830 @*/
DMLabelDestroyIndex(DMLabel label)831 PetscErrorCode DMLabelDestroyIndex(DMLabel label)
832 {
833 PetscFunctionBegin;
834 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
835 label->pStart = -1;
836 label->pEnd = -1;
837 PetscCall(PetscBTDestroy(&label->bt));
838 PetscFunctionReturn(PETSC_SUCCESS);
839 }
840
841 /*@
842 DMLabelGetBounds - Return the smallest and largest point in the label
843
844 Not Collective
845
846 Input Parameter:
847 . label - the `DMLabel`
848
849 Output Parameters:
850 + pStart - The smallest point
851 - pEnd - The largest point + 1
852
853 Level: intermediate
854
855 Note:
856 This will compute an index for the label if one does not exist.
857
858 .seealso: `DMLabel`, `DM`, `DMLabelHasPoint()`, `DMLabelCreateIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
859 @*/
DMLabelGetBounds(DMLabel label,PetscInt * pStart,PetscInt * pEnd)860 PetscErrorCode DMLabelGetBounds(DMLabel label, PetscInt *pStart, PetscInt *pEnd)
861 {
862 PetscFunctionBegin;
863 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
864 if ((label->pStart == -1) && (label->pEnd == -1)) PetscCall(DMLabelComputeIndex(label));
865 if (pStart) {
866 PetscAssertPointer(pStart, 2);
867 *pStart = label->pStart;
868 }
869 if (pEnd) {
870 PetscAssertPointer(pEnd, 3);
871 *pEnd = label->pEnd;
872 }
873 PetscFunctionReturn(PETSC_SUCCESS);
874 }
875
876 /*@
877 DMLabelHasValue - Determine whether a label assigns the value to any point
878
879 Not Collective
880
881 Input Parameters:
882 + label - the `DMLabel`
883 - value - the value
884
885 Output Parameter:
886 . contains - Flag indicating whether the label maps this value to any point
887
888 Level: developer
889
890 .seealso: `DMLabel`, `DM`, `DMLabelHasPoint()`, `DMLabelGetValue()`, `DMLabelSetValue()`
891 @*/
DMLabelHasValue(DMLabel label,PetscInt value,PetscBool * contains)892 PetscErrorCode DMLabelHasValue(DMLabel label, PetscInt value, PetscBool *contains)
893 {
894 PetscInt v;
895
896 PetscFunctionBegin;
897 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
898 PetscAssertPointer(contains, 3);
899 PetscCall(DMLabelLookupStratum(label, value, &v));
900 *contains = v < 0 ? PETSC_FALSE : PETSC_TRUE;
901 PetscFunctionReturn(PETSC_SUCCESS);
902 }
903
904 /*@
905 DMLabelHasPoint - Determine whether a label assigns a value to a point
906
907 Not Collective
908
909 Input Parameters:
910 + label - the `DMLabel`
911 - point - the point
912
913 Output Parameter:
914 . contains - Flag indicating whether the label maps this point to a value
915
916 Level: developer
917
918 Note:
919 The user must call `DMLabelCreateIndex()` before this function.
920
921 .seealso: `DMLabel`, `DM`, `DMLabelCreateIndex()`, `DMLabelGetValue()`, `DMLabelSetValue()`
922 @*/
DMLabelHasPoint(DMLabel label,PetscInt point,PetscBool * contains)923 PetscErrorCode DMLabelHasPoint(DMLabel label, PetscInt point, PetscBool *contains)
924 {
925 PetscInt pStart, pEnd;
926
927 PetscFunctionBeginHot;
928 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
929 PetscAssertPointer(contains, 3);
930 /* DMLabelGetBounds() calls DMLabelCreateIndex() only if needed */
931 PetscCall(DMLabelGetBounds(label, &pStart, &pEnd));
932 PetscCall(DMLabelMakeAllValid_Private(label));
933 *contains = point >= pStart && point < pEnd && (PetscBTLookup(label->bt, point - label->pStart) ? PETSC_TRUE : PETSC_FALSE);
934 PetscFunctionReturn(PETSC_SUCCESS);
935 }
936
937 /*@
938 DMLabelStratumHasPoint - Return true if the stratum contains a point
939
940 Not Collective
941
942 Input Parameters:
943 + label - the `DMLabel`
944 . value - the stratum value
945 - point - the point
946
947 Output Parameter:
948 . contains - true if the stratum contains the point
949
950 Level: intermediate
951
952 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelSetValue()`, `DMLabelClearValue()`
953 @*/
DMLabelStratumHasPoint(DMLabel label,PetscInt value,PetscInt point,PetscBool * contains)954 PetscErrorCode DMLabelStratumHasPoint(DMLabel label, PetscInt value, PetscInt point, PetscBool *contains)
955 {
956 PetscFunctionBeginHot;
957 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
958 PetscAssertPointer(contains, 4);
959 if (value == label->defaultValue) {
960 PetscInt pointVal;
961
962 PetscCall(DMLabelGetValue(label, point, &pointVal));
963 *contains = (PetscBool)(pointVal == value);
964 } else {
965 PetscInt v;
966
967 PetscCall(DMLabelLookupStratum(label, value, &v));
968 if (v >= 0) {
969 if (label->validIS[v] || label->readonly) {
970 IS is;
971 PetscInt i;
972
973 PetscUseTypeMethod(label, getstratumis, v, &is);
974 PetscCall(ISLocate(is, point, &i));
975 PetscCall(ISDestroy(&is));
976 *contains = (PetscBool)(i >= 0);
977 } else {
978 PetscCall(PetscHSetIHas(label->ht[v], point, contains));
979 }
980 } else { // value is not present
981 *contains = PETSC_FALSE;
982 }
983 }
984 PetscFunctionReturn(PETSC_SUCCESS);
985 }
986
987 /*@
988 DMLabelGetDefaultValue - Get the default value returned by `DMLabelGetValue()` if a point has not been explicitly given a value.
989 When a label is created, it is initialized to -1.
990
991 Not Collective
992
993 Input Parameter:
994 . label - a `DMLabel` object
995
996 Output Parameter:
997 . defaultValue - the default value
998
999 Level: beginner
1000
1001 .seealso: `DMLabel`, `DM`, `DMLabelSetDefaultValue()`, `DMLabelGetValue()`, `DMLabelSetValue()`
1002 @*/
DMLabelGetDefaultValue(DMLabel label,PetscInt * defaultValue)1003 PetscErrorCode DMLabelGetDefaultValue(DMLabel label, PetscInt *defaultValue)
1004 {
1005 PetscFunctionBegin;
1006 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1007 *defaultValue = label->defaultValue;
1008 PetscFunctionReturn(PETSC_SUCCESS);
1009 }
1010
1011 /*@
1012 DMLabelSetDefaultValue - Set the default value returned by `DMLabelGetValue()` if a point has not been explicitly given a value.
1013 When a label is created, it is initialized to -1.
1014
1015 Not Collective
1016
1017 Input Parameter:
1018 . label - a `DMLabel` object
1019
1020 Output Parameter:
1021 . defaultValue - the default value
1022
1023 Level: beginner
1024
1025 .seealso: `DMLabel`, `DM`, `DMLabelGetDefaultValue()`, `DMLabelGetValue()`, `DMLabelSetValue()`
1026 @*/
DMLabelSetDefaultValue(DMLabel label,PetscInt defaultValue)1027 PetscErrorCode DMLabelSetDefaultValue(DMLabel label, PetscInt defaultValue)
1028 {
1029 PetscFunctionBegin;
1030 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1031 label->defaultValue = defaultValue;
1032 PetscFunctionReturn(PETSC_SUCCESS);
1033 }
1034
1035 /*@
1036 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
1037 `DMLabelSetDefaultValue()`)
1038
1039 Not Collective
1040
1041 Input Parameters:
1042 + label - the `DMLabel`
1043 - point - the point
1044
1045 Output Parameter:
1046 . value - The point value, or the default value (-1 by default)
1047
1048 Level: intermediate
1049
1050 Note:
1051 A label may assign multiple values to a point. No guarantees are made about which value is returned in that case.
1052 Use `DMLabelStratumHasPoint()` to check for inclusion in a specific value stratum.
1053
1054 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelSetValue()`, `DMLabelClearValue()`, `DMLabelGetDefaultValue()`, `DMLabelSetDefaultValue()`
1055 @*/
DMLabelGetValue(DMLabel label,PetscInt point,PetscInt * value)1056 PetscErrorCode DMLabelGetValue(DMLabel label, PetscInt point, PetscInt *value)
1057 {
1058 PetscInt v;
1059
1060 PetscFunctionBeginHot;
1061 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1062 PetscAssertPointer(value, 3);
1063 *value = label->defaultValue;
1064 for (v = 0; v < label->numStrata; ++v) {
1065 if (label->validIS[v] || label->readonly) {
1066 IS is;
1067 PetscInt i;
1068
1069 PetscUseTypeMethod(label, getstratumis, v, &is);
1070 PetscCall(ISLocate(label->points[v], point, &i));
1071 PetscCall(ISDestroy(&is));
1072 if (i >= 0) {
1073 *value = label->stratumValues[v];
1074 break;
1075 }
1076 } else {
1077 PetscBool has;
1078
1079 PetscCall(PetscHSetIHas(label->ht[v], point, &has));
1080 if (has) {
1081 *value = label->stratumValues[v];
1082 break;
1083 }
1084 }
1085 }
1086 PetscFunctionReturn(PETSC_SUCCESS);
1087 }
1088
1089 /*@
1090 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
1091 be changed with `DMLabelSetDefaultValue()` to something different), then this function will do nothing.
1092
1093 Not Collective
1094
1095 Input Parameters:
1096 + label - the `DMLabel`
1097 . point - the point
1098 - value - The point value
1099
1100 Level: intermediate
1101
1102 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelClearValue()`, `DMLabelGetDefaultValue()`, `DMLabelSetDefaultValue()`
1103 @*/
DMLabelSetValue(DMLabel label,PetscInt point,PetscInt value)1104 PetscErrorCode DMLabelSetValue(DMLabel label, PetscInt point, PetscInt value)
1105 {
1106 PetscInt v;
1107
1108 PetscFunctionBegin;
1109 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1110 /* Find label value, add new entry if needed */
1111 if (value == label->defaultValue) PetscFunctionReturn(PETSC_SUCCESS);
1112 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1113 PetscCall(DMLabelLookupAddStratum(label, value, &v));
1114 /* Set key */
1115 PetscCall(DMLabelMakeInvalid_Private(label, v));
1116 PetscCall(PetscHSetIAdd(label->ht[v], point));
1117 PetscFunctionReturn(PETSC_SUCCESS);
1118 }
1119
1120 /*@
1121 DMLabelClearValue - Clear the value a label assigns to a point
1122
1123 Not Collective
1124
1125 Input Parameters:
1126 + label - the `DMLabel`
1127 . point - the point
1128 - value - The point value
1129
1130 Level: intermediate
1131
1132 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`
1133 @*/
DMLabelClearValue(DMLabel label,PetscInt point,PetscInt value)1134 PetscErrorCode DMLabelClearValue(DMLabel label, PetscInt point, PetscInt value)
1135 {
1136 PetscInt v;
1137
1138 PetscFunctionBegin;
1139 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1140 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1141 /* Find label value */
1142 PetscCall(DMLabelLookupStratum(label, value, &v));
1143 if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1144
1145 if (label->bt && point >= label->pStart && point < label->pEnd) PetscCall(PetscBTClear(label->bt, point - label->pStart));
1146
1147 /* Delete key */
1148 PetscCall(DMLabelMakeInvalid_Private(label, v));
1149 PetscCall(PetscHSetIDel(label->ht[v], point));
1150 PetscFunctionReturn(PETSC_SUCCESS);
1151 }
1152
1153 /*@
1154 DMLabelInsertIS - Set all points in the `IS` to a value
1155
1156 Not Collective
1157
1158 Input Parameters:
1159 + label - the `DMLabel`
1160 . is - the point `IS`
1161 - value - The point value
1162
1163 Level: intermediate
1164
1165 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1166 @*/
DMLabelInsertIS(DMLabel label,IS is,PetscInt value)1167 PetscErrorCode DMLabelInsertIS(DMLabel label, IS is, PetscInt value)
1168 {
1169 PetscInt v, n, p;
1170 const PetscInt *points;
1171
1172 PetscFunctionBegin;
1173 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1174 PetscValidHeaderSpecific(is, IS_CLASSID, 2);
1175 /* Find label value, add new entry if needed */
1176 if (value == label->defaultValue) PetscFunctionReturn(PETSC_SUCCESS);
1177 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1178 PetscCall(DMLabelLookupAddStratum(label, value, &v));
1179 /* Set keys */
1180 PetscCall(DMLabelMakeInvalid_Private(label, v));
1181 PetscCall(ISGetLocalSize(is, &n));
1182 PetscCall(ISGetIndices(is, &points));
1183 for (p = 0; p < n; ++p) PetscCall(PetscHSetIAdd(label->ht[v], points[p]));
1184 PetscCall(ISRestoreIndices(is, &points));
1185 PetscFunctionReturn(PETSC_SUCCESS);
1186 }
1187
1188 /*@
1189 DMLabelGetNumValues - Get the number of values that the `DMLabel` takes
1190
1191 Not Collective
1192
1193 Input Parameter:
1194 . label - the `DMLabel`
1195
1196 Output Parameter:
1197 . numValues - the number of values
1198
1199 Level: intermediate
1200
1201 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1202 @*/
DMLabelGetNumValues(DMLabel label,PetscInt * numValues)1203 PetscErrorCode DMLabelGetNumValues(DMLabel label, PetscInt *numValues)
1204 {
1205 PetscFunctionBegin;
1206 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1207 PetscAssertPointer(numValues, 2);
1208 *numValues = label->numStrata;
1209 PetscFunctionReturn(PETSC_SUCCESS);
1210 }
1211
1212 /*@
1213 DMLabelGetValueIS - Get an `IS` of all values that the `DMlabel` takes
1214
1215 Not Collective
1216
1217 Input Parameter:
1218 . label - the `DMLabel`
1219
1220 Output Parameter:
1221 . values - the value `IS`
1222
1223 Level: intermediate
1224
1225 Notes:
1226 The `values` should be destroyed when no longer needed.
1227
1228 Strata which are allocated but empty [`DMLabelGetStratumSize()` yields 0] are counted.
1229
1230 If you need to count only nonempty strata, use `DMLabelGetNonEmptyStratumValuesIS()`.
1231
1232 .seealso: `DMLabel`, `DM`, `DMLabelGetNonEmptyStratumValuesIS()`, `DMLabelGetValueISGlobal()`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1233 @*/
DMLabelGetValueIS(DMLabel label,IS * values)1234 PetscErrorCode DMLabelGetValueIS(DMLabel label, IS *values)
1235 {
1236 PetscFunctionBegin;
1237 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1238 PetscAssertPointer(values, 2);
1239 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, label->numStrata, label->stratumValues, PETSC_USE_POINTER, values));
1240 PetscFunctionReturn(PETSC_SUCCESS);
1241 }
1242
1243 /*@
1244 DMLabelGetValueBounds - Return the smallest and largest value in the label
1245
1246 Not Collective
1247
1248 Input Parameter:
1249 . label - the `DMLabel`
1250
1251 Output Parameters:
1252 + minValue - The smallest value
1253 - maxValue - The largest value
1254
1255 Level: intermediate
1256
1257 .seealso: `DMLabel`, `DM`, `DMLabelGetBounds()`, `DMLabelGetValue()`, `DMLabelSetValue()`
1258 @*/
DMLabelGetValueBounds(DMLabel label,PetscInt * minValue,PetscInt * maxValue)1259 PetscErrorCode DMLabelGetValueBounds(DMLabel label, PetscInt *minValue, PetscInt *maxValue)
1260 {
1261 PetscInt min = PETSC_INT_MAX, max = PETSC_INT_MIN;
1262
1263 PetscFunctionBegin;
1264 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1265 for (PetscInt v = 0; v < label->numStrata; ++v) {
1266 min = PetscMin(min, label->stratumValues[v]);
1267 max = PetscMax(max, label->stratumValues[v]);
1268 }
1269 if (minValue) {
1270 PetscAssertPointer(minValue, 2);
1271 *minValue = min;
1272 }
1273 if (maxValue) {
1274 PetscAssertPointer(maxValue, 3);
1275 *maxValue = max;
1276 }
1277 PetscFunctionReturn(PETSC_SUCCESS);
1278 }
1279
1280 /*@
1281 DMLabelGetNonEmptyStratumValuesIS - Get an `IS` of all values that the `DMlabel` takes
1282
1283 Not Collective
1284
1285 Input Parameter:
1286 . label - the `DMLabel`
1287
1288 Output Parameter:
1289 . values - the value `IS`
1290
1291 Level: intermediate
1292
1293 Notes:
1294 The `values` should be destroyed when no longer needed.
1295
1296 This is similar to `DMLabelGetValueIS()` but counts only nonempty strata.
1297
1298 .seealso: `DMLabel`, `DM`, `DMLabelGetValueIS()`, `DMLabelGetValueISGlobal()`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1299 @*/
DMLabelGetNonEmptyStratumValuesIS(DMLabel label,IS * values)1300 PetscErrorCode DMLabelGetNonEmptyStratumValuesIS(DMLabel label, IS *values)
1301 {
1302 PetscInt i, j;
1303 PetscInt *valuesArr;
1304
1305 PetscFunctionBegin;
1306 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1307 PetscAssertPointer(values, 2);
1308 PetscCall(PetscMalloc1(label->numStrata, &valuesArr));
1309 for (i = 0, j = 0; i < label->numStrata; i++) {
1310 PetscInt n;
1311
1312 PetscCall(DMLabelGetStratumSize_Private(label, i, &n));
1313 if (n) valuesArr[j++] = label->stratumValues[i];
1314 }
1315 if (j == label->numStrata) {
1316 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, label->numStrata, label->stratumValues, PETSC_USE_POINTER, values));
1317 } else {
1318 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, j, valuesArr, PETSC_COPY_VALUES, values));
1319 }
1320 PetscCall(PetscFree(valuesArr));
1321 PetscFunctionReturn(PETSC_SUCCESS);
1322 }
1323
1324 /*@
1325 DMLabelGetValueISGlobal - Get an `IS` of all values that the `DMlabel` takes across all ranks
1326
1327 Collective
1328
1329 Input Parameter:
1330 + comm - MPI communicator to collect values
1331 . label - the `DMLabel`, may be `NULL` for ranks in `comm` which do not have the corresponding `DMLabel`
1332 - get_nonempty - whether to get nonempty stratum values (akin to `DMLabelGetNonEmptyStratumValuesIS()`)
1333
1334 Output Parameter:
1335 . values - the value `IS`
1336
1337 Level: intermediate
1338
1339 Notes:
1340 The `values` should be destroyed when no longer needed.
1341
1342 This is similar to `DMLabelGetValueIS()` and `DMLabelGetNonEmptyStratumValuesIS()`, but gets the (nonempty) values across all ranks in `comm`.
1343
1344 .seealso: `DMLabel`, `DM`, `DMLabelGetValueIS()`, `DMLabelGetNonEmptyStratumValuesIS()`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1345 @*/
DMLabelGetValueISGlobal(MPI_Comm comm,DMLabel label,PetscBool get_nonempty,IS * values)1346 PetscErrorCode DMLabelGetValueISGlobal(MPI_Comm comm, DMLabel label, PetscBool get_nonempty, IS *values)
1347 {
1348 PetscInt num_values_local = 0, num_values_global, minmax_values[2], minmax_values_loc[2] = {PETSC_INT_MAX, PETSC_INT_MIN};
1349 IS is_values = NULL;
1350 const PetscInt *values_local = NULL;
1351 PetscInt *values_global;
1352
1353 PetscFunctionBegin;
1354 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
1355 if (PetscDefined(USE_DEBUG)) {
1356 // Shenanigans because PetscValidLogicalCollectiveBool must have a PetscObject to get a MPI_Comm from, but there is no such object in this function (generally, DMLabel is only PETSC_COMM_SELF)
1357 IS dummy;
1358 PetscCall(ISCreate(comm, &dummy));
1359 PetscValidLogicalCollectiveBool(dummy, get_nonempty, 3);
1360 PetscCall(ISDestroy(&dummy));
1361 }
1362 PetscAssertPointer(values, 4);
1363
1364 if (label) {
1365 if (get_nonempty) PetscCall(DMLabelGetNonEmptyStratumValuesIS(label, &is_values));
1366 else PetscCall(DMLabelGetValueIS(label, &is_values));
1367 PetscCall(ISGetIndices(is_values, &values_local));
1368 PetscCall(ISGetLocalSize(is_values, &num_values_local));
1369 }
1370 for (PetscInt i = 0; i < num_values_local; i++) {
1371 minmax_values_loc[0] = PetscMin(minmax_values_loc[0], values_local[i]);
1372 minmax_values_loc[1] = PetscMax(minmax_values_loc[1], values_local[i]);
1373 }
1374
1375 PetscCall(PetscGlobalMinMaxInt(comm, minmax_values_loc, minmax_values));
1376 PetscInt value_range = minmax_values[1] - minmax_values[0] + 1;
1377 PetscBT local_values_bt, global_values_bt;
1378
1379 // Create a "ballot" where each rank marks which values they have into the PetscBT.
1380 // An Allreduce using bitwise-OR over the ranks then communicates which values are owned by a rank in comm
1381 PetscCall(PetscBTCreate(value_range, &local_values_bt));
1382 PetscCall(PetscBTCreate(value_range, &global_values_bt));
1383 for (PetscInt i = 0; i < num_values_local; i++) PetscCall(PetscBTSet(local_values_bt, values_local[i] - minmax_values[0]));
1384 PetscCallMPI(MPIU_Allreduce(local_values_bt, global_values_bt, PetscBTLength(value_range), MPI_CHAR, MPI_BOR, comm));
1385 PetscCall(PetscBTDestroy(&local_values_bt));
1386 {
1387 PetscCount num_values_global_count;
1388 num_values_global_count = PetscBTCountSet(global_values_bt, value_range);
1389 PetscCall(PetscIntCast(num_values_global_count, &num_values_global));
1390 }
1391
1392 PetscCall(PetscMalloc1(num_values_global, &values_global));
1393 for (PetscInt i = 0, a = 0; i < value_range; i++) {
1394 if (PetscBTLookup(global_values_bt, i)) {
1395 values_global[a] = i + minmax_values[0];
1396 a++;
1397 }
1398 }
1399 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, num_values_global, values_global, PETSC_OWN_POINTER, values));
1400
1401 PetscCall(PetscBTDestroy(&global_values_bt));
1402 if (is_values) {
1403 PetscCall(ISRestoreIndices(is_values, &values_local));
1404 PetscCall(ISDestroy(&is_values));
1405 }
1406 PetscFunctionReturn(PETSC_SUCCESS);
1407 }
1408
1409 /*@
1410 DMLabelGetValueIndex - Get the index of a given value in the list of values for the `DMlabel`, or -1 if it is not present
1411
1412 Not Collective
1413
1414 Input Parameters:
1415 + label - the `DMLabel`
1416 - value - the value
1417
1418 Output Parameter:
1419 . index - the index of value in the list of values
1420
1421 Level: intermediate
1422
1423 .seealso: `DMLabel`, `DM`, `DMLabelGetValueIS()`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1424 @*/
DMLabelGetValueIndex(DMLabel label,PetscInt value,PetscInt * index)1425 PetscErrorCode DMLabelGetValueIndex(DMLabel label, PetscInt value, PetscInt *index)
1426 {
1427 PetscInt v;
1428
1429 PetscFunctionBegin;
1430 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1431 PetscAssertPointer(index, 3);
1432 /* Do not assume they are sorted */
1433 for (v = 0; v < label->numStrata; ++v)
1434 if (label->stratumValues[v] == value) break;
1435 if (v >= label->numStrata) *index = -1;
1436 else *index = v;
1437 PetscFunctionReturn(PETSC_SUCCESS);
1438 }
1439
1440 /*@
1441 DMLabelHasStratum - Determine whether points exist with the given value
1442
1443 Not Collective
1444
1445 Input Parameters:
1446 + label - the `DMLabel`
1447 - value - the stratum value
1448
1449 Output Parameter:
1450 . exists - Flag saying whether points exist
1451
1452 Level: intermediate
1453
1454 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1455 @*/
DMLabelHasStratum(DMLabel label,PetscInt value,PetscBool * exists)1456 PetscErrorCode DMLabelHasStratum(DMLabel label, PetscInt value, PetscBool *exists)
1457 {
1458 PetscInt v;
1459
1460 PetscFunctionBegin;
1461 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1462 PetscAssertPointer(exists, 3);
1463 PetscCall(DMLabelLookupStratum(label, value, &v));
1464 *exists = v < 0 ? PETSC_FALSE : PETSC_TRUE;
1465 PetscFunctionReturn(PETSC_SUCCESS);
1466 }
1467
1468 /*@
1469 DMLabelGetStratumSize - Get the size of a stratum
1470
1471 Not Collective
1472
1473 Input Parameters:
1474 + label - the `DMLabel`
1475 - value - the stratum value
1476
1477 Output Parameter:
1478 . size - The number of points in the stratum
1479
1480 Level: intermediate
1481
1482 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1483 @*/
DMLabelGetStratumSize(DMLabel label,PetscInt value,PetscInt * size)1484 PetscErrorCode DMLabelGetStratumSize(DMLabel label, PetscInt value, PetscInt *size)
1485 {
1486 PetscInt v;
1487
1488 PetscFunctionBegin;
1489 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1490 PetscAssertPointer(size, 3);
1491 PetscCall(DMLabelLookupStratum(label, value, &v));
1492 PetscCall(DMLabelGetStratumSize_Private(label, v, size));
1493 PetscFunctionReturn(PETSC_SUCCESS);
1494 }
1495
1496 /*@
1497 DMLabelGetStratumBounds - Get the largest and smallest point of a stratum
1498
1499 Not Collective
1500
1501 Input Parameters:
1502 + label - the `DMLabel`
1503 - value - the stratum value
1504
1505 Output Parameters:
1506 + start - the smallest point in the stratum
1507 - end - the largest point in the stratum
1508
1509 Level: intermediate
1510
1511 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1512 @*/
DMLabelGetStratumBounds(DMLabel label,PetscInt value,PetscInt * start,PetscInt * end)1513 PetscErrorCode DMLabelGetStratumBounds(DMLabel label, PetscInt value, PetscInt *start, PetscInt *end)
1514 {
1515 IS is;
1516 PetscInt v, min, max;
1517
1518 PetscFunctionBegin;
1519 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1520 if (start) {
1521 PetscAssertPointer(start, 3);
1522 *start = -1;
1523 }
1524 if (end) {
1525 PetscAssertPointer(end, 4);
1526 *end = -1;
1527 }
1528 PetscCall(DMLabelLookupStratum(label, value, &v));
1529 if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1530 PetscCall(DMLabelMakeValid_Private(label, v));
1531 if (label->stratumSizes[v] <= 0) PetscFunctionReturn(PETSC_SUCCESS);
1532 PetscUseTypeMethod(label, getstratumis, v, &is);
1533 PetscCall(ISGetMinMax(is, &min, &max));
1534 PetscCall(ISDestroy(&is));
1535 if (start) *start = min;
1536 if (end) *end = max + 1;
1537 PetscFunctionReturn(PETSC_SUCCESS);
1538 }
1539
DMLabelGetStratumIS_Concrete(DMLabel label,PetscInt v,IS * pointIS)1540 static PetscErrorCode DMLabelGetStratumIS_Concrete(DMLabel label, PetscInt v, IS *pointIS)
1541 {
1542 PetscFunctionBegin;
1543 PetscCall(PetscObjectReference((PetscObject)label->points[v]));
1544 *pointIS = label->points[v];
1545 PetscFunctionReturn(PETSC_SUCCESS);
1546 }
1547
1548 /*@
1549 DMLabelGetStratumIS - Get an `IS` with the stratum points
1550
1551 Not Collective
1552
1553 Input Parameters:
1554 + label - the `DMLabel`
1555 - value - the stratum value
1556
1557 Output Parameter:
1558 . points - The stratum points
1559
1560 Level: intermediate
1561
1562 Notes:
1563 The output `IS` should be destroyed when no longer needed.
1564 Returns `NULL` if the stratum is empty.
1565
1566 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1567 @*/
DMLabelGetStratumIS(DMLabel label,PetscInt value,IS * points)1568 PetscErrorCode DMLabelGetStratumIS(DMLabel label, PetscInt value, IS *points)
1569 {
1570 PetscInt v;
1571
1572 PetscFunctionBegin;
1573 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1574 PetscAssertPointer(points, 3);
1575 *points = NULL;
1576 PetscCall(DMLabelLookupStratum(label, value, &v));
1577 if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1578 PetscCall(DMLabelMakeValid_Private(label, v));
1579 PetscUseTypeMethod(label, getstratumis, v, points);
1580 PetscFunctionReturn(PETSC_SUCCESS);
1581 }
1582
1583 /*@
1584 DMLabelSetStratumIS - Set the stratum points using an `IS`
1585
1586 Not Collective
1587
1588 Input Parameters:
1589 + label - the `DMLabel`
1590 . value - the stratum value
1591 - is - The stratum points
1592
1593 Level: intermediate
1594
1595 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1596 @*/
DMLabelSetStratumIS(DMLabel label,PetscInt value,IS is)1597 PetscErrorCode DMLabelSetStratumIS(DMLabel label, PetscInt value, IS is)
1598 {
1599 PetscInt v;
1600
1601 PetscFunctionBegin;
1602 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1603 PetscValidHeaderSpecific(is, IS_CLASSID, 3);
1604 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1605 PetscCall(DMLabelLookupAddStratum(label, value, &v));
1606 if (is == label->points[v]) PetscFunctionReturn(PETSC_SUCCESS);
1607 PetscCall(DMLabelClearStratum(label, value));
1608 PetscCall(ISGetLocalSize(is, &label->stratumSizes[v]));
1609 PetscCall(PetscObjectReference((PetscObject)is));
1610 PetscCall(ISDestroy(&label->points[v]));
1611 label->points[v] = is;
1612 label->validIS[v] = PETSC_TRUE;
1613 PetscCall(PetscObjectStateIncrease((PetscObject)label));
1614 if (label->bt) {
1615 const PetscInt *points;
1616 PetscInt p;
1617
1618 PetscCall(ISGetIndices(is, &points));
1619 for (p = 0; p < label->stratumSizes[v]; ++p) {
1620 const PetscInt point = points[p];
1621
1622 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);
1623 PetscCall(PetscBTSet(label->bt, point - label->pStart));
1624 }
1625 }
1626 PetscFunctionReturn(PETSC_SUCCESS);
1627 }
1628
1629 /*@
1630 DMLabelClearStratum - Remove a stratum
1631
1632 Not Collective
1633
1634 Input Parameters:
1635 + label - the `DMLabel`
1636 - value - the stratum value
1637
1638 Level: intermediate
1639
1640 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1641 @*/
DMLabelClearStratum(DMLabel label,PetscInt value)1642 PetscErrorCode DMLabelClearStratum(DMLabel label, PetscInt value)
1643 {
1644 PetscInt v;
1645
1646 PetscFunctionBegin;
1647 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1648 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1649 PetscCall(DMLabelLookupStratum(label, value, &v));
1650 if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1651 if (label->validIS[v]) {
1652 if (label->bt) {
1653 PetscInt i;
1654 const PetscInt *points;
1655
1656 PetscCall(ISGetIndices(label->points[v], &points));
1657 for (i = 0; i < label->stratumSizes[v]; ++i) {
1658 const PetscInt point = points[i];
1659
1660 if (point >= label->pStart && point < label->pEnd) PetscCall(PetscBTClear(label->bt, point - label->pStart));
1661 }
1662 PetscCall(ISRestoreIndices(label->points[v], &points));
1663 }
1664 label->stratumSizes[v] = 0;
1665 PetscCall(ISDestroy(&label->points[v]));
1666 PetscCall(ISCreateStride(PETSC_COMM_SELF, 0, 0, 1, &label->points[v]));
1667 PetscCall(PetscObjectSetName((PetscObject)label->points[v], "indices"));
1668 PetscCall(PetscObjectStateIncrease((PetscObject)label));
1669 } else {
1670 PetscCall(PetscHSetIClear(label->ht[v]));
1671 }
1672 PetscFunctionReturn(PETSC_SUCCESS);
1673 }
1674
1675 /*@
1676 DMLabelSetStratumBounds - Efficiently give a contiguous set of points a given label value
1677
1678 Not Collective
1679
1680 Input Parameters:
1681 + label - The `DMLabel`
1682 . value - The label value for all points
1683 . pStart - The first point
1684 - pEnd - A point beyond all marked points
1685
1686 Level: intermediate
1687
1688 Note:
1689 The marks points are [`pStart`, `pEnd`), and only the bounds are stored.
1690
1691 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelSetStratumIS()`, `DMLabelGetStratumIS()`
1692 @*/
DMLabelSetStratumBounds(DMLabel label,PetscInt value,PetscInt pStart,PetscInt pEnd)1693 PetscErrorCode DMLabelSetStratumBounds(DMLabel label, PetscInt value, PetscInt pStart, PetscInt pEnd)
1694 {
1695 IS pIS;
1696
1697 PetscFunctionBegin;
1698 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd - pStart, pStart, 1, &pIS));
1699 PetscCall(DMLabelSetStratumIS(label, value, pIS));
1700 PetscCall(ISDestroy(&pIS));
1701 PetscFunctionReturn(PETSC_SUCCESS);
1702 }
1703
1704 /*@
1705 DMLabelGetStratumPointIndex - Get the index of a point in a given stratum
1706
1707 Not Collective
1708
1709 Input Parameters:
1710 + label - The `DMLabel`
1711 . value - The label value
1712 - p - A point with this value
1713
1714 Output Parameter:
1715 . 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
1716
1717 Level: intermediate
1718
1719 .seealso: `DMLabel`, `DM`, `DMLabelGetValueIndex()`, `DMLabelGetStratumIS()`, `DMLabelCreate()`
1720 @*/
DMLabelGetStratumPointIndex(DMLabel label,PetscInt value,PetscInt p,PetscInt * index)1721 PetscErrorCode DMLabelGetStratumPointIndex(DMLabel label, PetscInt value, PetscInt p, PetscInt *index)
1722 {
1723 IS pointIS;
1724 PetscInt v;
1725
1726 PetscFunctionBegin;
1727 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1728 PetscAssertPointer(index, 4);
1729 *index = -1;
1730 PetscCall(DMLabelLookupStratum(label, value, &v));
1731 if (v < 0) PetscFunctionReturn(PETSC_SUCCESS);
1732 PetscCall(DMLabelMakeValid_Private(label, v));
1733 PetscUseTypeMethod(label, getstratumis, v, &pointIS);
1734 PetscCall(ISLocate(pointIS, p, index));
1735 PetscCall(ISDestroy(&pointIS));
1736 PetscFunctionReturn(PETSC_SUCCESS);
1737 }
1738
1739 /*@
1740 DMLabelFilter - Remove all points outside of [`start`, `end`)
1741
1742 Not Collective
1743
1744 Input Parameters:
1745 + label - the `DMLabel`
1746 . start - the first point kept
1747 - end - one more than the last point kept
1748
1749 Level: intermediate
1750
1751 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1752 @*/
DMLabelFilter(DMLabel label,PetscInt start,PetscInt end)1753 PetscErrorCode DMLabelFilter(DMLabel label, PetscInt start, PetscInt end)
1754 {
1755 PetscInt v;
1756
1757 PetscFunctionBegin;
1758 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1759 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1760 PetscCall(DMLabelDestroyIndex(label));
1761 PetscCall(DMLabelMakeAllValid_Private(label));
1762 for (v = 0; v < label->numStrata; ++v) {
1763 PetscCall(ISGeneralFilter(label->points[v], start, end));
1764 PetscCall(ISGetLocalSize(label->points[v], &label->stratumSizes[v]));
1765 }
1766 PetscCall(DMLabelCreateIndex(label, start, end));
1767 PetscFunctionReturn(PETSC_SUCCESS);
1768 }
1769
1770 /*@
1771 DMLabelPermute - Create a new label with permuted points
1772
1773 Not Collective
1774
1775 Input Parameters:
1776 + label - the `DMLabel`
1777 - permutation - the point permutation
1778
1779 Output Parameter:
1780 . labelNew - the new label containing the permuted points
1781
1782 Level: intermediate
1783
1784 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1785 @*/
DMLabelPermute(DMLabel label,IS permutation,DMLabel * labelNew)1786 PetscErrorCode DMLabelPermute(DMLabel label, IS permutation, DMLabel *labelNew)
1787 {
1788 const PetscInt *perm;
1789 PetscInt numValues, numPoints, v, q;
1790
1791 PetscFunctionBegin;
1792 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1793 PetscValidHeaderSpecific(permutation, IS_CLASSID, 2);
1794 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
1795 PetscCall(DMLabelMakeAllValid_Private(label));
1796 PetscCall(DMLabelDuplicate(label, labelNew));
1797 PetscCall(DMLabelGetNumValues(*labelNew, &numValues));
1798 PetscCall(ISGetLocalSize(permutation, &numPoints));
1799 PetscCall(ISGetIndices(permutation, &perm));
1800 for (v = 0; v < numValues; ++v) {
1801 const PetscInt size = (*labelNew)->stratumSizes[v];
1802 const PetscInt *points;
1803 PetscInt *pointsNew;
1804
1805 PetscCall(ISGetIndices((*labelNew)->points[v], &points));
1806 PetscCall(PetscCalloc1(size, &pointsNew));
1807 for (q = 0; q < size; ++q) {
1808 const PetscInt point = points[q];
1809
1810 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);
1811 pointsNew[q] = perm[point];
1812 }
1813 PetscCall(ISRestoreIndices((*labelNew)->points[v], &points));
1814 PetscCall(PetscSortInt(size, pointsNew));
1815 PetscCall(ISDestroy(&(*labelNew)->points[v]));
1816 if (size > 0 && pointsNew[size - 1] == pointsNew[0] + size - 1) {
1817 PetscCall(ISCreateStride(PETSC_COMM_SELF, size, pointsNew[0], 1, &((*labelNew)->points[v])));
1818 PetscCall(PetscFree(pointsNew));
1819 } else {
1820 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, pointsNew, PETSC_OWN_POINTER, &((*labelNew)->points[v])));
1821 }
1822 PetscCall(PetscObjectSetName((PetscObject)((*labelNew)->points[v]), "indices"));
1823 }
1824 PetscCall(ISRestoreIndices(permutation, &perm));
1825 if (label->bt) {
1826 PetscCall(PetscBTDestroy(&label->bt));
1827 PetscCall(DMLabelCreateIndex(label, label->pStart, label->pEnd));
1828 }
1829 PetscFunctionReturn(PETSC_SUCCESS);
1830 }
1831
1832 /*@
1833 DMLabelPermuteValues - Permute the values in a label
1834
1835 Not collective
1836
1837 Input Parameters:
1838 + label - the `DMLabel`
1839 - permutation - the value permutation, permutation[old value] = new value
1840
1841 Output Parameter:
1842 . label - the `DMLabel` now with permuted values
1843
1844 Note:
1845 The modification is done in-place
1846
1847 Level: intermediate
1848
1849 .seealso: `DMLabelRewriteValues()`, `DMLabel`, `DM`, `DMLabelPermute()`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1850 @*/
DMLabelPermuteValues(DMLabel label,IS permutation)1851 PetscErrorCode DMLabelPermuteValues(DMLabel label, IS permutation)
1852 {
1853 PetscInt Nv, Np;
1854
1855 PetscFunctionBegin;
1856 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1857 PetscValidHeaderSpecific(permutation, IS_CLASSID, 2);
1858 PetscCall(DMLabelGetNumValues(label, &Nv));
1859 PetscCall(ISGetLocalSize(permutation, &Np));
1860 PetscCheck(Np == Nv, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_SIZ, "Permutation has size %" PetscInt_FMT " != %" PetscInt_FMT " number of label values", Np, Nv);
1861 if (PetscDefined(USE_DEBUG)) {
1862 PetscBool flg;
1863 PetscCall(ISGetInfo(permutation, IS_PERMUTATION, IS_LOCAL, PETSC_TRUE, &flg));
1864 PetscCheck(flg, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "IS is not a permutation");
1865 }
1866 PetscCall(DMLabelRewriteValues(label, permutation));
1867 PetscFunctionReturn(PETSC_SUCCESS);
1868 }
1869
1870 /*@
1871 DMLabelRewriteValues - Permute the values in a label, but some may be omitted
1872
1873 Not collective
1874
1875 Input Parameters:
1876 + label - the `DMLabel`
1877 - permutation - the value permutation, permutation[old value] = new value, but some maybe omitted
1878
1879 Output Parameter:
1880 . label - the `DMLabel` now with permuted values
1881
1882 Note:
1883 The modification is done in-place
1884
1885 Level: intermediate
1886
1887 .seealso: `DMLabelPermuteValues()`, `DMLabel`, `DM`, `DMLabelPermute()`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1888 @*/
DMLabelRewriteValues(DMLabel label,IS permutation)1889 PetscErrorCode DMLabelRewriteValues(DMLabel label, IS permutation)
1890 {
1891 const PetscInt *perm;
1892 PetscInt Nv, Np;
1893
1894 PetscFunctionBegin;
1895 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
1896 PetscValidHeaderSpecific(permutation, IS_CLASSID, 2);
1897 PetscCall(DMLabelMakeAllValid_Private(label));
1898 PetscCall(DMLabelGetNumValues(label, &Nv));
1899 PetscCall(ISGetLocalSize(permutation, &Np));
1900 PetscCheck(Np >= Nv, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_SIZ, "Permutation has size %" PetscInt_FMT " < %" PetscInt_FMT " number of label values", Np, Nv);
1901 PetscCall(ISGetIndices(permutation, &perm));
1902 for (PetscInt v = 0; v < Nv; ++v) label->stratumValues[v] = perm[label->stratumValues[v]];
1903 PetscCall(ISRestoreIndices(permutation, &perm));
1904 PetscFunctionReturn(PETSC_SUCCESS);
1905 }
1906
DMLabelDistribute_Internal(DMLabel label,PetscSF sf,PetscSection * leafSection,PetscInt ** leafStrata)1907 static PetscErrorCode DMLabelDistribute_Internal(DMLabel label, PetscSF sf, PetscSection *leafSection, PetscInt **leafStrata)
1908 {
1909 MPI_Comm comm;
1910 PetscInt s, l, nroots, nleaves, offset, size;
1911 PetscInt *remoteOffsets, *rootStrata, *rootIdx;
1912 PetscSection rootSection;
1913 PetscSF labelSF;
1914
1915 PetscFunctionBegin;
1916 if (label) PetscCall(DMLabelMakeAllValid_Private(label));
1917 PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
1918 /* Build a section of stratum values per point, generate the according SF
1919 and distribute point-wise stratum values to leaves. */
1920 PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, NULL, NULL));
1921 PetscCall(PetscSectionCreate(comm, &rootSection));
1922 PetscCall(PetscSectionSetChart(rootSection, 0, nroots));
1923 if (label) {
1924 for (s = 0; s < label->numStrata; ++s) {
1925 const PetscInt *points;
1926
1927 PetscCall(ISGetIndices(label->points[s], &points));
1928 for (l = 0; l < label->stratumSizes[s]; l++) PetscCall(PetscSectionAddDof(rootSection, points[l], 1));
1929 PetscCall(ISRestoreIndices(label->points[s], &points));
1930 }
1931 }
1932 PetscCall(PetscSectionSetUp(rootSection));
1933 /* Create a point-wise array of stratum values */
1934 PetscCall(PetscSectionGetStorageSize(rootSection, &size));
1935 PetscCall(PetscMalloc1(size, &rootStrata));
1936 PetscCall(PetscCalloc1(nroots, &rootIdx));
1937 if (label) {
1938 for (s = 0; s < label->numStrata; ++s) {
1939 const PetscInt *points;
1940
1941 PetscCall(ISGetIndices(label->points[s], &points));
1942 for (l = 0; l < label->stratumSizes[s]; l++) {
1943 const PetscInt p = points[l];
1944 PetscCall(PetscSectionGetOffset(rootSection, p, &offset));
1945 rootStrata[offset + rootIdx[p]++] = label->stratumValues[s];
1946 }
1947 PetscCall(ISRestoreIndices(label->points[s], &points));
1948 }
1949 }
1950 /* Build SF that maps label points to remote processes */
1951 PetscCall(PetscSectionCreate(comm, leafSection));
1952 PetscCall(PetscSFDistributeSection(sf, rootSection, &remoteOffsets, *leafSection));
1953 PetscCall(PetscSFCreateSectionSF(sf, rootSection, remoteOffsets, *leafSection, &labelSF));
1954 PetscCall(PetscFree(remoteOffsets));
1955 /* Send the strata for each point over the derived SF */
1956 PetscCall(PetscSectionGetStorageSize(*leafSection, &size));
1957 PetscCall(PetscMalloc1(size, leafStrata));
1958 PetscCall(PetscSFBcastBegin(labelSF, MPIU_INT, rootStrata, *leafStrata, MPI_REPLACE));
1959 PetscCall(PetscSFBcastEnd(labelSF, MPIU_INT, rootStrata, *leafStrata, MPI_REPLACE));
1960 /* Clean up */
1961 PetscCall(PetscFree(rootStrata));
1962 PetscCall(PetscFree(rootIdx));
1963 PetscCall(PetscSectionDestroy(&rootSection));
1964 PetscCall(PetscSFDestroy(&labelSF));
1965 PetscFunctionReturn(PETSC_SUCCESS);
1966 }
1967
1968 /*@
1969 DMLabelDistribute - Create a new label pushed forward over the `PetscSF`
1970
1971 Collective
1972
1973 Input Parameters:
1974 + label - the `DMLabel`
1975 - sf - the map from old to new distribution
1976
1977 Output Parameter:
1978 . labelNew - the new redistributed label
1979
1980 Level: intermediate
1981
1982 .seealso: `DMLabel`, `DM`, `DMLabelCreate()`, `DMLabelGetValue()`, `DMLabelSetValue()`, `DMLabelClearValue()`
1983 @*/
DMLabelDistribute(DMLabel label,PetscSF sf,DMLabel * labelNew)1984 PetscErrorCode DMLabelDistribute(DMLabel label, PetscSF sf, DMLabel *labelNew)
1985 {
1986 MPI_Comm comm;
1987 PetscSection leafSection;
1988 PetscInt p, pStart, pEnd, s, size, dof, offset, stratum;
1989 PetscInt *leafStrata, *strataIdx;
1990 PetscInt **points;
1991 const char *lname = NULL;
1992 char *name;
1993 PetscMPIInt nameSize;
1994 PetscHSetI stratumHash;
1995 size_t len = 0;
1996 PetscMPIInt rank;
1997
1998 PetscFunctionBegin;
1999 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
2000 if (label) {
2001 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
2002 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
2003 PetscCall(DMLabelMakeAllValid_Private(label));
2004 }
2005 PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
2006 PetscCallMPI(MPI_Comm_rank(comm, &rank));
2007 /* Bcast name */
2008 if (rank == 0) {
2009 PetscCall(PetscObjectGetName((PetscObject)label, &lname));
2010 PetscCall(PetscStrlen(lname, &len));
2011 }
2012 PetscCall(PetscMPIIntCast(len, &nameSize));
2013 PetscCallMPI(MPI_Bcast(&nameSize, 1, MPI_INT, 0, comm));
2014 PetscCall(PetscMalloc1(nameSize + 1, &name));
2015 if (rank == 0) PetscCall(PetscArraycpy(name, lname, nameSize + 1));
2016 PetscCallMPI(MPI_Bcast(name, nameSize + 1, MPI_CHAR, 0, comm));
2017 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, labelNew));
2018 PetscCall(PetscFree(name));
2019 /* Bcast defaultValue */
2020 if (rank == 0) (*labelNew)->defaultValue = label->defaultValue;
2021 PetscCallMPI(MPI_Bcast(&(*labelNew)->defaultValue, 1, MPIU_INT, 0, comm));
2022 /* Distribute stratum values over the SF and get the point mapping on the receiver */
2023 PetscCall(DMLabelDistribute_Internal(label, sf, &leafSection, &leafStrata));
2024 /* Determine received stratum values and initialise new label*/
2025 PetscCall(PetscHSetICreate(&stratumHash));
2026 PetscCall(PetscSectionGetStorageSize(leafSection, &size));
2027 for (p = 0; p < size; ++p) PetscCall(PetscHSetIAdd(stratumHash, leafStrata[p]));
2028 PetscCall(PetscHSetIGetSize(stratumHash, &(*labelNew)->numStrata));
2029 PetscCall(PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->validIS));
2030 for (s = 0; s < (*labelNew)->numStrata; ++s) (*labelNew)->validIS[s] = PETSC_TRUE;
2031 PetscCall(PetscMalloc1((*labelNew)->numStrata, &(*labelNew)->stratumValues));
2032 /* Turn leafStrata into indices rather than stratum values */
2033 offset = 0;
2034 PetscCall(PetscHSetIGetElems(stratumHash, &offset, (*labelNew)->stratumValues));
2035 PetscCall(PetscSortInt((*labelNew)->numStrata, (*labelNew)->stratumValues));
2036 for (s = 0; s < (*labelNew)->numStrata; ++s) PetscCall(PetscHMapISet((*labelNew)->hmap, (*labelNew)->stratumValues[s], s));
2037 for (p = 0; p < size; ++p) {
2038 for (s = 0; s < (*labelNew)->numStrata; ++s) {
2039 if (leafStrata[p] == (*labelNew)->stratumValues[s]) {
2040 leafStrata[p] = s;
2041 break;
2042 }
2043 }
2044 }
2045 /* Rebuild the point strata on the receiver */
2046 PetscCall(PetscCalloc1((*labelNew)->numStrata, &(*labelNew)->stratumSizes));
2047 PetscCall(PetscSectionGetChart(leafSection, &pStart, &pEnd));
2048 for (p = pStart; p < pEnd; p++) {
2049 PetscCall(PetscSectionGetDof(leafSection, p, &dof));
2050 PetscCall(PetscSectionGetOffset(leafSection, p, &offset));
2051 for (s = 0; s < dof; s++) (*labelNew)->stratumSizes[leafStrata[offset + s]]++;
2052 }
2053 PetscCall(PetscCalloc1((*labelNew)->numStrata, &(*labelNew)->ht));
2054 PetscCall(PetscCalloc1((*labelNew)->numStrata, &(*labelNew)->points));
2055 PetscCall(PetscCalloc1((*labelNew)->numStrata, &points));
2056 for (s = 0; s < (*labelNew)->numStrata; ++s) {
2057 PetscCall(PetscHSetICreate(&(*labelNew)->ht[s]));
2058 PetscCall(PetscMalloc1((*labelNew)->stratumSizes[s], &points[s]));
2059 }
2060 /* Insert points into new strata */
2061 PetscCall(PetscCalloc1((*labelNew)->numStrata, &strataIdx));
2062 PetscCall(PetscSectionGetChart(leafSection, &pStart, &pEnd));
2063 for (p = pStart; p < pEnd; p++) {
2064 PetscCall(PetscSectionGetDof(leafSection, p, &dof));
2065 PetscCall(PetscSectionGetOffset(leafSection, p, &offset));
2066 for (s = 0; s < dof; s++) {
2067 stratum = leafStrata[offset + s];
2068 points[stratum][strataIdx[stratum]++] = p;
2069 }
2070 }
2071 for (s = 0; s < (*labelNew)->numStrata; s++) {
2072 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, (*labelNew)->stratumSizes[s], &points[s][0], PETSC_OWN_POINTER, &((*labelNew)->points[s])));
2073 PetscCall(PetscObjectSetName((PetscObject)((*labelNew)->points[s]), "indices"));
2074 }
2075 PetscCall(PetscFree(points));
2076 PetscCall(PetscHSetIDestroy(&stratumHash));
2077 PetscCall(PetscFree(leafStrata));
2078 PetscCall(PetscFree(strataIdx));
2079 PetscCall(PetscSectionDestroy(&leafSection));
2080 PetscFunctionReturn(PETSC_SUCCESS);
2081 }
2082
2083 /*@
2084 DMLabelGather - Gather all label values from leafs into roots
2085
2086 Collective
2087
2088 Input Parameters:
2089 + label - the `DMLabel`
2090 - sf - the `PetscSF` communication map
2091
2092 Output Parameter:
2093 . labelNew - the new `DMLabel` with localised leaf values
2094
2095 Level: developer
2096
2097 Note:
2098 This is the inverse operation to `DMLabelDistribute()`.
2099
2100 .seealso: `DMLabel`, `DM`, `DMLabelDistribute()`
2101 @*/
DMLabelGather(DMLabel label,PetscSF sf,DMLabel * labelNew)2102 PetscErrorCode DMLabelGather(DMLabel label, PetscSF sf, DMLabel *labelNew)
2103 {
2104 MPI_Comm comm;
2105 PetscSection rootSection;
2106 PetscSF sfLabel;
2107 PetscSFNode *rootPoints, *leafPoints;
2108 PetscInt p, s, d, nroots, nleaves, nmultiroots, idx, dof, offset;
2109 const PetscInt *rootDegree, *ilocal;
2110 PetscInt *rootStrata;
2111 const char *lname;
2112 char *name;
2113 PetscMPIInt nameSize;
2114 size_t len = 0;
2115 PetscMPIInt rank, size;
2116
2117 PetscFunctionBegin;
2118 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
2119 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
2120 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
2121 PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
2122 PetscCallMPI(MPI_Comm_rank(comm, &rank));
2123 PetscCallMPI(MPI_Comm_size(comm, &size));
2124 /* Bcast name */
2125 if (rank == 0) {
2126 PetscCall(PetscObjectGetName((PetscObject)label, &lname));
2127 PetscCall(PetscStrlen(lname, &len));
2128 }
2129 PetscCall(PetscMPIIntCast(len, &nameSize));
2130 PetscCallMPI(MPI_Bcast(&nameSize, 1, MPI_INT, 0, comm));
2131 PetscCall(PetscMalloc1(nameSize + 1, &name));
2132 if (rank == 0) PetscCall(PetscArraycpy(name, lname, nameSize + 1));
2133 PetscCallMPI(MPI_Bcast(name, nameSize + 1, MPI_CHAR, 0, comm));
2134 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, labelNew));
2135 PetscCall(PetscFree(name));
2136 /* Gather rank/index pairs of leaves into local roots to build
2137 an inverse, multi-rooted SF. Note that this ignores local leaf
2138 indexing due to the use of the multiSF in PetscSFGather. */
2139 PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, NULL));
2140 PetscCall(PetscMalloc1(nroots, &leafPoints));
2141 for (p = 0; p < nroots; ++p) leafPoints[p].rank = leafPoints[p].index = -1;
2142 for (p = 0; p < nleaves; p++) {
2143 PetscInt ilp = ilocal ? ilocal[p] : p;
2144
2145 leafPoints[ilp].index = ilp;
2146 leafPoints[ilp].rank = rank;
2147 }
2148 PetscCall(PetscSFComputeDegreeBegin(sf, &rootDegree));
2149 PetscCall(PetscSFComputeDegreeEnd(sf, &rootDegree));
2150 for (p = 0, nmultiroots = 0; p < nroots; ++p) nmultiroots += rootDegree[p];
2151 PetscCall(PetscMalloc1(nmultiroots, &rootPoints));
2152 PetscCall(PetscSFGatherBegin(sf, MPIU_SF_NODE, leafPoints, rootPoints));
2153 PetscCall(PetscSFGatherEnd(sf, MPIU_SF_NODE, leafPoints, rootPoints));
2154 PetscCall(PetscSFCreate(comm, &sfLabel));
2155 PetscCall(PetscSFSetGraph(sfLabel, nroots, nmultiroots, NULL, PETSC_OWN_POINTER, rootPoints, PETSC_OWN_POINTER));
2156 /* Migrate label over inverted SF to pull stratum values at leaves into roots. */
2157 PetscCall(DMLabelDistribute_Internal(label, sfLabel, &rootSection, &rootStrata));
2158 /* Rebuild the point strata on the receiver */
2159 for (p = 0, idx = 0; p < nroots; p++) {
2160 for (d = 0; d < rootDegree[p]; d++) {
2161 PetscCall(PetscSectionGetDof(rootSection, idx + d, &dof));
2162 PetscCall(PetscSectionGetOffset(rootSection, idx + d, &offset));
2163 for (s = 0; s < dof; s++) PetscCall(DMLabelSetValue(*labelNew, p, rootStrata[offset + s]));
2164 }
2165 idx += rootDegree[p];
2166 }
2167 PetscCall(PetscFree(leafPoints));
2168 PetscCall(PetscFree(rootStrata));
2169 PetscCall(PetscSectionDestroy(&rootSection));
2170 PetscCall(PetscSFDestroy(&sfLabel));
2171 PetscFunctionReturn(PETSC_SUCCESS);
2172 }
2173
DMLabelPropagateInit_Internal(DMLabel label,PetscSF pointSF,PetscInt valArray[])2174 static PetscErrorCode DMLabelPropagateInit_Internal(DMLabel label, PetscSF pointSF, PetscInt valArray[])
2175 {
2176 const PetscInt *degree;
2177 const PetscInt *points;
2178 PetscInt Nr, r, Nl, l, val, defVal;
2179
2180 PetscFunctionBegin;
2181 PetscCall(DMLabelGetDefaultValue(label, &defVal));
2182 /* Add in leaves */
2183 PetscCall(PetscSFGetGraph(pointSF, &Nr, &Nl, &points, NULL));
2184 for (l = 0; l < Nl; ++l) {
2185 PetscCall(DMLabelGetValue(label, points[l], &val));
2186 if (val != defVal) valArray[points[l]] = val;
2187 }
2188 /* Add in shared roots */
2189 PetscCall(PetscSFComputeDegreeBegin(pointSF, °ree));
2190 PetscCall(PetscSFComputeDegreeEnd(pointSF, °ree));
2191 for (r = 0; r < Nr; ++r) {
2192 if (degree[r]) {
2193 PetscCall(DMLabelGetValue(label, r, &val));
2194 if (val != defVal) valArray[r] = val;
2195 }
2196 }
2197 PetscFunctionReturn(PETSC_SUCCESS);
2198 }
2199
DMLabelPropagateFini_Internal(DMLabel label,PetscSF pointSF,PetscInt valArray[],PetscErrorCode (* markPoint)(DMLabel,PetscInt,PetscInt,void *),PetscCtx ctx)2200 static PetscErrorCode DMLabelPropagateFini_Internal(DMLabel label, PetscSF pointSF, PetscInt valArray[], PetscErrorCode (*markPoint)(DMLabel, PetscInt, PetscInt, void *), PetscCtx ctx)
2201 {
2202 const PetscInt *degree;
2203 const PetscInt *points;
2204 PetscInt Nr, r, Nl, l, val, defVal;
2205
2206 PetscFunctionBegin;
2207 PetscCall(DMLabelGetDefaultValue(label, &defVal));
2208 /* Read out leaves */
2209 PetscCall(PetscSFGetGraph(pointSF, &Nr, &Nl, &points, NULL));
2210 for (l = 0; l < Nl; ++l) {
2211 const PetscInt p = points[l];
2212 const PetscInt cval = valArray[p];
2213
2214 if (cval != defVal) {
2215 PetscCall(DMLabelGetValue(label, p, &val));
2216 if (val == defVal) {
2217 PetscCall(DMLabelSetValue(label, p, cval));
2218 if (markPoint) PetscCall((*markPoint)(label, p, cval, ctx));
2219 }
2220 }
2221 }
2222 /* Read out shared roots */
2223 PetscCall(PetscSFComputeDegreeBegin(pointSF, °ree));
2224 PetscCall(PetscSFComputeDegreeEnd(pointSF, °ree));
2225 for (r = 0; r < Nr; ++r) {
2226 if (degree[r]) {
2227 const PetscInt cval = valArray[r];
2228
2229 if (cval != defVal) {
2230 PetscCall(DMLabelGetValue(label, r, &val));
2231 if (val == defVal) {
2232 PetscCall(DMLabelSetValue(label, r, cval));
2233 if (markPoint) PetscCall((*markPoint)(label, r, cval, ctx));
2234 }
2235 }
2236 }
2237 }
2238 PetscFunctionReturn(PETSC_SUCCESS);
2239 }
2240
2241 /*@
2242 DMLabelPropagateBegin - Setup a cycle of label propagation
2243
2244 Collective
2245
2246 Input Parameters:
2247 + label - The `DMLabel` to propagate across processes
2248 - sf - The `PetscSF` describing parallel layout of the label points
2249
2250 Level: intermediate
2251
2252 .seealso: `DMLabel`, `DM`, `DMLabelPropagateEnd()`, `DMLabelPropagatePush()`
2253 @*/
DMLabelPropagateBegin(DMLabel label,PetscSF sf)2254 PetscErrorCode DMLabelPropagateBegin(DMLabel label, PetscSF sf)
2255 {
2256 PetscInt Nr, r, defVal;
2257 PetscMPIInt size;
2258
2259 PetscFunctionBegin;
2260 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
2261 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)sf), &size));
2262 if (size > 1) {
2263 PetscCall(DMLabelGetDefaultValue(label, &defVal));
2264 PetscCall(PetscSFGetGraph(sf, &Nr, NULL, NULL, NULL));
2265 if (Nr >= 0) PetscCall(PetscMalloc1(Nr, &label->propArray));
2266 for (r = 0; r < Nr; ++r) label->propArray[r] = defVal;
2267 }
2268 PetscFunctionReturn(PETSC_SUCCESS);
2269 }
2270
2271 /*@
2272 DMLabelPropagateEnd - Tear down a cycle of label propagation
2273
2274 Collective
2275
2276 Input Parameters:
2277 + label - The `DMLabel` to propagate across processes
2278 - pointSF - The `PetscSF` describing parallel layout of the label points
2279
2280 Level: intermediate
2281
2282 .seealso: `DMLabel`, `DM`, `DMLabelPropagateBegin()`, `DMLabelPropagatePush()`
2283 @*/
DMLabelPropagateEnd(DMLabel label,PetscSF pointSF)2284 PetscErrorCode DMLabelPropagateEnd(DMLabel label, PetscSF pointSF)
2285 {
2286 PetscFunctionBegin;
2287 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
2288 PetscCall(PetscFree(label->propArray));
2289 label->propArray = NULL;
2290 PetscFunctionReturn(PETSC_SUCCESS);
2291 }
2292
2293 /*@C
2294 DMLabelPropagatePush - Tear down a cycle of label propagation
2295
2296 Collective
2297
2298 Input Parameters:
2299 + label - The `DMLabel` to propagate across processes
2300 . pointSF - The `PetscSF` describing parallel layout of the label points
2301 . markPoint - An optional callback that is called when a point is marked, or `NULL`
2302 - ctx - An optional user context for the callback, or `NULL`
2303
2304 Calling sequence of `markPoint`:
2305 + label - The `DMLabel`
2306 . p - The point being marked
2307 . val - The label value for `p`
2308 - ctx - An optional user context
2309
2310 Level: intermediate
2311
2312 .seealso: `DMLabel`, `DM`, `DMLabelPropagateBegin()`, `DMLabelPropagateEnd()`
2313 @*/
DMLabelPropagatePush(DMLabel label,PetscSF pointSF,PetscErrorCode (* markPoint)(DMLabel label,PetscInt p,PetscInt val,PetscCtx ctx),PetscCtx ctx)2314 PetscErrorCode DMLabelPropagatePush(DMLabel label, PetscSF pointSF, PetscErrorCode (*markPoint)(DMLabel label, PetscInt p, PetscInt val, PetscCtx ctx), PetscCtx ctx)
2315 {
2316 PetscInt *valArray = label->propArray, Nr;
2317 PetscMPIInt size;
2318
2319 PetscFunctionBegin;
2320 PetscCheck(!label->readonly, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_WRONG, "Read-only labels cannot be altered");
2321 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pointSF), &size));
2322 PetscCall(PetscSFGetGraph(pointSF, &Nr, NULL, NULL, NULL));
2323 if (size > 1 && Nr >= 0) {
2324 /* Communicate marked edges
2325 The current implementation allocates an array the size of the number of root. We put the label values into the
2326 array, and then call PetscSFReduce()+PetscSFBcast() to make the marks consistent.
2327
2328 TODO: We could use in-place communication with a different SF
2329 We use MPI_SUM for the Reduce, and check the result against the rootdegree. If sum >= rootdegree+1, then the edge has
2330 already been marked. If not, it might have been handled on the process in this round, but we add it anyway.
2331
2332 In order to update the queue with the new edges from the label communication, we use BcastAnOp(MPI_SUM), so that new
2333 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
2334 edge to the queue.
2335 */
2336 PetscCall(DMLabelPropagateInit_Internal(label, pointSF, valArray));
2337 PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, valArray, valArray, MPI_MAX));
2338 PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, valArray, valArray, MPI_MAX));
2339 PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, valArray, valArray, MPI_REPLACE));
2340 PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, valArray, valArray, MPI_REPLACE));
2341 PetscCall(DMLabelPropagateFini_Internal(label, pointSF, valArray, markPoint, ctx));
2342 }
2343 PetscFunctionReturn(PETSC_SUCCESS);
2344 }
2345
2346 /*@
2347 DMLabelConvertToSection - Make a `PetscSection`/`IS` pair that encodes the label
2348
2349 Not Collective
2350
2351 Input Parameter:
2352 . label - the `DMLabel`
2353
2354 Output Parameters:
2355 + section - the section giving offsets for each stratum
2356 - is - An `IS` containing all the label points
2357
2358 Level: developer
2359
2360 .seealso: `DMLabel`, `DM`, `DMLabelDistribute()`
2361 @*/
DMLabelConvertToSection(DMLabel label,PetscSection * section,IS * is)2362 PetscErrorCode DMLabelConvertToSection(DMLabel label, PetscSection *section, IS *is)
2363 {
2364 IS vIS;
2365 const PetscInt *values;
2366 PetscInt *points;
2367 PetscInt nV, vS = 0, vE = 0, v, N;
2368
2369 PetscFunctionBegin;
2370 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
2371 PetscCall(DMLabelGetNumValues(label, &nV));
2372 PetscCall(DMLabelGetValueIS(label, &vIS));
2373 PetscCall(ISGetIndices(vIS, &values));
2374 if (nV) {
2375 vS = values[0];
2376 vE = values[0] + 1;
2377 }
2378 for (v = 1; v < nV; ++v) {
2379 vS = PetscMin(vS, values[v]);
2380 vE = PetscMax(vE, values[v] + 1);
2381 }
2382 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, section));
2383 PetscCall(PetscSectionSetChart(*section, vS, vE));
2384 for (v = 0; v < nV; ++v) {
2385 PetscInt n;
2386
2387 PetscCall(DMLabelGetStratumSize(label, values[v], &n));
2388 PetscCall(PetscSectionSetDof(*section, values[v], n));
2389 }
2390 PetscCall(PetscSectionSetUp(*section));
2391 PetscCall(PetscSectionGetStorageSize(*section, &N));
2392 PetscCall(PetscMalloc1(N, &points));
2393 for (v = 0; v < nV; ++v) {
2394 IS is;
2395 const PetscInt *spoints;
2396 PetscInt dof, off, p;
2397
2398 PetscCall(PetscSectionGetDof(*section, values[v], &dof));
2399 PetscCall(PetscSectionGetOffset(*section, values[v], &off));
2400 PetscCall(DMLabelGetStratumIS(label, values[v], &is));
2401 PetscCall(ISGetIndices(is, &spoints));
2402 for (p = 0; p < dof; ++p) points[off + p] = spoints[p];
2403 PetscCall(ISRestoreIndices(is, &spoints));
2404 PetscCall(ISDestroy(&is));
2405 }
2406 PetscCall(ISRestoreIndices(vIS, &values));
2407 PetscCall(ISDestroy(&vIS));
2408 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, N, points, PETSC_OWN_POINTER, is));
2409 PetscFunctionReturn(PETSC_SUCCESS);
2410 }
2411
2412 /*@C
2413 DMLabelRegister - Adds a new label component implementation
2414
2415 Not Collective
2416
2417 Input Parameters:
2418 + name - The name of a new user-defined creation routine
2419 - create_func - The creation routine itself
2420
2421 Notes:
2422 `DMLabelRegister()` may be called multiple times to add several user-defined labels
2423
2424 Example Usage:
2425 .vb
2426 DMLabelRegister("my_label", MyLabelCreate);
2427 .ve
2428
2429 Then, your label type can be chosen with the procedural interface via
2430 .vb
2431 DMLabelCreate(MPI_Comm, DMLabel *);
2432 DMLabelSetType(DMLabel, "my_label");
2433 .ve
2434 or at runtime via the option
2435 .vb
2436 -dm_label_type my_label
2437 .ve
2438
2439 Level: advanced
2440
2441 .seealso: `DMLabel`, `DM`, `DMLabelType`, `DMLabelRegisterAll()`, `DMLabelRegisterDestroy()`
2442 @*/
DMLabelRegister(const char name[],PetscErrorCode (* create_func)(DMLabel))2443 PetscErrorCode DMLabelRegister(const char name[], PetscErrorCode (*create_func)(DMLabel))
2444 {
2445 PetscFunctionBegin;
2446 PetscCall(DMInitializePackage());
2447 PetscCall(PetscFunctionListAdd(&DMLabelList, name, create_func));
2448 PetscFunctionReturn(PETSC_SUCCESS);
2449 }
2450
2451 PETSC_EXTERN PetscErrorCode DMLabelCreate_Concrete(DMLabel);
2452 PETSC_EXTERN PetscErrorCode DMLabelCreate_Ephemeral(DMLabel);
2453
2454 /*@C
2455 DMLabelRegisterAll - Registers all of the `DMLabel` implementations in the `DM` package.
2456
2457 Not Collective
2458
2459 Level: advanced
2460
2461 .seealso: `DMLabel`, `DM`, `DMRegisterAll()`, `DMLabelRegisterDestroy()`
2462 @*/
DMLabelRegisterAll(void)2463 PetscErrorCode DMLabelRegisterAll(void)
2464 {
2465 PetscFunctionBegin;
2466 if (DMLabelRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
2467 DMLabelRegisterAllCalled = PETSC_TRUE;
2468
2469 PetscCall(DMLabelRegister(DMLABELCONCRETE, DMLabelCreate_Concrete));
2470 PetscCall(DMLabelRegister(DMLABELEPHEMERAL, DMLabelCreate_Ephemeral));
2471 PetscFunctionReturn(PETSC_SUCCESS);
2472 }
2473
2474 /*@C
2475 DMLabelRegisterDestroy - This function destroys the `DMLabel` registry. It is called from `PetscFinalize()`.
2476
2477 Level: developer
2478
2479 .seealso: `DMLabel`, `DM`, `PetscInitialize()`
2480 @*/
DMLabelRegisterDestroy(void)2481 PetscErrorCode DMLabelRegisterDestroy(void)
2482 {
2483 PetscFunctionBegin;
2484 PetscCall(PetscFunctionListDestroy(&DMLabelList));
2485 DMLabelRegisterAllCalled = PETSC_FALSE;
2486 PetscFunctionReturn(PETSC_SUCCESS);
2487 }
2488
2489 /*@
2490 DMLabelSetType - Sets the particular implementation for a label.
2491
2492 Collective
2493
2494 Input Parameters:
2495 + label - The label
2496 - method - The name of the label type
2497
2498 Options Database Key:
2499 . -dm_label_type <type> - Sets the label type; use -help for a list of available types or see `DMLabelType`
2500
2501 Level: intermediate
2502
2503 .seealso: `DMLabel`, `DM`, `DMLabelGetType()`, `DMLabelCreate()`
2504 @*/
DMLabelSetType(DMLabel label,DMLabelType method)2505 PetscErrorCode DMLabelSetType(DMLabel label, DMLabelType method)
2506 {
2507 PetscErrorCode (*r)(DMLabel);
2508 PetscBool match;
2509
2510 PetscFunctionBegin;
2511 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
2512 PetscCall(PetscObjectTypeCompare((PetscObject)label, method, &match));
2513 if (match) PetscFunctionReturn(PETSC_SUCCESS);
2514
2515 PetscCall(DMLabelRegisterAll());
2516 PetscCall(PetscFunctionListFind(DMLabelList, method, &r));
2517 PetscCheck(r, PetscObjectComm((PetscObject)label), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DMLabel type: %s", method);
2518
2519 PetscTryTypeMethod(label, destroy);
2520 PetscCall(PetscMemzero(label->ops, sizeof(*label->ops)));
2521 PetscCall(PetscObjectChangeTypeName((PetscObject)label, method));
2522 PetscCall((*r)(label));
2523 PetscFunctionReturn(PETSC_SUCCESS);
2524 }
2525
2526 /*@
2527 DMLabelGetType - Gets the type name (as a string) from the label.
2528
2529 Not Collective
2530
2531 Input Parameter:
2532 . label - The `DMLabel`
2533
2534 Output Parameter:
2535 . type - The `DMLabel` type name
2536
2537 Level: intermediate
2538
2539 .seealso: `DMLabel`, `DM`, `DMLabelSetType()`, `DMLabelCreate()`
2540 @*/
DMLabelGetType(DMLabel label,DMLabelType * type)2541 PetscErrorCode DMLabelGetType(DMLabel label, DMLabelType *type)
2542 {
2543 PetscFunctionBegin;
2544 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
2545 PetscAssertPointer(type, 2);
2546 PetscCall(DMLabelRegisterAll());
2547 *type = ((PetscObject)label)->type_name;
2548 PetscFunctionReturn(PETSC_SUCCESS);
2549 }
2550
DMLabelInitialize_Concrete(DMLabel label)2551 static PetscErrorCode DMLabelInitialize_Concrete(DMLabel label)
2552 {
2553 PetscFunctionBegin;
2554 label->ops->view = DMLabelView_Concrete;
2555 label->ops->setup = NULL;
2556 label->ops->duplicate = DMLabelDuplicate_Concrete;
2557 label->ops->getstratumis = DMLabelGetStratumIS_Concrete;
2558 PetscFunctionReturn(PETSC_SUCCESS);
2559 }
2560
DMLabelCreate_Concrete(DMLabel label)2561 PETSC_EXTERN PetscErrorCode DMLabelCreate_Concrete(DMLabel label)
2562 {
2563 PetscFunctionBegin;
2564 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 1);
2565 PetscCall(DMLabelInitialize_Concrete(label));
2566 PetscFunctionReturn(PETSC_SUCCESS);
2567 }
2568
2569 /*@
2570 PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
2571 the local section and an `PetscSF` describing the section point overlap.
2572
2573 Collective
2574
2575 Input Parameters:
2576 + s - The `PetscSection` for the local field layout
2577 . sf - The `PetscSF` describing parallel layout of the section points
2578 . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global field vector will not possess constrained dofs
2579 . label - The label specifying the points
2580 - labelValue - The label stratum specifying the points
2581
2582 Output Parameter:
2583 . gsection - The `PetscSection` for the global field layout
2584
2585 Level: developer
2586
2587 Note:
2588 This gives negative sizes and offsets to points not owned by this process
2589
2590 .seealso: `DMLabel`, `DM`, `PetscSectionCreate()`
2591 @*/
PetscSectionCreateGlobalSectionLabel(PetscSection s,PetscSF sf,PetscBool includeConstraints,DMLabel label,PetscInt labelValue,PetscSection * gsection)2592 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
2593 {
2594 PetscInt *neg = NULL, *tmpOff = NULL;
2595 PetscInt pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
2596
2597 PetscFunctionBegin;
2598 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1);
2599 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
2600 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
2601 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), gsection));
2602 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2603 PetscCall(PetscSectionSetChart(*gsection, pStart, pEnd));
2604 PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
2605 if (nroots >= 0) {
2606 PetscCheck(nroots >= pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %" PetscInt_FMT " < %" PetscInt_FMT " section size", nroots, pEnd - pStart);
2607 PetscCall(PetscCalloc1(nroots, &neg));
2608 if (nroots > pEnd - pStart) {
2609 PetscCall(PetscCalloc1(nroots, &tmpOff));
2610 } else {
2611 tmpOff = &(*gsection)->atlasDof[-pStart];
2612 }
2613 }
2614 /* Mark ghost points with negative dof */
2615 for (p = pStart; p < pEnd; ++p) {
2616 PetscInt value;
2617
2618 PetscCall(DMLabelGetValue(label, p, &value));
2619 if (value != labelValue) continue;
2620 PetscCall(PetscSectionGetDof(s, p, &dof));
2621 PetscCall(PetscSectionSetDof(*gsection, p, dof));
2622 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
2623 if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(*gsection, p, cdof));
2624 if (neg) neg[p] = -(dof + 1);
2625 }
2626 PetscCall(PetscSectionSetUpBC(*gsection));
2627 if (nroots >= 0) {
2628 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2629 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2630 if (nroots > pEnd - pStart) {
2631 for (p = pStart; p < pEnd; ++p) {
2632 if (tmpOff[p] < 0) (*gsection)->atlasDof[p - pStart] = tmpOff[p];
2633 }
2634 }
2635 }
2636 /* Calculate new sizes, get process offset, and calculate point offsets */
2637 for (p = 0, off = 0; p < pEnd - pStart; ++p) {
2638 cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
2639 (*gsection)->atlasOff[p] = off;
2640 off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p] - cdof : 0;
2641 }
2642 PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s)));
2643 globalOff -= off;
2644 for (p = 0, off = 0; p < pEnd - pStart; ++p) {
2645 (*gsection)->atlasOff[p] += globalOff;
2646 if (neg) neg[p] = -((*gsection)->atlasOff[p] + 1);
2647 }
2648 /* Put in negative offsets for ghost points */
2649 if (nroots >= 0) {
2650 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2651 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE));
2652 if (nroots > pEnd - pStart) {
2653 for (p = pStart; p < pEnd; ++p) {
2654 if (tmpOff[p] < 0) (*gsection)->atlasOff[p - pStart] = tmpOff[p];
2655 }
2656 }
2657 }
2658 if (nroots >= 0 && nroots > pEnd - pStart) PetscCall(PetscFree(tmpOff));
2659 PetscCall(PetscFree(neg));
2660 PetscFunctionReturn(PETSC_SUCCESS);
2661 }
2662
2663 typedef struct _n_PetscSectionSym_Label {
2664 DMLabel label;
2665 PetscCopyMode *modes;
2666 PetscInt *sizes;
2667 const PetscInt ***perms;
2668 const PetscScalar ***rots;
2669 PetscInt (*minMaxOrients)[2];
2670 PetscInt numStrata; /* numStrata is only increasing, functions as a state */
2671 } PetscSectionSym_Label;
2672
PetscSectionSymLabelReset(PetscSectionSym sym)2673 static PetscErrorCode PetscSectionSymLabelReset(PetscSectionSym sym)
2674 {
2675 PetscInt i, j;
2676 PetscSectionSym_Label *sl = (PetscSectionSym_Label *)sym->data;
2677
2678 PetscFunctionBegin;
2679 for (i = 0; i <= sl->numStrata; i++) {
2680 if (sl->modes[i] == PETSC_OWN_POINTER || sl->modes[i] == PETSC_COPY_VALUES) {
2681 for (j = sl->minMaxOrients[i][0]; j < sl->minMaxOrients[i][1]; j++) {
2682 if (sl->perms[i]) PetscCall(PetscFree(sl->perms[i][j]));
2683 if (sl->rots[i]) PetscCall(PetscFree(sl->rots[i][j]));
2684 }
2685 if (sl->perms[i]) {
2686 const PetscInt **perms = &sl->perms[i][sl->minMaxOrients[i][0]];
2687
2688 PetscCall(PetscFree(perms));
2689 }
2690 if (sl->rots[i]) {
2691 const PetscScalar **rots = &sl->rots[i][sl->minMaxOrients[i][0]];
2692
2693 PetscCall(PetscFree(rots));
2694 }
2695 }
2696 }
2697 PetscCall(PetscFree5(sl->modes, sl->sizes, sl->perms, sl->rots, sl->minMaxOrients));
2698 PetscCall(DMLabelDestroy(&sl->label));
2699 sl->numStrata = 0;
2700 PetscFunctionReturn(PETSC_SUCCESS);
2701 }
2702
PetscSectionSymDestroy_Label(PetscSectionSym sym)2703 static PetscErrorCode PetscSectionSymDestroy_Label(PetscSectionSym sym)
2704 {
2705 PetscFunctionBegin;
2706 PetscCall(PetscSectionSymLabelReset(sym));
2707 PetscCall(PetscFree(sym->data));
2708 PetscFunctionReturn(PETSC_SUCCESS);
2709 }
2710
PetscSectionSymView_Label(PetscSectionSym sym,PetscViewer viewer)2711 static PetscErrorCode PetscSectionSymView_Label(PetscSectionSym sym, PetscViewer viewer)
2712 {
2713 PetscSectionSym_Label *sl = (PetscSectionSym_Label *)sym->data;
2714 PetscBool isAscii;
2715 DMLabel label = sl->label;
2716 const char *name;
2717
2718 PetscFunctionBegin;
2719 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isAscii));
2720 if (isAscii) {
2721 PetscInt i, j, k;
2722 PetscViewerFormat format;
2723
2724 PetscCall(PetscViewerGetFormat(viewer, &format));
2725 if (label) {
2726 PetscCall(PetscViewerGetFormat(viewer, &format));
2727 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
2728 PetscCall(PetscViewerASCIIPushTab(viewer));
2729 PetscCall(DMLabelView(label, viewer));
2730 PetscCall(PetscViewerASCIIPopTab(viewer));
2731 } else {
2732 PetscCall(PetscObjectGetName((PetscObject)sl->label, &name));
2733 PetscCall(PetscViewerASCIIPrintf(viewer, " Label '%s'\n", name));
2734 }
2735 } else {
2736 PetscCall(PetscViewerASCIIPrintf(viewer, "No label given\n"));
2737 }
2738 PetscCall(PetscViewerASCIIPushTab(viewer));
2739 for (i = 0; i <= sl->numStrata; i++) {
2740 PetscInt value = i < sl->numStrata ? label->stratumValues[i] : label->defaultValue;
2741
2742 if (!(sl->perms[i] || sl->rots[i])) {
2743 PetscCall(PetscViewerASCIIPrintf(viewer, "Symmetry for stratum value %" PetscInt_FMT " (%" PetscInt_FMT " dofs per point): no symmetries\n", value, sl->sizes[i]));
2744 } else {
2745 PetscCall(PetscViewerASCIIPrintf(viewer, "Symmetry for stratum value %" PetscInt_FMT " (%" PetscInt_FMT " dofs per point):\n", value, sl->sizes[i]));
2746 PetscCall(PetscViewerASCIIPushTab(viewer));
2747 PetscCall(PetscViewerASCIIPrintf(viewer, "Orientation range: [%" PetscInt_FMT ", %" PetscInt_FMT ")\n", sl->minMaxOrients[i][0], sl->minMaxOrients[i][1]));
2748 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
2749 PetscCall(PetscViewerASCIIPushTab(viewer));
2750 for (j = sl->minMaxOrients[i][0]; j < sl->minMaxOrients[i][1]; j++) {
2751 if (!((sl->perms[i] && sl->perms[i][j]) || (sl->rots[i] && sl->rots[i][j]))) {
2752 PetscCall(PetscViewerASCIIPrintf(viewer, "Orientation %" PetscInt_FMT ": identity\n", j));
2753 } else {
2754 PetscInt tab;
2755
2756 PetscCall(PetscViewerASCIIPrintf(viewer, "Orientation %" PetscInt_FMT ":\n", j));
2757 PetscCall(PetscViewerASCIIPushTab(viewer));
2758 PetscCall(PetscViewerASCIIGetTab(viewer, &tab));
2759 if (sl->perms[i] && sl->perms[i][j]) {
2760 PetscCall(PetscViewerASCIIPrintf(viewer, "Permutation:"));
2761 PetscCall(PetscViewerASCIISetTab(viewer, 0));
2762 for (k = 0; k < sl->sizes[i]; k++) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sl->perms[i][j][k]));
2763 PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
2764 PetscCall(PetscViewerASCIISetTab(viewer, tab));
2765 }
2766 if (sl->rots[i] && sl->rots[i][j]) {
2767 PetscCall(PetscViewerASCIIPrintf(viewer, "Rotations: "));
2768 PetscCall(PetscViewerASCIISetTab(viewer, 0));
2769 #if defined(PETSC_USE_COMPLEX)
2770 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])));
2771 #else
2772 for (k = 0; k < sl->sizes[i]; k++) PetscCall(PetscViewerASCIIPrintf(viewer, " %+g", (double)sl->rots[i][j][k]));
2773 #endif
2774 PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
2775 PetscCall(PetscViewerASCIISetTab(viewer, tab));
2776 }
2777 PetscCall(PetscViewerASCIIPopTab(viewer));
2778 }
2779 }
2780 PetscCall(PetscViewerASCIIPopTab(viewer));
2781 }
2782 PetscCall(PetscViewerASCIIPopTab(viewer));
2783 }
2784 }
2785 PetscCall(PetscViewerASCIIPopTab(viewer));
2786 }
2787 PetscFunctionReturn(PETSC_SUCCESS);
2788 }
2789
2790 /*@
2791 PetscSectionSymLabelSetLabel - set the label whose strata will define the points that receive symmetries
2792
2793 Logically
2794
2795 Input Parameters:
2796 + sym - the section symmetries
2797 - label - the `DMLabel` describing the types of points
2798
2799 Level: developer:
2800
2801 .seealso: `DMLabel`, `DM`, `PetscSectionSymLabelSetStratum()`, `PetscSectionSymCreateLabel()`, `PetscSectionGetPointSyms()`
2802 @*/
PetscSectionSymLabelSetLabel(PetscSectionSym sym,DMLabel label)2803 PetscErrorCode PetscSectionSymLabelSetLabel(PetscSectionSym sym, DMLabel label)
2804 {
2805 PetscSectionSym_Label *sl;
2806
2807 PetscFunctionBegin;
2808 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
2809 sl = (PetscSectionSym_Label *)sym->data;
2810 if (sl->label && sl->label != label) PetscCall(PetscSectionSymLabelReset(sym));
2811 if (label) {
2812 sl->label = label;
2813 PetscCall(PetscObjectReference((PetscObject)label));
2814 PetscCall(DMLabelGetNumValues(label, &sl->numStrata));
2815 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));
2816 PetscCall(PetscMemzero((void *)sl->modes, (sl->numStrata + 1) * sizeof(PetscCopyMode)));
2817 PetscCall(PetscMemzero((void *)sl->sizes, (sl->numStrata + 1) * sizeof(PetscInt)));
2818 PetscCall(PetscMemzero((void *)sl->perms, (sl->numStrata + 1) * sizeof(const PetscInt **)));
2819 PetscCall(PetscMemzero((void *)sl->rots, (sl->numStrata + 1) * sizeof(const PetscScalar **)));
2820 PetscCall(PetscMemzero((void *)sl->minMaxOrients, (sl->numStrata + 1) * sizeof(PetscInt[2])));
2821 }
2822 PetscFunctionReturn(PETSC_SUCCESS);
2823 }
2824
2825 /*@C
2826 PetscSectionSymLabelGetStratum - get the symmetries for the orientations of a stratum
2827
2828 Logically Collective
2829
2830 Input Parameters:
2831 + sym - the section symmetries
2832 - stratum - the stratum value in the label that we are assigning symmetries for
2833
2834 Output Parameters:
2835 + size - the number of dofs for points in the `stratum` of the label
2836 . minOrient - the smallest orientation for a point in this `stratum`
2837 . maxOrient - one greater than the largest orientation for a ppoint in this `stratum` (i.e., orientations are in the range [`minOrient`, `maxOrient`))
2838 . perms - `NULL` if there are no permutations, or (`maxOrient` - `minOrient`) permutations, one for each orientation. A `NULL` permutation is the identity
2839 - 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
2840
2841 Level: developer
2842
2843 .seealso: `DMLabel`, `DM`, `PetscSectionSymLabelSetStratum()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreateLabel()`
2844 @*/
PetscSectionSymLabelGetStratum(PetscSectionSym sym,PetscInt stratum,PetscInt * size,PetscInt * minOrient,PetscInt * maxOrient,const PetscInt *** perms,const PetscScalar *** rots)2845 PetscErrorCode PetscSectionSymLabelGetStratum(PetscSectionSym sym, PetscInt stratum, PetscInt *size, PetscInt *minOrient, PetscInt *maxOrient, const PetscInt ***perms, const PetscScalar ***rots)
2846 {
2847 PetscSectionSym_Label *sl;
2848 const char *name;
2849 PetscInt i;
2850
2851 PetscFunctionBegin;
2852 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
2853 sl = (PetscSectionSym_Label *)sym->data;
2854 PetscCheck(sl->label, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_WRONGSTATE, "No label set yet");
2855 for (i = 0; i <= sl->numStrata; i++) {
2856 PetscInt value = (i < sl->numStrata) ? sl->label->stratumValues[i] : sl->label->defaultValue;
2857
2858 if (stratum == value) break;
2859 }
2860 PetscCall(PetscObjectGetName((PetscObject)sl->label, &name));
2861 PetscCheck(i <= sl->numStrata, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_OUTOFRANGE, "Stratum %" PetscInt_FMT " not found in label %s", stratum, name);
2862 if (size) {
2863 PetscAssertPointer(size, 3);
2864 *size = sl->sizes[i];
2865 }
2866 if (minOrient) {
2867 PetscAssertPointer(minOrient, 4);
2868 *minOrient = sl->minMaxOrients[i][0];
2869 }
2870 if (maxOrient) {
2871 PetscAssertPointer(maxOrient, 5);
2872 *maxOrient = sl->minMaxOrients[i][1];
2873 }
2874 if (perms) {
2875 PetscAssertPointer(perms, 6);
2876 *perms = PetscSafePointerPlusOffset(sl->perms[i], sl->minMaxOrients[i][0]);
2877 }
2878 if (rots) {
2879 PetscAssertPointer(rots, 7);
2880 *rots = PetscSafePointerPlusOffset(sl->rots[i], sl->minMaxOrients[i][0]);
2881 }
2882 PetscFunctionReturn(PETSC_SUCCESS);
2883 }
2884
2885 /*@C
2886 PetscSectionSymLabelSetStratum - set the symmetries for the orientations of a stratum
2887
2888 Logically
2889
2890 Input Parameters:
2891 + sym - the section symmetries
2892 . stratum - the stratum value in the label that we are assigning symmetries for
2893 . size - the number of dofs for points in the `stratum` of the label
2894 . minOrient - the smallest orientation for a point in this `stratum`
2895 . maxOrient - one greater than the largest orientation for a point in this `stratum` (i.e., orientations are in the range [`minOrient`, `maxOrient`))
2896 . mode - how `sym` should copy the `perms` and `rots` arrays
2897 . perms - `NULL` if there are no permutations, or (`maxOrient` - `minOrient`) permutations, one for each orientation. A `NULL` permutation is the identity
2898 - 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
2899
2900 Level: developer
2901
2902 .seealso: `DMLabel`, `DM`, `PetscSectionSymLabelGetStratum()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreateLabel()`
2903 @*/
PetscSectionSymLabelSetStratum(PetscSectionSym sym,PetscInt stratum,PetscInt size,PetscInt minOrient,PetscInt maxOrient,PetscCopyMode mode,const PetscInt ** perms,const PetscScalar ** rots)2904 PetscErrorCode PetscSectionSymLabelSetStratum(PetscSectionSym sym, PetscInt stratum, PetscInt size, PetscInt minOrient, PetscInt maxOrient, PetscCopyMode mode, const PetscInt **perms, const PetscScalar **rots)
2905 {
2906 PetscSectionSym_Label *sl;
2907 const char *name;
2908 PetscInt i, j, k;
2909
2910 PetscFunctionBegin;
2911 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1);
2912 sl = (PetscSectionSym_Label *)sym->data;
2913 PetscCheck(sl->label, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_WRONGSTATE, "No label set yet");
2914 for (i = 0; i <= sl->numStrata; i++) {
2915 PetscInt value = (i < sl->numStrata) ? sl->label->stratumValues[i] : sl->label->defaultValue;
2916
2917 if (stratum == value) break;
2918 }
2919 PetscCall(PetscObjectGetName((PetscObject)sl->label, &name));
2920 PetscCheck(i <= sl->numStrata, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_OUTOFRANGE, "Stratum %" PetscInt_FMT " not found in label %s", stratum, name);
2921 sl->sizes[i] = size;
2922 sl->modes[i] = mode;
2923 sl->minMaxOrients[i][0] = minOrient;
2924 sl->minMaxOrients[i][1] = maxOrient;
2925 if (mode == PETSC_COPY_VALUES) {
2926 if (perms) {
2927 PetscInt **ownPerms;
2928
2929 PetscCall(PetscCalloc1(maxOrient - minOrient, &ownPerms));
2930 for (j = 0; j < maxOrient - minOrient; j++) {
2931 if (perms[j]) {
2932 PetscCall(PetscMalloc1(size, &ownPerms[j]));
2933 for (k = 0; k < size; k++) ownPerms[j][k] = perms[j][k];
2934 }
2935 }
2936 sl->perms[i] = (const PetscInt **)&ownPerms[-minOrient];
2937 }
2938 if (rots) {
2939 PetscScalar **ownRots;
2940
2941 PetscCall(PetscCalloc1(maxOrient - minOrient, &ownRots));
2942 for (j = 0; j < maxOrient - minOrient; j++) {
2943 if (rots[j]) {
2944 PetscCall(PetscMalloc1(size, &ownRots[j]));
2945 for (k = 0; k < size; k++) ownRots[j][k] = rots[j][k];
2946 }
2947 }
2948 sl->rots[i] = (const PetscScalar **)&ownRots[-minOrient];
2949 }
2950 } else {
2951 sl->perms[i] = PetscSafePointerPlusOffset(perms, -minOrient);
2952 sl->rots[i] = PetscSafePointerPlusOffset(rots, -minOrient);
2953 }
2954 PetscFunctionReturn(PETSC_SUCCESS);
2955 }
2956
PetscSectionSymGetPoints_Label(PetscSectionSym sym,PetscSection section,PetscInt numPoints,const PetscInt * points,const PetscInt ** perms,const PetscScalar ** rots)2957 static PetscErrorCode PetscSectionSymGetPoints_Label(PetscSectionSym sym, PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt **perms, const PetscScalar **rots)
2958 {
2959 PetscInt i, j, numStrata;
2960 PetscSectionSym_Label *sl;
2961 DMLabel label;
2962
2963 PetscFunctionBegin;
2964 sl = (PetscSectionSym_Label *)sym->data;
2965 numStrata = sl->numStrata;
2966 label = sl->label;
2967 for (i = 0; i < numPoints; i++) {
2968 PetscInt point = points[2 * i];
2969 PetscInt ornt = points[2 * i + 1];
2970
2971 for (j = 0; j < numStrata; j++) {
2972 if (label->validIS[j]) {
2973 PetscInt k;
2974
2975 PetscCall(ISLocate(label->points[j], point, &k));
2976 if (k >= 0) break;
2977 } else {
2978 PetscBool has;
2979
2980 PetscCall(PetscHSetIHas(label->ht[j], point, &has));
2981 if (has) break;
2982 }
2983 }
2984 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],
2985 j < numStrata ? label->stratumValues[j] : label->defaultValue);
2986 if (perms) perms[i] = sl->perms[j] ? sl->perms[j][ornt] : NULL;
2987 if (rots) rots[i] = sl->rots[j] ? sl->rots[j][ornt] : NULL;
2988 }
2989 PetscFunctionReturn(PETSC_SUCCESS);
2990 }
2991
PetscSectionSymCopy_Label(PetscSectionSym sym,PetscSectionSym nsym)2992 static PetscErrorCode PetscSectionSymCopy_Label(PetscSectionSym sym, PetscSectionSym nsym)
2993 {
2994 PetscSectionSym_Label *sl = (PetscSectionSym_Label *)nsym->data;
2995 IS valIS;
2996 const PetscInt *values;
2997 PetscInt Nv, v;
2998
2999 PetscFunctionBegin;
3000 PetscCall(DMLabelGetNumValues(sl->label, &Nv));
3001 PetscCall(DMLabelGetValueIS(sl->label, &valIS));
3002 PetscCall(ISGetIndices(valIS, &values));
3003 for (v = 0; v < Nv; ++v) {
3004 const PetscInt val = values[v];
3005 PetscInt size, minOrient, maxOrient;
3006 const PetscInt **perms;
3007 const PetscScalar **rots;
3008
3009 PetscCall(PetscSectionSymLabelGetStratum(sym, val, &size, &minOrient, &maxOrient, &perms, &rots));
3010 PetscCall(PetscSectionSymLabelSetStratum(nsym, val, size, minOrient, maxOrient, PETSC_COPY_VALUES, perms, rots));
3011 }
3012 PetscCall(ISDestroy(&valIS));
3013 PetscFunctionReturn(PETSC_SUCCESS);
3014 }
3015
PetscSectionSymDistribute_Label(PetscSectionSym sym,PetscSF migrationSF,PetscSectionSym * dsym)3016 static PetscErrorCode PetscSectionSymDistribute_Label(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym)
3017 {
3018 PetscSectionSym_Label *sl = (PetscSectionSym_Label *)sym->data;
3019 DMLabel dlabel;
3020
3021 PetscFunctionBegin;
3022 PetscCall(DMLabelDistribute(sl->label, migrationSF, &dlabel));
3023 PetscCall(PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)sym), dlabel, dsym));
3024 PetscCall(DMLabelDestroy(&dlabel));
3025 PetscCall(PetscSectionSymCopy(sym, *dsym));
3026 PetscFunctionReturn(PETSC_SUCCESS);
3027 }
3028
PetscSectionSymCreate_Label(PetscSectionSym sym)3029 PetscErrorCode PetscSectionSymCreate_Label(PetscSectionSym sym)
3030 {
3031 PetscSectionSym_Label *sl;
3032
3033 PetscFunctionBegin;
3034 PetscCall(PetscNew(&sl));
3035 sym->ops->getpoints = PetscSectionSymGetPoints_Label;
3036 sym->ops->distribute = PetscSectionSymDistribute_Label;
3037 sym->ops->copy = PetscSectionSymCopy_Label;
3038 sym->ops->view = PetscSectionSymView_Label;
3039 sym->ops->destroy = PetscSectionSymDestroy_Label;
3040 sym->data = (void *)sl;
3041 PetscFunctionReturn(PETSC_SUCCESS);
3042 }
3043
3044 /*@
3045 PetscSectionSymCreateLabel - Create a section symmetry that assigns one symmetry to each stratum of a label
3046
3047 Collective
3048
3049 Input Parameters:
3050 + comm - the MPI communicator for the new symmetry
3051 - label - the label defining the strata
3052
3053 Output Parameter:
3054 . sym - the section symmetries
3055
3056 Level: developer
3057
3058 .seealso: `DMLabel`, `DM`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()`
3059 @*/
PetscSectionSymCreateLabel(MPI_Comm comm,DMLabel label,PetscSectionSym * sym)3060 PetscErrorCode PetscSectionSymCreateLabel(MPI_Comm comm, DMLabel label, PetscSectionSym *sym)
3061 {
3062 PetscFunctionBegin;
3063 PetscCall(DMInitializePackage());
3064 PetscCall(PetscSectionSymCreate(comm, sym));
3065 PetscCall(PetscSectionSymSetType(*sym, PETSCSECTIONSYMLABEL));
3066 PetscCall(PetscSectionSymLabelSetLabel(*sym, label));
3067 PetscFunctionReturn(PETSC_SUCCESS);
3068 }
3069