openPMD-api
 
Loading...
Searching...
No Matches
Numpy.hpp
1/* Copyright 2018-2025 Axel Huebl, 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#pragma once
22
23#include "openPMD/Datatype.hpp"
24
25#include "Common.hpp"
26
27#include <exception>
28#include <string>
29#include <type_traits>
30
31namespace openPMD
32{
33inline Datatype dtype_from_numpy(pybind11::dtype const dt)
34{
35 // ref: https://docs.scipy.org/doc/numpy/user/basics.types.html
36 // ref: https://github.com/numpy/numpy/issues/10678#issuecomment-369363551
37 if (dt.char_() == pybind11::dtype("b").char_())
38 if constexpr (std::is_signed_v<char>)
39 {
40 return Datatype::CHAR;
41 }
42 else
43 {
44 return Datatype::SCHAR;
45 }
46 else if (dt.char_() == pybind11::dtype("B").char_())
47 if constexpr (std::is_unsigned_v<char>)
48 {
49 return Datatype::CHAR;
50 }
51 else
52 {
53 return Datatype::UCHAR;
54 }
55 else if (dt.char_() == pybind11::dtype("short").char_())
56 return Datatype::SHORT;
57 else if (dt.char_() == pybind11::dtype("intc").char_())
58 return Datatype::INT;
59 else if (dt.char_() == pybind11::dtype("int_").char_())
60 return Datatype::LONG;
61 else if (dt.char_() == pybind11::dtype("longlong").char_())
62 return Datatype::LONGLONG;
63 else if (dt.char_() == pybind11::dtype("ushort").char_())
64 return Datatype::USHORT;
65 else if (dt.char_() == pybind11::dtype("uintc").char_())
66 return Datatype::UINT;
67 else if (dt.char_() == pybind11::dtype("uint").char_())
68 return Datatype::ULONG;
69 else if (dt.char_() == pybind11::dtype("ulonglong").char_())
70 return Datatype::ULONGLONG;
71 else if (dt.char_() == pybind11::dtype("clongdouble").char_())
72 return Datatype::CLONG_DOUBLE;
73 else if (dt.char_() == pybind11::dtype("cdouble").char_())
74 return Datatype::CDOUBLE;
75 else if (dt.char_() == pybind11::dtype("csingle").char_())
76 return Datatype::CFLOAT;
77 else if (dt.char_() == pybind11::dtype("longdouble").char_())
78 return Datatype::LONG_DOUBLE;
79 else if (dt.char_() == pybind11::dtype("double").char_())
80 return Datatype::DOUBLE;
81 else if (dt.char_() == pybind11::dtype("single").char_())
82 return Datatype::FLOAT;
83 else if (dt.char_() == pybind11::dtype("bool").char_())
84 return Datatype::BOOL;
85 else
86 {
87 pybind11::print(dt);
88 throw std::runtime_error(
89 std::string("Datatype '") + dt.char_() +
90 std::string("' not known in 'dtype_from_numpy'!")); // _s.format(dt)
91 }
92}
93
96inline Datatype dtype_from_bufferformat(std::string const &fmt)
97{
98 using DT = Datatype;
99
100 // refs:
101 // https://docs.scipy.org/doc/numpy-1.15.0/reference/arrays.interface.html
102 // https://docs.python.org/3/library/struct.html#format-characters
103 // std::cout << " scalar type '" << fmt << "'" << std::endl;
104 // typestring: encoding + type + number of bytes
105 if (fmt.find("?") != std::string::npos)
106 return DT::BOOL;
107 else if (fmt.find("b") != std::string::npos)
108 if constexpr (std::is_signed_v<char>)
109 {
110 return Datatype::CHAR;
111 }
112 else
113 {
114 return Datatype::SCHAR;
115 }
116 else if (fmt.find("h") != std::string::npos)
117 return DT::SHORT;
118 else if (fmt.find("i") != std::string::npos)
119 return DT::INT;
120 else if (fmt.find("l") != std::string::npos)
121 return DT::LONG;
122 else if (fmt.find("q") != std::string::npos)
123 return DT::LONGLONG;
124 else if (fmt.find("B") != std::string::npos)
125 if constexpr (std::is_unsigned_v<char>)
126 {
127 return Datatype::CHAR;
128 }
129 else
130 {
131 return Datatype::UCHAR;
132 }
133 else if (fmt.find("H") != std::string::npos)
134 return DT::USHORT;
135 else if (fmt.find("I") != std::string::npos)
136 return DT::UINT;
137 else if (fmt.find("L") != std::string::npos)
138 return DT::ULONG;
139 else if (fmt.find("Q") != std::string::npos)
140 return DT::ULONGLONG;
141 else if (fmt.find("Zf") != std::string::npos)
142 return DT::CFLOAT;
143 else if (fmt.find("Zd") != std::string::npos)
144 return DT::CDOUBLE;
145 else if (fmt.find("Zg") != std::string::npos)
146 return DT::CLONG_DOUBLE;
147 else if (fmt.find("f") != std::string::npos)
148 return DT::FLOAT;
149 else if (fmt.find("d") != std::string::npos)
150 return DT::DOUBLE;
151 else if (fmt.find("g") != std::string::npos)
152 return DT::LONG_DOUBLE;
153 else
154 throw std::runtime_error(
155 "dtype_from_bufferformat: Unknown "
156 "Python type '" +
157 fmt + "'");
158}
159
160inline pybind11::dtype dtype_to_numpy(Datatype const dt)
161{
162 using DT = Datatype;
163 switch (dt)
164 {
165 case DT::CHAR:
166 case DT::VEC_CHAR:
167 case DT::STRING:
168 case DT::VEC_STRING:
169 if constexpr (std::is_signed_v<char>)
170 {
171 return pybind11::dtype("b");
172 }
173 else
174 {
175 return pybind11::dtype("B");
176 }
177 case DT::SCHAR:
178 case DT::VEC_SCHAR:
179 return pybind11::dtype("b");
180 break;
181 case DT::UCHAR:
182 case DT::VEC_UCHAR:
183 return pybind11::dtype("B");
184 break;
185 // case DT::SCHAR:
186 // case DT::VEC_SCHAR:
187 // pybind11::dtype("b");
188 // break;
189 case DT::SHORT:
190 case DT::VEC_SHORT:
191 return pybind11::dtype("short");
192 break;
193 case DT::INT:
194 case DT::VEC_INT:
195 return pybind11::dtype("intc");
196 break;
197 case DT::LONG:
198 case DT::VEC_LONG:
199 return pybind11::dtype("int_");
200 break;
201 case DT::LONGLONG:
202 case DT::VEC_LONGLONG:
203 return pybind11::dtype("longlong");
204 break;
205 case DT::USHORT:
206 case DT::VEC_USHORT:
207 return pybind11::dtype("ushort");
208 break;
209 case DT::UINT:
210 case DT::VEC_UINT:
211 return pybind11::dtype("uintc");
212 break;
213 case DT::ULONG:
214 case DT::VEC_ULONG:
215 return pybind11::dtype("uint");
216 break;
217 case DT::ULONGLONG:
218 case DT::VEC_ULONGLONG:
219 return pybind11::dtype("ulonglong");
220 break;
221 case DT::FLOAT:
222 case DT::VEC_FLOAT:
223 return pybind11::dtype("single");
224 break;
225 case DT::DOUBLE:
226 case DT::VEC_DOUBLE:
227 case DT::ARR_DBL_7:
228 return pybind11::dtype("double");
229 break;
230 case DT::LONG_DOUBLE:
231 case DT::VEC_LONG_DOUBLE:
232 return pybind11::dtype("longdouble");
233 break;
234 case DT::CFLOAT:
235 case DT::VEC_CFLOAT:
236 return pybind11::dtype("csingle");
237 break;
238 case DT::CDOUBLE:
239 case DT::VEC_CDOUBLE:
240 return pybind11::dtype("cdouble");
241 break;
242 case DT::CLONG_DOUBLE:
243 case DT::VEC_CLONG_DOUBLE:
244 return pybind11::dtype("clongdouble");
245 break;
246 case DT::BOOL:
247 return pybind11::dtype("bool"); // also "?"
248 break;
249 case DT::UNDEFINED:
250 default:
251 throw std::runtime_error(
252 "dtype_to_numpy: Invalid Datatype '{...}'!"); // _s.format(dt)
253 break;
254 }
255}
256} // namespace openPMD
Public definitions of openPMD-api.
Definition Date.cpp:29
Datatype dtype_from_bufferformat(std::string const &fmt)
Return openPMD::Datatype from py::buffer_info::format.
Definition Numpy.hpp:96
Datatype
Concrete datatype of an object available at runtime.
Definition Datatype.hpp:51