1# -------------------------------------------------------------------- 2 3class ISType(object): 4 """The index set types.""" 5 GENERAL = S_(ISGENERAL) 6 BLOCK = S_(ISBLOCK) 7 STRIDE = S_(ISSTRIDE) 8 9# -------------------------------------------------------------------- 10 11 12cdef class IS(Object): 13 """A collection of indices. 14 15 IS objects are used to index into vectors and matrices and to set up vector 16 scatters. 17 18 See Also 19 -------- 20 petsc.IS 21 22 """ 23 24 Type = ISType 25 26 # 27 28 def __cinit__(self): 29 self.obj = <PetscObject*> &self.iset 30 self.iset = NULL 31 32 # buffer interface (PEP 3118) 33 34 def __getbuffer__(self, Py_buffer *view, int flags): 35 cdef _IS_buffer buf = _IS_buffer(self) 36 buf.acquirebuffer(view, flags) 37 38 def __releasebuffer__(self, Py_buffer *view): 39 cdef _IS_buffer buf = <_IS_buffer>(view.obj) 40 buf.releasebuffer(view) 41 <void>self # unused 42 43 # 'with' statement (PEP 343) 44 45 def __enter__(self): 46 cdef _IS_buffer buf = _IS_buffer(self) 47 self.set_attr('__buffer__', buf) 48 return buf.enter() 49 50 def __exit__(self, *exc): 51 cdef _IS_buffer buf = self.get_attr('__buffer__') 52 self.set_attr('__buffer__', None) 53 return buf.exit() 54 # 55 56 def view(self, Viewer viewer=None) -> None: 57 """Display the index set. 58 59 Collective. 60 61 Parameters 62 ---------- 63 viewer 64 Viewer used to display the IS. 65 66 See Also 67 -------- 68 petsc.ISView 69 70 """ 71 cdef PetscViewer cviewer = NULL 72 if viewer is not None: cviewer = viewer.vwr 73 CHKERR(ISView(self.iset, cviewer)) 74 75 def destroy(self) -> Self: 76 """Destroy the index set. 77 78 Collective. 79 80 See Also 81 -------- 82 petsc.ISDestroy 83 84 """ 85 CHKERR(ISDestroy(&self.iset)) 86 return self 87 88 def create(self, comm: Comm | None = None) -> Self: 89 """Create an IS. 90 91 Collective. 92 93 Parameters 94 ---------- 95 comm 96 MPI communicator, defaults to `Sys.getDefaultComm`. 97 98 See Also 99 -------- 100 petsc.ISCreate 101 102 """ 103 cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT) 104 cdef PetscIS newiset = NULL 105 CHKERR(ISCreate(ccomm, &newiset)) 106 CHKERR(PetscCLEAR(self.obj)); self.iset = newiset 107 return self 108 109 def setType(self, is_type: IS.Type | str) -> None: 110 """Set the type of the index set. 111 112 Collective. 113 114 Parameters 115 ---------- 116 is_type 117 The index set type. 118 119 See Also 120 -------- 121 petsc.ISSetType 122 123 """ 124 cdef PetscISType cval = NULL 125 is_type = str2bytes(is_type, &cval) 126 CHKERR(ISSetType(self.iset, cval)) 127 128 def getType(self) -> str: 129 """Return the index set type associated with the IS. 130 131 Not collective. 132 133 See Also 134 -------- 135 petsc.ISGetType 136 137 """ 138 cdef PetscISType cval = NULL 139 CHKERR(ISGetType(self.iset, &cval)) 140 return bytes2str(cval) 141 142 def createGeneral( 143 self, 144 indices: Sequence[int], 145 comm: Comm | None = None) -> Self: 146 """Create an IS with indices. 147 148 Collective. 149 150 Parameters 151 ---------- 152 indices 153 Integer array. 154 comm 155 MPI communicator, defaults to `Sys.getDefaultComm`. 156 157 See Also 158 -------- 159 petsc.ISCreateGeneral 160 161 """ 162 cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT) 163 cdef PetscInt nidx = 0, *idx = NULL 164 cdef PetscCopyMode cm = PETSC_COPY_VALUES 165 cdef PetscIS newiset = NULL 166 indices = iarray_i(indices, &nidx, &idx) 167 CHKERR(ISCreateGeneral(ccomm, nidx, idx, cm, &newiset)) 168 CHKERR(PetscCLEAR(self.obj)); self.iset = newiset 169 return self 170 171 def createBlock( 172 self, 173 bsize: int, 174 indices: Sequence[int], 175 comm: Comm | None = None) -> Self: 176 """Create a blocked index set. 177 178 Collective. 179 180 Parameters 181 ---------- 182 bsize 183 Block size. 184 indices 185 Integer array of indices. 186 comm 187 MPI communicator, defaults to `Sys.getDefaultComm`. 188 189 See Also 190 -------- 191 petsc.ISCreateBlock 192 193 """ 194 cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT) 195 cdef PetscInt bs = asInt(bsize) 196 cdef PetscInt nidx = 0, *idx = NULL 197 cdef PetscCopyMode cm = PETSC_COPY_VALUES 198 cdef PetscIS newiset = NULL 199 indices = iarray_i(indices, &nidx, &idx) 200 CHKERR(ISCreateBlock(ccomm, bs, nidx, idx, cm, &newiset)) 201 CHKERR(PetscCLEAR(self.obj)); self.iset = newiset 202 return self 203 204 def createStride( 205 self, 206 size: int, 207 first: int = 0, 208 step: int = 1, 209 comm: Comm | None = None) -> Self: 210 """Create an index set consisting of evenly spaced values. 211 212 Collective. 213 214 Parameters 215 ---------- 216 size 217 The length of the locally owned portion of the index set. 218 first 219 The first element of the index set. 220 step 221 The difference between adjacent indices. 222 comm 223 MPI communicator, defaults to `Sys.getDefaultComm`. 224 225 See Also 226 -------- 227 petsc.ISCreateStride 228 229 """ 230 cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT) 231 cdef PetscInt csize = asInt(size) 232 cdef PetscInt cfirst = asInt(first) 233 cdef PetscInt cstep = asInt(step) 234 cdef PetscIS newiset = NULL 235 CHKERR(ISCreateStride(ccomm, csize, cfirst, cstep, &newiset)) 236 CHKERR(PetscCLEAR(self.obj)); self.iset = newiset 237 return self 238 239 def duplicate(self) -> IS: 240 """Create a copy of the index set. 241 242 Collective. 243 244 See Also 245 -------- 246 IS.copy, petsc.ISDuplicate 247 248 """ 249 cdef IS iset = type(self)() 250 CHKERR(ISDuplicate(self.iset, &iset.iset)) 251 return iset 252 253 def copy(self, IS result=None) -> IS: 254 """Copy the contents of the index set into another. 255 256 Collective. 257 258 Parameters 259 ---------- 260 result 261 The target index set. If `None` then `IS.duplicate` is called first. 262 263 Returns 264 ------- 265 IS 266 The copied index set. If ``result`` is not `None` then this is 267 returned here. 268 269 See Also 270 -------- 271 IS.duplicate, petsc.ISCopy 272 273 """ 274 if result is None: 275 result = type(self)() 276 if result.iset == NULL: 277 CHKERR(ISDuplicate(self.iset, &result.iset)) 278 CHKERR(ISCopy(self.iset, result.iset)) 279 return result 280 281 def load(self, Viewer viewer) -> Self: 282 """Load a stored index set. 283 284 Collective. 285 286 Parameters 287 ---------- 288 viewer 289 Binary file viewer, either `Viewer.Type.BINARY` or `Viewer.Type.HDF5`. 290 291 See Also 292 -------- 293 petsc.ISLoad 294 295 """ 296 cdef MPI_Comm comm = MPI_COMM_NULL 297 cdef PetscObject obj = <PetscObject>(viewer.vwr) 298 if self.iset == NULL: 299 CHKERR(PetscObjectGetComm(obj, &comm)) 300 CHKERR(ISCreate(comm, &self.iset)) 301 CHKERR(ISLoad(self.iset, viewer.vwr)) 302 return self 303 304 def allGather(self) -> IS: 305 """Concatenate index sets stored across processors. 306 307 Collective. 308 309 The returned index set will be the same on every processor. 310 311 See Also 312 -------- 313 petsc.ISAllGather 314 315 """ 316 cdef IS iset = IS() 317 CHKERR(ISAllGather(self.iset, &iset.iset)) 318 return iset 319 320 def toGeneral(self) -> Self: 321 """Convert the index set type to `IS.Type.GENERAL`. 322 323 Collective. 324 325 See Also 326 -------- 327 petsc.ISToGeneral, petsc.ISType 328 329 """ 330 CHKERR(ISToGeneral(self.iset)) 331 return self 332 333 def buildTwoSided(self, IS toindx=None) -> IS: 334 """Create an index set describing a global mapping. 335 336 Collective. 337 338 This function generates an index set that contains new numbers from 339 remote or local on the index set. 340 341 Parameters 342 ---------- 343 toindx 344 Index set describing which indices to send, default is to send 345 natural numbering. 346 347 Returns 348 ------- 349 IS 350 New index set containing the new numbers from remote or local. 351 352 See Also 353 -------- 354 petsc.ISBuildTwoSided 355 356 """ 357 cdef PetscIS ctoindx = NULL 358 if toindx is not None: ctoindx = toindx.iset 359 cdef IS result = IS() 360 CHKERR(ISBuildTwoSided(self.iset, ctoindx, &result.iset)) 361 return result 362 363 def invertPermutation(self, nlocal: int | None = None) -> IS: 364 """Invert the index set. 365 366 Collective. 367 368 For this to be correct the index set must be a permutation. 369 370 Parameters 371 ---------- 372 nlocal 373 The number of indices on this processor in the resulting index set, 374 defaults to ``PETSC_DECIDE``. 375 376 See Also 377 -------- 378 petsc.ISInvertPermutation 379 380 """ 381 cdef PetscInt cnlocal = PETSC_DECIDE 382 if nlocal is not None: cnlocal = asInt(nlocal) 383 cdef IS iset = IS() 384 CHKERR(ISInvertPermutation(self.iset, cnlocal, &iset.iset)) 385 return iset 386 387 def partitioningToNumbering(self) -> IS: 388 """Return the new global numbering after a partitioning. 389 390 Collective. 391 392 Assuming that the index set represents a partitioning, generate another 393 index set with the new global node number in the new ordering. 394 395 See Also 396 -------- 397 petsc.ISPartitioningToNumbering 398 399 """ 400 cdef IS iset = IS() 401 CHKERR(ISPartitioningToNumbering(self.iset, &iset.iset)) 402 return iset 403 404 def partitioningCount(self, npart: int | None = None) -> ArrayInt: 405 """Return the number of elements per process after a partitioning. 406 407 Collective. 408 409 Assuming that the index set represents a partitioning, determine the 410 number of elements on each (partition) rank. 411 412 Parameters 413 ---------- 414 npart 415 The number of partitions, 416 defaults to the size of the communicator. 417 418 See Also 419 -------- 420 petsc.ISPartitioningCount 421 422 """ 423 cdef PetscInt size 424 if npart is None: size = getCommSize(self.iset) 425 else: size = asInt(npart) 426 cdef PetscInt *counts = NULL 427 CHKERR(PetscMalloc(<size_t>size*sizeof(PetscInt), &counts)) 428 CHKERR(ISPartitioningCount(self.iset, size, counts)) 429 cdef object ocounts = None 430 try: 431 ocounts = array_i(size, counts) 432 finally: 433 CHKERR(PetscFree(counts)) 434 return ocounts 435 436 def getSize(self) -> int: 437 """Return the global length of an index set. 438 439 Not collective. 440 441 See Also 442 -------- 443 petsc.ISGetSize 444 445 """ 446 cdef PetscInt N = 0 447 CHKERR(ISGetSize(self.iset, &N)) 448 return toInt(N) 449 450 def getLocalSize(self) -> int: 451 """Return the process-local length of the index set. 452 453 Not collective. 454 455 See Also 456 -------- 457 petsc.ISGetLocalSize 458 459 """ 460 cdef PetscInt n = 0 461 CHKERR(ISGetLocalSize(self.iset, &n)) 462 return toInt(n) 463 464 def getSizes(self) -> tuple[int, int]: 465 """Return the local and global sizes of the index set. 466 467 Not collective. 468 469 Returns 470 ------- 471 local_size : int 472 The local size. 473 global_size : int 474 The global size. 475 476 See Also 477 -------- 478 IS.getLocalSize, IS.getSize 479 480 """ 481 cdef PetscInt n = 0, N = 0 482 CHKERR(ISGetLocalSize(self.iset, &n)) 483 CHKERR(ISGetSize(self.iset, &N)) 484 return (toInt(n), toInt(N)) 485 486 def getBlockSize(self) -> int: 487 """Return the number of elements in a block. 488 489 Not collective. 490 491 See Also 492 -------- 493 petsc.ISGetBlockSize 494 495 """ 496 cdef PetscInt bs = 1 497 CHKERR(ISGetBlockSize(self.iset, &bs)) 498 return toInt(bs) 499 500 def setBlockSize(self, bs: int) -> None: 501 """Set the block size of the index set. 502 503 Logically collective. 504 505 Parameters 506 ---------- 507 bs 508 Block size. 509 510 See Also 511 -------- 512 petsc.ISSetBlockSize 513 514 """ 515 cdef PetscInt cbs = asInt(bs) 516 CHKERR(ISSetBlockSize(self.iset, cbs)) 517 518 def sort(self) -> Self: 519 """Sort the indices of an index set. 520 521 Collective. 522 523 See Also 524 -------- 525 petsc.ISSort 526 527 """ 528 CHKERR(ISSort(self.iset)) 529 return self 530 531 def isSorted(self) -> bool: 532 """Return whether the indices have been sorted. 533 534 Collective. 535 536 See Also 537 -------- 538 petsc.ISSorted 539 540 """ 541 cdef PetscBool flag = PETSC_FALSE 542 CHKERR(ISSorted(self.iset, &flag)) 543 return toBool(flag) 544 545 def setPermutation(self) -> Self: 546 """Mark the index set as being a permutation. 547 548 Logically collective. 549 550 See Also 551 -------- 552 petsc.ISSetPermutation 553 554 """ 555 CHKERR(ISSetPermutation(self.iset)) 556 return self 557 558 def isPermutation(self) -> bool: 559 """Return whether an index set has been declared to be a permutation. 560 561 Logically collective. 562 563 See Also 564 -------- 565 petsc.ISPermutation 566 567 """ 568 cdef PetscBool flag = PETSC_FALSE 569 CHKERR(ISPermutation(self.iset, &flag)) 570 return toBool(flag) 571 572 def setIdentity(self) -> Self: 573 """Mark the index set as being an identity. 574 575 Logically collective. 576 577 See Also 578 -------- 579 petsc.ISSetIdentity 580 581 """ 582 CHKERR(ISSetIdentity(self.iset)) 583 return self 584 585 def isIdentity(self) -> bool: 586 """Return whether the index set has been declared as an identity. 587 588 Collective. 589 590 See Also 591 -------- 592 petsc.ISIdentity 593 594 """ 595 cdef PetscBool flag = PETSC_FALSE 596 CHKERR(ISIdentity(self.iset, &flag)) 597 return toBool(flag) 598 599 def equal(self, IS iset) -> bool: 600 """Return whether the index sets have the same set of indices or not. 601 602 Collective. 603 604 Parameters 605 ---------- 606 iset 607 The index set to compare indices with. 608 609 See Also 610 -------- 611 petsc.ISEqual 612 613 """ 614 cdef PetscBool flag = PETSC_FALSE 615 CHKERR(ISEqual(self.iset, iset.iset, &flag)) 616 return toBool(flag) 617 618 def sum(self, IS iset) -> IS: 619 """Return the union of two (sorted) index sets. 620 621 Collective. 622 623 Parameters 624 ---------- 625 iset 626 The index set to compute the union with. 627 628 See Also 629 -------- 630 petsc.ISSum 631 632 """ 633 cdef IS out = IS() 634 CHKERR(ISSum(self.iset, iset.iset, &out.iset)) 635 return out 636 637 def expand(self, IS iset) -> IS: 638 """Return the union of two (possibly unsorted) index sets. 639 640 Collective. 641 642 To compute the union, `expand` concatenates the two index sets 643 and removes any duplicates. 644 645 Parameters 646 ---------- 647 iset 648 Index set to compute the union with. 649 650 Returns 651 ------- 652 IS 653 The new, combined, index set. 654 655 See Also 656 -------- 657 petsc.ISExpand 658 659 """ 660 cdef IS out = IS() 661 CHKERR(ISExpand(self.iset, iset.iset, &out.iset)) 662 return out 663 664 def union(self, IS iset) -> IS: 665 """Return the union of two (possibly unsorted) index sets. 666 667 Collective. 668 669 This function will call either `petsc.ISSum` or `petsc.ISExpand` depending 670 on whether or not the input sets are already sorted. 671 672 Sequential only (as `petsc.ISSum` is sequential only). 673 674 Parameters 675 ---------- 676 iset 677 Index set to compute the union with. 678 679 Returns 680 ------- 681 IS 682 The new, combined, index set. 683 684 See Also 685 -------- 686 IS.expand, IS.sum 687 688 """ 689 cdef PetscBool flag1=PETSC_FALSE, flag2=PETSC_FALSE 690 CHKERR(ISSorted(self.iset, &flag1)) 691 CHKERR(ISSorted(iset.iset, &flag2)) 692 cdef IS out = IS() 693 if flag1==PETSC_TRUE and flag2==PETSC_TRUE: 694 CHKERR(ISSum(self.iset, iset.iset, &out.iset)) 695 else: 696 CHKERR(ISExpand(self.iset, iset.iset, &out.iset)) 697 return out 698 699 def difference(self, IS iset: IS) -> IS: 700 """Return the difference between two index sets. 701 702 Collective. 703 704 Parameters 705 ---------- 706 iset 707 Index set to compute the difference with. 708 709 Returns 710 ------- 711 IS 712 Index set representing the difference between ``self`` and ``iset``. 713 714 See Also 715 -------- 716 petsc.ISDifference 717 718 """ 719 cdef IS out = IS() 720 CHKERR(ISDifference(self.iset, iset.iset, &out.iset)) 721 return out 722 723 def complement(self, nmin: int, nmax: int) -> IS: 724 """Create a complement index set. 725 726 Collective. 727 728 The complement set of indices is all indices that are not 729 in the provided set (and within the provided bounds). 730 731 Parameters 732 ---------- 733 nmin 734 Minimum index that can be found in the local part of the complement 735 index set. 736 nmax 737 One greater than the maximum index that can be found in the local 738 part of the complement index set. 739 740 Notes 741 ----- 742 For a parallel index set, this will generate the local part of the 743 complement on each process. 744 745 To generate the entire complement (on each process) of a parallel 746 index set, first call `IS.allGather` and then call this method. 747 748 See Also 749 -------- 750 IS.allGather, petsc.ISComplement 751 752 """ 753 cdef PetscInt cnmin = asInt(nmin) 754 cdef PetscInt cnmax = asInt(nmax) 755 cdef IS out = IS() 756 CHKERR(ISComplement(self.iset, cnmin, cnmax, &out.iset)) 757 return out 758 759 def embed(self, IS iset, drop: bool) -> IS: 760 """Embed ``self`` into ``iset``. 761 762 Not collective. 763 764 The embedding is performed by finding the locations in ``iset`` that 765 have the same indices as ``self``. 766 767 Parameters 768 ---------- 769 iset 770 The index set to embed into. 771 drop 772 Flag indicating whether to drop indices from ``self`` that are not 773 in ``iset``. 774 775 Returns 776 ------- 777 IS 778 The embedded index set. 779 780 See Also 781 -------- 782 petsc.ISEmbed 783 784 """ 785 cdef PetscBool bval = drop 786 cdef IS out = IS() 787 CHKERR(ISEmbed(self.iset, iset.iset, bval, &out.iset)) 788 return out 789 790 def renumber(self, IS mult=None) -> tuple[int, IS]: 791 """Renumber the non-negative entries of an index set, starting from 0. 792 793 Collective. 794 795 Parameters 796 ---------- 797 mult 798 The multiplicity of each entry in ``self``, default implies a 799 multiplicity of 1. 800 801 Returns 802 ------- 803 int 804 One past the largest entry of the new index set. 805 IS 806 The renumbered index set. 807 808 See Also 809 -------- 810 petsc.ISRenumber 811 812 """ 813 cdef PetscIS mlt = NULL 814 if mult is not None: mlt = mult.iset 815 cdef IS out = IS() 816 cdef PetscInt n = 0 817 CHKERR(ISRenumber(self.iset, mlt, &n, &out.iset)) 818 return (toInt(n), out) 819 # 820 821 def setIndices(self, indices: Sequence[int]) -> None: 822 """Set the indices of an index set. 823 824 Logically collective. 825 826 The index set is assumed to be of type `IS.Type.GENERAL`. 827 828 See Also 829 -------- 830 petsc.ISGeneralSetIndices 831 832 """ 833 cdef PetscInt nidx = 0, *idx = NULL 834 cdef PetscCopyMode cm = PETSC_COPY_VALUES 835 indices = iarray_i(indices, &nidx, &idx) 836 CHKERR(ISGeneralSetIndices(self.iset, nidx, idx, cm)) 837 838 def getIndices(self) -> ArrayInt: 839 """Return the indices of the index set. 840 841 Not collective. 842 843 See Also 844 -------- 845 petsc.ISGetIndices 846 847 """ 848 cdef PetscInt size = 0 849 cdef const PetscInt *indices = NULL 850 CHKERR(ISGetLocalSize(self.iset, &size)) 851 CHKERR(ISGetIndices(self.iset, &indices)) 852 cdef object oindices = None 853 try: 854 oindices = array_i(size, indices) 855 finally: 856 CHKERR(ISRestoreIndices(self.iset, &indices)) 857 return oindices 858 859 def setBlockIndices(self, bsize: int, indices: Sequence[int]) -> None: 860 """Set the indices for an index set with type `IS.Type.BLOCK`. 861 862 Collective. 863 864 Parameters 865 ---------- 866 bsize 867 Number of elements in each block. 868 indices 869 List of integers. 870 871 See Also 872 -------- 873 petsc.ISBlockSetIndices 874 875 """ 876 cdef PetscInt bs = asInt(bsize) 877 cdef PetscInt nidx = 0, *idx = NULL 878 cdef PetscCopyMode cm = PETSC_COPY_VALUES 879 indices = iarray_i(indices, &nidx, &idx) 880 CHKERR(ISBlockSetIndices(self.iset, bs, nidx, idx, cm)) 881 882 def getBlockIndices(self) -> ArrayInt: 883 """Return the indices of an index set with type `IS.Type.BLOCK`. 884 885 Not collective. 886 887 See Also 888 -------- 889 petsc.ISBlockGetIndices 890 891 """ 892 cdef PetscInt size = 0, bs = 1 893 cdef const PetscInt *indices = NULL 894 CHKERR(ISGetLocalSize(self.iset, &size)) 895 CHKERR(ISGetBlockSize(self.iset, &bs)) 896 CHKERR(ISBlockGetIndices(self.iset, &indices)) 897 cdef object oindices = None 898 try: 899 oindices = array_i(size//bs, indices) 900 finally: 901 CHKERR(ISBlockRestoreIndices(self.iset, &indices)) 902 return oindices 903 904 def setStride(self, size: int, first: int = 0, step: int = 1) -> None: 905 """Set the stride information for an index set with type `IS.Type.STRIDE`. 906 907 Logically collective. 908 909 Parameters 910 ---------- 911 size 912 Length of the locally owned portion of the index set. 913 first 914 First element of the index set. 915 step 916 Difference between adjacent indices. 917 918 See Also 919 -------- 920 petsc.ISStrideSetStride 921 922 """ 923 cdef PetscInt csize = asInt(size) 924 cdef PetscInt cfirst = asInt(first) 925 cdef PetscInt cstep = asInt(step) 926 CHKERR(ISStrideSetStride(self.iset, csize, cfirst, cstep)) 927 928 def getStride(self) -> tuple[int, int, int]: 929 """Return size and stride information. 930 931 Not collective. 932 933 Returns 934 ------- 935 size : int 936 Length of the locally owned portion of the index set. 937 first : int 938 First element of the index set. 939 step : int 940 Difference between adjacent indices. 941 942 See Also 943 -------- 944 petsc.ISGetLocalSize, petsc.ISStrideGetInfo 945 946 """ 947 cdef PetscInt size=0, first=0, step=0 948 CHKERR(ISGetLocalSize(self.iset, &size)) 949 CHKERR(ISStrideGetInfo(self.iset, &first, &step)) 950 return (toInt(size), toInt(first), toInt(step)) 951 952 def getInfo(self) -> tuple[int, int]: 953 """Return stride information for an index set with type `IS.Type.STRIDE`. 954 955 Not collective. 956 957 Returns 958 ------- 959 first : int 960 First element of the index set. 961 step : int 962 Difference between adjacent indices. 963 964 See Also 965 -------- 966 IS.getStride, petsc.ISStrideGetInfo 967 968 """ 969 cdef PetscInt first = 0, step = 0 970 CHKERR(ISStrideGetInfo(self.iset, &first, &step)) 971 return (toInt(first), toInt(step)) 972 973 # 974 975 property permutation: 976 """`True` if index set is a permutation, `False` otherwise. 977 978 Logically collective. 979 980 See Also 981 -------- 982 IS.isPermutation 983 984 """ 985 def __get__(self) -> bool: 986 return self.isPermutation() 987 988 property identity: 989 """`True` if index set is an identity, `False` otherwise. 990 991 Collective. 992 993 See Also 994 -------- 995 IS.isIdentity 996 997 """ 998 def __get__(self) -> bool: 999 return self.isIdentity() 1000 1001 property sorted: 1002 """`True` if index set is sorted, `False` otherwise. 1003 1004 Collective. 1005 1006 See Also 1007 -------- 1008 IS.isSorted 1009 1010 """ 1011 def __get__(self) -> bool: 1012 return self.isSorted() 1013 1014 # 1015 1016 property sizes: 1017 """The local and global sizes of the index set. 1018 1019 Not collective. 1020 1021 See Also 1022 -------- 1023 IS.getSizes 1024 1025 """ 1026 def __get__(self) -> tuple[int, int]: 1027 return self.getSizes() 1028 1029 property size: 1030 """The global size of the index set. 1031 1032 Not collective. 1033 1034 See Also 1035 -------- 1036 IS.getSize 1037 1038 """ 1039 def __get__(self) -> int: 1040 return self.getSize() 1041 1042 property local_size: 1043 """The local size of the index set. 1044 1045 Not collective. 1046 1047 See Also 1048 -------- 1049 IS.getLocalSize 1050 1051 """ 1052 def __get__(self) -> int: 1053 return self.getLocalSize() 1054 1055 property block_size: 1056 """The number of elements in a block. 1057 1058 Not collective. 1059 1060 See Also 1061 -------- 1062 IS.getBlockSize 1063 1064 """ 1065 def __get__(self) -> int: 1066 return self.getBlockSize() 1067 1068 property indices: 1069 """The indices of the index set. 1070 1071 Not collective. 1072 1073 See Also 1074 -------- 1075 IS.getIndices 1076 1077 """ 1078 def __get__(self) -> ArrayInt: 1079 return self.getIndices() 1080 1081 property array: 1082 """View of the index set as an array of integers. 1083 1084 Not collective. 1085 1086 """ 1087 def __get__(self) -> ArrayInt: 1088 return asarray(self) 1089 1090 # --- NumPy array interface (legacy) --- 1091 1092 property __array_interface__: 1093 def __get__(self): 1094 cdef _IS_buffer buf = _IS_buffer(self) 1095 return buf.__array_interface__ 1096 1097# -------------------------------------------------------------------- 1098 1099 1100class LGMapMapMode(object): 1101 """Enum describing mapping behavior when global indices are missing. 1102 1103 MASK 1104 Give missing global indices a local index of -1. 1105 DROP 1106 Drop missing global indices. 1107 1108 See Also 1109 -------- 1110 petsc.ISGlobalToLocalMappingMode 1111 1112 """ 1113 MASK = PETSC_IS_GTOLM_MASK 1114 DROP = PETSC_IS_GTOLM_DROP 1115 1116 1117class LGMapType(object): 1118 """Local to global map types.""" 1119 BASIC = S_(ISLOCALTOGLOBALMAPPINGBASIC) 1120 HASH = S_(ISLOCALTOGLOBALMAPPINGHASH) 1121 1122 1123# -------------------------------------------------------------------- 1124 1125cdef class LGMap(Object): 1126 """Mapping from a local to a global ordering. 1127 1128 See Also 1129 -------- 1130 petsc.ISLocalToGlobalMapping 1131 1132 """ 1133 1134 MapMode = LGMapMapMode 1135 1136 Type = LGMapType 1137 # 1138 1139 def __cinit__(self) -> None: 1140 self.obj = <PetscObject*> &self.lgm 1141 self.lgm = NULL 1142 1143 def __call__( 1144 self, 1145 indices: Sequence[int], 1146 result: ArrayInt | None = None) -> None: 1147 """Convert a locally numbered list of integers to a global numbering. 1148 1149 Not collective. 1150 1151 Parameters 1152 ---------- 1153 indices 1154 Input indices in local numbering. 1155 result 1156 Array to write the global numbering to. If `None` then a 1157 new array will be allocated. 1158 1159 See Also 1160 -------- 1161 IS.apply, petsc.ISLocalToGlobalMappingApply 1162 1163 """ 1164 self.apply(indices, result) 1165 1166 # 1167 1168 def setType(self, lgmap_type: LGMap.Type | str) -> None: 1169 """Set the type of the local-to-global map. 1170 1171 Logically collective. 1172 1173 Parameters 1174 ---------- 1175 lgmap_type 1176 The type of the local-to-global mapping. 1177 1178 Notes 1179 ----- 1180 Use ``-islocaltoglobalmapping_type`` to set the type in the 1181 options database. 1182 1183 See Also 1184 -------- 1185 petsc_options, petsc.ISLocalToGlobalMappingSetType 1186 1187 """ 1188 cdef PetscISLocalToGlobalMappingType cval = NULL 1189 lgmap_type = str2bytes(lgmap_type, &cval) 1190 CHKERR(ISLocalToGlobalMappingSetType(self.lgm, cval)) 1191 1192 def setFromOptions(self) -> None: 1193 """Set mapping options from the options database. 1194 1195 Not collective. 1196 1197 See Also 1198 -------- 1199 petsc_options, petsc.ISLocalToGlobalMappingSetFromOptions 1200 1201 """ 1202 CHKERR(ISLocalToGlobalMappingSetFromOptions(self.lgm)) 1203 1204 def view(self, Viewer viewer=None) -> None: 1205 """View the local-to-global mapping. 1206 1207 Not collective. 1208 1209 Parameters 1210 ---------- 1211 viewer 1212 Viewer instance, defaults to an instance of `Viewer.Type.ASCII`. 1213 1214 See Also 1215 -------- 1216 load, petsc.ISLocalToGlobalMappingView 1217 1218 """ 1219 cdef PetscViewer cviewer = NULL 1220 if viewer is not None: cviewer = viewer.vwr 1221 CHKERR(ISLocalToGlobalMappingView(self.lgm, cviewer)) 1222 1223 def load(self, Viewer viewer) -> Self: 1224 """Load a local-to-global mapping. 1225 1226 Collective. 1227 1228 See Also 1229 -------- 1230 view, petsc.ISLocalToGlobalMappingLoad 1231 1232 """ 1233 cdef MPI_Comm comm = MPI_COMM_NULL 1234 cdef PetscObject obj = <PetscObject>(viewer.vwr) 1235 if self.lgm == NULL: 1236 CHKERR(PetscObjectGetComm(obj, &comm)) 1237 CHKERR(ISLocalToGlobalMappingCreate(comm, 1, 0, NULL, PETSC_USE_POINTER, &self.lgm)) 1238 CHKERR(ISLocalToGlobalMappingLoad(self.lgm, viewer.vwr)) 1239 return self 1240 1241 def destroy(self) -> Self: 1242 """Destroy the local-to-global mapping. 1243 1244 Not collective. 1245 1246 See Also 1247 -------- 1248 petsc.ISLocalToGlobalMappingDestroy 1249 1250 """ 1251 CHKERR(ISLocalToGlobalMappingDestroy(&self.lgm)) 1252 return self 1253 1254 def create( 1255 self, 1256 indices: Sequence[int], 1257 bsize: int | None = None, 1258 comm: Comm | None = None) -> Self: 1259 """Create a local-to-global mapping. 1260 1261 Not collective. 1262 1263 Parameters 1264 ---------- 1265 indices 1266 Global index for each local element. 1267 bsize 1268 Block size, defaults to 1. 1269 comm 1270 MPI communicator, defaults to `Sys.getDefaultComm`. 1271 1272 See Also 1273 -------- 1274 petsc.ISLocalToGlobalMappingCreate 1275 1276 """ 1277 cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT) 1278 cdef PetscInt bs = 1, nidx = 0, *idx = NULL 1279 cdef PetscCopyMode cm = PETSC_COPY_VALUES 1280 cdef PetscLGMap newlgm = NULL 1281 if bsize is not None: bs = asInt(bsize) 1282 if bs == PETSC_DECIDE: bs = 1 1283 indices = iarray_i(indices, &nidx, &idx) 1284 CHKERR(ISLocalToGlobalMappingCreate( 1285 ccomm, bs, nidx, idx, cm, &newlgm)) 1286 CHKERR(PetscCLEAR(self.obj)); self.lgm = newlgm 1287 return self 1288 1289 def createIS(self, IS iset) -> Self: 1290 """Create a local-to-global mapping from an index set. 1291 1292 Not collective. 1293 1294 Parameters 1295 ---------- 1296 iset 1297 Index set containing the global numbers for each local number. 1298 1299 See Also 1300 -------- 1301 petsc.ISLocalToGlobalMappingCreateIS 1302 1303 """ 1304 cdef PetscLGMap newlgm = NULL 1305 CHKERR(ISLocalToGlobalMappingCreateIS( 1306 iset.iset, &newlgm)) 1307 CHKERR(PetscCLEAR(self.obj)); self.lgm = newlgm 1308 return self 1309 1310 def createSF(self, SF sf, start: int) -> Self: 1311 """Create a local-to-global mapping from a star forest. 1312 1313 Collective. 1314 1315 Parameters 1316 ---------- 1317 sf 1318 Star forest mapping contiguous local indices to (rank, offset). 1319 start 1320 First global index on this process. 1321 1322 See Also 1323 -------- 1324 petsc.ISLocalToGlobalMappingCreateSF 1325 1326 """ 1327 cdef PetscLGMap newlgm = NULL 1328 cdef PetscInt cstart = asInt(start) 1329 CHKERR(ISLocalToGlobalMappingCreateSF(sf.sf, cstart, &newlgm)) 1330 CHKERR(PetscCLEAR(self.obj)); self.lgm = newlgm 1331 return self 1332 1333 def getSize(self) -> int: 1334 """Return the local size of the local-to-global mapping. 1335 1336 Not collective. 1337 1338 See Also 1339 -------- 1340 petsc.ISLocalToGlobalMappingGetSize 1341 1342 """ 1343 cdef PetscInt n = 0 1344 CHKERR(ISLocalToGlobalMappingGetSize(self.lgm, &n)) 1345 return toInt(n) 1346 1347 def getBlockSize(self) -> int: 1348 """Return the block size of the local-to-global mapping. 1349 1350 Not collective. 1351 1352 See Also 1353 -------- 1354 petsc.ISLocalToGlobalMappingGetBlockSize 1355 1356 """ 1357 cdef PetscInt bs = 1 1358 CHKERR(ISLocalToGlobalMappingGetBlockSize(self.lgm, &bs)) 1359 return toInt(bs) 1360 1361 def getIndices(self) -> ArrayInt: 1362 """Return the global indices for each local point in the mapping. 1363 1364 Not collective. 1365 1366 See Also 1367 -------- 1368 petsc.ISLocalToGlobalMappingGetIndices 1369 1370 """ 1371 cdef PetscInt size = 0 1372 cdef const PetscInt *indices = NULL 1373 CHKERR(ISLocalToGlobalMappingGetSize( 1374 self.lgm, &size)) 1375 CHKERR(ISLocalToGlobalMappingGetIndices( 1376 self.lgm, &indices)) 1377 cdef object oindices = None 1378 try: 1379 oindices = array_i(size, indices) 1380 finally: 1381 CHKERR(ISLocalToGlobalMappingRestoreIndices( 1382 self.lgm, &indices)) 1383 return oindices 1384 1385 def getBlockIndices(self) -> ArrayInt: 1386 """Return the global indices for each local block. 1387 1388 Not collective. 1389 1390 See Also 1391 -------- 1392 petsc.ISLocalToGlobalMappingGetBlockIndices 1393 1394 """ 1395 cdef PetscInt size = 0, bs = 1 1396 cdef const PetscInt *indices = NULL 1397 CHKERR(ISLocalToGlobalMappingGetSize( 1398 self.lgm, &size)) 1399 CHKERR(ISLocalToGlobalMappingGetBlockSize( 1400 self.lgm, &bs)) 1401 CHKERR(ISLocalToGlobalMappingGetBlockIndices( 1402 self.lgm, &indices)) 1403 cdef object oindices = None 1404 try: 1405 oindices = array_i(size//bs, indices) 1406 finally: 1407 CHKERR(ISLocalToGlobalMappingRestoreBlockIndices( 1408 self.lgm, &indices)) 1409 return oindices 1410 1411 def getInfo(self) -> dict[int, ArrayInt]: 1412 """Determine the indices shared with neighboring processes. 1413 1414 Collective. 1415 1416 Returns 1417 ------- 1418 dict 1419 Mapping from neighboring processor number to an array of shared 1420 indices (in local numbering). 1421 1422 See Also 1423 -------- 1424 petsc.ISLocalToGlobalMappingGetInfo 1425 1426 """ 1427 cdef PetscInt i, nproc = 0, *procs = NULL, 1428 cdef PetscInt *numprocs = NULL, **indices = NULL 1429 cdef dict neighs = {} 1430 CHKERR(ISLocalToGlobalMappingGetInfo( 1431 self.lgm, &nproc, &procs, &numprocs, &indices)) 1432 try: 1433 for i from 0 <= i < nproc: 1434 neighs[toInt(procs[i])] = array_i(numprocs[i], indices[i]) 1435 finally: 1436 ISLocalToGlobalMappingRestoreInfo( 1437 self.lgm, &nproc, &procs, &numprocs, &indices) 1438 return neighs 1439 1440 def getBlockInfo(self) -> dict[int, ArrayInt]: 1441 """Determine the block indices shared with neighboring processes. 1442 1443 Collective. 1444 1445 Returns 1446 ------- 1447 dict 1448 Mapping from neighboring processor number to an array of shared 1449 block indices (in local numbering). 1450 1451 See Also 1452 -------- 1453 petsc.ISLocalToGlobalMappingGetBlockInfo 1454 1455 """ 1456 cdef PetscInt i, nproc = 0, *procs = NULL, 1457 cdef PetscInt *numprocs = NULL, **indices = NULL 1458 cdef dict neighs = {} 1459 CHKERR(ISLocalToGlobalMappingGetBlockInfo( 1460 self.lgm, &nproc, &procs, &numprocs, &indices)) 1461 try: 1462 for i from 0 <= i < nproc: 1463 neighs[toInt(procs[i])] = array_i(numprocs[i], indices[i]) 1464 finally: 1465 ISLocalToGlobalMappingRestoreBlockInfo( 1466 self.lgm, &nproc, &procs, &numprocs, &indices) 1467 return neighs 1468 1469 # 1470 1471 def apply( 1472 self, 1473 indices: Sequence[int], 1474 result: ArrayInt | None = None) -> ArrayInt: 1475 """Convert a locally numbered list of integers to a global numbering. 1476 1477 Not collective. 1478 1479 Parameters 1480 ---------- 1481 indices 1482 Input indices in local numbering. 1483 result 1484 Array to write the global numbering to. If `None` then a 1485 new array will be allocated. 1486 1487 Returns 1488 ------- 1489 ArrayInt 1490 Indices in global numbering. If ``result`` is not `None` then this is 1491 returned here. 1492 1493 See Also 1494 -------- 1495 LGMap.applyBlock, petsc.ISLocalToGlobalMappingApply 1496 1497 """ 1498 cdef PetscInt niidx = 0, *iidx = NULL 1499 cdef PetscInt noidx = 0, *oidx = NULL 1500 indices = iarray_i(indices, &niidx, &iidx) 1501 if result is None: result = empty_i(niidx) 1502 result = oarray_i(result, &noidx, &oidx) 1503 assert niidx == noidx, "incompatible array sizes" 1504 CHKERR(ISLocalToGlobalMappingApply( 1505 self.lgm, niidx, iidx, oidx)) 1506 return result 1507 1508 def applyBlock( 1509 self, 1510 indices: Sequence[int], 1511 result: ArrayInt | None = None) -> ArrayInt: 1512 """Convert a local block numbering to a global block numbering. 1513 1514 Not collective. 1515 1516 Parameters 1517 ---------- 1518 indices 1519 Input block indices in local numbering. 1520 result 1521 Array to write the global numbering to. If `None` then a 1522 new array will be allocated. 1523 1524 Returns 1525 ------- 1526 ArrayInt 1527 Block indices in global numbering. If ``result`` is not `None` 1528 then this is returned here. 1529 1530 See Also 1531 -------- 1532 LGMap.apply, petsc.ISLocalToGlobalMappingApplyBlock 1533 1534 """ 1535 cdef PetscInt niidx = 0, *iidx = NULL 1536 cdef PetscInt noidx = 0, *oidx = NULL 1537 indices = iarray_i(indices, &niidx, &iidx) 1538 if result is None: result = empty_i(niidx) 1539 result = oarray_i(result, &noidx, &oidx) 1540 assert niidx == noidx, "incompatible array sizes" 1541 CHKERR(ISLocalToGlobalMappingApplyBlock( 1542 self.lgm, niidx, iidx, oidx)) 1543 return result 1544 1545 def applyIS(self, IS iset) -> IS: 1546 """Create an index set with global numbering from a local numbering. 1547 1548 Collective. 1549 1550 Parameters 1551 ---------- 1552 iset 1553 Index set with local numbering. 1554 1555 Returns 1556 ------- 1557 IS 1558 Index set with global numbering. 1559 1560 See Also 1561 -------- 1562 petsc.ISLocalToGlobalMappingApplyIS 1563 1564 """ 1565 cdef IS result = IS() 1566 CHKERR(ISLocalToGlobalMappingApplyIS( 1567 self.lgm, iset.iset, &result.iset)) 1568 return result 1569 1570 def applyInverse( 1571 self, 1572 indices: Sequence[int], 1573 mode: LGMap.MapMode | str | None = None) -> ArrayInt: 1574 """Compute local numbering from global numbering. 1575 1576 Not collective. 1577 1578 Parameters 1579 ---------- 1580 indices 1581 Indices with a global numbering. 1582 mode 1583 Flag indicating what to do with indices that have no local value, 1584 defaults to ``"mask"``. 1585 1586 Returns 1587 ------- 1588 ArrayInt 1589 Indices with a local numbering. 1590 1591 See Also 1592 -------- 1593 petsc.ISGlobalToLocalMappingApply 1594 1595 """ 1596 cdef PetscGLMapMode cmode = PETSC_IS_GTOLM_MASK 1597 if mode is not None: cmode = mode 1598 cdef PetscInt n = 0, *idx = NULL 1599 indices = iarray_i(indices, &n, &idx) 1600 cdef PetscInt nout = n, *idxout = NULL 1601 if cmode != PETSC_IS_GTOLM_MASK: 1602 CHKERR(ISGlobalToLocalMappingApply( 1603 self.lgm, cmode, n, idx, &nout, NULL)) 1604 result = oarray_i(empty_i(nout), &nout, &idxout) 1605 CHKERR(ISGlobalToLocalMappingApply( 1606 self.lgm, cmode, n, idx, &nout, idxout)) 1607 return result 1608 1609 def applyBlockInverse( 1610 self, 1611 indices: Sequence[int], 1612 mode: LGMap.MapMode | str | None = None) -> ArrayInt: 1613 """Compute blocked local numbering from blocked global numbering. 1614 1615 Not collective. 1616 1617 Parameters 1618 ---------- 1619 indices 1620 Indices with a global block numbering. 1621 mode 1622 Flag indicating what to do with indices that have no local value, 1623 defaults to ``"mask"``. 1624 1625 Returns 1626 ------- 1627 ArrayInt 1628 Indices with a local block numbering. 1629 1630 See Also 1631 -------- 1632 petsc.ISGlobalToLocalMappingApplyBlock 1633 1634 """ 1635 cdef PetscGLMapMode cmode = PETSC_IS_GTOLM_MASK 1636 if mode is not None: cmode = mode 1637 cdef PetscInt n = 0, *idx = NULL 1638 indices = iarray_i(indices, &n, &idx) 1639 cdef PetscInt nout = n, *idxout = NULL 1640 if cmode != PETSC_IS_GTOLM_MASK: 1641 CHKERR(ISGlobalToLocalMappingApply( 1642 self.lgm, cmode, n, idx, &nout, NULL)) 1643 result = oarray_i(empty_i(nout), &nout, &idxout) 1644 CHKERR(ISGlobalToLocalMappingApplyBlock( 1645 self.lgm, cmode, n, idx, &nout, idxout)) 1646 return result 1647 # 1648 1649 property size: 1650 """The local size. 1651 1652 Not collective. 1653 1654 See Also 1655 -------- 1656 LGMap.getSize 1657 1658 """ 1659 def __get__(self) -> int: 1660 return self.getSize() 1661 1662 property block_size: 1663 """The block size. 1664 1665 Not collective. 1666 1667 See Also 1668 -------- 1669 LGMap.getBlockSize 1670 1671 """ 1672 def __get__(self) -> int: 1673 return self.getBlockSize() 1674 1675 property indices: 1676 """The global indices for each local point in the mapping. 1677 1678 Not collective. 1679 1680 See Also 1681 -------- 1682 LGMap.getIndices, petsc.ISLocalToGlobalMappingGetIndices 1683 1684 """ 1685 def __get__(self) -> ArrayInt: 1686 return self.getIndices() 1687 1688 property block_indices: 1689 """The global indices for each local block in the mapping. 1690 1691 Not collective. 1692 1693 See Also 1694 -------- 1695 LGMap.getBlockIndices, petsc.ISLocalToGlobalMappingGetBlockIndices 1696 1697 """ 1698 def __get__(self) -> ArrayInt: 1699 return self.getBlockIndices() 1700 1701 property info: 1702 """Mapping describing indices shared with neighboring processes. 1703 1704 Collective. 1705 1706 See Also 1707 -------- 1708 LGMap.getInfo, petsc.ISLocalToGlobalMappingGetInfo 1709 1710 """ 1711 def __get__(self) -> dict[int, ArrayInt]: 1712 return self.getInfo() 1713 1714 property block_info: 1715 """Mapping describing block indices shared with neighboring processes. 1716 1717 Collective. 1718 1719 See Also 1720 -------- 1721 LGMap.getBlockInfo, petsc.ISLocalToGlobalMappingGetBlockInfo 1722 1723 """ 1724 def __get__(self) -> dict[int, ArrayInt]: 1725 return self.getBlockInfo() 1726 1727# -------------------------------------------------------------------- 1728 1729del ISType 1730del LGMapMapMode 1731del LGMapType 1732# -------------------------------------------------------------------- 1733