MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
cnpy2 Namespace Reference

Functions

char BigEndianTest ()
 
void change_shape_in_header (const string &filename, const size_t data_len, const size_t numcols)
 Change shape in numpy header. More...
 
bool is_valid_numpy_file (FILE *fp)
 Check if a numpy file is sane or not. More...
 
char map_type (const std::type_info &t)
 
void parse_header (FILE *fp, string &header)
 Parser header from a numpy file. Store it in vector. More...
 
template<typename T >
void save_numpy (const string &outfile, const vector< double > &vec, vector< string > colnames, const string openmode, const char version= '1')
 
void split (vector< string > &strs, string &input, const string &pat)
 
template<typename T >
void write_header (FILE *fp, const vector< string > &colnames, vector< unsigned int >shape, char version)
 

Variables

static char __pre__ [__pre__size__]
 
static const unsigned int __pre__size__ = 8
 

Function Documentation

char cnpy2::BigEndianTest ( )

Definition at line 29 of file cnpy.cpp.

Referenced by write_header().

29  {
30  unsigned char x[] = {1,0};
31  short y = *(short*) x;
32  return y == 1 ? '<' : '>';
33 }

+ Here is the caller graph for this function:

void cnpy2::change_shape_in_header ( const string &  filename,
const size_t  data_len,
const size_t  numcols 
)

Change shape in numpy header.

Parameters
@paramdata_len

Definition at line 130 of file cnpy.cpp.

References parse_header(), moose::showWarn(), split(), and moose::toString().

Referenced by save_numpy().

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 }
string toString(double x)
Convert a given value to string.
Definition: global.cpp:199
void split(vector< string > &strs, string &input, const string &pat)
Definition: cnpy.cpp:63
void parse_header(FILE *fp, string &header)
Parser header from a numpy file. Store it in vector.
Definition: cnpy.cpp:109
void showWarn(string msg)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool cnpy2::is_valid_numpy_file ( FILE *  fp)

Check if a numpy file is sane or not.

Read first 8 bytes and compare with standard header.

Parameters
npy_filePath to file.
Returns
true if file is sane, else false.

Definition at line 84 of file cnpy.cpp.

References __pre__, and __pre__size__.

Referenced by save_numpy().

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 }
static char __pre__[__pre__size__]
Definition: cnpy.hpp:89
static const unsigned int __pre__size__
Definition: cnpy.hpp:88

+ Here is the caller graph for this function:

char cnpy2::map_type ( const std::type_info &  t)

Definition at line 36 of file cnpy.cpp.

Referenced by write_header().

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 }

+ Here is the caller graph for this function:

void cnpy2::parse_header ( FILE *  fp,
string &  header 
)

Parser header from a numpy file. Store it in vector.

Parameters
header

Definition at line 109 of file cnpy.cpp.

References __pre__size__.

Referenced by change_shape_in_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 }
static const unsigned int __pre__size__
Definition: cnpy.hpp:88

+ Here is the caller graph for this function:

template<typename T >
void cnpy2::save_numpy ( const string &  outfile,
const vector< double > &  vec,
vector< string >  colnames,
const string  openmode,
const char  version = '1' 
)

Definition at line 159 of file cnpy.hpp.

References change_shape_in_header(), is_valid_numpy_file(), moose::showError(), and moose::showWarn().

166 {
167 
168  // In our application, we need to write a vector as matrix. We do not
169  // support the stacking of matrices.
170  vector<unsigned int> shape;
171 
172  if( colnames.size() == 0)
173  return;
174 
175  shape.push_back( vec.size() / colnames.size());
176 
177  /* In mode "w", open the file and write a header as well. When file is open
178  * in mode "a", we assume that file is alreay a valid numpy file.
179  */
180  if( openmode == "w" )
181  {
182  FILE* fp = fopen( outfile.c_str(), "wb" );
183  if( NULL == fp )
184  {
185  moose::showWarn( "Could not open file " + outfile );
186  return;
187  }
188  write_header<T>( fp, colnames, shape, version );
189  fclose( fp );
190  }
191  else /* Append mode. */
192  {
193  // Do a sanity check if file is really a numpy file.
194  FILE* fp = fopen( outfile.c_str(), "r" );
195  if( ! fp )
196  {
197  moose::showError( "Can't open " + outfile + " to validate" );
198  return;
199  }
200  else if(! is_valid_numpy_file( fp ) )
201  {
202  moose::showWarn( outfile + " is not a valid numpy file"
203  + " I am not goind to write to it"
204  );
205  return;
206  }
207  if( fp )
208  fclose( fp );
209  // And change the shape in header.
210  change_shape_in_header( outfile, vec.size(), colnames.size() );
211  }
212 
213  FILE* fp = fopen( outfile.c_str(), "ab" );
214  if( NULL == fp )
215  {
216  moose::showWarn( "Could not open " + outfile + " to write " );
217  return;
218  }
219  fwrite( &vec[0], sizeof(T), vec.size(), fp );
220  fclose( fp );
221 
222 }
void showError(string msg)
bool is_valid_numpy_file(FILE *fp)
Check if a numpy file is sane or not.
Definition: cnpy.cpp:84
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

