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