1 /* 2 Provides the functions for index sets (IS) defined by a list of integers. 3 These are for blocks of data, each block is indicated with a single integer. 4 */ 5 #include <petsc/private/isimpl.h> /*I "petscis.h" I*/ 6 #include <petscviewer.h> 7 8 typedef struct { 9 PetscBool sorted; /* are the blocks sorted? */ 10 PetscBool allocated; /* did we allocate the index array ourselves? */ 11 PetscInt *idx; 12 } IS_Block; 13 14 static PetscErrorCode ISDestroy_Block(IS is) 15 { 16 IS_Block *sub = (IS_Block *)is->data; 17 18 PetscFunctionBegin; 19 if (sub->allocated) PetscCall(PetscFree(sub->idx)); 20 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISBlockSetIndices_C", NULL)); 21 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISBlockGetIndices_C", NULL)); 22 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISBlockRestoreIndices_C", NULL)); 23 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISBlockGetSize_C", NULL)); 24 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISBlockGetLocalSize_C", NULL)); 25 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISShift_C", NULL)); 26 PetscCall(PetscFree(is->data)); 27 PetscFunctionReturn(PETSC_SUCCESS); 28 } 29 30 static PetscErrorCode ISLocate_Block(IS is, PetscInt key, PetscInt *location) 31 { 32 IS_Block *sub = (IS_Block *)is->data; 33 PetscInt numIdx, i, bs, bkey, mkey; 34 PetscBool sorted; 35 36 PetscFunctionBegin; 37 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 38 PetscCall(PetscLayoutGetLocalSize(is->map, &numIdx)); 39 numIdx /= bs; 40 bkey = key / bs; 41 mkey = key % bs; 42 if (mkey < 0) { 43 bkey--; 44 mkey += bs; 45 } 46 PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, &sorted)); 47 if (sorted) { 48 PetscCall(PetscFindInt(bkey, numIdx, sub->idx, location)); 49 } else { 50 const PetscInt *idx = sub->idx; 51 52 *location = -1; 53 for (i = 0; i < numIdx; i++) { 54 if (idx[i] == bkey) { 55 *location = i; 56 break; 57 } 58 } 59 } 60 if (*location >= 0) *location = *location * bs + mkey; 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 static PetscErrorCode ISGetIndices_Block(IS in, const PetscInt *idx[]) 65 { 66 IS_Block *sub = (IS_Block *)in->data; 67 PetscInt i, j, k, bs, n, *ii, *jj; 68 69 PetscFunctionBegin; 70 PetscCall(PetscLayoutGetBlockSize(in->map, &bs)); 71 PetscCall(PetscLayoutGetLocalSize(in->map, &n)); 72 n /= bs; 73 if (bs == 1) *idx = sub->idx; 74 else { 75 if (n) { 76 PetscCall(PetscMalloc1(bs * n, &jj)); 77 *idx = jj; 78 k = 0; 79 ii = sub->idx; 80 for (i = 0; i < n; i++) 81 for (j = 0; j < bs; j++) jj[k++] = bs * ii[i] + j; 82 } else { 83 /* do not malloc for zero size because F90Array1dCreate() inside ISRestoreArrayF90() does not keep array when zero length array */ 84 *idx = NULL; 85 } 86 } 87 PetscFunctionReturn(PETSC_SUCCESS); 88 } 89 90 static PetscErrorCode ISRestoreIndices_Block(IS is, const PetscInt *idx[]) 91 { 92 IS_Block *sub = (IS_Block *)is->data; 93 PetscInt bs; 94 95 PetscFunctionBegin; 96 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 97 if (bs != 1) { 98 PetscCall(PetscFree(*(void **)idx)); 99 } else { 100 /* F90Array1dCreate() inside ISRestoreArrayF90() does not keep array when zero length array */ 101 PetscCheck(is->map->n <= 0 || *idx == sub->idx, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must restore with value from ISGetIndices()"); 102 } 103 PetscFunctionReturn(PETSC_SUCCESS); 104 } 105 106 static PetscErrorCode ISInvertPermutation_Block(IS is, PetscInt nlocal, IS *isout) 107 { 108 IS_Block *sub = (IS_Block *)is->data; 109 PetscInt i, *ii, bs, n, *idx = sub->idx; 110 PetscMPIInt size; 111 112 PetscFunctionBegin; 113 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)is), &size)); 114 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 115 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 116 n /= bs; 117 if (size == 1) { 118 PetscCall(PetscMalloc1(n, &ii)); 119 for (i = 0; i < n; i++) ii[idx[i]] = i; 120 PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n, ii, PETSC_OWN_POINTER, isout)); 121 PetscCall(ISSetPermutation(*isout)); 122 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No inversion written yet for block IS"); 123 PetscFunctionReturn(PETSC_SUCCESS); 124 } 125 126 static PetscErrorCode ISView_Block(IS is, PetscViewer viewer) 127 { 128 IS_Block *sub = (IS_Block *)is->data; 129 PetscInt i, bs, n, *idx = sub->idx; 130 PetscBool iascii, ibinary; 131 132 PetscFunctionBegin; 133 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 134 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 135 n /= bs; 136 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 137 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary)); 138 if (iascii) { 139 PetscViewerFormat fmt; 140 141 PetscCall(PetscViewerGetFormat(viewer, &fmt)); 142 if (fmt == PETSC_VIEWER_ASCII_MATLAB) { 143 IS ist; 144 const char *name; 145 const PetscInt *idx; 146 PetscInt n; 147 148 PetscCall(PetscObjectGetName((PetscObject)is, &name)); 149 PetscCall(ISGetLocalSize(is, &n)); 150 PetscCall(ISGetIndices(is, &idx)); 151 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), n, idx, PETSC_USE_POINTER, &ist)); 152 PetscCall(PetscObjectSetName((PetscObject)ist, name)); 153 PetscCall(ISView(ist, viewer)); 154 PetscCall(ISDestroy(&ist)); 155 PetscCall(ISRestoreIndices(is, &idx)); 156 } else { 157 PetscBool isperm; 158 159 PetscCall(ISGetInfo(is, IS_PERMUTATION, IS_GLOBAL, PETSC_FALSE, &isperm)); 160 if (isperm) PetscCall(PetscViewerASCIIPrintf(viewer, "Block Index set is permutation\n")); 161 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 162 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Block size %" PetscInt_FMT "\n", bs)); 163 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Number of block indices in set %" PetscInt_FMT "\n", n)); 164 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "The first indices of each block are\n")); 165 for (i = 0; i < n; i++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Block %" PetscInt_FMT " Index %" PetscInt_FMT "\n", i, idx[i])); 166 PetscCall(PetscViewerFlush(viewer)); 167 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 168 } 169 } else if (ibinary) PetscCall(ISView_Binary(is, viewer)); 170 PetscFunctionReturn(PETSC_SUCCESS); 171 } 172 173 static PetscErrorCode ISSort_Block(IS is) 174 { 175 IS_Block *sub = (IS_Block *)is->data; 176 PetscInt bs, n; 177 178 PetscFunctionBegin; 179 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 180 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 181 PetscCall(PetscIntSortSemiOrdered(n / bs, sub->idx)); 182 PetscFunctionReturn(PETSC_SUCCESS); 183 } 184 185 static PetscErrorCode ISSortRemoveDups_Block(IS is) 186 { 187 IS_Block *sub = (IS_Block *)is->data; 188 PetscInt bs, n, nb; 189 PetscBool sorted; 190 191 PetscFunctionBegin; 192 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 193 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 194 nb = n / bs; 195 PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, &sorted)); 196 if (sorted) { 197 PetscCall(PetscSortedRemoveDupsInt(&nb, sub->idx)); 198 } else { 199 PetscCall(PetscSortRemoveDupsInt(&nb, sub->idx)); 200 } 201 PetscCall(PetscLayoutDestroy(&is->map)); 202 PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)is), nb * bs, PETSC_DECIDE, bs, &is->map)); 203 PetscFunctionReturn(PETSC_SUCCESS); 204 } 205 206 static PetscErrorCode ISSorted_Block(IS is, PetscBool *flg) 207 { 208 PetscFunctionBegin; 209 PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, flg)); 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 static PetscErrorCode ISSortedLocal_Block(IS is, PetscBool *flg) 214 { 215 IS_Block *sub = (IS_Block *)is->data; 216 PetscInt n, bs, i, *idx; 217 218 PetscFunctionBegin; 219 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 220 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 221 n /= bs; 222 idx = sub->idx; 223 for (i = 1; i < n; i++) 224 if (idx[i] < idx[i - 1]) break; 225 if (i < n) *flg = PETSC_FALSE; 226 else *flg = PETSC_TRUE; 227 PetscFunctionReturn(PETSC_SUCCESS); 228 } 229 230 static PetscErrorCode ISUniqueLocal_Block(IS is, PetscBool *flg) 231 { 232 IS_Block *sub = (IS_Block *)is->data; 233 PetscInt n, bs, i, *idx, *idxcopy = NULL; 234 PetscBool sortedLocal; 235 236 PetscFunctionBegin; 237 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 238 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 239 n /= bs; 240 idx = sub->idx; 241 PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, &sortedLocal)); 242 if (!sortedLocal) { 243 PetscCall(PetscMalloc1(n, &idxcopy)); 244 PetscCall(PetscArraycpy(idxcopy, idx, n)); 245 PetscCall(PetscIntSortSemiOrdered(n, idxcopy)); 246 idx = idxcopy; 247 } 248 for (i = 1; i < n; i++) 249 if (idx[i] == idx[i - 1]) break; 250 if (i < n) *flg = PETSC_FALSE; 251 else *flg = PETSC_TRUE; 252 PetscCall(PetscFree(idxcopy)); 253 PetscFunctionReturn(PETSC_SUCCESS); 254 } 255 256 static PetscErrorCode ISPermutationLocal_Block(IS is, PetscBool *flg) 257 { 258 IS_Block *sub = (IS_Block *)is->data; 259 PetscInt n, bs, i, *idx, *idxcopy = NULL; 260 PetscBool sortedLocal; 261 262 PetscFunctionBegin; 263 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 264 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 265 n /= bs; 266 idx = sub->idx; 267 PetscCall(ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, &sortedLocal)); 268 if (!sortedLocal) { 269 PetscCall(PetscMalloc1(n, &idxcopy)); 270 PetscCall(PetscArraycpy(idxcopy, idx, n)); 271 PetscCall(PetscIntSortSemiOrdered(n, idxcopy)); 272 idx = idxcopy; 273 } 274 for (i = 0; i < n; i++) 275 if (idx[i] != i) break; 276 if (i < n) *flg = PETSC_FALSE; 277 else *flg = PETSC_TRUE; 278 PetscCall(PetscFree(idxcopy)); 279 PetscFunctionReturn(PETSC_SUCCESS); 280 } 281 282 static PetscErrorCode ISIntervalLocal_Block(IS is, PetscBool *flg) 283 { 284 IS_Block *sub = (IS_Block *)is->data; 285 PetscInt n, bs, i, *idx; 286 287 PetscFunctionBegin; 288 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 289 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 290 n /= bs; 291 idx = sub->idx; 292 for (i = 1; i < n; i++) 293 if (idx[i] != idx[i - 1] + 1) break; 294 if (i < n) *flg = PETSC_FALSE; 295 else *flg = PETSC_TRUE; 296 PetscFunctionReturn(PETSC_SUCCESS); 297 } 298 299 static PetscErrorCode ISDuplicate_Block(IS is, IS *newIS) 300 { 301 IS_Block *sub = (IS_Block *)is->data; 302 PetscInt bs, n; 303 304 PetscFunctionBegin; 305 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 306 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 307 n /= bs; 308 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)is), bs, n, sub->idx, PETSC_COPY_VALUES, newIS)); 309 PetscFunctionReturn(PETSC_SUCCESS); 310 } 311 312 static PetscErrorCode ISCopy_Block(IS is, IS isy) 313 { 314 IS_Block *is_block = (IS_Block *)is->data, *isy_block = (IS_Block *)isy->data; 315 PetscInt bs, n; 316 317 PetscFunctionBegin; 318 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 319 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 320 PetscCall(PetscArraycpy(isy_block->idx, is_block->idx, n / bs)); 321 PetscFunctionReturn(PETSC_SUCCESS); 322 } 323 324 static PetscErrorCode ISOnComm_Block(IS is, MPI_Comm comm, PetscCopyMode mode, IS *newis) 325 { 326 IS_Block *sub = (IS_Block *)is->data; 327 PetscInt bs, n; 328 329 PetscFunctionBegin; 330 PetscCheck(mode != PETSC_OWN_POINTER, comm, PETSC_ERR_ARG_WRONG, "Cannot use PETSC_OWN_POINTER"); 331 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 332 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 333 PetscCall(ISCreateBlock(comm, bs, n / bs, sub->idx, mode, newis)); 334 PetscFunctionReturn(PETSC_SUCCESS); 335 } 336 337 static PetscErrorCode ISShift_Block(IS is, PetscInt shift, IS isy) 338 { 339 IS_Block *isb = (IS_Block *)is->data; 340 IS_Block *isby = (IS_Block *)isy->data; 341 PetscInt i, n, bs; 342 343 PetscFunctionBegin; 344 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 345 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 346 shift /= bs; 347 for (i = 0; i < n / bs; i++) isby->idx[i] = isb->idx[i] + shift; 348 PetscFunctionReturn(PETSC_SUCCESS); 349 } 350 351 static PetscErrorCode ISSetBlockSize_Block(IS is, PetscInt bs) 352 { 353 PetscFunctionBegin; 354 PetscCheck(is->map->bs <= 0 || bs == is->map->bs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot change blocksize %" PetscInt_FMT " (to %" PetscInt_FMT ") if ISType is ISBLOCK", is->map->bs, bs); 355 PetscCall(PetscLayoutSetBlockSize(is->map, bs)); 356 PetscFunctionReturn(PETSC_SUCCESS); 357 } 358 359 static PetscErrorCode ISToGeneral_Block(IS inis) 360 { 361 IS_Block *sub = (IS_Block *)inis->data; 362 PetscInt bs, n; 363 const PetscInt *idx; 364 365 PetscFunctionBegin; 366 PetscCall(ISGetBlockSize(inis, &bs)); 367 PetscCall(ISGetLocalSize(inis, &n)); 368 PetscCall(ISGetIndices(inis, &idx)); 369 if (bs == 1) { 370 PetscCopyMode mode = sub->allocated ? PETSC_OWN_POINTER : PETSC_USE_POINTER; 371 sub->allocated = PETSC_FALSE; /* prevent deallocation when changing the subtype*/ 372 PetscCall(ISSetType(inis, ISGENERAL)); 373 PetscCall(ISGeneralSetIndices(inis, n, idx, mode)); 374 } else { 375 PetscCall(ISSetType(inis, ISGENERAL)); 376 PetscCall(ISGeneralSetIndices(inis, n, idx, PETSC_OWN_POINTER)); 377 } 378 PetscFunctionReturn(PETSC_SUCCESS); 379 } 380 381 // clang-format off 382 static const struct _ISOps myops = { 383 PetscDesignatedInitializer(getindices, ISGetIndices_Block), 384 PetscDesignatedInitializer(restoreindices, ISRestoreIndices_Block), 385 PetscDesignatedInitializer(invertpermutation, ISInvertPermutation_Block), 386 PetscDesignatedInitializer(sort, ISSort_Block), 387 PetscDesignatedInitializer(sortremovedups, ISSortRemoveDups_Block), 388 PetscDesignatedInitializer(sorted, ISSorted_Block), 389 PetscDesignatedInitializer(duplicate, ISDuplicate_Block), 390 PetscDesignatedInitializer(destroy, ISDestroy_Block), 391 PetscDesignatedInitializer(view, ISView_Block), 392 PetscDesignatedInitializer(load, ISLoad_Default), 393 PetscDesignatedInitializer(copy, ISCopy_Block), 394 PetscDesignatedInitializer(togeneral, ISToGeneral_Block), 395 PetscDesignatedInitializer(oncomm, ISOnComm_Block), 396 PetscDesignatedInitializer(setblocksize, ISSetBlockSize_Block), 397 PetscDesignatedInitializer(contiguous, NULL), 398 PetscDesignatedInitializer(locate, ISLocate_Block), 399 /* we can have specialized local routines for determining properties, 400 * but unless the block size is the same on each process (which is not guaranteed at 401 * the moment), then trying to do something specialized for global properties is too 402 * complicated */ 403 PetscDesignatedInitializer(sortedlocal, ISSortedLocal_Block), 404 PetscDesignatedInitializer(sortedglobal, NULL), 405 PetscDesignatedInitializer(uniquelocal, ISUniqueLocal_Block), 406 PetscDesignatedInitializer(uniqueglobal, NULL), 407 PetscDesignatedInitializer(permlocal, ISPermutationLocal_Block), 408 PetscDesignatedInitializer(permglobal, NULL), 409 PetscDesignatedInitializer(intervallocal, ISIntervalLocal_Block), 410 PetscDesignatedInitializer(intervalglobal, NULL) 411 }; 412 // clang-format on 413 414 /*@ 415 ISBlockSetIndices - Set integers representing blocks of indices in an index set of `ISType` `ISBLOCK` 416 417 Collective 418 419 Input Parameters: 420 + is - the index set 421 . bs - number of elements in each block 422 . n - the length of the index set (the number of blocks) 423 . idx - the list of integers, one for each block, the integers contain the index of the first index of each block divided by the block size 424 - mode - see `PetscCopyMode`, only `PETSC_COPY_VALUES` and `PETSC_OWN_POINTER` are supported 425 426 Level: beginner 427 428 Notes: 429 When the communicator is not `MPI_COMM_SELF`, the operations on the 430 index sets, IS, are NOT conceptually the same as `MPI_Group` operations. 431 The index sets are then distributed sets of indices and thus certain operations 432 on them are collective. 433 434 The convenience routine `ISCreateBlock()` allows one to create the `IS` and provide the blocks in a single function call. 435 436 Example: 437 If you wish to index the values {0,1,4,5}, then use 438 a block size of 2 and idx of {0,2}. 439 440 .seealso: [](sec_scatter), `IS`, `ISCreateStride()`, `ISCreateGeneral()`, `ISAllGather()`, `ISCreateBlock()`, `ISBLOCK`, `ISGeneralSetIndices()` 441 @*/ 442 PetscErrorCode ISBlockSetIndices(IS is, PetscInt bs, PetscInt n, const PetscInt idx[], PetscCopyMode mode) 443 { 444 PetscFunctionBegin; 445 PetscCall(ISClearInfoCache(is, PETSC_FALSE)); 446 PetscUseMethod(is, "ISBlockSetIndices_C", (IS, PetscInt, PetscInt, const PetscInt[], PetscCopyMode), (is, bs, n, idx, mode)); 447 PetscFunctionReturn(PETSC_SUCCESS); 448 } 449 450 static PetscErrorCode ISBlockSetIndices_Block(IS is, PetscInt bs, PetscInt n, const PetscInt idx[], PetscCopyMode mode) 451 { 452 PetscInt i, min, max; 453 IS_Block *sub = (IS_Block *)is->data; 454 PetscLayout map; 455 456 PetscFunctionBegin; 457 PetscCheck(bs >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "block size < 1"); 458 PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length < 0"); 459 if (n) PetscAssertPointer(idx, 4); 460 461 PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)is), n * bs, is->map->N, bs, &map)); 462 PetscCall(PetscLayoutDestroy(&is->map)); 463 is->map = map; 464 465 if (sub->allocated) PetscCall(PetscFree(sub->idx)); 466 if (mode == PETSC_COPY_VALUES) { 467 PetscCall(PetscMalloc1(n, &sub->idx)); 468 PetscCall(PetscArraycpy(sub->idx, idx, n)); 469 sub->allocated = PETSC_TRUE; 470 } else if (mode == PETSC_OWN_POINTER) { 471 sub->idx = (PetscInt *)idx; 472 sub->allocated = PETSC_TRUE; 473 } else if (mode == PETSC_USE_POINTER) { 474 sub->idx = (PetscInt *)idx; 475 sub->allocated = PETSC_FALSE; 476 } 477 478 if (n) { 479 min = max = idx[0]; 480 for (i = 1; i < n; i++) { 481 if (idx[i] < min) min = idx[i]; 482 if (idx[i] > max) max = idx[i]; 483 } 484 is->min = bs * min; 485 is->max = bs * max + bs - 1; 486 } else { 487 is->min = PETSC_MAX_INT; 488 is->max = PETSC_MIN_INT; 489 } 490 PetscFunctionReturn(PETSC_SUCCESS); 491 } 492 493 /*@ 494 ISCreateBlock - Creates a data structure for an index set containing 495 a list of integers. Each integer represents a fixed block size set of indices. 496 497 Collective 498 499 Input Parameters: 500 + comm - the MPI communicator 501 . bs - number of elements in each block 502 . n - the length of the index set (the number of blocks) 503 . idx - the list of integers, one for each block, the integers contain the index of the first entry of each block divided by the block size 504 - mode - see `PetscCopyMode`, only `PETSC_COPY_VALUES` and `PETSC_OWN_POINTER` are supported in this routine 505 506 Output Parameter: 507 . is - the new index set 508 509 Level: beginner 510 511 Notes: 512 When the communicator is not `MPI_COMM_SELF`, the operations on the 513 index sets, `IS`, are NOT conceptually the same as `MPI_Group` operations. 514 The index sets are then distributed sets of indices and thus certain operations 515 on them are collective. 516 517 The routine `ISBlockSetIndices()` can be used to provide the indices to a preexisting block `IS` 518 519 Example: 520 If you wish to index the values {0,1,6,7}, then use 521 a block size of 2 and idx of {0,3}. 522 523 .seealso: [](sec_scatter), `IS`, `ISCreateStride()`, `ISCreateGeneral()`, `ISAllGather()`, `ISBlockSetIndices()`, `ISBLOCK`, `ISGENERAL` 524 @*/ 525 PetscErrorCode ISCreateBlock(MPI_Comm comm, PetscInt bs, PetscInt n, const PetscInt idx[], PetscCopyMode mode, IS *is) 526 { 527 PetscFunctionBegin; 528 PetscAssertPointer(is, 6); 529 PetscCheck(bs >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "block size < 1"); 530 PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length < 0"); 531 if (n) PetscAssertPointer(idx, 4); 532 533 PetscCall(ISCreate(comm, is)); 534 PetscCall(ISSetType(*is, ISBLOCK)); 535 PetscCall(ISBlockSetIndices(*is, bs, n, idx, mode)); 536 PetscFunctionReturn(PETSC_SUCCESS); 537 } 538 539 static PetscErrorCode ISBlockGetIndices_Block(IS is, const PetscInt *idx[]) 540 { 541 IS_Block *sub = (IS_Block *)is->data; 542 543 PetscFunctionBegin; 544 *idx = sub->idx; 545 PetscFunctionReturn(PETSC_SUCCESS); 546 } 547 548 static PetscErrorCode ISBlockRestoreIndices_Block(IS is, const PetscInt *idx[]) 549 { 550 PetscFunctionBegin; 551 PetscFunctionReturn(PETSC_SUCCESS); 552 } 553 554 /*@C 555 ISBlockGetIndices - Gets the indices associated with each block in an `ISBLOCK` 556 557 Not Collective 558 559 Input Parameter: 560 . is - the index set 561 562 Output Parameter: 563 . idx - the integer indices, one for each block and count of block not indices 564 565 Level: intermediate 566 567 Note: 568 Call `ISBlockRestoreIndices()` when you no longer need access to the indices 569 570 .seealso: [](sec_scatter), `IS`, `ISBLOCK`, `ISGetIndices()`, `ISBlockRestoreIndices()`, `ISBlockSetIndices()`, `ISCreateBlock()` 571 @*/ 572 PetscErrorCode ISBlockGetIndices(IS is, const PetscInt *idx[]) 573 { 574 PetscFunctionBegin; 575 PetscUseMethod(is, "ISBlockGetIndices_C", (IS, const PetscInt *[]), (is, idx)); 576 PetscFunctionReturn(PETSC_SUCCESS); 577 } 578 579 /*@C 580 ISBlockRestoreIndices - Restores the indices associated with each block in an `ISBLOCK` obtained with `ISBlockGetIndices()` 581 582 Not Collective 583 584 Input Parameter: 585 . is - the index set 586 587 Output Parameter: 588 . idx - the integer indices 589 590 Level: intermediate 591 592 .seealso: [](sec_scatter), `IS`, `ISBLOCK`, `ISRestoreIndices()`, `ISBlockGetIndices()` 593 @*/ 594 PetscErrorCode ISBlockRestoreIndices(IS is, const PetscInt *idx[]) 595 { 596 PetscFunctionBegin; 597 PetscUseMethod(is, "ISBlockRestoreIndices_C", (IS, const PetscInt *[]), (is, idx)); 598 PetscFunctionReturn(PETSC_SUCCESS); 599 } 600 601 /*@ 602 ISBlockGetLocalSize - Returns the local number of blocks in the index set of `ISType` `ISBLOCK` 603 604 Not Collective 605 606 Input Parameter: 607 . is - the index set 608 609 Output Parameter: 610 . size - the local number of blocks 611 612 Level: intermediate 613 614 .seealso: [](sec_scatter), `IS`, `ISGetBlockSize()`, `ISBlockGetSize()`, `ISGetSize()`, `ISCreateBlock()`, `ISBLOCK` 615 @*/ 616 PetscErrorCode ISBlockGetLocalSize(IS is, PetscInt *size) 617 { 618 PetscFunctionBegin; 619 PetscUseMethod(is, "ISBlockGetLocalSize_C", (IS, PetscInt *), (is, size)); 620 PetscFunctionReturn(PETSC_SUCCESS); 621 } 622 623 static PetscErrorCode ISBlockGetLocalSize_Block(IS is, PetscInt *size) 624 { 625 PetscInt bs, n; 626 627 PetscFunctionBegin; 628 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 629 PetscCall(PetscLayoutGetLocalSize(is->map, &n)); 630 *size = n / bs; 631 PetscFunctionReturn(PETSC_SUCCESS); 632 } 633 634 /*@ 635 ISBlockGetSize - Returns the global number of blocks in parallel in the index set of `ISType` `ISBLOCK` 636 637 Not Collective 638 639 Input Parameter: 640 . is - the index set 641 642 Output Parameter: 643 . size - the global number of blocks 644 645 Level: intermediate 646 647 .seealso: [](sec_scatter), `IS`, `ISGetBlockSize()`, `ISBlockGetLocalSize()`, `ISGetSize()`, `ISCreateBlock()`, `ISBLOCK` 648 @*/ 649 PetscErrorCode ISBlockGetSize(IS is, PetscInt *size) 650 { 651 PetscFunctionBegin; 652 PetscUseMethod(is, "ISBlockGetSize_C", (IS, PetscInt *), (is, size)); 653 PetscFunctionReturn(PETSC_SUCCESS); 654 } 655 656 static PetscErrorCode ISBlockGetSize_Block(IS is, PetscInt *size) 657 { 658 PetscInt bs, N; 659 660 PetscFunctionBegin; 661 PetscCall(PetscLayoutGetBlockSize(is->map, &bs)); 662 PetscCall(PetscLayoutGetSize(is->map, &N)); 663 *size = N / bs; 664 PetscFunctionReturn(PETSC_SUCCESS); 665 } 666 667 PETSC_INTERN PetscErrorCode ISCreate_Block(IS is) 668 { 669 IS_Block *sub; 670 671 PetscFunctionBegin; 672 PetscCall(PetscNew(&sub)); 673 is->data = (void *)sub; 674 is->ops[0] = myops; 675 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISBlockSetIndices_C", ISBlockSetIndices_Block)); 676 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISBlockGetIndices_C", ISBlockGetIndices_Block)); 677 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISBlockRestoreIndices_C", ISBlockRestoreIndices_Block)); 678 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISBlockGetSize_C", ISBlockGetSize_Block)); 679 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISBlockGetLocalSize_C", ISBlockGetLocalSize_Block)); 680 PetscCall(PetscObjectComposeFunction((PetscObject)is, "ISShift_C", ISShift_Block)); 681 PetscFunctionReturn(PETSC_SUCCESS); 682 } 683