1 #include <petsc/private/isimpl.h> /*I "petscis.h" I*/ 2 #include <petsc/private/hashmapi.h> 3 #include <petscsf.h> 4 #include <petscviewer.h> 5 #include <petscbt.h> 6 7 PetscClassId IS_LTOGM_CLASSID; 8 static PetscErrorCode ISLocalToGlobalMappingSetUpBlockInfo_Private(ISLocalToGlobalMapping); 9 10 typedef struct { 11 PetscInt *globals; 12 } ISLocalToGlobalMapping_Basic; 13 14 typedef struct { 15 PetscHMapI globalht; 16 } ISLocalToGlobalMapping_Hash; 17 18 /*@C 19 ISGetPointRange - Returns a description of the points in an `IS` suitable for traversal 20 21 Not Collective 22 23 Input Parameter: 24 . pointIS - The `IS` object 25 26 Output Parameters: 27 + pStart - The first index, see notes 28 . pEnd - One past the last index, see notes 29 - points - The indices, see notes 30 31 Level: intermediate 32 33 Notes: 34 If the `IS` contains contiguous indices in an `ISSTRIDE`, then the indices are contained in [pStart, pEnd) and points = `NULL`. 35 Otherwise, `pStart = 0`, `pEnd = numIndices`, and points is an array of the indices. This supports the following pattern 36 .vb 37 ISGetPointRange(is, &pStart, &pEnd, &points); 38 for (p = pStart; p < pEnd; ++p) { 39 const PetscInt point = points ? points[p] : p; 40 // use point 41 } 42 ISRestorePointRange(is, &pstart, &pEnd, &points); 43 .ve 44 Hence the same code can be written for `pointIS` being a `ISSTRIDE` or `ISGENERAL` 45 46 .seealso: [](sec_scatter), `IS`, `ISRestorePointRange()`, `ISGetPointSubrange()`, `ISGetIndices()`, `ISCreateStride()` 47 @*/ 48 PetscErrorCode ISGetPointRange(IS pointIS, PetscInt *pStart, PetscInt *pEnd, const PetscInt *points[]) 49 { 50 PetscInt numCells, step = 1; 51 PetscBool isStride; 52 53 PetscFunctionBeginHot; 54 *pStart = 0; 55 *points = NULL; 56 PetscCall(ISGetLocalSize(pointIS, &numCells)); 57 PetscCall(PetscObjectTypeCompare((PetscObject)pointIS, ISSTRIDE, &isStride)); 58 if (isStride) PetscCall(ISStrideGetInfo(pointIS, pStart, &step)); 59 *pEnd = *pStart + numCells; 60 if (!isStride || step != 1) PetscCall(ISGetIndices(pointIS, points)); 61 PetscFunctionReturn(PETSC_SUCCESS); 62 } 63 64 /*@C 65 ISRestorePointRange - Destroys the traversal description created with `ISGetPointRange()` 66 67 Not Collective 68 69 Input Parameters: 70 + pointIS - The `IS` object 71 . pStart - The first index, from `ISGetPointRange()` 72 . pEnd - One past the last index, from `ISGetPointRange()` 73 - points - The indices, from `ISGetPointRange()` 74 75 Level: intermediate 76 77 .seealso: [](sec_scatter), `IS`, `ISGetPointRange()`, `ISGetPointSubrange()`, `ISGetIndices()`, `ISCreateStride()` 78 @*/ 79 PetscErrorCode ISRestorePointRange(IS pointIS, PetscInt *pStart, PetscInt *pEnd, const PetscInt *points[]) 80 { 81 PetscInt step = 1; 82 PetscBool isStride; 83 84 PetscFunctionBeginHot; 85 PetscCall(PetscObjectTypeCompare((PetscObject)pointIS, ISSTRIDE, &isStride)); 86 if (isStride) PetscCall(ISStrideGetInfo(pointIS, pStart, &step)); 87 if (!isStride || step != 1) PetscCall(ISGetIndices(pointIS, points)); 88 PetscFunctionReturn(PETSC_SUCCESS); 89 } 90 91 /*@ 92 ISGetPointSubrange - Configures the input `IS` to be a subrange for the traversal information given 93 94 Not Collective 95 96 Input Parameters: 97 + subpointIS - The `IS` object to be configured 98 . pStart - The first index of the subrange 99 . pEnd - One past the last index for the subrange 100 - points - The indices for the entire range, from `ISGetPointRange()` 101 102 Output Parameters: 103 . subpointIS - The `IS` object now configured to be a subrange 104 105 Level: intermediate 106 107 Note: 108 The input `IS` will now respond properly to calls to `ISGetPointRange()` and return the subrange. 109 110 .seealso: [](sec_scatter), `IS`, `ISGetPointRange()`, `ISRestorePointRange()`, `ISGetIndices()`, `ISCreateStride()` 111 @*/ 112 PetscErrorCode ISGetPointSubrange(IS subpointIS, PetscInt pStart, PetscInt pEnd, const PetscInt points[]) 113 { 114 PetscFunctionBeginHot; 115 if (points) { 116 PetscCall(ISSetType(subpointIS, ISGENERAL)); 117 PetscCall(ISGeneralSetIndices(subpointIS, pEnd - pStart, &points[pStart], PETSC_USE_POINTER)); 118 } else { 119 PetscCall(ISSetType(subpointIS, ISSTRIDE)); 120 PetscCall(ISStrideSetStride(subpointIS, pEnd - pStart, pStart, 1)); 121 } 122 PetscFunctionReturn(PETSC_SUCCESS); 123 } 124 125 /* -----------------------------------------------------------------------------------------*/ 126 127 /* 128 Creates the global mapping information in the ISLocalToGlobalMapping structure 129 130 If the user has not selected how to handle the global to local mapping then use HASH for "large" problems 131 */ 132 static PetscErrorCode ISGlobalToLocalMappingSetUp(ISLocalToGlobalMapping mapping) 133 { 134 PetscInt i, *idx = mapping->indices, n = mapping->n, end, start; 135 136 PetscFunctionBegin; 137 if (mapping->data) PetscFunctionReturn(PETSC_SUCCESS); 138 end = 0; 139 start = PETSC_INT_MAX; 140 141 for (i = 0; i < n; i++) { 142 if (idx[i] < 0) continue; 143 if (idx[i] < start) start = idx[i]; 144 if (idx[i] > end) end = idx[i]; 145 } 146 if (start > end) { 147 start = 0; 148 end = -1; 149 } 150 mapping->globalstart = start; 151 mapping->globalend = end; 152 if (!((PetscObject)mapping)->type_name) { 153 if ((end - start) > PetscMax(4 * n, 1000000)) { 154 PetscCall(ISLocalToGlobalMappingSetType(mapping, ISLOCALTOGLOBALMAPPINGHASH)); 155 } else { 156 PetscCall(ISLocalToGlobalMappingSetType(mapping, ISLOCALTOGLOBALMAPPINGBASIC)); 157 } 158 } 159 PetscTryTypeMethod(mapping, globaltolocalmappingsetup); 160 PetscFunctionReturn(PETSC_SUCCESS); 161 } 162 163 static PetscErrorCode ISGlobalToLocalMappingSetUp_Basic(ISLocalToGlobalMapping mapping) 164 { 165 PetscInt i, *idx = mapping->indices, n = mapping->n, end, start, *globals; 166 ISLocalToGlobalMapping_Basic *map; 167 168 PetscFunctionBegin; 169 start = mapping->globalstart; 170 end = mapping->globalend; 171 PetscCall(PetscNew(&map)); 172 PetscCall(PetscMalloc1(end - start + 2, &globals)); 173 map->globals = globals; 174 for (i = 0; i < end - start + 1; i++) globals[i] = -1; 175 for (i = 0; i < n; i++) { 176 if (idx[i] < 0) continue; 177 globals[idx[i] - start] = i; 178 } 179 mapping->data = (void *)map; 180 PetscFunctionReturn(PETSC_SUCCESS); 181 } 182 183 static PetscErrorCode ISGlobalToLocalMappingSetUp_Hash(ISLocalToGlobalMapping mapping) 184 { 185 PetscInt i, *idx = mapping->indices, n = mapping->n; 186 ISLocalToGlobalMapping_Hash *map; 187 188 PetscFunctionBegin; 189 PetscCall(PetscNew(&map)); 190 PetscCall(PetscHMapICreate(&map->globalht)); 191 for (i = 0; i < n; i++) { 192 if (idx[i] < 0) continue; 193 PetscCall(PetscHMapISet(map->globalht, idx[i], i)); 194 } 195 mapping->data = (void *)map; 196 PetscFunctionReturn(PETSC_SUCCESS); 197 } 198 199 static PetscErrorCode ISLocalToGlobalMappingDestroy_Basic(ISLocalToGlobalMapping mapping) 200 { 201 ISLocalToGlobalMapping_Basic *map = (ISLocalToGlobalMapping_Basic *)mapping->data; 202 203 PetscFunctionBegin; 204 if (!map) PetscFunctionReturn(PETSC_SUCCESS); 205 PetscCall(PetscFree(map->globals)); 206 PetscCall(PetscFree(mapping->data)); 207 PetscFunctionReturn(PETSC_SUCCESS); 208 } 209 210 static PetscErrorCode ISLocalToGlobalMappingDestroy_Hash(ISLocalToGlobalMapping mapping) 211 { 212 ISLocalToGlobalMapping_Hash *map = (ISLocalToGlobalMapping_Hash *)mapping->data; 213 214 PetscFunctionBegin; 215 if (!map) PetscFunctionReturn(PETSC_SUCCESS); 216 PetscCall(PetscHMapIDestroy(&map->globalht)); 217 PetscCall(PetscFree(mapping->data)); 218 PetscFunctionReturn(PETSC_SUCCESS); 219 } 220 221 static PetscErrorCode ISLocalToGlobalMappingResetBlockInfo_Private(ISLocalToGlobalMapping mapping) 222 { 223 PetscFunctionBegin; 224 PetscCall(PetscFree(mapping->info_procs)); 225 PetscCall(PetscFree(mapping->info_numprocs)); 226 if (mapping->info_indices) { 227 for (PetscInt i = 0; i < mapping->info_nproc; i++) PetscCall(PetscFree(mapping->info_indices[i])); 228 PetscCall(PetscFree(mapping->info_indices)); 229 } 230 if (mapping->info_nodei) PetscCall(PetscFree(mapping->info_nodei[0])); 231 PetscCall(PetscFree2(mapping->info_nodec, mapping->info_nodei)); 232 PetscCall(PetscSFDestroy(&mapping->multileaves_sf)); 233 PetscFunctionReturn(PETSC_SUCCESS); 234 } 235 236 #define GTOLTYPE _Basic 237 #define GTOLNAME _Basic 238 #define GTOLBS mapping->bs 239 #define GTOL(g, local) \ 240 do { \ 241 local = map->globals[g / bs - start]; \ 242 if (local >= 0) local = bs * local + (g % bs); \ 243 } while (0) 244 245 #include <../src/vec/is/utils/isltog.h> 246 247 #define GTOLTYPE _Basic 248 #define GTOLNAME Block_Basic 249 #define GTOLBS 1 250 #define GTOL(g, local) \ 251 do { \ 252 local = map->globals[g - start]; \ 253 } while (0) 254 #include <../src/vec/is/utils/isltog.h> 255 256 #define GTOLTYPE _Hash 257 #define GTOLNAME _Hash 258 #define GTOLBS mapping->bs 259 #define GTOL(g, local) \ 260 do { \ 261 (void)PetscHMapIGet(map->globalht, g / bs, &local); \ 262 if (local >= 0) local = bs * local + (g % bs); \ 263 } while (0) 264 #include <../src/vec/is/utils/isltog.h> 265 266 #define GTOLTYPE _Hash 267 #define GTOLNAME Block_Hash 268 #define GTOLBS 1 269 #define GTOL(g, local) \ 270 do { \ 271 (void)PetscHMapIGet(map->globalht, g, &local); \ 272 } while (0) 273 #include <../src/vec/is/utils/isltog.h> 274 275 /*@ 276 ISLocalToGlobalMappingDuplicate - Duplicates the local to global mapping object 277 278 Not Collective 279 280 Input Parameter: 281 . ltog - local to global mapping 282 283 Output Parameter: 284 . nltog - the duplicated local to global mapping 285 286 Level: advanced 287 288 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()` 289 @*/ 290 PetscErrorCode ISLocalToGlobalMappingDuplicate(ISLocalToGlobalMapping ltog, ISLocalToGlobalMapping *nltog) 291 { 292 ISLocalToGlobalMappingType l2gtype; 293 294 PetscFunctionBegin; 295 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 296 PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)ltog), ltog->bs, ltog->n, ltog->indices, PETSC_COPY_VALUES, nltog)); 297 PetscCall(ISLocalToGlobalMappingGetType(ltog, &l2gtype)); 298 PetscCall(ISLocalToGlobalMappingSetType(*nltog, l2gtype)); 299 PetscFunctionReturn(PETSC_SUCCESS); 300 } 301 302 /*@ 303 ISLocalToGlobalMappingGetSize - Gets the local size of a local to global mapping 304 305 Not Collective 306 307 Input Parameter: 308 . mapping - local to global mapping 309 310 Output Parameter: 311 . n - the number of entries in the local mapping, `ISLocalToGlobalMappingGetIndices()` returns an array of this length 312 313 Level: advanced 314 315 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()` 316 @*/ 317 PetscErrorCode ISLocalToGlobalMappingGetSize(ISLocalToGlobalMapping mapping, PetscInt *n) 318 { 319 PetscFunctionBegin; 320 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 321 PetscAssertPointer(n, 2); 322 *n = mapping->bs * mapping->n; 323 PetscFunctionReturn(PETSC_SUCCESS); 324 } 325 326 /*@ 327 ISLocalToGlobalMappingViewFromOptions - View an `ISLocalToGlobalMapping` based on values in the options database 328 329 Collective 330 331 Input Parameters: 332 + A - the local to global mapping object 333 . obj - Optional object that provides the options prefix used for the options database query 334 - name - command line option 335 336 Level: intermediate 337 338 Note: 339 See `PetscObjectViewFromOptions()` for the available `PetscViewer` and `PetscViewerFormat` 340 341 .seealso: [](sec_scatter), `PetscViewer`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingView`, `PetscObjectViewFromOptions()`, `ISLocalToGlobalMappingCreate()` 342 @*/ 343 PetscErrorCode ISLocalToGlobalMappingViewFromOptions(ISLocalToGlobalMapping A, PetscObject obj, const char name[]) 344 { 345 PetscFunctionBegin; 346 PetscValidHeaderSpecific(A, IS_LTOGM_CLASSID, 1); 347 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name)); 348 PetscFunctionReturn(PETSC_SUCCESS); 349 } 350 351 /*@ 352 ISLocalToGlobalMappingView - View a local to global mapping 353 354 Collective on viewer 355 356 Input Parameters: 357 + mapping - local to global mapping 358 - viewer - viewer 359 360 Level: intermediate 361 362 .seealso: [](sec_scatter), `PetscViewer`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()` 363 @*/ 364 PetscErrorCode ISLocalToGlobalMappingView(ISLocalToGlobalMapping mapping, PetscViewer viewer) 365 { 366 PetscBool iascii, isbinary; 367 PetscViewerFormat format; 368 369 PetscFunctionBegin; 370 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 371 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mapping), &viewer)); 372 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 373 374 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 375 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 376 PetscCall(PetscViewerGetFormat(viewer, &format)); 377 if (iascii) { 378 if (format == PETSC_VIEWER_ASCII_MATLAB) { 379 const PetscInt *idxs; 380 IS is; 381 const char *name = ((PetscObject)mapping)->name; 382 char iname[PETSC_MAX_PATH_LEN]; 383 384 PetscCall(PetscSNPrintf(iname, sizeof(iname), "%sl2g", name ? name : "")); 385 PetscCall(ISLocalToGlobalMappingGetIndices(mapping, &idxs)); 386 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), mapping->n * mapping->bs, idxs, PETSC_USE_POINTER, &is)); 387 PetscCall(PetscObjectSetName((PetscObject)is, iname)); 388 PetscCall(ISView(is, viewer)); 389 PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, &idxs)); 390 PetscCall(ISDestroy(&is)); 391 } else { 392 PetscMPIInt rank; 393 394 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mapping), &rank)); 395 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)mapping, viewer)); 396 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 397 for (PetscInt i = 0; i < mapping->n; i++) { 398 PetscInt bs = mapping->bs, g = mapping->indices[i]; 399 if (bs == 1) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT " %" PetscInt_FMT "\n", rank, i, g)); 400 else PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT ":%" PetscInt_FMT " %" PetscInt_FMT ":%" PetscInt_FMT "\n", rank, i * bs, (i + 1) * bs, g * bs, (g + 1) * bs)); 401 } 402 PetscCall(PetscViewerFlush(viewer)); 403 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 404 } 405 } else if (isbinary) { 406 PetscBool skipHeader; 407 408 PetscCall(PetscViewerSetUp(viewer)); 409 PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader)); 410 if (!skipHeader) { 411 PetscMPIInt size; 412 PetscInt tr[3]; 413 414 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size)); 415 tr[0] = IS_LTOGM_FILE_CLASSID; 416 tr[1] = mapping->bs; 417 tr[2] = size; 418 PetscCall(PetscViewerBinaryWrite(viewer, tr, 3, PETSC_INT)); 419 PetscCall(PetscViewerBinaryWriteAll(viewer, &mapping->n, 1, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT)); 420 } 421 /* write block indices */ 422 PetscCall(PetscViewerBinaryWriteAll(viewer, mapping->indices, mapping->n, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT)); 423 } 424 PetscFunctionReturn(PETSC_SUCCESS); 425 } 426 427 /*@ 428 ISLocalToGlobalMappingLoad - Loads a local-to-global mapping that has been stored in binary format. 429 430 Collective on viewer 431 432 Input Parameters: 433 + mapping - the newly loaded map, this needs to have been created with `ISLocalToGlobalMappingCreate()` or some related function before a call to `ISLocalToGlobalMappingLoad()` 434 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` 435 436 Level: intermediate 437 438 .seealso: [](sec_scatter), `PetscViewer`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingView()`, `ISLocalToGlobalMappingCreate()` 439 @*/ 440 PetscErrorCode ISLocalToGlobalMappingLoad(ISLocalToGlobalMapping mapping, PetscViewer viewer) 441 { 442 PetscBool isbinary, skipHeader; 443 444 PetscFunctionBegin; 445 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 446 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 447 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 448 PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name); 449 450 /* reset previous data */ 451 PetscCall(ISLocalToGlobalMappingResetBlockInfo_Private(mapping)); 452 453 PetscCall(PetscViewerSetUp(viewer)); 454 PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader)); 455 456 /* When skipping header, it assumes bs and n have been already set */ 457 if (!skipHeader) { 458 MPI_Comm comm = PetscObjectComm((PetscObject)viewer); 459 PetscInt tr[3], nold = mapping->n, *sizes, nmaps = PETSC_DECIDE, st = 0; 460 461 PetscCall(PetscViewerBinaryRead(viewer, tr, 3, NULL, PETSC_INT)); 462 PetscCheck(tr[0] == IS_LTOGM_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a local-to-global map next in file"); 463 464 mapping->bs = tr[1]; 465 PetscCall(PetscMalloc1(tr[2], &sizes)); 466 PetscCall(PetscViewerBinaryRead(viewer, sizes, tr[2], NULL, PETSC_INT)); 467 468 /* consume the input, read multiple maps per process if needed */ 469 PetscCall(PetscSplitOwnership(comm, &nmaps, &tr[2])); 470 PetscCallMPI(MPI_Exscan(&nmaps, &st, 1, MPIU_INT, MPI_SUM, comm)); 471 mapping->n = 0; 472 for (PetscInt i = st; i < st + nmaps; i++) mapping->n += sizes[i]; 473 PetscCall(PetscFree(sizes)); 474 475 if (nold != mapping->n) { 476 if (mapping->dealloc_indices) PetscCall(PetscFree(mapping->indices)); 477 mapping->indices = NULL; 478 } 479 } 480 481 /* read indices */ 482 if (mapping->n && !mapping->indices) { 483 PetscCall(PetscMalloc1(mapping->n, &mapping->indices)); 484 mapping->dealloc_indices = PETSC_TRUE; 485 } 486 PetscCall(PetscViewerBinaryReadAll(viewer, mapping->indices, mapping->n, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT)); 487 PetscFunctionReturn(PETSC_SUCCESS); 488 } 489 490 /*@ 491 ISLocalToGlobalMappingCreateIS - Creates a mapping between a local (0 to n) 492 ordering and a global parallel ordering. 493 494 Not Collective 495 496 Input Parameter: 497 . is - index set containing the global numbers for each local number 498 499 Output Parameter: 500 . mapping - new mapping data structure 501 502 Level: advanced 503 504 Note: 505 the block size of the `IS` determines the block size of the mapping 506 507 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetFromOptions()` 508 @*/ 509 PetscErrorCode ISLocalToGlobalMappingCreateIS(IS is, ISLocalToGlobalMapping *mapping) 510 { 511 PetscInt n, bs; 512 const PetscInt *indices; 513 MPI_Comm comm; 514 PetscBool isblock; 515 516 PetscFunctionBegin; 517 PetscValidHeaderSpecific(is, IS_CLASSID, 1); 518 PetscAssertPointer(mapping, 2); 519 520 PetscCall(PetscObjectGetComm((PetscObject)is, &comm)); 521 PetscCall(ISGetLocalSize(is, &n)); 522 PetscCall(PetscObjectTypeCompare((PetscObject)is, ISBLOCK, &isblock)); 523 if (!isblock) { 524 PetscCall(ISGetIndices(is, &indices)); 525 PetscCall(ISLocalToGlobalMappingCreate(comm, 1, n, indices, PETSC_COPY_VALUES, mapping)); 526 PetscCall(ISRestoreIndices(is, &indices)); 527 } else { 528 PetscCall(ISGetBlockSize(is, &bs)); 529 PetscCall(ISBlockGetIndices(is, &indices)); 530 PetscCall(ISLocalToGlobalMappingCreate(comm, bs, n / bs, indices, PETSC_COPY_VALUES, mapping)); 531 PetscCall(ISBlockRestoreIndices(is, &indices)); 532 } 533 PetscFunctionReturn(PETSC_SUCCESS); 534 } 535 536 /*@ 537 ISLocalToGlobalMappingCreateSF - Creates a mapping between a local (0 to n) ordering and a global parallel ordering induced by a star forest. 538 539 Collective 540 541 Input Parameters: 542 + sf - star forest mapping contiguous local indices to (rank, offset) 543 - start - first global index on this process, or `PETSC_DECIDE` to compute contiguous global numbering automatically 544 545 Output Parameter: 546 . mapping - new mapping data structure 547 548 Level: advanced 549 550 Note: 551 If a process calls this function with `start` = `PETSC_DECIDE` then all processes must, otherwise the program will hang. 552 553 .seealso: [](sec_scatter), `PetscSF`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingSetFromOptions()` 554 @*/ 555 PetscErrorCode ISLocalToGlobalMappingCreateSF(PetscSF sf, PetscInt start, ISLocalToGlobalMapping *mapping) 556 { 557 PetscInt i, maxlocal, nroots, nleaves, *globals, *ltog; 558 MPI_Comm comm; 559 560 PetscFunctionBegin; 561 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1); 562 PetscAssertPointer(mapping, 3); 563 PetscCall(PetscObjectGetComm((PetscObject)sf, &comm)); 564 PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, NULL, NULL)); 565 if (start == PETSC_DECIDE) { 566 start = 0; 567 PetscCallMPI(MPI_Exscan(&nroots, &start, 1, MPIU_INT, MPI_SUM, comm)); 568 } else PetscCheck(start >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "start must be nonnegative or PETSC_DECIDE"); 569 PetscCall(PetscSFGetLeafRange(sf, NULL, &maxlocal)); 570 ++maxlocal; 571 PetscCall(PetscMalloc1(nroots, &globals)); 572 PetscCall(PetscMalloc1(maxlocal, <og)); 573 for (i = 0; i < nroots; i++) globals[i] = start + i; 574 for (i = 0; i < maxlocal; i++) ltog[i] = -1; 575 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, globals, ltog, MPI_REPLACE)); 576 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, globals, ltog, MPI_REPLACE)); 577 PetscCall(ISLocalToGlobalMappingCreate(comm, 1, maxlocal, ltog, PETSC_OWN_POINTER, mapping)); 578 PetscCall(PetscFree(globals)); 579 PetscFunctionReturn(PETSC_SUCCESS); 580 } 581 582 /*@ 583 ISLocalToGlobalMappingSetBlockSize - Sets the blocksize of the mapping 584 585 Not Collective 586 587 Input Parameters: 588 + mapping - mapping data structure 589 - bs - the blocksize 590 591 Level: advanced 592 593 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()` 594 @*/ 595 PetscErrorCode ISLocalToGlobalMappingSetBlockSize(ISLocalToGlobalMapping mapping, PetscInt bs) 596 { 597 PetscInt *nid; 598 const PetscInt *oid; 599 PetscInt i, cn, on, obs, nn; 600 601 PetscFunctionBegin; 602 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 603 PetscCheck(bs >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid block size %" PetscInt_FMT, bs); 604 if (bs == mapping->bs) PetscFunctionReturn(PETSC_SUCCESS); 605 on = mapping->n; 606 obs = mapping->bs; 607 oid = mapping->indices; 608 nn = (on * obs) / bs; 609 PetscCheck((on * obs) % bs == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Block size %" PetscInt_FMT " is inconsistent with block size %" PetscInt_FMT " and number of block indices %" PetscInt_FMT, bs, obs, on); 610 611 PetscCall(PetscMalloc1(nn, &nid)); 612 PetscCall(ISLocalToGlobalMappingGetIndices(mapping, &oid)); 613 for (i = 0; i < nn; i++) { 614 PetscInt j; 615 for (j = 0, cn = 0; j < bs - 1; j++) { 616 if (oid[i * bs + j] < 0) { 617 cn++; 618 continue; 619 } 620 PetscCheck(oid[i * bs + j] == oid[i * bs + j + 1] - 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Block sizes %" PetscInt_FMT " and %" PetscInt_FMT " are incompatible with the block indices: non consecutive indices %" PetscInt_FMT " %" PetscInt_FMT, bs, obs, oid[i * bs + j], oid[i * bs + j + 1]); 621 } 622 if (oid[i * bs + j] < 0) cn++; 623 if (cn) { 624 PetscCheck(cn == bs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Block sizes %" PetscInt_FMT " and %" PetscInt_FMT " are incompatible with the block indices: invalid number of negative entries in block %" PetscInt_FMT, bs, obs, cn); 625 nid[i] = -1; 626 } else { 627 nid[i] = oid[i * bs] / bs; 628 } 629 } 630 PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, &oid)); 631 632 mapping->n = nn; 633 mapping->bs = bs; 634 PetscCall(PetscFree(mapping->indices)); 635 mapping->indices = nid; 636 mapping->globalstart = 0; 637 mapping->globalend = 0; 638 639 /* reset the cached information */ 640 PetscCall(ISLocalToGlobalMappingResetBlockInfo_Private(mapping)); 641 PetscTryTypeMethod(mapping, destroy); 642 PetscFunctionReturn(PETSC_SUCCESS); 643 } 644 645 /*@ 646 ISLocalToGlobalMappingGetBlockSize - Gets the blocksize of the mapping 647 ordering and a global parallel ordering. 648 649 Not Collective 650 651 Input Parameter: 652 . mapping - mapping data structure 653 654 Output Parameter: 655 . bs - the blocksize 656 657 Level: advanced 658 659 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()` 660 @*/ 661 PetscErrorCode ISLocalToGlobalMappingGetBlockSize(ISLocalToGlobalMapping mapping, PetscInt *bs) 662 { 663 PetscFunctionBegin; 664 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 665 *bs = mapping->bs; 666 PetscFunctionReturn(PETSC_SUCCESS); 667 } 668 669 /*@ 670 ISLocalToGlobalMappingCreate - Creates a mapping between a local (0 to n) 671 ordering and a global parallel ordering. 672 673 Not Collective, but communicator may have more than one process 674 675 Input Parameters: 676 + comm - MPI communicator 677 . bs - the block size 678 . n - the number of local elements divided by the block size, or equivalently the number of block indices 679 . indices - the global index for each local element, these do not need to be in increasing order (sorted), these values should not be scaled (i.e. multiplied) by the blocksize bs 680 - mode - see PetscCopyMode 681 682 Output Parameter: 683 . mapping - new mapping data structure 684 685 Level: advanced 686 687 Notes: 688 There is one integer value in indices per block and it represents the actual indices bs*idx + j, where j=0,..,bs-1 689 690 For "small" problems when using `ISGlobalToLocalMappingApply()` and `ISGlobalToLocalMappingApplyBlock()`, the `ISLocalToGlobalMappingType` 691 of `ISLOCALTOGLOBALMAPPINGBASIC` will be used; this uses more memory but is faster; this approach is not scalable for extremely large mappings. 692 693 For large problems `ISLOCALTOGLOBALMAPPINGHASH` is used, this is scalable. 694 Use `ISLocalToGlobalMappingSetType()` or call `ISLocalToGlobalMappingSetFromOptions()` with the option 695 `-islocaltoglobalmapping_type` <`basic`,`hash`> to control which is used. 696 697 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingSetFromOptions()`, 698 `ISLOCALTOGLOBALMAPPINGBASIC`, `ISLOCALTOGLOBALMAPPINGHASH` 699 `ISLocalToGlobalMappingSetType()`, `ISLocalToGlobalMappingType` 700 @*/ 701 PetscErrorCode ISLocalToGlobalMappingCreate(MPI_Comm comm, PetscInt bs, PetscInt n, const PetscInt indices[], PetscCopyMode mode, ISLocalToGlobalMapping *mapping) 702 { 703 PetscInt *in; 704 705 PetscFunctionBegin; 706 if (n) PetscAssertPointer(indices, 4); 707 PetscAssertPointer(mapping, 6); 708 709 *mapping = NULL; 710 PetscCall(ISInitializePackage()); 711 712 PetscCall(PetscHeaderCreate(*mapping, IS_LTOGM_CLASSID, "ISLocalToGlobalMapping", "Local to global mapping", "IS", comm, ISLocalToGlobalMappingDestroy, ISLocalToGlobalMappingView)); 713 (*mapping)->n = n; 714 (*mapping)->bs = bs; 715 if (mode == PETSC_COPY_VALUES) { 716 PetscCall(PetscMalloc1(n, &in)); 717 PetscCall(PetscArraycpy(in, indices, n)); 718 (*mapping)->indices = in; 719 (*mapping)->dealloc_indices = PETSC_TRUE; 720 } else if (mode == PETSC_OWN_POINTER) { 721 (*mapping)->indices = (PetscInt *)indices; 722 (*mapping)->dealloc_indices = PETSC_TRUE; 723 } else if (mode == PETSC_USE_POINTER) { 724 (*mapping)->indices = (PetscInt *)indices; 725 } else SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid mode %d", mode); 726 PetscFunctionReturn(PETSC_SUCCESS); 727 } 728 729 PetscFunctionList ISLocalToGlobalMappingList = NULL; 730 731 /*@ 732 ISLocalToGlobalMappingSetFromOptions - Set mapping options from the options database. 733 734 Not Collective 735 736 Input Parameter: 737 . mapping - mapping data structure 738 739 Options Database Key: 740 . -islocaltoglobalmapping_type - <basic,hash> nonscalable and scalable versions 741 742 Level: advanced 743 744 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, 745 `ISLocalToGlobalMappingCreateIS()`, `ISLOCALTOGLOBALMAPPINGBASIC`, 746 `ISLOCALTOGLOBALMAPPINGHASH`, `ISLocalToGlobalMappingSetType()`, `ISLocalToGlobalMappingType` 747 @*/ 748 PetscErrorCode ISLocalToGlobalMappingSetFromOptions(ISLocalToGlobalMapping mapping) 749 { 750 char type[256]; 751 ISLocalToGlobalMappingType defaulttype = "Not set"; 752 PetscBool flg; 753 754 PetscFunctionBegin; 755 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 756 PetscCall(ISLocalToGlobalMappingRegisterAll()); 757 PetscObjectOptionsBegin((PetscObject)mapping); 758 PetscCall(PetscOptionsFList("-islocaltoglobalmapping_type", "ISLocalToGlobalMapping method", "ISLocalToGlobalMappingSetType", ISLocalToGlobalMappingList, ((PetscObject)mapping)->type_name ? ((PetscObject)mapping)->type_name : defaulttype, type, 256, &flg)); 759 if (flg) PetscCall(ISLocalToGlobalMappingSetType(mapping, type)); 760 PetscOptionsEnd(); 761 PetscFunctionReturn(PETSC_SUCCESS); 762 } 763 764 /*@ 765 ISLocalToGlobalMappingDestroy - Destroys a mapping between a local (0 to n) 766 ordering and a global parallel ordering. 767 768 Not Collective 769 770 Input Parameter: 771 . mapping - mapping data structure 772 773 Level: advanced 774 775 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingCreate()` 776 @*/ 777 PetscErrorCode ISLocalToGlobalMappingDestroy(ISLocalToGlobalMapping *mapping) 778 { 779 PetscFunctionBegin; 780 if (!*mapping) PetscFunctionReturn(PETSC_SUCCESS); 781 PetscValidHeaderSpecific(*mapping, IS_LTOGM_CLASSID, 1); 782 if (--((PetscObject)*mapping)->refct > 0) { 783 *mapping = NULL; 784 PetscFunctionReturn(PETSC_SUCCESS); 785 } 786 if ((*mapping)->dealloc_indices) PetscCall(PetscFree((*mapping)->indices)); 787 PetscCall(ISLocalToGlobalMappingResetBlockInfo_Private(*mapping)); 788 PetscTryTypeMethod(*mapping, destroy); 789 PetscCall(PetscHeaderDestroy(mapping)); 790 PetscFunctionReturn(PETSC_SUCCESS); 791 } 792 793 /*@ 794 ISLocalToGlobalMappingApplyIS - Creates from an `IS` in the local numbering 795 a new index set using the global numbering defined in an `ISLocalToGlobalMapping` 796 context. 797 798 Collective 799 800 Input Parameters: 801 + mapping - mapping between local and global numbering 802 - is - index set in local numbering 803 804 Output Parameter: 805 . newis - index set in global numbering 806 807 Level: advanced 808 809 Note: 810 The output `IS` will have the same communicator as the input `IS`. 811 812 .seealso: [](sec_scatter), `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingCreate()`, 813 `ISLocalToGlobalMappingDestroy()`, `ISGlobalToLocalMappingApply()` 814 @*/ 815 PetscErrorCode ISLocalToGlobalMappingApplyIS(ISLocalToGlobalMapping mapping, IS is, IS *newis) 816 { 817 PetscInt n, *idxout; 818 const PetscInt *idxin; 819 820 PetscFunctionBegin; 821 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 822 PetscValidHeaderSpecific(is, IS_CLASSID, 2); 823 PetscAssertPointer(newis, 3); 824 825 PetscCall(ISGetLocalSize(is, &n)); 826 PetscCall(ISGetIndices(is, &idxin)); 827 PetscCall(PetscMalloc1(n, &idxout)); 828 PetscCall(ISLocalToGlobalMappingApply(mapping, n, idxin, idxout)); 829 PetscCall(ISRestoreIndices(is, &idxin)); 830 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)is), n, idxout, PETSC_OWN_POINTER, newis)); 831 PetscFunctionReturn(PETSC_SUCCESS); 832 } 833 834 /*@ 835 ISLocalToGlobalMappingApply - Takes a list of integers in a local numbering 836 and converts them to the global numbering. 837 838 Not Collective 839 840 Input Parameters: 841 + mapping - the local to global mapping context 842 . N - number of integers 843 - in - input indices in local numbering 844 845 Output Parameter: 846 . out - indices in global numbering 847 848 Level: advanced 849 850 Note: 851 The `in` and `out` array parameters may be identical. 852 853 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApplyBlock()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingDestroy()`, 854 `ISLocalToGlobalMappingApplyIS()`, `AOCreateBasic()`, `AOApplicationToPetsc()`, 855 `AOPetscToApplication()`, `ISGlobalToLocalMappingApply()` 856 @*/ 857 PetscErrorCode ISLocalToGlobalMappingApply(ISLocalToGlobalMapping mapping, PetscInt N, const PetscInt in[], PetscInt out[]) 858 { 859 PetscInt i, bs, Nmax; 860 861 PetscFunctionBegin; 862 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 863 bs = mapping->bs; 864 Nmax = bs * mapping->n; 865 if (bs == 1) { 866 const PetscInt *idx = mapping->indices; 867 for (i = 0; i < N; i++) { 868 if (in[i] < 0) { 869 out[i] = in[i]; 870 continue; 871 } 872 PetscCheck(in[i] < Nmax, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local index %" PetscInt_FMT " too large %" PetscInt_FMT " (max) at %" PetscInt_FMT, in[i], Nmax - 1, i); 873 out[i] = idx[in[i]]; 874 } 875 } else { 876 const PetscInt *idx = mapping->indices; 877 for (i = 0; i < N; i++) { 878 if (in[i] < 0) { 879 out[i] = in[i]; 880 continue; 881 } 882 PetscCheck(in[i] < Nmax, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local index %" PetscInt_FMT " too large %" PetscInt_FMT " (max) at %" PetscInt_FMT, in[i], Nmax - 1, i); 883 out[i] = idx[in[i] / bs] * bs + (in[i] % bs); 884 } 885 } 886 PetscFunctionReturn(PETSC_SUCCESS); 887 } 888 889 /*@ 890 ISLocalToGlobalMappingApplyBlock - Takes a list of integers in a local block numbering and converts them to the global block numbering 891 892 Not Collective 893 894 Input Parameters: 895 + mapping - the local to global mapping context 896 . N - number of integers 897 - in - input indices in local block numbering 898 899 Output Parameter: 900 . out - indices in global block numbering 901 902 Example: 903 If the index values are {0,1,6,7} set with a call to `ISLocalToGlobalMappingCreate`(`PETSC_COMM_SELF`,2,2,{0,3}) then the mapping applied to 0 904 (the first block) would produce 0 and the mapping applied to 1 (the second block) would produce 3. 905 906 Level: advanced 907 908 Note: 909 The `in` and `out` array parameters may be identical. 910 911 .seealso: [](sec_scatter), `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingDestroy()`, 912 `ISLocalToGlobalMappingApplyIS()`, `AOCreateBasic()`, `AOApplicationToPetsc()`, 913 `AOPetscToApplication()`, `ISGlobalToLocalMappingApply()` 914 @*/ 915 PetscErrorCode ISLocalToGlobalMappingApplyBlock(ISLocalToGlobalMapping mapping, PetscInt N, const PetscInt in[], PetscInt out[]) 916 { 917 PetscInt i, Nmax; 918 const PetscInt *idx; 919 920 PetscFunctionBegin; 921 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 922 Nmax = mapping->n; 923 idx = mapping->indices; 924 for (i = 0; i < N; i++) { 925 if (in[i] < 0) { 926 out[i] = in[i]; 927 continue; 928 } 929 PetscCheck(in[i] < Nmax, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local block index %" PetscInt_FMT " too large %" PetscInt_FMT " (max) at %" PetscInt_FMT, in[i], Nmax - 1, i); 930 out[i] = idx[in[i]]; 931 } 932 PetscFunctionReturn(PETSC_SUCCESS); 933 } 934 935 /*@ 936 ISGlobalToLocalMappingApply - Provides the local numbering for a list of integers 937 specified with a global numbering. 938 939 Not Collective 940 941 Input Parameters: 942 + mapping - mapping between local and global numbering 943 . type - `IS_GTOLM_MASK` - maps global indices with no local value to -1 in the output list (i.e., mask them) 944 `IS_GTOLM_DROP` - drops the indices with no local value from the output list 945 . n - number of global indices to map 946 - idx - global indices to map 947 948 Output Parameters: 949 + nout - number of indices in output array (if type == `IS_GTOLM_MASK` then nout = n) 950 - idxout - local index of each global index, one must pass in an array long enough 951 to hold all the indices. You can call `ISGlobalToLocalMappingApply()` with 952 idxout == NULL to determine the required length (returned in nout) 953 and then allocate the required space and call `ISGlobalToLocalMappingApply()` 954 a second time to set the values. 955 956 Level: advanced 957 958 Notes: 959 Either `nout` or `idxout` may be `NULL`. `idx` and `idxout` may be identical. 960 961 For "small" problems when using `ISGlobalToLocalMappingApply()` and `ISGlobalToLocalMappingApplyBlock()`, the `ISLocalToGlobalMappingType` of 962 `ISLOCALTOGLOBALMAPPINGBASIC` will be used; 963 this uses more memory but is faster; this approach is not scalable for extremely large mappings. For large problems `ISLOCALTOGLOBALMAPPINGHASH` is used, this is scalable. 964 Use `ISLocalToGlobalMappingSetType()` or call `ISLocalToGlobalMappingSetFromOptions()` with the option -islocaltoglobalmapping_type <basic,hash> to control which is used. 965 966 Developer Notes: 967 The manual page states that `idx` and `idxout` may be identical but the calling 968 sequence declares `idx` as const so it cannot be the same as `idxout`. 969 970 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApply()`, `ISGlobalToLocalMappingApplyBlock()`, `ISLocalToGlobalMappingCreate()`, 971 `ISLocalToGlobalMappingDestroy()` 972 @*/ 973 PetscErrorCode ISGlobalToLocalMappingApply(ISLocalToGlobalMapping mapping, ISGlobalToLocalMappingMode type, PetscInt n, const PetscInt idx[], PetscInt *nout, PetscInt idxout[]) 974 { 975 PetscFunctionBegin; 976 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 977 if (!mapping->data) PetscCall(ISGlobalToLocalMappingSetUp(mapping)); 978 PetscUseTypeMethod(mapping, globaltolocalmappingapply, type, n, idx, nout, idxout); 979 PetscFunctionReturn(PETSC_SUCCESS); 980 } 981 982 /*@ 983 ISGlobalToLocalMappingApplyIS - Creates from an `IS` in the global numbering 984 a new index set using the local numbering defined in an `ISLocalToGlobalMapping` 985 context. 986 987 Not Collective 988 989 Input Parameters: 990 + mapping - mapping between local and global numbering 991 . type - `IS_GTOLM_MASK` - maps global indices with no local value to -1 in the output list (i.e., mask them) 992 `IS_GTOLM_DROP` - drops the indices with no local value from the output list 993 - is - index set in global numbering 994 995 Output Parameter: 996 . newis - index set in local numbering 997 998 Level: advanced 999 1000 Note: 1001 The output `IS` will be sequential, as it encodes a purely local operation 1002 1003 .seealso: [](sec_scatter), `ISGlobalToLocalMapping`, `ISGlobalToLocalMappingApply()`, `ISLocalToGlobalMappingCreate()`, 1004 `ISLocalToGlobalMappingDestroy()` 1005 @*/ 1006 PetscErrorCode ISGlobalToLocalMappingApplyIS(ISLocalToGlobalMapping mapping, ISGlobalToLocalMappingMode type, IS is, IS *newis) 1007 { 1008 PetscInt n, nout, *idxout; 1009 const PetscInt *idxin; 1010 1011 PetscFunctionBegin; 1012 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1013 PetscValidHeaderSpecific(is, IS_CLASSID, 3); 1014 PetscAssertPointer(newis, 4); 1015 1016 PetscCall(ISGetLocalSize(is, &n)); 1017 PetscCall(ISGetIndices(is, &idxin)); 1018 if (type == IS_GTOLM_MASK) { 1019 PetscCall(PetscMalloc1(n, &idxout)); 1020 } else { 1021 PetscCall(ISGlobalToLocalMappingApply(mapping, type, n, idxin, &nout, NULL)); 1022 PetscCall(PetscMalloc1(nout, &idxout)); 1023 } 1024 PetscCall(ISGlobalToLocalMappingApply(mapping, type, n, idxin, &nout, idxout)); 1025 PetscCall(ISRestoreIndices(is, &idxin)); 1026 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nout, idxout, PETSC_OWN_POINTER, newis)); 1027 PetscFunctionReturn(PETSC_SUCCESS); 1028 } 1029 1030 /*@ 1031 ISGlobalToLocalMappingApplyBlock - Provides the local block numbering for a list of integers 1032 specified with a block global numbering. 1033 1034 Not Collective 1035 1036 Input Parameters: 1037 + mapping - mapping between local and global numbering 1038 . type - `IS_GTOLM_MASK` - maps global indices with no local value to -1 in the output list (i.e., mask them) 1039 `IS_GTOLM_DROP` - drops the indices with no local value from the output list 1040 . n - number of global indices to map 1041 - idx - global indices to map 1042 1043 Output Parameters: 1044 + nout - number of indices in output array (if type == `IS_GTOLM_MASK` then nout = n) 1045 - idxout - local index of each global index, one must pass in an array long enough 1046 to hold all the indices. You can call `ISGlobalToLocalMappingApplyBlock()` with 1047 idxout == NULL to determine the required length (returned in nout) 1048 and then allocate the required space and call `ISGlobalToLocalMappingApplyBlock()` 1049 a second time to set the values. 1050 1051 Level: advanced 1052 1053 Notes: 1054 Either `nout` or `idxout` may be `NULL`. `idx` and `idxout` may be identical. 1055 1056 For "small" problems when using `ISGlobalToLocalMappingApply()` and `ISGlobalToLocalMappingApplyBlock()`, the `ISLocalToGlobalMappingType` of 1057 `ISLOCALTOGLOBALMAPPINGBASIC` will be used; 1058 this uses more memory but is faster; this approach is not scalable for extremely large mappings. For large problems `ISLOCALTOGLOBALMAPPINGHASH` is used, this is scalable. 1059 Use `ISLocalToGlobalMappingSetType()` or call `ISLocalToGlobalMappingSetFromOptions()` with the option -islocaltoglobalmapping_type <basic,hash> to control which is used. 1060 1061 Developer Notes: 1062 The manual page states that `idx` and `idxout` may be identical but the calling 1063 sequence declares `idx` as const so it cannot be the same as `idxout`. 1064 1065 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApply()`, `ISGlobalToLocalMappingApply()`, `ISLocalToGlobalMappingCreate()`, 1066 `ISLocalToGlobalMappingDestroy()` 1067 @*/ 1068 PetscErrorCode ISGlobalToLocalMappingApplyBlock(ISLocalToGlobalMapping mapping, ISGlobalToLocalMappingMode type, PetscInt n, const PetscInt idx[], PetscInt *nout, PetscInt idxout[]) 1069 { 1070 PetscFunctionBegin; 1071 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1072 if (!mapping->data) PetscCall(ISGlobalToLocalMappingSetUp(mapping)); 1073 PetscUseTypeMethod(mapping, globaltolocalmappingapplyblock, type, n, idx, nout, idxout); 1074 PetscFunctionReturn(PETSC_SUCCESS); 1075 } 1076 1077 /*@C 1078 ISLocalToGlobalMappingGetBlockInfo - Gets the neighbor information 1079 1080 Collective the first time it is called 1081 1082 Input Parameter: 1083 . mapping - the mapping from local to global indexing 1084 1085 Output Parameters: 1086 + nproc - number of processes that are connected to the calling process 1087 . procs - neighboring processes 1088 . numprocs - number of block indices for each process 1089 - indices - block indices (in local numbering) shared with neighbors (sorted by global numbering) 1090 1091 Level: advanced 1092 1093 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1094 `ISLocalToGlobalMappingRestoreBlockInfo()`, `ISLocalToGlobalMappingGetBlockMultiLeavesSF()` 1095 @*/ 1096 PetscErrorCode ISLocalToGlobalMappingGetBlockInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[]) 1097 { 1098 PetscFunctionBegin; 1099 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1100 PetscCall(ISLocalToGlobalMappingSetUpBlockInfo_Private(mapping)); 1101 if (nproc) *nproc = mapping->info_nproc; 1102 if (procs) *procs = mapping->info_procs; 1103 if (numprocs) *numprocs = mapping->info_numprocs; 1104 if (indices) *indices = mapping->info_indices; 1105 PetscFunctionReturn(PETSC_SUCCESS); 1106 } 1107 1108 /*@C 1109 ISLocalToGlobalMappingGetBlockNodeInfo - Gets the neighbor information for each local block index 1110 1111 Collective the first time it is called 1112 1113 Input Parameter: 1114 . mapping - the mapping from local to global indexing 1115 1116 Output Parameters: 1117 + n - number of local block nodes 1118 . n_procs - an array storing the number of processes for each local block node (including self) 1119 - procs - the processes' rank for each local block node (sorted, self is first) 1120 1121 Level: advanced 1122 1123 Notes: 1124 The user needs to call `ISLocalToGlobalMappingRestoreBlockNodeInfo()` when the data is no longer needed. 1125 The information returned by this function complements that of `ISLocalToGlobalMappingGetBlockInfo()`. 1126 The latter only provides local information, and the neighboring information 1127 cannot be inferred in the general case, unless the mapping is locally one-to-one on each process. 1128 1129 .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1130 `ISLocalToGlobalMappingGetBlockInfo()`, `ISLocalToGlobalMappingRestoreBlockNodeInfo()`, `ISLocalToGlobalMappingGetNodeInfo()` 1131 @*/ 1132 PetscErrorCode ISLocalToGlobalMappingGetBlockNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[]) 1133 { 1134 PetscFunctionBegin; 1135 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1136 PetscCall(ISLocalToGlobalMappingSetUpBlockInfo_Private(mapping)); 1137 if (n) *n = mapping->n; 1138 if (n_procs) *n_procs = mapping->info_nodec; 1139 if (procs) *procs = mapping->info_nodei; 1140 PetscFunctionReturn(PETSC_SUCCESS); 1141 } 1142 1143 /*@C 1144 ISLocalToGlobalMappingRestoreBlockNodeInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetBlockNodeInfo()` 1145 1146 Not Collective 1147 1148 Input Parameters: 1149 + mapping - the mapping from local to global indexing 1150 . n - number of local block nodes 1151 . n_procs - an array storing the number of processes for each local block nodes (including self) 1152 - procs - the processes' rank for each local block node (sorted, self is first) 1153 1154 Level: advanced 1155 1156 .seealso: `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1157 `ISLocalToGlobalMappingGetBlockNodeInfo()` 1158 @*/ 1159 PetscErrorCode ISLocalToGlobalMappingRestoreBlockNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[]) 1160 { 1161 PetscFunctionBegin; 1162 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1163 if (n) *n = 0; 1164 if (n_procs) *n_procs = NULL; 1165 if (procs) *procs = NULL; 1166 PetscFunctionReturn(PETSC_SUCCESS); 1167 } 1168 1169 /*@C 1170 ISLocalToGlobalMappingGetBlockMultiLeavesSF - Get the star-forest to communicate multi-leaf block data 1171 1172 Collective the first time it is called 1173 1174 Input Parameter: 1175 . mapping - the mapping from local to global indexing 1176 1177 Output Parameter: 1178 . mlsf - the `PetscSF` 1179 1180 Level: advanced 1181 1182 Notes: 1183 The returned star forest is suitable to exchange local information with other processes sharing the same global block index. 1184 For example, suppose a mapping with two processes has been created with 1185 .vb 1186 rank 0 global block indices: [0, 1, 2] 1187 rank 1 global block indices: [2, 3, 4] 1188 .ve 1189 and we want to share the local information 1190 .vb 1191 rank 0 data: [-1, -2, -3] 1192 rank 1 data: [1, 2, 3] 1193 .ve 1194 then, the broadcasting action of `mlsf` will allow to collect 1195 .vb 1196 rank 0 mlleafdata: [-1, -2, -3, 3] 1197 rank 1 mlleafdata: [-3, 3, 1, 2] 1198 .ve 1199 Use ``ISLocalToGlobalMappingGetBlockNodeInfo()`` to index into the multi-leaf data. 1200 1201 .seealso: [](sec_scatter), `ISLocalToGlobalMappingGetBlockNodeInfo()`, `PetscSF` 1202 @*/ 1203 PetscErrorCode ISLocalToGlobalMappingGetBlockMultiLeavesSF(ISLocalToGlobalMapping mapping, PetscSF *mlsf) 1204 { 1205 PetscFunctionBegin; 1206 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1207 PetscAssertPointer(mlsf, 2); 1208 PetscCall(ISLocalToGlobalMappingSetUpBlockInfo_Private(mapping)); 1209 *mlsf = mapping->multileaves_sf; 1210 PetscFunctionReturn(PETSC_SUCCESS); 1211 } 1212 1213 static PetscErrorCode ISLocalToGlobalMappingSetUpBlockInfo_Private(ISLocalToGlobalMapping mapping) 1214 { 1215 PetscSF sf, sf2, imsf, msf; 1216 MPI_Comm comm; 1217 const PetscSFNode *sfnode; 1218 PetscSFNode *newsfnode; 1219 PetscLayout layout; 1220 PetscHMapI neighs; 1221 PetscHashIter iter; 1222 PetscBool missing; 1223 const PetscInt *gidxs, *rootdegree; 1224 PetscInt *mask, *mrootdata, *leafdata, *newleafdata, *leafrd, *tmpg; 1225 PetscInt nroots, nleaves, newnleaves, bs, i, j, m, mnroots, p; 1226 PetscMPIInt rank, size; 1227 1228 PetscFunctionBegin; 1229 if (mapping->multileaves_sf) PetscFunctionReturn(PETSC_SUCCESS); 1230 PetscCall(PetscObjectGetComm((PetscObject)mapping, &comm)); 1231 PetscCallMPI(MPI_Comm_size(comm, &size)); 1232 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1233 1234 /* Get mapping indices */ 1235 PetscCall(ISLocalToGlobalMappingGetBlockSize(mapping, &bs)); 1236 PetscCall(ISLocalToGlobalMappingGetBlockIndices(mapping, &gidxs)); 1237 PetscCall(ISLocalToGlobalMappingGetSize(mapping, &nleaves)); 1238 nleaves /= bs; 1239 1240 /* Create layout for global indices */ 1241 for (i = 0, m = 0; i < nleaves; i++) m = PetscMax(m, gidxs[i]); 1242 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &m, 1, MPIU_INT, MPI_MAX, comm)); 1243 PetscCall(PetscLayoutCreate(comm, &layout)); 1244 PetscCall(PetscLayoutSetSize(layout, m + 1)); 1245 PetscCall(PetscLayoutSetUp(layout)); 1246 1247 /* Create SF to share global indices */ 1248 PetscCall(PetscSFCreate(comm, &sf)); 1249 PetscCall(PetscSFSetGraphLayout(sf, layout, nleaves, NULL, PETSC_OWN_POINTER, gidxs)); 1250 PetscCall(PetscSFSetUp(sf)); 1251 PetscCall(PetscLayoutDestroy(&layout)); 1252 1253 /* communicate root degree to leaves */ 1254 PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, &sfnode)); 1255 PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree)); 1256 PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree)); 1257 for (i = 0, mnroots = 0; i < nroots; i++) mnroots += rootdegree[i]; 1258 PetscCall(PetscMalloc3(2 * PetscMax(mnroots, nroots), &mrootdata, 2 * nleaves, &leafdata, nleaves, &leafrd)); 1259 for (i = 0, m = 0; i < nroots; i++) { 1260 mrootdata[2 * i + 0] = rootdegree[i]; 1261 mrootdata[2 * i + 1] = m; 1262 m += rootdegree[i]; 1263 } 1264 PetscCall(PetscSFBcastBegin(sf, MPIU_2INT, mrootdata, leafdata, MPI_REPLACE)); 1265 PetscCall(PetscSFBcastEnd(sf, MPIU_2INT, mrootdata, leafdata, MPI_REPLACE)); 1266 1267 /* allocate enough space to store ranks */ 1268 for (i = 0, newnleaves = 0; i < nleaves; i++) { 1269 newnleaves += leafdata[2 * i]; 1270 leafrd[i] = leafdata[2 * i]; 1271 } 1272 1273 /* create new SF nodes to collect multi-root data at leaves */ 1274 PetscCall(PetscMalloc1(newnleaves, &newsfnode)); 1275 for (i = 0, m = 0; i < nleaves; i++) { 1276 for (j = 0; j < leafrd[i]; j++) { 1277 newsfnode[m].rank = sfnode[i].rank; 1278 newsfnode[m].index = leafdata[2 * i + 1] + j; 1279 m++; 1280 } 1281 } 1282 1283 /* gather ranks at multi roots */ 1284 for (i = 0; i < mnroots; i++) mrootdata[i] = -1; 1285 for (i = 0; i < nleaves; i++) leafdata[i] = rank; 1286 1287 PetscCall(PetscSFGatherBegin(sf, MPIU_INT, leafdata, mrootdata)); 1288 PetscCall(PetscSFGatherEnd(sf, MPIU_INT, leafdata, mrootdata)); 1289 1290 /* from multi-roots to multi-leaves */ 1291 PetscCall(PetscSFCreate(comm, &sf2)); 1292 PetscCall(PetscSFSetGraph(sf2, mnroots, newnleaves, NULL, PETSC_OWN_POINTER, newsfnode, PETSC_OWN_POINTER)); 1293 PetscCall(PetscSFSetUp(sf2)); 1294 1295 /* broadcast multi-root data to multi-leaves */ 1296 PetscCall(PetscMalloc1(newnleaves, &newleafdata)); 1297 PetscCall(PetscSFBcastBegin(sf2, MPIU_INT, mrootdata, newleafdata, MPI_REPLACE)); 1298 PetscCall(PetscSFBcastEnd(sf2, MPIU_INT, mrootdata, newleafdata, MPI_REPLACE)); 1299 1300 /* sort sharing ranks */ 1301 for (i = 0, m = 0; i < nleaves; i++) { 1302 PetscCall(PetscSortInt(leafrd[i], newleafdata + m)); 1303 m += leafrd[i]; 1304 } 1305 1306 /* Number of neighbors and their ranks */ 1307 PetscCall(PetscHMapICreate(&neighs)); 1308 for (i = 0; i < newnleaves; i++) PetscCall(PetscHMapIPut(neighs, newleafdata[i], &iter, &missing)); 1309 PetscCall(PetscHMapIGetSize(neighs, &mapping->info_nproc)); 1310 PetscCall(PetscMalloc1(mapping->info_nproc + 1, &mapping->info_procs)); 1311 PetscCall(PetscHMapIGetKeys(neighs, (i = 0, &i), mapping->info_procs)); 1312 for (i = 0; i < mapping->info_nproc; i++) { /* put info for self first */ 1313 if (mapping->info_procs[i] == rank) { 1314 PetscInt newr = mapping->info_procs[0]; 1315 1316 mapping->info_procs[0] = rank; 1317 mapping->info_procs[i] = newr; 1318 break; 1319 } 1320 } 1321 if (mapping->info_nproc) PetscCall(PetscSortInt(mapping->info_nproc - 1, mapping->info_procs + 1)); 1322 PetscCall(PetscHMapIDestroy(&neighs)); 1323 1324 /* collect info data */ 1325 PetscCall(PetscMalloc1(mapping->info_nproc, &mapping->info_numprocs)); 1326 PetscCall(PetscMalloc1(mapping->info_nproc, &mapping->info_indices)); 1327 for (i = 0; i < mapping->info_nproc; i++) mapping->info_indices[i] = NULL; 1328 1329 PetscCall(PetscMalloc1(nleaves, &mask)); 1330 PetscCall(PetscMalloc1(nleaves, &tmpg)); 1331 for (p = 0; p < mapping->info_nproc; p++) { 1332 PetscInt *tmp, trank = mapping->info_procs[p]; 1333 1334 PetscCall(PetscMemzero(mask, nleaves * sizeof(*mask))); 1335 for (i = 0, m = 0; i < nleaves; i++) { 1336 for (j = 0; j < leafrd[i]; j++) { 1337 if (newleafdata[m] == trank) mask[i]++; 1338 if (!p && newleafdata[m] != rank) mask[i]++; 1339 m++; 1340 } 1341 } 1342 for (i = 0, m = 0; i < nleaves; i++) 1343 if (mask[i] > (!p ? 1 : 0)) m++; 1344 1345 PetscCall(PetscMalloc1(m, &tmp)); 1346 for (i = 0, m = 0; i < nleaves; i++) 1347 if (mask[i] > (!p ? 1 : 0)) { 1348 tmp[m] = i; 1349 tmpg[m] = gidxs[i]; 1350 m++; 1351 } 1352 PetscCall(PetscSortIntWithArray(m, tmpg, tmp)); 1353 mapping->info_indices[p] = tmp; 1354 mapping->info_numprocs[p] = m; 1355 } 1356 1357 /* Node info */ 1358 PetscCall(PetscMalloc2(nleaves, &mapping->info_nodec, nleaves + 1, &mapping->info_nodei)); 1359 PetscCall(PetscArraycpy(mapping->info_nodec, leafrd, nleaves)); 1360 PetscCall(PetscMalloc1(newnleaves, &mapping->info_nodei[0])); 1361 for (i = 0; i < nleaves - 1; i++) mapping->info_nodei[i + 1] = mapping->info_nodei[i] + mapping->info_nodec[i]; 1362 PetscCall(PetscArraycpy(mapping->info_nodei[0], newleafdata, newnleaves)); 1363 1364 /* Create SF from leaves to multi-leaves */ 1365 PetscCall(PetscSFGetMultiSF(sf, &msf)); 1366 PetscCall(PetscSFCreateInverseSF(msf, &imsf)); 1367 PetscCall(PetscSFCompose(imsf, sf2, &mapping->multileaves_sf)); 1368 PetscCall(PetscSFDestroy(&imsf)); 1369 PetscCall(PetscSFDestroy(&sf)); 1370 PetscCall(PetscSFDestroy(&sf2)); 1371 1372 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(mapping, &gidxs)); 1373 PetscCall(PetscFree(tmpg)); 1374 PetscCall(PetscFree(mask)); 1375 PetscCall(PetscFree3(mrootdata, leafdata, leafrd)); 1376 PetscCall(PetscFree(newleafdata)); 1377 PetscFunctionReturn(PETSC_SUCCESS); 1378 } 1379 1380 /*@C 1381 ISLocalToGlobalMappingRestoreBlockInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetBlockInfo()` 1382 1383 Not Collective 1384 1385 Input Parameters: 1386 + mapping - the mapping from local to global indexing 1387 . nproc - number of processes that are connected to the calling process 1388 . procs - neighboring processes 1389 . numprocs - number of block indices for each process 1390 - indices - block indices (in local numbering) shared with neighbors (sorted by global numbering) 1391 1392 Level: advanced 1393 1394 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1395 `ISLocalToGlobalMappingGetInfo()` 1396 @*/ 1397 PetscErrorCode ISLocalToGlobalMappingRestoreBlockInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[]) 1398 { 1399 PetscFunctionBegin; 1400 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1401 if (nproc) *nproc = 0; 1402 if (procs) *procs = NULL; 1403 if (numprocs) *numprocs = NULL; 1404 if (indices) *indices = NULL; 1405 PetscFunctionReturn(PETSC_SUCCESS); 1406 } 1407 1408 /*@C 1409 ISLocalToGlobalMappingGetInfo - Gets the neighbor information for each process 1410 1411 Collective the first time it is called 1412 1413 Input Parameter: 1414 . mapping - the mapping from local to global indexing 1415 1416 Output Parameters: 1417 + nproc - number of processes that are connected to the calling process 1418 . procs - neighboring processes 1419 . numprocs - number of indices for each process 1420 - indices - indices (in local numbering) shared with neighbors (sorted by global numbering) 1421 1422 Level: advanced 1423 1424 Note: 1425 The user needs to call `ISLocalToGlobalMappingRestoreInfo()` when the data is no longer needed. 1426 1427 Fortran Notes: 1428 There is no `ISLocalToGlobalMappingRestoreInfo()` in Fortran. You must make sure that 1429 `procs`[], `numprocs`[] and `indices`[][] are large enough arrays, either by allocating them 1430 dynamically or defining static ones large enough. 1431 1432 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1433 `ISLocalToGlobalMappingRestoreInfo()`, `ISLocalToGlobalMappingGetNodeInfo()` 1434 @*/ 1435 PetscErrorCode ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[]) 1436 { 1437 PetscInt **bindices = NULL, *bnumprocs = NULL, bs, i, j, k, n, *bprocs; 1438 1439 PetscFunctionBegin; 1440 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1441 bs = mapping->bs; 1442 PetscCall(ISLocalToGlobalMappingGetBlockInfo(mapping, &n, &bprocs, &bnumprocs, &bindices)); 1443 if (bs > 1) { /* we need to expand the cached info */ 1444 if (indices) PetscCall(PetscCalloc1(n, indices)); 1445 if (numprocs) PetscCall(PetscCalloc1(n, numprocs)); 1446 if (indices || numprocs) { 1447 for (i = 0; i < n; i++) { 1448 if (indices) { 1449 PetscCall(PetscMalloc1(bs * bnumprocs[i], &(*indices)[i])); 1450 for (j = 0; j < bnumprocs[i]; j++) { 1451 for (k = 0; k < bs; k++) (*indices)[i][j * bs + k] = bs * bindices[i][j] + k; 1452 } 1453 } 1454 if (numprocs) (*numprocs)[i] = bnumprocs[i] * bs; 1455 } 1456 } 1457 } else { 1458 if (numprocs) *numprocs = bnumprocs; 1459 if (indices) *indices = bindices; 1460 } 1461 if (nproc) *nproc = n; 1462 if (procs) *procs = bprocs; 1463 PetscFunctionReturn(PETSC_SUCCESS); 1464 } 1465 1466 /*@C 1467 ISLocalToGlobalMappingRestoreInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetInfo()` 1468 1469 Not Collective 1470 1471 Input Parameters: 1472 + mapping - the mapping from local to global indexing 1473 . nproc - number of processes that are connected to the calling process 1474 . procs - neighboring processes 1475 . numprocs - number of indices for each process 1476 - indices - indices (in local numbering) shared with neighbors (sorted by global numbering) 1477 1478 Level: advanced 1479 1480 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1481 `ISLocalToGlobalMappingGetInfo()` 1482 @*/ 1483 PetscErrorCode ISLocalToGlobalMappingRestoreInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[]) 1484 { 1485 PetscFunctionBegin; 1486 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1487 if (mapping->bs > 1) { 1488 if (numprocs) PetscCall(PetscFree(*numprocs)); 1489 if (indices) { 1490 if (*indices) 1491 for (PetscInt i = 0; i < *nproc; i++) PetscCall(PetscFree((*indices)[i])); 1492 PetscCall(PetscFree(*indices)); 1493 } 1494 } 1495 PetscFunctionReturn(PETSC_SUCCESS); 1496 } 1497 1498 /*@C 1499 ISLocalToGlobalMappingGetNodeInfo - Gets the neighbor information of local nodes 1500 1501 Collective the first time it is called 1502 1503 Input Parameter: 1504 . mapping - the mapping from local to global indexing 1505 1506 Output Parameters: 1507 + n - number of local nodes 1508 . n_procs - an array storing the number of processes for each local node (including self) 1509 - procs - the processes' rank for each local node (sorted, self is first) 1510 1511 Level: advanced 1512 1513 Note: 1514 The user needs to call `ISLocalToGlobalMappingRestoreNodeInfo()` when the data is no longer needed. 1515 1516 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1517 `ISLocalToGlobalMappingGetInfo()`, `ISLocalToGlobalMappingRestoreNodeInfo()`, `ISLocalToGlobalMappingGetBlockNodeInfo()` 1518 @*/ 1519 PetscErrorCode ISLocalToGlobalMappingGetNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[]) 1520 { 1521 PetscInt **bprocs = NULL, *bn_procs = NULL, bs, i, j, k, bn; 1522 1523 PetscFunctionBegin; 1524 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1525 bs = mapping->bs; 1526 PetscCall(ISLocalToGlobalMappingGetBlockNodeInfo(mapping, &bn, &bn_procs, &bprocs)); 1527 if (bs > 1) { /* we need to expand the cached info */ 1528 PetscInt *tn_procs; 1529 PetscInt c; 1530 1531 PetscCall(PetscMalloc1(bn * bs, &tn_procs)); 1532 for (i = 0, c = 0; i < bn; i++) { 1533 for (k = 0; k < bs; k++) tn_procs[i * bs + k] = bn_procs[i]; 1534 c += bs * bn_procs[i]; 1535 } 1536 if (n) *n = bn * bs; 1537 if (procs) { 1538 PetscInt **tprocs; 1539 PetscInt tn = bn * bs; 1540 1541 PetscCall(PetscMalloc1(tn, &tprocs)); 1542 if (tn) PetscCall(PetscMalloc1(c, &tprocs[0])); 1543 for (i = 0; i < tn - 1; i++) tprocs[i + 1] = tprocs[i] + tn_procs[i]; 1544 for (i = 0; i < bn; i++) { 1545 for (k = 0; k < bs; k++) { 1546 for (j = 0; j < bn_procs[i]; j++) tprocs[i * bs + k][j] = bprocs[i][j]; 1547 } 1548 } 1549 *procs = tprocs; 1550 } 1551 if (n_procs) *n_procs = tn_procs; 1552 else PetscCall(PetscFree(tn_procs)); 1553 } else { 1554 if (n) *n = bn; 1555 if (n_procs) *n_procs = bn_procs; 1556 if (procs) *procs = bprocs; 1557 } 1558 PetscFunctionReturn(PETSC_SUCCESS); 1559 } 1560 1561 /*@C 1562 ISLocalToGlobalMappingRestoreNodeInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetNodeInfo()` 1563 1564 Not Collective 1565 1566 Input Parameters: 1567 + mapping - the mapping from local to global indexing 1568 . n - number of local nodes 1569 . n_procs - an array storing the number of processes for each local node (including self) 1570 - procs - the processes' rank for each local node (sorted, self is first) 1571 1572 Level: advanced 1573 1574 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1575 `ISLocalToGlobalMappingGetInfo()` 1576 @*/ 1577 PetscErrorCode ISLocalToGlobalMappingRestoreNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[]) 1578 { 1579 PetscFunctionBegin; 1580 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1581 if (mapping->bs > 1) { 1582 if (n_procs) PetscCall(PetscFree(*n_procs)); 1583 if (procs) { 1584 if (*procs) PetscCall(PetscFree((*procs)[0])); 1585 PetscCall(PetscFree(*procs)); 1586 } 1587 } 1588 PetscCall(ISLocalToGlobalMappingRestoreBlockNodeInfo(mapping, n, n_procs, procs)); 1589 PetscFunctionReturn(PETSC_SUCCESS); 1590 } 1591 1592 /*@C 1593 ISLocalToGlobalMappingGetIndices - Get global indices for every local point that is mapped 1594 1595 Not Collective 1596 1597 Input Parameter: 1598 . ltog - local to global mapping 1599 1600 Output Parameter: 1601 . array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()` 1602 1603 Level: advanced 1604 1605 Note: 1606 `ISLocalToGlobalMappingGetSize()` returns the length the this array 1607 1608 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingRestoreIndices()`, 1609 `ISLocalToGlobalMappingGetBlockIndices()`, `ISLocalToGlobalMappingRestoreBlockIndices()` 1610 @*/ 1611 PetscErrorCode ISLocalToGlobalMappingGetIndices(ISLocalToGlobalMapping ltog, const PetscInt *array[]) 1612 { 1613 PetscFunctionBegin; 1614 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1615 PetscAssertPointer(array, 2); 1616 if (ltog->bs == 1) { 1617 *array = ltog->indices; 1618 } else { 1619 PetscInt *jj, k, i, j, n = ltog->n, bs = ltog->bs; 1620 const PetscInt *ii; 1621 1622 PetscCall(PetscMalloc1(bs * n, &jj)); 1623 *array = jj; 1624 k = 0; 1625 ii = ltog->indices; 1626 for (i = 0; i < n; i++) 1627 for (j = 0; j < bs; j++) jj[k++] = bs * ii[i] + j; 1628 } 1629 PetscFunctionReturn(PETSC_SUCCESS); 1630 } 1631 1632 /*@C 1633 ISLocalToGlobalMappingRestoreIndices - Restore indices obtained with `ISLocalToGlobalMappingGetIndices()` 1634 1635 Not Collective 1636 1637 Input Parameters: 1638 + ltog - local to global mapping 1639 - array - array of indices 1640 1641 Level: advanced 1642 1643 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()` 1644 @*/ 1645 PetscErrorCode ISLocalToGlobalMappingRestoreIndices(ISLocalToGlobalMapping ltog, const PetscInt *array[]) 1646 { 1647 PetscFunctionBegin; 1648 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1649 PetscAssertPointer(array, 2); 1650 PetscCheck(ltog->bs != 1 || *array == ltog->indices, PETSC_COMM_SELF, PETSC_ERR_ARG_BADPTR, "Trying to return mismatched pointer"); 1651 if (ltog->bs > 1) PetscCall(PetscFree(*(void **)array)); 1652 PetscFunctionReturn(PETSC_SUCCESS); 1653 } 1654 1655 /*@C 1656 ISLocalToGlobalMappingGetBlockIndices - Get global indices for every local block in a `ISLocalToGlobalMapping` 1657 1658 Not Collective 1659 1660 Input Parameter: 1661 . ltog - local to global mapping 1662 1663 Output Parameter: 1664 . array - array of indices 1665 1666 Level: advanced 1667 1668 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, 1669 `ISLocalToGlobalMappingRestoreBlockIndices()` 1670 @*/ 1671 PetscErrorCode ISLocalToGlobalMappingGetBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt *array[]) 1672 { 1673 PetscFunctionBegin; 1674 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1675 PetscAssertPointer(array, 2); 1676 *array = ltog->indices; 1677 PetscFunctionReturn(PETSC_SUCCESS); 1678 } 1679 1680 /*@C 1681 ISLocalToGlobalMappingRestoreBlockIndices - Restore indices obtained with `ISLocalToGlobalMappingGetBlockIndices()` 1682 1683 Not Collective 1684 1685 Input Parameters: 1686 + ltog - local to global mapping 1687 - array - array of indices 1688 1689 Level: advanced 1690 1691 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()` 1692 @*/ 1693 PetscErrorCode ISLocalToGlobalMappingRestoreBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt *array[]) 1694 { 1695 PetscFunctionBegin; 1696 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1697 PetscAssertPointer(array, 2); 1698 PetscCheck(*array == ltog->indices, PETSC_COMM_SELF, PETSC_ERR_ARG_BADPTR, "Trying to return mismatched pointer"); 1699 *array = NULL; 1700 PetscFunctionReturn(PETSC_SUCCESS); 1701 } 1702 1703 /*@ 1704 ISLocalToGlobalMappingConcatenate - Create a new mapping that concatenates a list of mappings 1705 1706 Not Collective 1707 1708 Input Parameters: 1709 + comm - communicator for the new mapping, must contain the communicator of every mapping to concatenate 1710 . n - number of mappings to concatenate 1711 - ltogs - local to global mappings 1712 1713 Output Parameter: 1714 . ltogcat - new mapping 1715 1716 Level: advanced 1717 1718 Note: 1719 This currently always returns a mapping with block size of 1 1720 1721 Developer Notes: 1722 If all the input mapping have the same block size we could easily handle that as a special case 1723 1724 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingCreate()` 1725 @*/ 1726 PetscErrorCode ISLocalToGlobalMappingConcatenate(MPI_Comm comm, PetscInt n, const ISLocalToGlobalMapping ltogs[], ISLocalToGlobalMapping *ltogcat) 1727 { 1728 PetscInt i, cnt, m, *idx; 1729 1730 PetscFunctionBegin; 1731 PetscCheck(n >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Must have a non-negative number of mappings, given %" PetscInt_FMT, n); 1732 if (n > 0) PetscAssertPointer(ltogs, 3); 1733 for (i = 0; i < n; i++) PetscValidHeaderSpecific(ltogs[i], IS_LTOGM_CLASSID, 3); 1734 PetscAssertPointer(ltogcat, 4); 1735 for (cnt = 0, i = 0; i < n; i++) { 1736 PetscCall(ISLocalToGlobalMappingGetSize(ltogs[i], &m)); 1737 cnt += m; 1738 } 1739 PetscCall(PetscMalloc1(cnt, &idx)); 1740 for (cnt = 0, i = 0; i < n; i++) { 1741 const PetscInt *subidx; 1742 PetscCall(ISLocalToGlobalMappingGetSize(ltogs[i], &m)); 1743 PetscCall(ISLocalToGlobalMappingGetIndices(ltogs[i], &subidx)); 1744 PetscCall(PetscArraycpy(&idx[cnt], subidx, m)); 1745 PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogs[i], &subidx)); 1746 cnt += m; 1747 } 1748 PetscCall(ISLocalToGlobalMappingCreate(comm, 1, cnt, idx, PETSC_OWN_POINTER, ltogcat)); 1749 PetscFunctionReturn(PETSC_SUCCESS); 1750 } 1751 1752 /*MC 1753 ISLOCALTOGLOBALMAPPINGBASIC - basic implementation of the `ISLocalToGlobalMapping` object. When `ISGlobalToLocalMappingApply()` is 1754 used this is good for only small and moderate size problems. 1755 1756 Options Database Key: 1757 . -islocaltoglobalmapping_type basic - select this method 1758 1759 Level: beginner 1760 1761 Developer Note: 1762 This stores all the mapping information on each MPI rank. 1763 1764 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGHASH` 1765 M*/ 1766 PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Basic(ISLocalToGlobalMapping ltog) 1767 { 1768 PetscFunctionBegin; 1769 ltog->ops->globaltolocalmappingapply = ISGlobalToLocalMappingApply_Basic; 1770 ltog->ops->globaltolocalmappingsetup = ISGlobalToLocalMappingSetUp_Basic; 1771 ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Basic; 1772 ltog->ops->destroy = ISLocalToGlobalMappingDestroy_Basic; 1773 PetscFunctionReturn(PETSC_SUCCESS); 1774 } 1775 1776 /*MC 1777 ISLOCALTOGLOBALMAPPINGHASH - hash implementation of the `ISLocalToGlobalMapping` object. When `ISGlobalToLocalMappingApply()` is 1778 used this is good for large memory problems. 1779 1780 Options Database Key: 1781 . -islocaltoglobalmapping_type hash - select this method 1782 1783 Level: beginner 1784 1785 Note: 1786 This is selected automatically for large problems if the user does not set the type. 1787 1788 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGBASIC` 1789 M*/ 1790 PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Hash(ISLocalToGlobalMapping ltog) 1791 { 1792 PetscFunctionBegin; 1793 ltog->ops->globaltolocalmappingapply = ISGlobalToLocalMappingApply_Hash; 1794 ltog->ops->globaltolocalmappingsetup = ISGlobalToLocalMappingSetUp_Hash; 1795 ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Hash; 1796 ltog->ops->destroy = ISLocalToGlobalMappingDestroy_Hash; 1797 PetscFunctionReturn(PETSC_SUCCESS); 1798 } 1799 1800 /*@C 1801 ISLocalToGlobalMappingRegister - Registers a method for applying a global to local mapping with an `ISLocalToGlobalMapping` 1802 1803 Not Collective, No Fortran Support 1804 1805 Input Parameters: 1806 + sname - name of a new method 1807 - function - routine to create method context 1808 1809 Example Usage: 1810 .vb 1811 ISLocalToGlobalMappingRegister("my_mapper", MyCreate); 1812 .ve 1813 1814 Then, your mapping can be chosen with the procedural interface via 1815 $ ISLocalToGlobalMappingSetType(ltog, "my_mapper") 1816 or at runtime via the option 1817 $ -islocaltoglobalmapping_type my_mapper 1818 1819 Level: advanced 1820 1821 Note: 1822 `ISLocalToGlobalMappingRegister()` may be called multiple times to add several user-defined mappings. 1823 1824 .seealso: [](sec_scatter), `ISLocalToGlobalMappingRegisterAll()`, `ISLocalToGlobalMappingRegisterDestroy()`, `ISLOCALTOGLOBALMAPPINGBASIC`, 1825 `ISLOCALTOGLOBALMAPPINGHASH`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApply()` 1826 @*/ 1827 PetscErrorCode ISLocalToGlobalMappingRegister(const char sname[], PetscErrorCode (*function)(ISLocalToGlobalMapping)) 1828 { 1829 PetscFunctionBegin; 1830 PetscCall(ISInitializePackage()); 1831 PetscCall(PetscFunctionListAdd(&ISLocalToGlobalMappingList, sname, function)); 1832 PetscFunctionReturn(PETSC_SUCCESS); 1833 } 1834 1835 /*@ 1836 ISLocalToGlobalMappingSetType - Sets the implementation type `ISLocalToGlobalMapping` will use 1837 1838 Logically Collective 1839 1840 Input Parameters: 1841 + ltog - the `ISLocalToGlobalMapping` object 1842 - type - a known method 1843 1844 Options Database Key: 1845 . -islocaltoglobalmapping_type <method> - Sets the method; use -help for a list of available methods (for instance, basic or hash) 1846 1847 Level: intermediate 1848 1849 Notes: 1850 See `ISLocalToGlobalMappingType` for available methods 1851 1852 Normally, it is best to use the `ISLocalToGlobalMappingSetFromOptions()` command and 1853 then set the `ISLocalToGlobalMappingType` from the options database rather than by using 1854 this routine. 1855 1856 Developer Notes: 1857 `ISLocalToGlobalMappingRegister()` is used to add new types to `ISLocalToGlobalMappingList` from which they 1858 are accessed by `ISLocalToGlobalMappingSetType()`. 1859 1860 .seealso: [](sec_scatter), `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingGetType()` 1861 @*/ 1862 PetscErrorCode ISLocalToGlobalMappingSetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType type) 1863 { 1864 PetscBool match; 1865 PetscErrorCode (*r)(ISLocalToGlobalMapping) = NULL; 1866 1867 PetscFunctionBegin; 1868 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1869 if (type) PetscAssertPointer(type, 2); 1870 1871 PetscCall(PetscObjectTypeCompare((PetscObject)ltog, type, &match)); 1872 if (match) PetscFunctionReturn(PETSC_SUCCESS); 1873 1874 /* L2G maps defer type setup at globaltolocal calls, allow passing NULL here */ 1875 if (type) { 1876 PetscCall(PetscFunctionListFind(ISLocalToGlobalMappingList, type, &r)); 1877 PetscCheck(r, PetscObjectComm((PetscObject)ltog), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested ISLocalToGlobalMapping type %s", type); 1878 } 1879 /* Destroy the previous private LTOG context */ 1880 PetscTryTypeMethod(ltog, destroy); 1881 ltog->ops->destroy = NULL; 1882 1883 PetscCall(PetscObjectChangeTypeName((PetscObject)ltog, type)); 1884 if (r) PetscCall((*r)(ltog)); 1885 PetscFunctionReturn(PETSC_SUCCESS); 1886 } 1887 1888 /*@ 1889 ISLocalToGlobalMappingGetType - Get the type of the `ISLocalToGlobalMapping` 1890 1891 Not Collective 1892 1893 Input Parameter: 1894 . ltog - the `ISLocalToGlobalMapping` object 1895 1896 Output Parameter: 1897 . type - the type 1898 1899 Level: intermediate 1900 1901 .seealso: [](sec_scatter), `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()` 1902 @*/ 1903 PetscErrorCode ISLocalToGlobalMappingGetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType *type) 1904 { 1905 PetscFunctionBegin; 1906 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1907 PetscAssertPointer(type, 2); 1908 *type = ((PetscObject)ltog)->type_name; 1909 PetscFunctionReturn(PETSC_SUCCESS); 1910 } 1911 1912 PetscBool ISLocalToGlobalMappingRegisterAllCalled = PETSC_FALSE; 1913 1914 /*@C 1915 ISLocalToGlobalMappingRegisterAll - Registers all of the local to global mapping components in the `IS` package. 1916 1917 Not Collective 1918 1919 Level: advanced 1920 1921 .seealso: [](sec_scatter), `ISRegister()`, `ISLocalToGlobalRegister()` 1922 @*/ 1923 PetscErrorCode ISLocalToGlobalMappingRegisterAll(void) 1924 { 1925 PetscFunctionBegin; 1926 if (ISLocalToGlobalMappingRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 1927 ISLocalToGlobalMappingRegisterAllCalled = PETSC_TRUE; 1928 PetscCall(ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGBASIC, ISLocalToGlobalMappingCreate_Basic)); 1929 PetscCall(ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGHASH, ISLocalToGlobalMappingCreate_Hash)); 1930 PetscFunctionReturn(PETSC_SUCCESS); 1931 } 1932