openPMD-api
 
Loading...
Searching...
No Matches
Mpi.hpp
1/* Copyright 2021 Axel Huebl and Franz Poeschel
2 *
3 * This file is part of openPMD-api.
4 *
5 * openPMD-api is free software: you can redistribute it and/or modify
6 * it under the terms of of either the GNU General Public License or
7 * the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * openPMD-api is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License and the GNU Lesser General Public License
15 * for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * and the GNU Lesser General Public License along with openPMD-api.
19 * If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#pragma once
23
24#include "openPMD/config.hpp"
25
26#if openPMD_HAVE_MPI
27
28#include "openPMD/binding/python/Common.hpp"
29
30#include <mpi.h>
31
40{
41 PyObject_HEAD MPI_Comm ob_mpi;
42 unsigned int flags;
43};
44using openPMD_PyMPIIntracommObject = openPMD_PyMPICommObject;
45
47{
48 enum class error_type
49 {
50 invalid_data,
51 is_not_an_mpi_communicator
52 };
53 using error_type = error_type;
54
55 std::string error_msg;
56 error_type type;
57
58 operator std::string() const
59 {
60 return error_msg;
61 }
62};
63
64inline std::variant<MPI_Comm, py_object_to_mpi_comm_error>
65pythonObjectAsMpiComm(pybind11::object &comm)
66{
67 namespace py = pybind11;
74 // if( import_mpi4py() < 0 ) { here be dragons }
75
77 using e_t = e::error_type;
78
79 if (comm.ptr() == Py_None)
80 return e{"MPI communicator cannot be None.", e_t::invalid_data};
81 if (comm.ptr() == nullptr)
82 return e{"MPI communicator is a nullptr.", e_t::invalid_data};
83
84 // check type string to see if this is mpi4py
85 // __str__ (pretty)
86 // __repr__ (unambiguous)
87 // mpi4py: <mpi4py.MPI.Intracomm object at 0x7f998e6e28d0>
88 // pyMPI: ... (TODO)
89 py::str const comm_pystr = py::repr(comm);
90 std::string const comm_str = comm_pystr.cast<std::string>();
91 if (comm_str.substr(0, 12) != std::string("<mpi4py.MPI."))
92 return e{
93 "comm is not an mpi4py communicator: " + comm_str,
94 e_t::is_not_an_mpi_communicator};
95 // only checks same layout, e.g. an `int` in `PyObject` could pass this
96 if (!py::isinstance<py::class_<openPMD_PyMPIIntracommObject> >(
97 py::type::of(comm)))
98 // TODO add mpi4py version from above import check to error message
99 return e{
100 "comm has unexpected type layout in " + comm_str +
101 " (Mismatched MPI at compile vs. runtime? "
102 "Breaking mpi4py release?)",
103 e_t::invalid_data};
104
105 // todo other possible implementations:
106 // - pyMPI (inactive since 2008?): import mpi; mpi.WORLD
107
108 // reimplementation of mpi4py's:
109 // MPI_Comm* mpiCommPtr = PyMPIComm_Get(comm.ptr());
110 MPI_Comm *mpiCommPtr =
111 &((openPMD_PyMPIIntracommObject *)(comm.ptr()))->ob_mpi;
112
113 if (PyErr_Occurred())
114 return e{"MPI communicator access error.", e_t::invalid_data};
115 if (mpiCommPtr == nullptr)
116 {
117 return e{
118 "MPI communicator cast failed. "
119 "(Mismatched MPI at compile vs. runtime?)",
120 e_t::invalid_data};
121 }
122 return {*mpiCommPtr};
123}
124
125#endif
mpi4py communicator wrapper
Definition Mpi.hpp:40
Definition Mpi.hpp:47