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