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