+ Here is the call graph for this function:

void cnpy2::split ( vector< string > &  strs,
string &  input,
const string &  pat 
)

Definition at line 63 of file cnpy.cpp.

Referenced by change_shape_in_header().

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 }

+ Here is the caller graph for this function:

template<typename T >
void cnpy2::write_header ( FILE *  fp,
const vector< string > &  colnames,
vector< unsigned int >  shape,
char  version 
)

Definition at line 95 of file cnpy.hpp.

References __pre__, __pre__size__, BigEndianTest(), map_type(), and moose::toString().

100 {
101  // Heder are always at the begining of file.
102  fseek( fp, 0, SEEK_SET );
103  char endianChar = cnpy2::BigEndianTest();
104  char formatChar = cnpy2::map_type( typeid(T) );
105 
106  string dict = ""; // This is the header to numpy file
107  dict += "{'descr': [";
108  for( vector<string>::const_iterator it = colnames.begin();
109  it != colnames.end(); it++ )
110  dict += "('" + *it + "' , '" + endianChar + formatChar + "'),";
111 
112  dict += "], 'fortran_order': False, 'shape': (";
113  dict += moose::toString(shape[0]);
114  for(size_t i = 1; i < shape.size(); i++)
115  {
116  dict += ",";
117  dict += moose::toString(shape[i]);
118  }
119  if( shape.size() == 1) dict += ",";
120  dict += "), }";
121 
122  // When appending to this file, we need to rewrite header. Size of header
123  // might change since shape values might change. Minimum shape from (1,)
124  // could become quite large (13132131321,) etc. For safety region, append a
125  // chunk of whitespace characters so that overwriting header does not
126  // overwrite the data. This trick would save us from copying data into
127  // memory.
128  dict += string(11, ' '); /* 32 bit number is fit */
129 
130  // pad with spaces so that preamble+headerlen+dict is modulo 16 bytes.
131  // preamble is 8 bytes, header len is 4 bytes, total 12.
132  // dict needs to end with \n
133  unsigned int remainder = 16 - (12 + dict.size()) % 16;
134  dict.insert(dict.end(),remainder,' ');
135  *(dict.end()-1) = '\n';
136 
137  if( version == '2' )
138  __pre__[6] = (char) 0x02;
139 
140  fwrite( __pre__, sizeof( char ), __pre__size__, fp );
141 
142  // Now write the size of dict. It is 2bytes long in version 1 and 4 bytes
143  // long in version 2.
144  if( version == '2' )
145  {
146  uint32_t s = dict.size();
147  fwrite( (char*)&s, sizeof( uint32_t ), 1, fp );
148  }
149  else
150  {
151  int16_t s = dict.size();
152  fwrite( (char*)&s, sizeof( uint16_t ), 1, fp );
153  }
154  fwrite( dict.c_str(), sizeof(char), dict.size(), fp );
155 }
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
static char __pre__[__pre__size__]
Definition: cnpy.hpp:89
static const unsigned int __pre__size__
Definition: cnpy.hpp:88
char BigEndianTest()
Definition: cnpy.cpp:29

+ Here is the call graph for this function:

Variable Documentation

char cnpy2::__pre__[__pre__size__]
static
Initial value:
= {
(char)0x93, 'N', 'U', 'M', 'P', 'Y'
, (char)0x01, (char) 0x00
}

Definition at line 89 of file cnpy.hpp.

Referenced by is_valid_numpy_file(), and write_header().

const unsigned int cnpy2::__pre__size__ = 8
static

Definition at line 88 of file cnpy.hpp.

Referenced by is_valid_numpy_file(), parse_header(), and write_header().