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