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 /*@C 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_MAX_INT; 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 PetscFunctionReturn(PETSC_SUCCESS); 233 } 234 235 #define GTOLTYPE _Basic 236 #define GTOLNAME _Basic 237 #define GTOLBS mapping->bs 238 #define GTOL(g, local) \ 239 do { \ 240 local = map->globals[g / bs - start]; \ 241 if (local >= 0) local = bs * local + (g % bs); \ 242 } while (0) 243 244 #include <../src/vec/is/utils/isltog.h> 245 246 #define GTOLTYPE _Basic 247 #define GTOLNAME Block_Basic 248 #define GTOLBS 1 249 #define GTOL(g, local) \ 250 do { \ 251 local = map->globals[g - start]; \ 252 } while (0) 253 #include <../src/vec/is/utils/isltog.h> 254 255 #define GTOLTYPE _Hash 256 #define GTOLNAME _Hash 257 #define GTOLBS mapping->bs 258 #define GTOL(g, local) \ 259 do { \ 260 (void)PetscHMapIGet(map->globalht, g / bs, &local); \ 261 if (local >= 0) local = bs * local + (g % bs); \ 262 } while (0) 263 #include <../src/vec/is/utils/isltog.h> 264 265 #define GTOLTYPE _Hash 266 #define GTOLNAME Block_Hash 267 #define GTOLBS 1 268 #define GTOL(g, local) \ 269 do { \ 270 (void)PetscHMapIGet(map->globalht, g, &local); \ 271 } while (0) 272 #include <../src/vec/is/utils/isltog.h> 273 274 /*@ 275 ISLocalToGlobalMappingDuplicate - Duplicates the local to global mapping object 276 277 Not Collective 278 279 Input Parameter: 280 . ltog - local to global mapping 281 282 Output Parameter: 283 . nltog - the duplicated local to global mapping 284 285 Level: advanced 286 287 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()` 288 @*/ 289 PetscErrorCode ISLocalToGlobalMappingDuplicate(ISLocalToGlobalMapping ltog, ISLocalToGlobalMapping *nltog) 290 { 291 ISLocalToGlobalMappingType l2gtype; 292 293 PetscFunctionBegin; 294 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 295 PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)ltog), ltog->bs, ltog->n, ltog->indices, PETSC_COPY_VALUES, nltog)); 296 PetscCall(ISLocalToGlobalMappingGetType(ltog, &l2gtype)); 297 PetscCall(ISLocalToGlobalMappingSetType(*nltog, l2gtype)); 298 PetscFunctionReturn(PETSC_SUCCESS); 299 } 300 301 /*@ 302 ISLocalToGlobalMappingGetSize - Gets the local size of a local to global mapping 303 304 Not Collective 305 306 Input Parameter: 307 . mapping - local to global mapping 308 309 Output Parameter: 310 . n - the number of entries in the local mapping, `ISLocalToGlobalMappingGetIndices()` returns an array of this length 311 312 Level: advanced 313 314 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()` 315 @*/ 316 PetscErrorCode ISLocalToGlobalMappingGetSize(ISLocalToGlobalMapping mapping, PetscInt *n) 317 { 318 PetscFunctionBegin; 319 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 320 PetscAssertPointer(n, 2); 321 *n = mapping->bs * mapping->n; 322 PetscFunctionReturn(PETSC_SUCCESS); 323 } 324 325 /*@C 326 ISLocalToGlobalMappingViewFromOptions - View an `ISLocalToGlobalMapping` based on values in the options database 327 328 Collective 329 330 Input Parameters: 331 + A - the local to global mapping object 332 . obj - Optional object that provides the options prefix used for the options database query 333 - name - command line option 334 335 Level: intermediate 336 337 Note: 338 See `PetscObjectViewFromOptions()` for the available `PetscViewer` and `PetscViewerFormat` 339 340 .seealso: [](sec_scatter), `PetscViewer`, ``ISLocalToGlobalMapping`, `ISLocalToGlobalMappingView`, `PetscObjectViewFromOptions()`, `ISLocalToGlobalMappingCreate()` 341 @*/ 342 PetscErrorCode ISLocalToGlobalMappingViewFromOptions(ISLocalToGlobalMapping A, PetscObject obj, const char name[]) 343 { 344 PetscFunctionBegin; 345 PetscValidHeaderSpecific(A, IS_LTOGM_CLASSID, 1); 346 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name)); 347 PetscFunctionReturn(PETSC_SUCCESS); 348 } 349 350 /*@C 351 ISLocalToGlobalMappingView - View a local to global mapping 352 353 Collective on viewer 354 355 Input Parameters: 356 + mapping - local to global mapping 357 - viewer - viewer 358 359 Level: intermediate 360 361 .seealso: [](sec_scatter), `PetscViewer`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()` 362 @*/ 363 PetscErrorCode ISLocalToGlobalMappingView(ISLocalToGlobalMapping mapping, PetscViewer viewer) 364 { 365 PetscBool iascii, isbinary; 366 PetscViewerFormat format; 367 368 PetscFunctionBegin; 369 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 370 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mapping), &viewer)); 371 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 372 373 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 374 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 375 PetscCall(PetscViewerGetFormat(viewer, &format)); 376 if (iascii) { 377 if (format == PETSC_VIEWER_ASCII_MATLAB) { 378 const PetscInt *idxs; 379 IS is; 380 const char *name = ((PetscObject)mapping)->name; 381 char iname[PETSC_MAX_PATH_LEN]; 382 383 PetscCall(PetscSNPrintf(iname, sizeof(iname), "%sl2g", name ? name : "")); 384 PetscCall(ISLocalToGlobalMappingGetIndices(mapping, &idxs)); 385 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), mapping->n * mapping->bs, idxs, PETSC_USE_POINTER, &is)); 386 PetscCall(PetscObjectSetName((PetscObject)is, iname)); 387 PetscCall(ISView(is, viewer)); 388 PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, &idxs)); 389 PetscCall(ISDestroy(&is)); 390 } else { 391 PetscMPIInt rank; 392 393 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mapping), &rank)); 394 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)mapping, viewer)); 395 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 396 for (PetscInt i = 0; i < mapping->n; i++) { 397 PetscInt bs = mapping->bs, g = mapping->indices[i]; 398 if (bs == 1) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %" PetscInt_FMT " %" PetscInt_FMT "\n", rank, i, g)); 399 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)); 400 } 401 PetscCall(PetscViewerFlush(viewer)); 402 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 403 } 404 } else if (isbinary) { 405 PetscBool skipHeader; 406 407 PetscCall(PetscViewerSetUp(viewer)); 408 PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader)); 409 if (!skipHeader) { 410 PetscMPIInt size; 411 PetscInt tr[3]; 412 413 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size)); 414 tr[0] = IS_LTOGM_FILE_CLASSID; 415 tr[1] = mapping->bs; 416 tr[2] = size; 417 PetscCall(PetscViewerBinaryWrite(viewer, tr, 3, PETSC_INT)); 418 PetscCall(PetscViewerBinaryWriteAll(viewer, &mapping->n, 1, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT)); 419 } 420 /* write block indices */ 421 PetscCall(PetscViewerBinaryWriteAll(viewer, mapping->indices, mapping->n, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT)); 422 } 423 PetscFunctionReturn(PETSC_SUCCESS); 424 } 425 426 /*@ 427 ISLocalToGlobalMappingLoad - Loads a local-to-global mapping that has been stored in binary format. 428 429 Collective on viewer 430 431 Input Parameters: 432 + mapping - the newly loaded map, this needs to have been created with `ISLocalToGlobalMappingCreate()` or some related function before a call to `ISLocalToGlobalMappingLoad()` 433 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` 434 435 Level: intermediate 436 437 .seealso: [](sec_scatter), `PetscViewer`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingView()`, `ISLocalToGlobalMappingCreate()` 438 @*/ 439 PetscErrorCode ISLocalToGlobalMappingLoad(ISLocalToGlobalMapping mapping, PetscViewer viewer) 440 { 441 PetscBool isbinary, skipHeader; 442 443 PetscFunctionBegin; 444 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 445 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 446 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 447 PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name); 448 449 /* reset previous data */ 450 PetscCall(ISLocalToGlobalMappingResetBlockInfo_Private(mapping)); 451 452 PetscCall(PetscViewerSetUp(viewer)); 453 PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader)); 454 455 /* When skipping header, it assumes bs and n have been already set */ 456 if (!skipHeader) { 457 MPI_Comm comm = PetscObjectComm((PetscObject)viewer); 458 PetscInt tr[3], nold = mapping->n, *sizes, nmaps = PETSC_DECIDE, st = 0; 459 460 PetscCall(PetscViewerBinaryRead(viewer, tr, 3, NULL, PETSC_INT)); 461 PetscCheck(tr[0] == IS_LTOGM_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a local-to-global map next in file"); 462 463 mapping->bs = tr[1]; 464 PetscCall(PetscMalloc1(tr[2], &sizes)); 465 PetscCall(PetscViewerBinaryRead(viewer, sizes, tr[2], NULL, PETSC_INT)); 466 467 /* consume the input, read multiple maps per process if needed */ 468 PetscCall(PetscSplitOwnership(comm, &nmaps, &tr[2])); 469 PetscCallMPI(MPI_Exscan(&nmaps, &st, 1, MPIU_INT, MPI_SUM, comm)); 470 mapping->n = 0; 471 for (PetscInt i = st; i < st + nmaps; i++) mapping->n += sizes[i]; 472 PetscCall(PetscFree(sizes)); 473 474 if (nold != mapping->n) { 475 if (mapping->dealloc_indices) PetscCall(PetscFree(mapping->indices)); 476 mapping->indices = NULL; 477 } 478 } 479 480 /* read indices */ 481 if (mapping->n && !mapping->indices) { 482 PetscCall(PetscMalloc1(mapping->n, &mapping->indices)); 483 mapping->dealloc_indices = PETSC_TRUE; 484 } 485 PetscCall(PetscViewerBinaryReadAll(viewer, mapping->indices, mapping->n, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT)); 486 PetscFunctionReturn(PETSC_SUCCESS); 487 } 488 489 /*@ 490 ISLocalToGlobalMappingCreateIS - Creates a mapping between a local (0 to n) 491 ordering and a global parallel ordering. 492 493 Not Collective 494 495 Input Parameter: 496 . is - index set containing the global numbers for each local number 497 498 Output Parameter: 499 . mapping - new mapping data structure 500 501 Level: advanced 502 503 Note: 504 the block size of the `IS` determines the block size of the mapping 505 506 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetFromOptions()` 507 @*/ 508 PetscErrorCode ISLocalToGlobalMappingCreateIS(IS is, ISLocalToGlobalMapping *mapping) 509 { 510 PetscInt n, bs; 511 const PetscInt *indices; 512 MPI_Comm comm; 513 PetscBool isblock; 514 515 PetscFunctionBegin; 516 PetscValidHeaderSpecific(is, IS_CLASSID, 1); 517 PetscAssertPointer(mapping, 2); 518 519 PetscCall(PetscObjectGetComm((PetscObject)is, &comm)); 520 PetscCall(ISGetLocalSize(is, &n)); 521 PetscCall(PetscObjectTypeCompare((PetscObject)is, ISBLOCK, &isblock)); 522 if (!isblock) { 523 PetscCall(ISGetIndices(is, &indices)); 524 PetscCall(ISLocalToGlobalMappingCreate(comm, 1, n, indices, PETSC_COPY_VALUES, mapping)); 525 PetscCall(ISRestoreIndices(is, &indices)); 526 } else { 527 PetscCall(ISGetBlockSize(is, &bs)); 528 PetscCall(ISBlockGetIndices(is, &indices)); 529 PetscCall(ISLocalToGlobalMappingCreate(comm, bs, n / bs, indices, PETSC_COPY_VALUES, mapping)); 530 PetscCall(ISBlockRestoreIndices(is, &indices)); 531 } 532 PetscFunctionReturn(PETSC_SUCCESS); 533 } 534 535 /*@C 536 ISLocalToGlobalMappingCreateSF - Creates a mapping between a local (0 to n) 537 ordering and a global parallel ordering. 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, (char *)(((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()` 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 Parameter: 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 static PetscErrorCode ISLocalToGlobalMappingSetUpBlockInfo_Private(ISLocalToGlobalMapping mapping) 1170 { 1171 PetscSF sf; 1172 MPI_Comm comm; 1173 const PetscSFNode *sfnode; 1174 PetscSFNode *newsfnode; 1175 PetscLayout layout; 1176 PetscHMapI neighs; 1177 PetscHashIter iter; 1178 PetscBool missing; 1179 const PetscInt *gidxs, *rootdegree; 1180 PetscInt *mask, *mrootdata, *leafdata, *newleafdata, *leafrd, *tmpg; 1181 PetscInt nroots, nleaves, newnleaves, bs, i, j, m, mnroots, p; 1182 PetscMPIInt rank, size; 1183 1184 PetscFunctionBegin; 1185 if (mapping->info_numprocs) PetscFunctionReturn(PETSC_SUCCESS); 1186 PetscCall(PetscObjectGetComm((PetscObject)mapping, &comm)); 1187 PetscCallMPI(MPI_Comm_size(comm, &size)); 1188 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1189 1190 /* Get mapping indices */ 1191 PetscCall(ISLocalToGlobalMappingGetBlockSize(mapping, &bs)); 1192 PetscCall(ISLocalToGlobalMappingGetBlockIndices(mapping, &gidxs)); 1193 PetscCall(ISLocalToGlobalMappingGetSize(mapping, &nleaves)); 1194 nleaves /= bs; 1195 1196 /* Create layout for global indices */ 1197 for (i = 0, m = 0; i < nleaves; i++) m = PetscMax(m, gidxs[i]); 1198 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &m, 1, MPIU_INT, MPI_MAX, comm)); 1199 PetscCall(PetscLayoutCreate(comm, &layout)); 1200 PetscCall(PetscLayoutSetSize(layout, m + 1)); 1201 PetscCall(PetscLayoutSetUp(layout)); 1202 1203 /* Create SF to share global indices */ 1204 PetscCall(PetscSFCreate(comm, &sf)); 1205 PetscCall(PetscSFSetGraphLayout(sf, layout, nleaves, NULL, PETSC_OWN_POINTER, gidxs)); 1206 PetscCall(PetscSFSetUp(sf)); 1207 PetscCall(PetscLayoutDestroy(&layout)); 1208 1209 /* communicate root degree to leaves */ 1210 PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, &sfnode)); 1211 PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree)); 1212 PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree)); 1213 for (i = 0, mnroots = 0; i < nroots; i++) mnroots += rootdegree[i]; 1214 PetscCall(PetscMalloc3(2 * PetscMax(mnroots, nroots), &mrootdata, 2 * nleaves, &leafdata, nleaves, &leafrd)); 1215 for (i = 0, m = 0; i < nroots; i++) { 1216 mrootdata[2 * i + 0] = rootdegree[i]; 1217 mrootdata[2 * i + 1] = m; 1218 m += rootdegree[i]; 1219 } 1220 PetscCall(PetscSFBcastBegin(sf, MPIU_2INT, mrootdata, leafdata, MPI_REPLACE)); 1221 PetscCall(PetscSFBcastEnd(sf, MPIU_2INT, mrootdata, leafdata, MPI_REPLACE)); 1222 1223 /* allocate enough space to store ranks */ 1224 for (i = 0, newnleaves = 0; i < nleaves; i++) { 1225 newnleaves += leafdata[2 * i]; 1226 leafrd[i] = leafdata[2 * i]; 1227 } 1228 1229 /* create new SF nodes to collect multi-root data at leaves */ 1230 PetscCall(PetscMalloc1(newnleaves, &newsfnode)); 1231 for (i = 0, m = 0; i < nleaves; i++) { 1232 for (j = 0; j < leafrd[i]; j++) { 1233 newsfnode[m].rank = sfnode[i].rank; 1234 newsfnode[m].index = leafdata[2 * i + 1] + j; 1235 m++; 1236 } 1237 } 1238 1239 /* gather ranks at multi roots */ 1240 for (i = 0; i < mnroots; i++) mrootdata[i] = -1; 1241 for (i = 0; i < nleaves; i++) leafdata[i] = (PetscInt)rank; 1242 1243 PetscCall(PetscSFGatherBegin(sf, MPIU_INT, leafdata, mrootdata)); 1244 PetscCall(PetscSFGatherEnd(sf, MPIU_INT, leafdata, mrootdata)); 1245 1246 /* set new multi-leaves graph into the SF */ 1247 PetscCall(PetscSFSetGraph(sf, mnroots, newnleaves, NULL, PETSC_OWN_POINTER, newsfnode, PETSC_OWN_POINTER)); 1248 PetscCall(PetscSFSetUp(sf)); 1249 1250 /* broadcast multi-root data to multi-leaves */ 1251 PetscCall(PetscMalloc1(newnleaves, &newleafdata)); 1252 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, mrootdata, newleafdata, MPI_REPLACE)); 1253 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, mrootdata, newleafdata, MPI_REPLACE)); 1254 1255 /* sort sharing ranks */ 1256 for (i = 0, m = 0; i < nleaves; i++) { 1257 PetscCall(PetscSortInt(leafrd[i], newleafdata + m)); 1258 m += leafrd[i]; 1259 } 1260 1261 /* Number of neighbors and their ranks */ 1262 PetscCall(PetscHMapICreate(&neighs)); 1263 for (i = 0; i < newnleaves; i++) PetscCall(PetscHMapIPut(neighs, newleafdata[i], &iter, &missing)); 1264 PetscCall(PetscHMapIGetSize(neighs, &mapping->info_nproc)); 1265 PetscCall(PetscMalloc1(mapping->info_nproc + 1, &mapping->info_procs)); 1266 PetscCall(PetscHMapIGetKeys(neighs, (i = 0, &i), mapping->info_procs)); 1267 for (i = 0; i < mapping->info_nproc; i++) { /* put info for self first */ 1268 if (mapping->info_procs[i] == rank) { 1269 PetscInt newr = mapping->info_procs[0]; 1270 1271 mapping->info_procs[0] = rank; 1272 mapping->info_procs[i] = newr; 1273 break; 1274 } 1275 } 1276 if (mapping->info_nproc) PetscCall(PetscSortInt(mapping->info_nproc - 1, mapping->info_procs + 1)); 1277 PetscCall(PetscHMapIDestroy(&neighs)); 1278 1279 /* collect info data */ 1280 PetscCall(PetscMalloc1(mapping->info_nproc + 1, &mapping->info_numprocs)); 1281 PetscCall(PetscMalloc1(mapping->info_nproc + 1, &mapping->info_indices)); 1282 for (i = 0; i < mapping->info_nproc + 1; i++) mapping->info_indices[i] = NULL; 1283 1284 PetscCall(PetscMalloc1(nleaves, &mask)); 1285 PetscCall(PetscMalloc1(nleaves, &tmpg)); 1286 for (p = 0; p < mapping->info_nproc; p++) { 1287 PetscInt *tmp, trank = mapping->info_procs[p]; 1288 1289 PetscCall(PetscMemzero(mask, nleaves * sizeof(*mask))); 1290 for (i = 0, m = 0; i < nleaves; i++) { 1291 for (j = 0; j < leafrd[i]; j++) { 1292 if (newleafdata[m] == trank) mask[i]++; 1293 if (!p && newleafdata[m] != rank) mask[i]++; 1294 m++; 1295 } 1296 } 1297 for (i = 0, m = 0; i < nleaves; i++) 1298 if (mask[i] > (!p ? 1 : 0)) m++; 1299 1300 PetscCall(PetscMalloc1(m, &tmp)); 1301 for (i = 0, m = 0; i < nleaves; i++) 1302 if (mask[i] > (!p ? 1 : 0)) { 1303 tmp[m] = i; 1304 tmpg[m] = gidxs[i]; 1305 m++; 1306 } 1307 PetscCall(PetscSortIntWithArray(m, tmpg, tmp)); 1308 mapping->info_indices[p] = tmp; 1309 mapping->info_numprocs[p] = m; 1310 } 1311 1312 /* Node info */ 1313 PetscCall(PetscMalloc2(nleaves, &mapping->info_nodec, nleaves + 1, &mapping->info_nodei)); 1314 PetscCall(PetscArraycpy(mapping->info_nodec, leafrd, nleaves)); 1315 PetscCall(PetscMalloc1(newnleaves, &mapping->info_nodei[0])); 1316 for (i = 0; i < nleaves - 1; i++) mapping->info_nodei[i + 1] = mapping->info_nodei[i] + mapping->info_nodec[i]; 1317 PetscCall(PetscArraycpy(mapping->info_nodei[0], newleafdata, newnleaves)); 1318 1319 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(mapping, &gidxs)); 1320 PetscCall(PetscFree(tmpg)); 1321 PetscCall(PetscFree(mask)); 1322 PetscCall(PetscSFDestroy(&sf)); 1323 PetscCall(PetscFree3(mrootdata, leafdata, leafrd)); 1324 PetscCall(PetscFree(newleafdata)); 1325 PetscFunctionReturn(PETSC_SUCCESS); 1326 } 1327 1328 /*@C 1329 ISLocalToGlobalMappingRestoreBlockInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetBlockInfo()` 1330 1331 Not Collective 1332 1333 Input Parameters: 1334 + mapping - the mapping from local to global indexing 1335 . nproc - number of processes that are connected to the calling process 1336 . procs - neighboring processes 1337 . numprocs - number of block indices for each process 1338 - indices - block indices (in local numbering) shared with neighbors (sorted by global numbering) 1339 1340 Level: advanced 1341 1342 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1343 `ISLocalToGlobalMappingGetInfo()` 1344 @*/ 1345 PetscErrorCode ISLocalToGlobalMappingRestoreBlockInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[]) 1346 { 1347 PetscFunctionBegin; 1348 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1349 if (nproc) *nproc = 0; 1350 if (procs) *procs = NULL; 1351 if (numprocs) *numprocs = NULL; 1352 if (indices) *indices = NULL; 1353 PetscFunctionReturn(PETSC_SUCCESS); 1354 } 1355 1356 /*@C 1357 ISLocalToGlobalMappingGetInfo - Gets the neighbor information for each process 1358 1359 Collective the first time it is called 1360 1361 Input Parameter: 1362 . mapping - the mapping from local to global indexing 1363 1364 Output Parameters: 1365 + nproc - number of processes that are connected to the calling process 1366 . procs - neighboring processes 1367 . numprocs - number of indices for each process 1368 - indices - indices (in local numbering) shared with neighbors (sorted by global numbering) 1369 1370 Level: advanced 1371 1372 Note: 1373 The user needs to call `ISLocalToGlobalMappingRestoreInfo()` when the data is no longer needed. 1374 1375 Fortran Notes: 1376 There is no `ISLocalToGlobalMappingRestoreInfo()` in Fortran. You must make sure that 1377 `procs`[], `numprocs`[] and `indices`[][] are large enough arrays, either by allocating them 1378 dynamically or defining static ones large enough. 1379 1380 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1381 `ISLocalToGlobalMappingRestoreInfo()`, `ISLocalToGlobalMappingGetNodeInfo()` 1382 @*/ 1383 PetscErrorCode ISLocalToGlobalMappingGetInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[]) 1384 { 1385 PetscInt **bindices = NULL, *bnumprocs = NULL, bs, i, j, k, n, *bprocs; 1386 1387 PetscFunctionBegin; 1388 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1389 bs = mapping->bs; 1390 PetscCall(ISLocalToGlobalMappingGetBlockInfo(mapping, &n, &bprocs, &bnumprocs, &bindices)); 1391 if (bs > 1) { /* we need to expand the cached info */ 1392 if (indices) PetscCall(PetscCalloc1(n, indices)); 1393 if (numprocs) PetscCall(PetscCalloc1(n, numprocs)); 1394 if (indices || numprocs) { 1395 for (i = 0; i < n; i++) { 1396 if (indices) { 1397 PetscCall(PetscMalloc1(bs * bnumprocs[i], &(*indices)[i])); 1398 for (j = 0; j < bnumprocs[i]; j++) { 1399 for (k = 0; k < bs; k++) (*indices)[i][j * bs + k] = bs * bindices[i][j] + k; 1400 } 1401 } 1402 if (numprocs) (*numprocs)[i] = bnumprocs[i] * bs; 1403 } 1404 } 1405 } else { 1406 if (numprocs) *numprocs = bnumprocs; 1407 if (indices) *indices = bindices; 1408 } 1409 if (nproc) *nproc = n; 1410 if (procs) *procs = bprocs; 1411 PetscFunctionReturn(PETSC_SUCCESS); 1412 } 1413 1414 /*@C 1415 ISLocalToGlobalMappingRestoreInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetInfo()` 1416 1417 Not Collective 1418 1419 Input Parameters: 1420 + mapping - the mapping from local to global indexing 1421 . nproc - number of processes that are connected to the calling process 1422 . procs - neighboring processes 1423 . numprocs - number of indices for each process 1424 - indices - indices (in local numbering) shared with neighbors (sorted by global numbering) 1425 1426 Level: advanced 1427 1428 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1429 `ISLocalToGlobalMappingGetInfo()` 1430 @*/ 1431 PetscErrorCode ISLocalToGlobalMappingRestoreInfo(ISLocalToGlobalMapping mapping, PetscInt *nproc, PetscInt *procs[], PetscInt *numprocs[], PetscInt **indices[]) 1432 { 1433 PetscFunctionBegin; 1434 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1435 if (mapping->bs > 1) { 1436 if (numprocs) PetscCall(PetscFree(*numprocs)); 1437 if (indices) { 1438 if (*indices) 1439 for (PetscInt i = 0; i < *nproc; i++) PetscCall(PetscFree((*indices)[i])); 1440 PetscCall(PetscFree(*indices)); 1441 } 1442 } 1443 PetscFunctionReturn(PETSC_SUCCESS); 1444 } 1445 1446 /*@C 1447 ISLocalToGlobalMappingGetNodeInfo - Gets the neighbor information of local nodes 1448 1449 Collective the first time it is called 1450 1451 Input Parameter: 1452 . mapping - the mapping from local to global indexing 1453 1454 Output Parameters: 1455 + n - number of local nodes 1456 . n_procs - an array storing the number of processes for each local node (including self) 1457 - procs - the processes' rank for each local node (sorted, self is first) 1458 1459 Level: advanced 1460 1461 Note: 1462 The user needs to call `ISLocalToGlobalMappingRestoreNodeInfo()` when the data is no longer needed. 1463 1464 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1465 `ISLocalToGlobalMappingGetInfo()`, `ISLocalToGlobalMappingRestoreNodeInfo()`, `ISLocalToGlobalMappingGetBlockNodeInfo()` 1466 @*/ 1467 PetscErrorCode ISLocalToGlobalMappingGetNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[]) 1468 { 1469 PetscInt **bprocs = NULL, *bn_procs = NULL, bs, i, j, k, bn; 1470 1471 PetscFunctionBegin; 1472 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1473 bs = mapping->bs; 1474 PetscCall(ISLocalToGlobalMappingGetBlockNodeInfo(mapping, &bn, &bn_procs, &bprocs)); 1475 if (bs > 1) { /* we need to expand the cached info */ 1476 PetscInt *tn_procs; 1477 PetscInt c; 1478 1479 PetscCall(PetscMalloc1(bn * bs, &tn_procs)); 1480 for (i = 0, c = 0; i < bn; i++) { 1481 for (k = 0; k < bs; k++) tn_procs[i * bs + k] = bn_procs[i]; 1482 c += bs * bn_procs[i]; 1483 } 1484 if (n) *n = bn * bs; 1485 if (procs) { 1486 PetscInt **tprocs; 1487 PetscInt tn = bn * bs; 1488 1489 PetscCall(PetscMalloc1(tn, &tprocs)); 1490 if (tn) PetscCall(PetscMalloc1(c, &tprocs[0])); 1491 for (i = 0; i < tn - 1; i++) tprocs[i + 1] = tprocs[i] + tn_procs[i]; 1492 for (i = 0; i < bn; i++) { 1493 for (k = 0; k < bs; k++) { 1494 for (j = 0; j < bn_procs[i]; j++) tprocs[i * bs + k][j] = bprocs[i][j]; 1495 } 1496 } 1497 *procs = tprocs; 1498 } 1499 if (n_procs) *n_procs = tn_procs; 1500 else PetscCall(PetscFree(tn_procs)); 1501 } else { 1502 if (n) *n = bn; 1503 if (n_procs) *n_procs = bn_procs; 1504 if (procs) *procs = bprocs; 1505 } 1506 PetscFunctionReturn(PETSC_SUCCESS); 1507 } 1508 1509 /*@C 1510 ISLocalToGlobalMappingRestoreNodeInfo - Frees the memory allocated by `ISLocalToGlobalMappingGetNodeInfo()` 1511 1512 Not Collective 1513 1514 Input Parameters: 1515 + mapping - the mapping from local to global indexing 1516 . n - number of local nodes 1517 . n_procs - an array storing the number of processes for each local node (including self) 1518 - procs - the processes' rank for each local node (sorted, self is first) 1519 1520 Level: advanced 1521 1522 .seealso: [](sec_scatter), `ISLocalToGlobalMappingDestroy()`, `ISLocalToGlobalMappingCreateIS()`, `ISLocalToGlobalMappingCreate()`, 1523 `ISLocalToGlobalMappingGetInfo()` 1524 @*/ 1525 PetscErrorCode ISLocalToGlobalMappingRestoreNodeInfo(ISLocalToGlobalMapping mapping, PetscInt *n, PetscInt *n_procs[], PetscInt **procs[]) 1526 { 1527 PetscFunctionBegin; 1528 PetscValidHeaderSpecific(mapping, IS_LTOGM_CLASSID, 1); 1529 if (mapping->bs > 1) { 1530 if (n_procs) PetscCall(PetscFree(*n_procs)); 1531 if (procs) { 1532 if (*procs) PetscCall(PetscFree((*procs)[0])); 1533 PetscCall(PetscFree(*procs)); 1534 } 1535 } 1536 PetscCall(ISLocalToGlobalMappingRestoreBlockNodeInfo(mapping, n, n_procs, procs)); 1537 PetscFunctionReturn(PETSC_SUCCESS); 1538 } 1539 1540 /*MC 1541 ISLocalToGlobalMappingGetIndicesF90 - Get global indices for every local point that is mapped 1542 1543 Synopsis: 1544 ISLocalToGlobalMappingGetIndicesF90(ISLocalToGlobalMapping ltog, PetscInt, pointer :: array(:)}, integer ierr) 1545 1546 Not Collective 1547 1548 Input Parameter: 1549 . A - the matrix 1550 1551 Output Parameter: 1552 . array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()` 1553 1554 Level: advanced 1555 1556 Note: 1557 Use `ISLocalToGlobalMappingGetIndicesF90()` when you no longer need access to the data 1558 1559 .seealso: [](sec_fortranarrays), [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingGetIndices()`, `ISLocalToGlobalMappingRestoreIndices()`, 1560 `ISLocalToGlobalMappingRestoreIndicesF90()` 1561 M*/ 1562 1563 /*MC 1564 ISLocalToGlobalMappingRestoreIndicesF90 - restores the global indices for every local point that is mapped obtained with `ISLocalToGlobalMappingGetIndicesF90()` 1565 1566 Synopsis: 1567 ISLocalToGlobalMappingRestoreIndicesF90(ISLocalToGlobalMapping ltog, PetscInt, pointer :: array(:)}, integer ierr) 1568 1569 Not Collective 1570 1571 Input Parameters: 1572 + A - the matrix 1573 - array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()` 1574 1575 Level: advanced 1576 1577 .seealso: [](sec_fortranarrays), [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingGetIndices()`, `ISLocalToGlobalMappingRestoreIndices()`, 1578 `ISLocalToGlobalMappingGetIndicesF90()` 1579 M*/ 1580 1581 /*@C 1582 ISLocalToGlobalMappingGetIndices - Get global indices for every local point that is mapped 1583 1584 Not Collective 1585 1586 Input Parameter: 1587 . ltog - local to global mapping 1588 1589 Output Parameter: 1590 . array - array of indices, the length of this array may be obtained with `ISLocalToGlobalMappingGetSize()` 1591 1592 Level: advanced 1593 1594 Note: 1595 `ISLocalToGlobalMappingGetSize()` returns the length the this array 1596 1597 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingRestoreIndices()`, 1598 `ISLocalToGlobalMappingGetBlockIndices()`, `ISLocalToGlobalMappingRestoreBlockIndices()` 1599 @*/ 1600 PetscErrorCode ISLocalToGlobalMappingGetIndices(ISLocalToGlobalMapping ltog, const PetscInt **array) 1601 { 1602 PetscFunctionBegin; 1603 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1604 PetscAssertPointer(array, 2); 1605 if (ltog->bs == 1) { 1606 *array = ltog->indices; 1607 } else { 1608 PetscInt *jj, k, i, j, n = ltog->n, bs = ltog->bs; 1609 const PetscInt *ii; 1610 1611 PetscCall(PetscMalloc1(bs * n, &jj)); 1612 *array = jj; 1613 k = 0; 1614 ii = ltog->indices; 1615 for (i = 0; i < n; i++) 1616 for (j = 0; j < bs; j++) jj[k++] = bs * ii[i] + j; 1617 } 1618 PetscFunctionReturn(PETSC_SUCCESS); 1619 } 1620 1621 /*@C 1622 ISLocalToGlobalMappingRestoreIndices - Restore indices obtained with `ISLocalToGlobalMappingGetIndices()` 1623 1624 Not Collective 1625 1626 Input Parameters: 1627 + ltog - local to global mapping 1628 - array - array of indices 1629 1630 Level: advanced 1631 1632 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()` 1633 @*/ 1634 PetscErrorCode ISLocalToGlobalMappingRestoreIndices(ISLocalToGlobalMapping ltog, const PetscInt **array) 1635 { 1636 PetscFunctionBegin; 1637 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1638 PetscAssertPointer(array, 2); 1639 PetscCheck(ltog->bs != 1 || *array == ltog->indices, PETSC_COMM_SELF, PETSC_ERR_ARG_BADPTR, "Trying to return mismatched pointer"); 1640 if (ltog->bs > 1) PetscCall(PetscFree(*(void **)array)); 1641 PetscFunctionReturn(PETSC_SUCCESS); 1642 } 1643 1644 /*@C 1645 ISLocalToGlobalMappingGetBlockIndices - Get global indices for every local block 1646 1647 Not Collective 1648 1649 Input Parameter: 1650 . ltog - local to global mapping 1651 1652 Output Parameter: 1653 . array - array of indices 1654 1655 Level: advanced 1656 1657 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingRestoreBlockIndices()` 1658 @*/ 1659 PetscErrorCode ISLocalToGlobalMappingGetBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt **array) 1660 { 1661 PetscFunctionBegin; 1662 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1663 PetscAssertPointer(array, 2); 1664 *array = ltog->indices; 1665 PetscFunctionReturn(PETSC_SUCCESS); 1666 } 1667 1668 /*@C 1669 ISLocalToGlobalMappingRestoreBlockIndices - Restore indices obtained with `ISLocalToGlobalMappingGetBlockIndices()` 1670 1671 Not Collective 1672 1673 Input Parameters: 1674 + ltog - local to global mapping 1675 - array - array of indices 1676 1677 Level: advanced 1678 1679 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingApply()`, `ISLocalToGlobalMappingGetIndices()` 1680 @*/ 1681 PetscErrorCode ISLocalToGlobalMappingRestoreBlockIndices(ISLocalToGlobalMapping ltog, const PetscInt **array) 1682 { 1683 PetscFunctionBegin; 1684 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1685 PetscAssertPointer(array, 2); 1686 PetscCheck(*array == ltog->indices, PETSC_COMM_SELF, PETSC_ERR_ARG_BADPTR, "Trying to return mismatched pointer"); 1687 *array = NULL; 1688 PetscFunctionReturn(PETSC_SUCCESS); 1689 } 1690 1691 /*@C 1692 ISLocalToGlobalMappingConcatenate - Create a new mapping that concatenates a list of mappings 1693 1694 Not Collective 1695 1696 Input Parameters: 1697 + comm - communicator for the new mapping, must contain the communicator of every mapping to concatenate 1698 . n - number of mappings to concatenate 1699 - ltogs - local to global mappings 1700 1701 Output Parameter: 1702 . ltogcat - new mapping 1703 1704 Level: advanced 1705 1706 Note: 1707 This currently always returns a mapping with block size of 1 1708 1709 Developer Notes: 1710 If all the input mapping have the same block size we could easily handle that as a special case 1711 1712 .seealso: [](sec_scatter), `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingCreate()` 1713 @*/ 1714 PetscErrorCode ISLocalToGlobalMappingConcatenate(MPI_Comm comm, PetscInt n, const ISLocalToGlobalMapping ltogs[], ISLocalToGlobalMapping *ltogcat) 1715 { 1716 PetscInt i, cnt, m, *idx; 1717 1718 PetscFunctionBegin; 1719 PetscCheck(n >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Must have a non-negative number of mappings, given %" PetscInt_FMT, n); 1720 if (n > 0) PetscAssertPointer(ltogs, 3); 1721 for (i = 0; i < n; i++) PetscValidHeaderSpecific(ltogs[i], IS_LTOGM_CLASSID, 3); 1722 PetscAssertPointer(ltogcat, 4); 1723 for (cnt = 0, i = 0; i < n; i++) { 1724 PetscCall(ISLocalToGlobalMappingGetSize(ltogs[i], &m)); 1725 cnt += m; 1726 } 1727 PetscCall(PetscMalloc1(cnt, &idx)); 1728 for (cnt = 0, i = 0; i < n; i++) { 1729 const PetscInt *subidx; 1730 PetscCall(ISLocalToGlobalMappingGetSize(ltogs[i], &m)); 1731 PetscCall(ISLocalToGlobalMappingGetIndices(ltogs[i], &subidx)); 1732 PetscCall(PetscArraycpy(&idx[cnt], subidx, m)); 1733 PetscCall(ISLocalToGlobalMappingRestoreIndices(ltogs[i], &subidx)); 1734 cnt += m; 1735 } 1736 PetscCall(ISLocalToGlobalMappingCreate(comm, 1, cnt, idx, PETSC_OWN_POINTER, ltogcat)); 1737 PetscFunctionReturn(PETSC_SUCCESS); 1738 } 1739 1740 /*MC 1741 ISLOCALTOGLOBALMAPPINGBASIC - basic implementation of the `ISLocalToGlobalMapping` object. When `ISGlobalToLocalMappingApply()` is 1742 used this is good for only small and moderate size problems. 1743 1744 Options Database Key: 1745 . -islocaltoglobalmapping_type basic - select this method 1746 1747 Level: beginner 1748 1749 Developer Note: 1750 This stores all the mapping information on each MPI rank. 1751 1752 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGHASH` 1753 M*/ 1754 PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Basic(ISLocalToGlobalMapping ltog) 1755 { 1756 PetscFunctionBegin; 1757 ltog->ops->globaltolocalmappingapply = ISGlobalToLocalMappingApply_Basic; 1758 ltog->ops->globaltolocalmappingsetup = ISGlobalToLocalMappingSetUp_Basic; 1759 ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Basic; 1760 ltog->ops->destroy = ISLocalToGlobalMappingDestroy_Basic; 1761 PetscFunctionReturn(PETSC_SUCCESS); 1762 } 1763 1764 /*MC 1765 ISLOCALTOGLOBALMAPPINGHASH - hash implementation of the `ISLocalToGlobalMapping` object. When `ISGlobalToLocalMappingApply()` is 1766 used this is good for large memory problems. 1767 1768 Options Database Key: 1769 . -islocaltoglobalmapping_type hash - select this method 1770 1771 Level: beginner 1772 1773 Note: 1774 This is selected automatically for large problems if the user does not set the type. 1775 1776 .seealso: [](sec_scatter), `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()`, `ISLOCALTOGLOBALMAPPINGBASIC` 1777 M*/ 1778 PETSC_EXTERN PetscErrorCode ISLocalToGlobalMappingCreate_Hash(ISLocalToGlobalMapping ltog) 1779 { 1780 PetscFunctionBegin; 1781 ltog->ops->globaltolocalmappingapply = ISGlobalToLocalMappingApply_Hash; 1782 ltog->ops->globaltolocalmappingsetup = ISGlobalToLocalMappingSetUp_Hash; 1783 ltog->ops->globaltolocalmappingapplyblock = ISGlobalToLocalMappingApplyBlock_Hash; 1784 ltog->ops->destroy = ISLocalToGlobalMappingDestroy_Hash; 1785 PetscFunctionReturn(PETSC_SUCCESS); 1786 } 1787 1788 /*@C 1789 ISLocalToGlobalMappingRegister - Registers a method for applying a global to local mapping with an `ISLocalToGlobalMapping` 1790 1791 Not Collective 1792 1793 Input Parameters: 1794 + sname - name of a new method 1795 - function - routine to create method context 1796 1797 Example Usage: 1798 .vb 1799 ISLocalToGlobalMappingRegister("my_mapper", MyCreate); 1800 .ve 1801 1802 Then, your mapping can be chosen with the procedural interface via 1803 $ ISLocalToGlobalMappingSetType(ltog, "my_mapper") 1804 or at runtime via the option 1805 $ -islocaltoglobalmapping_type my_mapper 1806 1807 Level: advanced 1808 1809 Note: 1810 `ISLocalToGlobalMappingRegister()` may be called multiple times to add several user-defined mappings. 1811 1812 .seealso: [](sec_scatter), `ISLocalToGlobalMappingRegisterAll()`, `ISLocalToGlobalMappingRegisterDestroy()`, `ISLOCALTOGLOBALMAPPINGBASIC`, 1813 `ISLOCALTOGLOBALMAPPINGHASH`, `ISLocalToGlobalMapping`, `ISLocalToGlobalMappingApply()` 1814 @*/ 1815 PetscErrorCode ISLocalToGlobalMappingRegister(const char sname[], PetscErrorCode (*function)(ISLocalToGlobalMapping)) 1816 { 1817 PetscFunctionBegin; 1818 PetscCall(ISInitializePackage()); 1819 PetscCall(PetscFunctionListAdd(&ISLocalToGlobalMappingList, sname, function)); 1820 PetscFunctionReturn(PETSC_SUCCESS); 1821 } 1822 1823 /*@C 1824 ISLocalToGlobalMappingSetType - Sets the implementation type `ISLocalToGlobalMapping` will use 1825 1826 Logically Collective 1827 1828 Input Parameters: 1829 + ltog - the `ISLocalToGlobalMapping` object 1830 - type - a known method 1831 1832 Options Database Key: 1833 . -islocaltoglobalmapping_type <method> - Sets the method; use -help for a list of available methods (for instance, basic or hash) 1834 1835 Level: intermediate 1836 1837 Notes: 1838 See `ISLocalToGlobalMappingType` for available methods 1839 1840 Normally, it is best to use the `ISLocalToGlobalMappingSetFromOptions()` command and 1841 then set the `ISLocalToGlobalMappingType` from the options database rather than by using 1842 this routine. 1843 1844 Developer Notes: 1845 `ISLocalToGlobalMappingRegister()` is used to add new types to `ISLocalToGlobalMappingList` from which they 1846 are accessed by `ISLocalToGlobalMappingSetType()`. 1847 1848 .seealso: [](sec_scatter), `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingGetType()` 1849 @*/ 1850 PetscErrorCode ISLocalToGlobalMappingSetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType type) 1851 { 1852 PetscBool match; 1853 PetscErrorCode (*r)(ISLocalToGlobalMapping) = NULL; 1854 1855 PetscFunctionBegin; 1856 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1857 if (type) PetscAssertPointer(type, 2); 1858 1859 PetscCall(PetscObjectTypeCompare((PetscObject)ltog, type, &match)); 1860 if (match) PetscFunctionReturn(PETSC_SUCCESS); 1861 1862 /* L2G maps defer type setup at globaltolocal calls, allow passing NULL here */ 1863 if (type) { 1864 PetscCall(PetscFunctionListFind(ISLocalToGlobalMappingList, type, &r)); 1865 PetscCheck(r, PetscObjectComm((PetscObject)ltog), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unable to find requested ISLocalToGlobalMapping type %s", type); 1866 } 1867 /* Destroy the previous private LTOG context */ 1868 PetscTryTypeMethod(ltog, destroy); 1869 ltog->ops->destroy = NULL; 1870 1871 PetscCall(PetscObjectChangeTypeName((PetscObject)ltog, type)); 1872 if (r) PetscCall((*r)(ltog)); 1873 PetscFunctionReturn(PETSC_SUCCESS); 1874 } 1875 1876 /*@C 1877 ISLocalToGlobalMappingGetType - Get the type of the `ISLocalToGlobalMapping` 1878 1879 Not Collective 1880 1881 Input Parameter: 1882 . ltog - the `ISLocalToGlobalMapping` object 1883 1884 Output Parameter: 1885 . type - the type 1886 1887 Level: intermediate 1888 1889 .seealso: [](sec_scatter), `ISLocalToGlobalMappingType`, `ISLocalToGlobalMappingRegister()`, `ISLocalToGlobalMappingCreate()`, `ISLocalToGlobalMappingSetType()` 1890 @*/ 1891 PetscErrorCode ISLocalToGlobalMappingGetType(ISLocalToGlobalMapping ltog, ISLocalToGlobalMappingType *type) 1892 { 1893 PetscFunctionBegin; 1894 PetscValidHeaderSpecific(ltog, IS_LTOGM_CLASSID, 1); 1895 PetscAssertPointer(type, 2); 1896 *type = ((PetscObject)ltog)->type_name; 1897 PetscFunctionReturn(PETSC_SUCCESS); 1898 } 1899 1900 PetscBool ISLocalToGlobalMappingRegisterAllCalled = PETSC_FALSE; 1901 1902 /*@C 1903 ISLocalToGlobalMappingRegisterAll - Registers all of the local to global mapping components in the `IS` package. 1904 1905 Not Collective 1906 1907 Level: advanced 1908 1909 .seealso: [](sec_scatter), `ISRegister()`, `ISLocalToGlobalRegister()` 1910 @*/ 1911 PetscErrorCode ISLocalToGlobalMappingRegisterAll(void) 1912 { 1913 PetscFunctionBegin; 1914 if (ISLocalToGlobalMappingRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 1915 ISLocalToGlobalMappingRegisterAllCalled = PETSC_TRUE; 1916 PetscCall(ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGBASIC, ISLocalToGlobalMappingCreate_Basic)); 1917 PetscCall(ISLocalToGlobalMappingRegister(ISLOCALTOGLOBALMAPPINGHASH, ISLocalToGlobalMappingCreate_Hash)); 1918 PetscFunctionReturn(PETSC_SUCCESS); 1919 } 1920