laddu_python/
lib.rs

1#![warn(clippy::perf, clippy::style)]
2#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
3use pyo3::prelude::*;
4use pyo3::types::PyDict;
5
6#[cfg_attr(coverage_nightly, coverage(off))]
7pub mod amplitudes;
8#[cfg_attr(coverage_nightly, coverage(off))]
9pub mod data;
10#[cfg_attr(coverage_nightly, coverage(off))]
11pub mod utils;
12
13#[cfg(feature = "mpi")]
14#[cfg_attr(coverage_nightly, coverage(off))]
15pub mod mpi {
16    use super::*;
17    /// Use the Message Passing Interface (MPI) to run on a distributed system
18    ///
19    /// Parameters
20    /// ----------
21    /// trigger: bool, default=True
22    ///     An optional parameter which allows MPI to only be used under some boolean
23    ///     condition.
24    ///
25    /// Notes
26    /// -----
27    /// You must have MPI installed for this to work, and you must call the program with
28    /// ``mpirun <executable>``, or bad things will happen.
29    ///
30    /// MPI runs an identical program on each process, but gives the program an ID called its
31    /// "rank". Only the results of methods on the root process (rank 0) should be
32    /// considered valid, as other processes only contain portions of each dataset. To ensure
33    /// you don't save or print data at other ranks, use the provided ``laddu.mpi.is_root()``
34    /// method to check if the process is the root process.
35    ///
36    /// Once MPI is enabled, it cannot be disabled. If MPI could be toggled (which it can't),
37    /// the other processes will still run, but they will be independent of the root process
38    /// and will no longer communicate with it. The root process stores no data, so it would
39    /// be difficult (and convoluted) to get the results which were already processed via
40    /// MPI.
41    ///
42    /// Additionally, MPI must be enabled at the beginning of a script, at least before any
43    /// other ``laddu`` functions are called. For this reason, it is suggested that you use the
44    /// context manager ``laddu.mpi.MPI`` to ensure the MPI backend is used properly.
45    ///
46    /// If ``laddu.mpi.use_mpi()`` is called multiple times, the subsequent calls will have no
47    /// effect.
48    ///
49    /// You **must** call ``laddu.mpi.finalize_mpi()`` before your program exits for MPI to terminate
50    /// smoothly.
51    ///
52    /// See Also
53    /// --------
54    /// laddu.mpi.MPI
55    /// laddu.mpi.using_mpi
56    /// laddu.mpi.is_root
57    /// laddu.mpi.get_rank
58    /// laddu.mpi.get_size
59    /// laddu.mpi.finalize_mpi
60    ///
61    #[pyfunction]
62    #[pyo3(signature = (*, trigger=true))]
63    pub fn use_mpi(trigger: bool) {
64        laddu_core::mpi::use_mpi(trigger);
65    }
66
67    /// Drop the MPI universe and finalize MPI at the end of a program
68    ///
69    /// This should only be called once and should be called at the end of all ``laddu``-related
70    /// function calls. This **must** be called at the end of any program which uses MPI.
71    ///
72    /// See Also
73    /// --------
74    /// laddu.mpi.use_mpi
75    ///
76    #[pyfunction]
77    pub fn finalize_mpi() {
78        laddu_core::mpi::finalize_mpi();
79    }
80
81    /// Check if MPI is enabled
82    ///
83    /// This can be combined with ``laddu.mpi.is_root()`` to ensure valid results are only
84    /// returned from the root rank process on the condition that MPI is enabled.
85    ///
86    /// See Also
87    /// --------
88    /// laddu.mpi.use_mpi
89    /// laddu.mpi.is_root
90    ///
91    #[pyfunction]
92    pub fn using_mpi() -> bool {
93        laddu_core::mpi::using_mpi()
94    }
95
96    /// Check if the current MPI process is the root process
97    ///
98    /// This can be combined with ``laddu.mpi.using_mpi()`` to ensure valid results are only
99    /// returned from the root rank process on the condition that MPI is enabled.
100    ///
101    /// See Also
102    /// --------
103    /// laddu.mpi.use_mpi
104    /// laddu.mpi.using_mpi
105    ///
106    #[pyfunction]
107    pub fn is_root() -> bool {
108        laddu_core::mpi::is_root()
109    }
110
111    /// Get the rank of the current MPI process
112    ///
113    /// Returns ``None`` if MPI is not enabled
114    ///
115    /// See Also
116    /// --------
117    /// laddu.mpi.use_mpi
118    ///
119    #[pyfunction]
120    pub fn get_rank() -> Option<i32> {
121        laddu_core::mpi::get_rank()
122    }
123
124    /// Get the total number of MPI processes (including the root process)
125    ///
126    /// Returns ``None`` if MPI is not enabled
127    ///
128    /// See Also
129    /// --------
130    /// laddu.mpi.use_mpi
131    ///
132    #[pyfunction]
133    pub fn get_size() -> Option<i32> {
134        laddu_core::mpi::get_size()
135    }
136}
137
138pub trait GetStrExtractObj {
139    fn get_extract<T>(&self, key: &str) -> PyResult<Option<T>>
140    where
141        T: for<'py> FromPyObject<'py>;
142}
143
144#[cfg_attr(coverage_nightly, coverage(off))]
145impl GetStrExtractObj for Bound<'_, PyDict> {
146    fn get_extract<T>(&self, key: &str) -> PyResult<Option<T>>
147    where
148        T: for<'py> FromPyObject<'py>,
149    {
150        self.get_item(key)?
151            .map(|value| value.extract::<T>())
152            .transpose()
153    }
154}