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