11#include <unsupported/Eigen/CXX11/Tensor>
35 NpyArray(
const std::vector<size_t>& _shape,
size_t _word_size,
36 bool _fortran_order, std::string _number_type) :
37 shape(_shape), word_size(_word_size), fortran_order(_fortran_order),
38 number_type(_number_type)
42 for (
size_t i = 0; i < shape.size(); i++)
47 data_holder = std::shared_ptr<std::vector<char >> (
48 new std::vector<char>(num_vals * word_size));
51 NpyArray() : shape(0), word_size(0), fortran_order(0), num_vals(0) { }
56 return reinterpret_cast<T*
>(& (* data_holder)[0]);
62 return reinterpret_cast<T*
>(& (* data_holder)[0]);
66 std::vector<T> as_vec()
68 if (number_type ==
"f4")
70 float* p = data<float>();
71 return std::vector<T>(
static_cast<float*
>(p),
72 static_cast<float*
>(p) + num_vals);
75 if (number_type ==
"f8")
77 double* p = data<double>();
78 return std::vector<T>(
static_cast<double*
>(p),
79 static_cast<double*
>(p) + num_vals);
82 if (number_type ==
"f16")
84 long double* p = data<long double>();
85 return std::vector<T>(
static_cast<long double*
>(p),
86 static_cast<long double*
>(p) + num_vals);
89 if (number_type ==
"i2")
91 short* p = data<short>();
92 return std::vector<T>(
static_cast<short*
>(p),
93 static_cast<short*
>(p) + num_vals);
96 if (number_type ==
"i4")
99 return std::vector<T>(
static_cast<int*
>(p),
static_cast<int*
>(p) + num_vals);
102 if (number_type ==
"i8")
104 long* p = data<long>();
105 return std::vector<T>(
static_cast<long*
>(p),
static_cast<long*
>(p) + num_vals);
123 if (number_type ==
"u2")
125 unsigned short* p = data<unsigned short>();
126 return std::vector<T>(
static_cast<unsigned short*
>(p),
127 static_cast<unsigned short*
>(p) + num_vals);
130 if (number_type ==
"u4")
132 unsigned int* p = data<unsigned int>();
133 return std::vector<T>(
static_cast<unsigned int*
>(p),
134 static_cast<unsigned int*
>(p) + num_vals);
137 if (number_type ==
"u8")
139 unsigned long* p = data<unsigned long>();
140 return std::vector<T>(
static_cast<unsigned long*
>(p),
141 static_cast<unsigned long*
>(p) + num_vals);
144 if (number_type ==
"f8")
146 double* p = data<double>();
147 return std::vector<T>(
static_cast<double*
>(p),
148 static_cast<double*
>(p) + num_vals);
152 size_t num_bytes()
const
154 return data_holder->size();
157 std::shared_ptr<std::vector<char >> data_holder;
158 std::vector<size_t> shape;
161 std::string number_type;
165using npz_t = std::map<std::string, NpyArray>;
168char map_type(
const std::type_info& t);
169template<
typename T> std::vector<char> create_npy_header(
170 const std::vector<size_t>& shape);
171void parse_npy_header(FILE* fp,
size_t& word_size, std::vector<size_t>& shape,
172 bool& fortran_order, std::string& number_type);
173void parse_npy_header(
unsigned char* buffer,
size_t& word_size,
174 std::vector<size_t>& shape,
bool& fortran_order, std::string& number_type);
175void parse_zip_footer(FILE* fp, uint16_t& nrecs,
size_t& global_header_size,
176 size_t& global_header_offset);
177npz_t npz_load(std::string fname);
178NpyArray npz_load(std::string fname, std::string varname);
179NpyArray npy_load(std::string fname);
181template<
typename T> std::vector<char>& operator+=(std::vector<char>& lhs,
185 for (
size_t byte = 0;
byte <
sizeof(T);
byte++)
187 char val = * ((
char*) & rhs +
byte);
194template<> std::vector<char>& operator+=(std::vector<char>& lhs,
195 const std::string rhs);
196template<> std::vector<char>& operator+=(std::vector<char>& lhs,
200template<
typename T>
void npy_save(std::string fname,
const T* data,
201 const std::vector<size_t> shape, std::string mode =
"w")
209 fp = fopen(fname.c_str(),
"r+b");
217 std::string number_type;
218 parse_npy_header(fp, word_size, true_data_shape, fortran_order, number_type);
219 assert(!fortran_order);
221 if (word_size !=
sizeof(T))
223 Foam::Info <<
"libnpy error: " << fname <<
" has word size " << word_size <<
224 " but npy_save appending data sized " <<
sizeof(T) <<
"\n";
225 assert( word_size ==
sizeof(T) );
228 if (true_data_shape.size() != shape.size())
231 "libnpy error: npy_save attempting to append misdimensioned data to " << fname
233 assert(true_data_shape.size() != shape.size());
236 for (
size_t i = 1; i < shape.size(); i++)
238 if (shape[i] != true_data_shape[i])
240 Foam::Info <<
"libnpy error: npy_save attempting to append misshaped data to " <<
242 assert(shape[i] == true_data_shape[i]);
246 true_data_shape[0] += shape[0];
250 fp = fopen(fname.c_str(),
"wb");
251 true_data_shape = shape;
254 std::vector<char> header = create_npy_header<T>(true_data_shape);
255 size_t nels = std::accumulate(shape.begin(), shape.end(), 1,
256 std::multiplies<size_t>());
257 fseek(fp, 0, SEEK_SET);
258 fwrite(& header[0],
sizeof(
char), header.size(), fp);
259 fseek(fp, 0, SEEK_END);
260 fwrite(data,
sizeof(T), nels, fp);
264template<
typename T>
void npz_save(std::string zipname, std::string fname,
265 const T* data,
const std::vector<size_t>& shape, std::string mode =
"w",
266 bool compress =
false)
273 size_t global_header_offset = 0;
274 std::vector<char> global_header;
278 fp = fopen(zipname.c_str(),
"r+b");
287 size_t global_header_size;
288 parse_zip_footer(fp, nrecs, global_header_size, global_header_offset);
289 fseek(fp, global_header_offset, SEEK_SET);
290 global_header.resize(global_header_size);
291 size_t res = fread(&global_header[0],
sizeof(
char), global_header_size, fp);
293 if (res != global_header_size)
295 throw std::runtime_error(
"npz_save: header read error while adding to existing zip");
298 fseek(fp, global_header_offset, SEEK_SET);
302 fp = fopen(zipname.c_str(),
"wb");
305 std::vector<char> npy_header = create_npy_header<T>(shape);
306 size_t nels = std::accumulate(shape.begin(), shape.end(), 1,
307 std::multiplies<size_t>());
308 size_t nbytes_uncompressed = nels *
sizeof(T) + npy_header.size();
310 std::vector<uint8_t> buffer_compressed;
311 size_t nbytes_on_disk;
312 uint16_t compression_method;
318 std::vector<uint8_t> uncompressed(nbytes_uncompressed);
319 memcpy(&uncompressed[0], &npy_header[0], npy_header.size());
320 memcpy(&uncompressed[npy_header.size()], data, nels *
sizeof(T));
322 crc = crc32(0L, &uncompressed[0], nbytes_uncompressed);
324 uLongf max_compressed_size = compressBound(nbytes_uncompressed);
325 buffer_compressed.resize(max_compressed_size);
327 strm.zalloc = Z_NULL;
329 strm.opaque = Z_NULL;
330 int ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8,
336 throw std::runtime_error(
"npz_save: deflateInit2 failed");
339 strm.avail_in = nbytes_uncompressed;
340 strm.next_in = &uncompressed[0];
341 strm.avail_out = max_compressed_size;
342 strm.next_out = &buffer_compressed[0];
343 ret = deflate(&strm, Z_FINISH);
345 if (ret != Z_STREAM_END)
349 throw std::runtime_error(
"npz_save: deflate failed");
352 nbytes_on_disk = strm.total_out;
354 compression_method = 8;
359 crc = crc32(0L, (uint8_t*)&npy_header[0], npy_header.size());
360 crc = crc32(crc, (uint8_t*)data, nels *
sizeof(T));
361 nbytes_on_disk = nbytes_uncompressed;
362 compression_method = 0;
366 std::vector<char> local_header;
367 local_header +=
"PK";
368 local_header += (uint16_t) 0x0403;
369 local_header += (uint16_t) 20;
370 local_header += (uint16_t) 0;
371 local_header += (uint16_t) compression_method;
372 local_header += (uint16_t) 0;
373 local_header += (uint16_t) 0;
374 local_header += (uint32_t) crc;
375 local_header += (uint32_t) nbytes_on_disk;
376 local_header += (uint32_t) nbytes_uncompressed;
377 local_header += (uint16_t) fname.size();
378 local_header += (uint16_t) 0;
379 local_header += fname;
381 global_header +=
"PK";
382 global_header += (uint16_t) 0x0201;
383 global_header += (uint16_t) 20;
384 global_header.insert(global_header.end(), local_header.begin() + 4,
385 local_header.begin() + 30);
386 global_header += (uint16_t) 0;
387 global_header += (uint16_t) 0;
388 global_header += (uint16_t) 0;
389 global_header += (uint32_t) 0;
390 global_header += (uint32_t)
391 global_header_offset;
392 global_header += fname;
394 std::vector<char> footer;
396 footer += (uint16_t) 0x0605;
397 footer += (uint16_t) 0;
398 footer += (uint16_t) 0;
399 footer += (uint16_t) (nrecs + 1);
400 footer += (uint16_t) (nrecs + 1);
401 footer += (uint32_t) global_header.size();
402 footer += (uint32_t) (global_header_offset + nbytes_on_disk +
403 local_header.size());
404 footer += (uint16_t) 0;
406 fwrite(&local_header[0],
sizeof(
char), local_header.size(), fp);
410 fwrite(&buffer_compressed[0],
sizeof(
char), nbytes_on_disk, fp);
414 fwrite(&npy_header[0],
sizeof(
char), npy_header.size(), fp);
415 fwrite(data,
sizeof(T), nels, fp);
418 fwrite(&global_header[0],
sizeof(
char), global_header.size(), fp);
419 fwrite(&footer[0],
sizeof(
char), footer.size(), fp);
423template<
typename T>
void npy_save(std::string fname,
const std::vector<T> data,
424 std::string mode =
"w")
426 std::vector<size_t> shape;
427 shape.push_back(data.size());
428 npy_save(fname, & data[0], shape, mode);
431template<
typename T>
void npz_save(std::string zipname, std::string fname,
432 const std::vector<T> data, std::string mode =
"w",
bool compress =
false)
434 std::vector<size_t> shape;
435 shape.push_back(data.size());
436 npz_save(zipname, fname, &data[0], shape, mode, compress);
440template<
typename T>
void npz_save_compressed(std::string zipname,
441 std::string fname,
const T* data,
const std::vector<size_t>& shape,
442 std::string mode =
"w")
444 npz_save(zipname, fname, data, shape, mode,
true);
446template<
typename T>
void npz_save_compressed(std::string zipname,
447 std::string fname,
const std::vector<T> data, std::string mode =
"w")
449 std::vector<size_t> shape;
450 shape.push_back(data.size());
451 npz_save(zipname, fname, &data[0], shape, mode,
true);
454template<
typename T> std::vector<char> create_npy_header(
455 const std::vector<size_t>& shape)
457 std::vector<char> dict;
458 dict +=
"{'descr': '";
459 dict += BigEndianTest();
460 dict += map_type(
typeid(T));
461 dict += std::to_string(
sizeof(T));
462 dict +=
"', 'fortran_order': False, 'shape': (";
463 dict += std::to_string(shape[0]);
465 for (
size_t i = 1; i < shape.size(); i++)
468 dict += std::to_string(shape[i]);
471 if (shape.size() == 1)
478 int remainder = 16 - (10 + dict.size()) % 16;
479 dict.insert(dict.end(), remainder,
' ');
481 std::vector<char> header;
482 header += (char) 0x93;
484 header += (char) 0x01;
485 header += (char) 0x00;
486 header += (uint16_t) dict.size();
487 header.insert(header.end(), dict.begin(), dict.end());
491template<
typename T,
int dim>
492Eigen::Matrix < T, -1, dim > load(Eigen::Matrix < T, -1, dim > & mat,
493 const std::string fname);
496Eigen::SparseMatrix<T> load(Eigen::SparseMatrix<T>& mat,
497 const std::string fname);
500Eigen::Tensor<T, 3> load(Eigen::Tensor<T, 3>& tens,
501 const std::string fname);
503template<
typename T,
int dim>
504void save(
const Eigen::Matrix < T, -1, dim > & mat,
const std::string fname);
507void save(
const Eigen::Tensor<T, 3>& tensor,
const std::string fname);
510void save(
const Eigen::SparseMatrix<T>& mat,
const std::string fname);
512cnpy::NpyArray load_the_npy_file(FILE* fp);
513cnpy::NpyArray load_the_npy_file(std::string fname);