MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
cnpy.cpp
Go to the documentation of this file.
1 /*
2  * =====================================================================================
3  *
4  * Filename: cnpy.cpp
5  *
6  * Description: Write vector to numpy file.
7  *
8  * Version: 1.0
9  * Created: 05/05/2016 11:58:40 AM
10  * Revision: none
11  * Compiler: gcc
12  *
13  * Author: Dilawar Singh (), dilawars@ncbs.res.in
14  * Organization: NCBS Bangalore
15  *
16  * =====================================================================================
17  */
18 
19 #include "cnpy.hpp"
20 #include <cstring>
21 #include "print_function.hpp"
22 
23 using namespace std;
24 
25 namespace cnpy2 {
26 
27 // Check the endian-ness of machine at run-time. This is from library
28 // https://github.com/rogersce/cnpy
29 char BigEndianTest() {
30  unsigned char x[] = {1,0};
31  short y = *(short*) x;
32  return y == 1 ? '<' : '>';
33 }
34 
35 // And another function to convert given std datatype to numpy representation.
36 char map_type(const std::type_info& t)
37 {
38  if(t == typeid(float) ) return 'f';
39  if(t == typeid(double) ) return 'd';
40  if(t == typeid(long double) ) return 'd';
41 
42  if(t == typeid(int) ) return 'i';
43  if(t == typeid(char) ) return 'i';
44  if(t == typeid(short) ) return 'i';
45  if(t == typeid(long) ) return 'i';
46  if(t == typeid(long long) ) return 'i';
47 
48  if(t == typeid(unsigned char) ) return 'u';
49  if(t == typeid(unsigned short) ) return 'u';
50  if(t == typeid(unsigned long) ) return 'u';
51  if(t == typeid(unsigned long long) ) return 'u';
52  if(t == typeid(unsigned int) ) return 'u';
53 
54  if(t == typeid(bool) ) return 'b';
55 
56  if(t == typeid(std::complex<float>) ) return 'c';
57  if(t == typeid(std::complex<double>) ) return 'c';
58  if(t == typeid(std::complex<long double>) ) return 'c';
59 
60  else return '?';
61 }
62 
63 void split(vector<string>& strs, string& input, const string& pat)
64 {
65  char* pch;
66  pch = strtok( &input[0], pat.c_str() );
67  while( pch != NULL )
68  {
69  strs.push_back( string(pch ) );
70  pch = strtok( NULL, pat.c_str() );
71  }
72  delete pch;
73 }
74 
84 bool is_valid_numpy_file( FILE* fp )
85 {
86  assert( fp );
87  char buffer[__pre__size__];
88  size_t nr = fread( buffer, sizeof(char), __pre__size__, fp );
89 
90  if( 0 == nr )
91  return false;
92 
93  bool equal = true;
94  // Check for equality
95  for(size_t i = 0; i < __pre__size__; i++ )
96  if( buffer[i] != __pre__[i] )
97  {
98  equal = false;
99  break;
100  }
101  return equal;
102 }
103 
109 void parse_header( FILE* fp, string& header )
110 {
111  // Read header, till we hit newline character.
112  char ch;
113  header.clear();
114  while( ( ch = fgetc( fp )) != EOF )
115  {
116  if( '\n' == ch )
117  break;
118  header.push_back( ch );
119  }
120  assert( header.size() >= __pre__size__ );
121 }
122 
130 void change_shape_in_header( const string& filename
131  , const size_t data_len, const size_t numcols
132  )
133 {
134  string header;
135 
136  // Always open file in r+b mode. a+b mode always append at the end.
137  FILE* fp = fopen( filename.c_str(), "r+b" );
138  if( ! fp )
139  {
140  moose::showWarn( "Failed to open " + filename );
141  return;
142  }
143 
144  parse_header( fp, header );
145 
146  size_t shapePos = header.find( "'shape':" );
147  size_t lbrac = header.find( '(', shapePos );
148  size_t rbrac = header.find( ')', lbrac );
149  assert( lbrac > shapePos );
150  assert( rbrac > lbrac );
151 
152  string prefixHeader = header.substr( 0, lbrac + 1 );
153  string postfixHeader = header.substr( rbrac );
154 
155  string shapeStr = header.substr( lbrac + 1, rbrac - lbrac - 1);
156 
157  vector<string> tokens;
158  split( tokens, shapeStr, "," );
159 
160  string newShape = "";
161  for (size_t i = 0; i < tokens.size(); i++)
162  newShape += moose::toString( atoi( tokens[i].c_str() ) + data_len/numcols ) + ",";
163 
164  string newHeader = prefixHeader + newShape + postfixHeader + "\n";
165  if( newHeader.size() < header.size() )
166  {
167  cout << "Warn: Modified header can not be smaller than old header" << endl;
168  }
169 
170  // Move to at the begining of file and write the new header.
171  fseek(fp, 0, SEEK_SET);
172  fwrite( newHeader.c_str(), sizeof(char), newHeader.size(), fp );
173  fclose( fp );
174 }
175 
176 } /* Namespace cnpy2 ends. */
string toString(double x)
Convert a given value to string.
Definition: global.cpp:199
char map_type(const std::type_info &t)
Definition: cnpy.cpp:36
void split(vector< string > &strs, string &input, const string &pat)
Definition: cnpy.cpp:63
static char __pre__[__pre__size__]
Definition: cnpy.hpp:89
bool is_valid_numpy_file(FILE *fp)
Check if a numpy file is sane or not.
Definition: cnpy.cpp:84
static const unsigned int __pre__size__
Definition: cnpy.hpp:88
void parse_header(FILE *fp, string &header)
Parser header from a numpy file. Store it in vector.
Definition: cnpy.cpp:109
char BigEndianTest()
Definition: cnpy.cpp:29
void showWarn(string msg)
void change_shape_in_header(const string &filename, const size_t data_len, const size_t numcols)
Change shape in numpy header.
Definition: cnpy.cpp:130