xref: /petsc/src/binding/petsc4py/src/petsc4py/PETSc/Comm.pyx (revision 552edb6364df478b294b3111f33a8f37ca096b20)
1# --------------------------------------------------------------------
2
3cdef class Comm:
4    """Communicator object.
5
6    Predefined instances:
7
8    `COMM_NULL`
9        The *null* (or invalid) communicator.
10    `COMM_SELF`
11        The *self* communicator.
12    `COMM_WORLD`
13        The *world* communicator.
14
15    See Also
16    --------
17    Sys.setDefaultComm, Sys.getDefaultComm
18
19    """
20
21    #
22
23    def __cinit__(self, comm=None):
24        self.comm = def_Comm(comm, MPI_COMM_NULL)
25        self.isdup = 0
26        if self.comm != MPI_COMM_NULL:
27            self.base = comm
28        else:
29            self.base = None
30
31    def __dealloc__(self):
32        if self.isdup:
33            CHKERR(PetscCommDEALLOC(&self.comm))
34        self.comm = MPI_COMM_NULL
35        self.isdup = 0
36        self.base = None
37
38    def __richcmp__(self, other, int op):
39        if not isinstance(self,  Comm): return NotImplemented
40        if not isinstance(other, Comm): return NotImplemented
41        if op!=2 and op!=3: raise TypeError("only '==' and '!='")
42        cdef Comm s = self
43        cdef Comm o = other
44        cdef int eq = (op == 2)
45        cdef MPI_Comm comm1 = s.comm
46        cdef MPI_Comm comm2 = o.comm
47        cdef int flag = 0
48        if comm1 != MPI_COMM_NULL and comm2 != MPI_COMM_NULL:
49            CHKERR(<PetscErrorCode>MPI_Comm_compare(comm1, comm2, &flag))
50            if eq: return (flag==<int>MPI_IDENT or  flag==<int>MPI_CONGRUENT)
51            else:  return (flag!=<int>MPI_IDENT and flag!=<int>MPI_CONGRUENT)
52        else:
53            if eq: return (comm1 == comm2)
54            else:  return (comm1 != comm2)
55
56    def __bool__(self) -> bool:
57        return self.comm != MPI_COMM_NULL
58
59    #
60
61    def destroy(self) -> None:
62        """Destroy the communicator.
63
64        Collective.
65
66        See Also
67        --------
68        petsc.PetscCommDestroy
69
70        """
71        if self.comm == MPI_COMM_NULL: return
72        if not self.isdup:
73            raise ValueError("communicator not owned")
74        CHKERR(PetscCommDestroy(&self.comm))
75        self.comm = MPI_COMM_NULL
76        self.isdup = 0
77        self.base = None
78
79    def duplicate(self) -> Self:
80        """Duplicate the communicator.
81
82        Collective.
83
84        See Also
85        --------
86        petsc.PetscCommDuplicate
87
88        """
89        if self.comm == MPI_COMM_NULL:
90            raise ValueError("null communicator")
91        cdef MPI_Comm newcomm = MPI_COMM_NULL
92        CHKERR(PetscCommDuplicate(self.comm, &newcomm, NULL))
93        cdef Comm comm = type(self)()
94        comm.comm  = newcomm
95        comm.isdup = 1
96        comm.base = self.base
97        return comm
98
99    def getSize(self) -> int:
100        """Return the number of processes in the communicator.
101
102        Not collective.
103
104        """
105        if self.comm == MPI_COMM_NULL:
106            raise ValueError("null communicator")
107        cdef int size=0
108        CHKERRMPI(MPI_Comm_size(self.comm, &size))
109        return size
110
111    def getRank(self) -> int:
112        """Return the rank of the calling processes in the communicator.
113
114        Not collective.
115
116        """
117        if self.comm == MPI_COMM_NULL:
118            raise ValueError("null communicator")
119        cdef int rank=0
120        CHKERRMPI(MPI_Comm_rank(self.comm, &rank))
121        return rank
122
123    def barrier(self) -> None:
124        """Barrier synchronization.
125
126        Collective.
127
128        """
129        if self.comm == MPI_COMM_NULL:
130            raise ValueError("null communicator")
131        CHKERRMPI(MPI_Barrier(self.comm))
132
133    # --- properties ---
134
135    property size:
136        """Communicator size."""
137        def __get__(self) -> int:
138            return self.getSize()
139
140    property rank:
141        """Communicator rank."""
142        def __get__(self) -> int:
143            return self.getRank()
144
145    # --- Fortran support ---
146
147    property fortran:
148        """Fortran handle."""
149        def __get__(self) -> int:
150            cdef MPI_Comm comm = self.comm
151            return MPI_Comm_c2f(comm)
152
153    # --- mpi4py support ---
154
155    def tompi4py(self) -> Intracomm:
156        """Convert communicator to `mpi4py`.
157
158        Not collective.
159
160        See Also
161        --------
162        mpi4py.MPI.Comm, mpi4py.MPI.Intracomm
163
164        """
165        cdef MPI_Comm comm = self.comm
166        return mpi4py_Comm_New(comm)
167
168    # --- mpi4py compatibility API ---
169
170    Free     = destroy
171    Clone    = duplicate
172    Dup      = duplicate
173    Get_size = getSize
174    Get_rank = getRank
175    Barrier  = barrier
176
177# --------------------------------------------------------------------
178
179cdef Comm __COMM_NULL__  = Comm()
180cdef Comm __COMM_SELF__  = Comm()
181cdef Comm __COMM_WORLD__ = Comm()
182
183COMM_NULL  = __COMM_NULL__
184COMM_SELF  = __COMM_SELF__
185COMM_WORLD = __COMM_WORLD__
186
187# --------------------------------------------------------------------
188
189cdef MPI_Comm PETSC_COMM_DEFAULT = MPI_COMM_NULL
190
191cdef MPI_Comm GetComm(
192    object comm, MPI_Comm defv,
193) except? MPI_COMM_NULL:
194    return def_Comm(comm, defv)
195
196cdef MPI_Comm GetCommDefault():
197    return PETSC_COMM_DEFAULT
198
199# --------------------------------------------------------------------
200