xref: /petsc/src/binding/petsc4py/src/petsc4py/PETSc/Sys.pyx (revision 690fd307ada3915ac6109302b997fc1af8d1b58a) !
1# ------------------------------------------------------------------------------
2
3cdef class Sys:
4
5    """System utilities."""
6
7    @classmethod
8    def getVersion(
9        cls,
10        devel: bool = False,
11        date: bool = False,
12        author: bool = False) -> tuple[int, int, int]:
13        """Return PETSc version information.
14
15        Not collective.
16
17        Parameters
18        ----------
19        devel
20            Additionally, return whether using an in-development version.
21        date
22            Additionally, return date information.
23        author
24            Additionally, return author information.
25
26        Returns
27        -------
28        major : int
29            Major version number.
30        minor : int
31            Minor version number.
32        micro : int
33            Micro (or patch) version number.
34
35        See Also
36        --------
37        petsc.PetscGetVersion, petsc.PetscGetVersionNumber
38
39        """
40        cdef char cversion[256]
41        cdef PetscInt major=0, minor=0, micro=0, release=0
42        CHKERR(PetscGetVersion(cversion, sizeof(cversion)))
43        CHKERR(PetscGetVersionNumber(&major, &minor, &micro, &release))
44        out = version = (toInt(major), toInt(minor), toInt(micro))
45        if devel or date or author:
46            out = [version]
47            if devel:
48                out.append(not <bint>release)
49            if date:
50                vstr = bytes2str(cversion)
51                if release != 0:
52                    date = vstr.split(",", 1)[-1].strip()
53                else:
54                    date = vstr.split("Git Date:")[-1].strip()
55                out.append(date)
56            if author:
57                author = bytes2str(PETSC_AUTHOR_INFO).split('\n')
58                author = tuple([s.strip() for s in author if s])
59                out.append(author)
60        return tuple(out)
61
62    @classmethod
63    def getVersionInfo(cls) -> dict[str, bool | int | str]:
64        """Return PETSc version information.
65
66        Not collective.
67
68        Returns
69        -------
70        info : dict
71            Dictionary with version information.
72
73        See Also
74        --------
75        petsc.PetscGetVersion, petsc.PetscGetVersionNumber
76
77        """
78        version, dev, date, author = cls.getVersion(True, True, True)
79        return dict(major      = version[0],
80                    minor      = version[1],
81                    subminor   = version[2],
82                    release    = not dev,
83                    date       = date,
84                    authorinfo = author)
85
86    # --- xxx ---
87
88    @classmethod
89    def isInitialized(cls) -> bool:
90        """Return whether PETSc has been initialized.
91
92        Not collective.
93
94        See Also
95        --------
96        isFinalized
97
98        """
99        return toBool(PetscInitializeCalled)
100
101    @classmethod
102    def isFinalized(cls) -> bool:
103        """Return whether PETSc has been finalized.
104
105        Not collective.
106
107        See Also
108        --------
109        isInitialized
110
111        """
112        return toBool(PetscFinalizeCalled)
113
114    # --- xxx ---
115
116    @classmethod
117    def getDefaultComm(cls) -> Comm:
118        """Get the default MPI communicator used to create PETSc objects.
119
120        Not collective.
121
122        See Also
123        --------
124        setDefaultComm
125
126        """
127        cdef Comm comm = Comm()
128        comm.comm = PETSC_COMM_DEFAULT
129        return comm
130
131    @classmethod
132    def setDefaultComm(cls, comm: Comm | None) -> None:
133        """Set the default MPI communicator used to create PETSc objects.
134
135        Logically collective.
136
137        Parameters
138        ----------
139        comm
140            MPI communicator. If set to `None`, uses `COMM_WORLD`.
141
142        See Also
143        --------
144        getDefaultComm
145
146        """
147        cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_WORLD)
148        if ccomm == MPI_COMM_NULL:
149            raise ValueError("null communicator")
150        global PETSC_COMM_DEFAULT
151        PETSC_COMM_DEFAULT = ccomm
152
153    # --- xxx ---
154
155    @classmethod
156    def Print(
157        cls,
158        *args: Any,
159        sep: str = ' ',
160        end: str = '\n',
161        comm: Comm | None = None,
162        **kwargs: Any) -> None: # noqa: E129
163        """Print output from the first processor of a communicator.
164
165        Collective.
166
167        Parameters
168        ----------
169        *args
170            Positional arguments.
171        sep
172            String inserted between values, by default a space.
173        end
174            String appended after the last value, by default a newline.
175        comm
176            MPI communicator, defaults to `getDefaultComm`.
177        **kwargs
178            Keyword arguments.
179
180        See Also
181        --------
182        petsc.PetscPrintf
183
184        """
185        cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT)
186        if comm_rank(ccomm) == 0:
187            if not args: args = ('',)
188            format = ['%s', sep] * len(args)
189            format[-1] = end
190            message = ''.join(format) % args
191        else:
192            message = ''
193        cdef const char *m = NULL
194        message = str2bytes(message, &m)
195        CHKERR(PetscPrintf(ccomm, '%s', m))
196
197    @classmethod
198    def syncPrint(
199        cls,
200        *args: Any,
201        sep: str = ' ',
202        end: str = '\n',
203        flush: bool = False,
204        comm: Comm | None = None,
205        **kwargs: Any) -> None: # noqa: E129
206        """Print synchronized output from several processors of a communicator.
207
208        Not collective.
209
210        Parameters
211        ----------
212        *args
213            Positional arguments.
214        sep
215            String inserted between values, by default a space.
216        end
217            String appended after the last value, by default a newline.
218        flush
219            Whether to flush output with `syncFlush`.
220        comm
221            MPI communicator, defaults to `getDefaultComm`.
222        **kwargs
223            Keyword arguments.
224
225        See Also
226        --------
227        petsc.PetscSynchronizedPrintf, petsc.PetscSynchronizedFlush
228
229        """
230        cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT)
231        if not args: args = ('',)
232        format = ['%s', sep] * len(args)
233        format[-1] = end
234        message = ''.join(format) % args
235        cdef const char *m = NULL
236        message = str2bytes(message, &m)
237        CHKERR(PetscSynchronizedPrintf(ccomm, '%s', m))
238        if flush: CHKERR(PetscSynchronizedFlush(ccomm, PETSC_STDOUT))
239
240    @classmethod
241    def syncFlush(cls, comm: Comm | None = None) -> None:
242        """Flush output from previous `syncPrint` calls.
243
244        Collective.
245
246        Parameters
247        ----------
248        comm
249            MPI communicator, defaults to `getDefaultComm`.
250
251        See Also
252        --------
253        petsc.PetscSynchronizedPrintf, petsc.PetscSynchronizedFlush
254
255        """
256        cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT)
257        CHKERR(PetscSynchronizedFlush(ccomm, PETSC_STDOUT))
258
259    # --- xxx ---
260
261    @classmethod
262    def splitOwnership(
263        cls,
264        size: int | tuple[int, int],
265        bsize: int | None = None,
266        comm: Comm | None = None) -> tuple[int, int]:
267        """Given a global (or local) size determines a local (or global) size.
268
269        Collective.
270
271        Parameters
272        ----------
273        size
274            Global size ``N`` or 2-tuple ``(n, N)`` with local and global
275            sizes. Either of ``n`` or ``N`` (but not both) can be `None`.
276        bsize
277            Block size, defaults to ``1``.
278        comm
279            MPI communicator, defaults to `getDefaultComm`.
280
281        Returns
282        -------
283        n : int
284            The local size.
285        N : int
286            The global size.
287
288        Notes
289        -----
290        The ``size`` argument corresponds to the full size of the
291        vector. That is, an array with 10 blocks and a block size of 3 will
292        have a ``size`` of 30, not 10.
293
294        See Also
295        --------
296        petsc.PetscSplitOwnership
297
298        """
299        cdef MPI_Comm ccomm = def_Comm(comm, PETSC_COMM_DEFAULT)
300        cdef PetscInt bs=0, n=0, N=0
301        Sys_Sizes(size, bsize, &bs, &n, &N)
302        if bs == PETSC_DECIDE: bs = 1
303        if n > 0: n = n // bs
304        if N > 0: N = N // bs
305        CHKERR(PetscSplitOwnership(ccomm, &n, &N))
306        n = n * bs
307        N = N * bs
308        return (toInt(n), toInt(N))
309
310    @classmethod
311    def sleep(cls, seconds: float = 1.0) -> None:
312        """Sleep some number of seconds.
313
314        Not collective.
315
316        Parameters
317        ----------
318        seconds
319            Time to sleep in seconds.
320
321        See Also
322        --------
323        petsc.PetscSleep
324
325        """
326        cdef PetscReal s = asReal(seconds)
327        CHKERR(PetscSleep(s))
328
329    # --- xxx ---
330
331    @classmethod
332    def pushErrorHandler(cls, errhandler: str) -> None:
333        """Set the current error handler.
334
335        Logically collective.
336
337        Parameters
338        ----------
339        errhandler
340            The name of the error handler.
341
342        See Also
343        --------
344        petsc.PetscPushErrorHandler
345
346        """
347        cdef PetscErrorHandlerFunction handler = NULL
348        if errhandler == "python":
349            handler = <PetscErrorHandlerFunction> PetscPythonErrorHandler
350        elif errhandler == "debugger":
351            handler = PetscAttachDebuggerErrorHandler
352        elif errhandler == "emacs":
353            handler = PetscEmacsClientErrorHandler
354        elif errhandler == "traceback":
355            handler = PetscTraceBackErrorHandler
356        elif errhandler == "ignore":
357            handler = PetscIgnoreErrorHandler
358        elif errhandler == "mpiabort":
359            handler = PetscMPIAbortErrorHandler
360        elif errhandler == "abort":
361            handler = PetscAbortErrorHandler
362        else:
363            raise ValueError(f"unknown error handler: {errhandler!r}")
364        CHKERR(PetscPushErrorHandler(handler, NULL))
365
366    @classmethod
367    def popErrorHandler(cls) -> None:
368        """Remove the current error handler.
369
370        Logically collective.
371
372        See Also
373        --------
374        petsc.PetscPopErrorHandler
375
376        """
377        CHKERR(PetscPopErrorHandler())
378
379    @classmethod
380    def popSignalHandler(cls) -> None:
381        """Remove the current signal handler.
382
383        Logically collective.
384
385        See Also
386        --------
387        petsc.PetscPopSignalHandler
388
389        """
390        CHKERR(PetscPopSignalHandler())
391
392    @classmethod
393    def infoAllow(
394        cls,
395        flag: bool,
396        filename: str | None = None,
397        mode: str = "w") -> None:
398        """Enables or disables PETSc info messages.
399
400        Not collective.
401
402        Parameters
403        ----------
404        flag
405            Whether to enable info messages.
406        filename
407            Name of a file where to dump output.
408        mode
409            Write mode for file, by default ``"w"``.
410
411        See Also
412        --------
413        petsc.PetscInfoAllow, petsc.PetscInfoSetFile
414
415        """
416        cdef PetscBool tval = PETSC_FALSE
417        cdef const char *cfilename = NULL
418        cdef const char *cmode = NULL
419        if flag: tval = PETSC_TRUE
420        CHKERR(PetscInfoAllow(tval))
421        if filename is not None:
422            filename = str2bytes(filename, &cfilename)
423            mode = str2bytes(mode, &cmode)
424            CHKERR(PetscInfoSetFile(cfilename, cmode))
425
426    @classmethod
427    def registerCitation(cls, citation: str) -> None:
428        """Register BibTeX citation.
429
430        Not collective.
431
432        Parameters
433        ----------
434        citation
435            The BibTex citation entry to register.
436
437        See Also
438        --------
439        petsc.PetscCitationsRegister
440
441        """
442        if not citation: raise ValueError("empty citation")
443        cdef const char *cit = NULL
444        citation = str2bytes(citation, &cit)
445        cdef PetscBool flag = get_citation(citation)
446        CHKERR(PetscCitationsRegister(cit, &flag))
447        set_citation(citation, toBool(flag))
448
449    @classmethod
450    def hasExternalPackage(cls, package: str) -> bool:
451        """Return whether PETSc has support for external package.
452
453        Not collective.
454
455        Parameters
456        ----------
457        package
458            The external package name.
459
460        See Also
461        --------
462        petsc.PetscHasExternalPackage
463
464        """
465        cdef const char *cpackage = NULL
466        package = str2bytes(package, &cpackage)
467        cdef PetscBool has = PETSC_FALSE
468        CHKERR(PetscHasExternalPackage(cpackage, &has))
469        return toBool(has)
470
471
472cdef dict citations_registry = {}
473
474cdef PetscBool get_citation(object citation):
475    cdef bint is_set = citations_registry.get(citation)
476    return PETSC_TRUE if is_set else PETSC_FALSE
477
478cdef set_citation(object citation, bint is_set):
479    citations_registry[citation] = is_set
480
481# ------------------------------------------------------------------------------
482