MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Streamer.cpp
Go to the documentation of this file.
1 /***
2  * Filename: Streamer.cpp
3  *
4  * Description: Stream table data.
5  *
6  * Version: 0.0.1
7  * Created: 2016-04-26
8 
9  * Revision: none
10  *
11  * Author: Dilawar Singh <dilawars@ncbs.res.in>
12  * Organization: NCBS Bangalore
13  *
14  * License: GNU GPL2
15  */
16 
17 #include <algorithm>
18 #include <sstream>
19 
20 #include "global.h"
21 #include "header.h"
22 #include "Streamer.h"
23 #include "Clock.h"
24 #include "utility/utility.h"
25 #include "../shell/Shell.h"
26 
27 
29 {
30  /*-----------------------------------------------------------------------------
31  * Finfos
32  *-----------------------------------------------------------------------------*/
33  static ValueFinfo< Streamer, string > outfile(
34  "outfile"
35  , "File/stream to write table data to. Default is is __moose_tables__.dat.n"
36  " By default, this object writes data every second \n"
39  );
40 
41  static ValueFinfo< Streamer, string > format(
42  "format"
43  , "Format of output file, default is csv"
46  );
47 
49  "numTables"
50  , "Number of Tables handled by Streamer "
52  );
53 
54  /*-----------------------------------------------------------------------------
55  *
56  *-----------------------------------------------------------------------------*/
57  static DestFinfo process(
58  "process"
59  , "Handle process call"
61  );
62 
63  static DestFinfo reinit(
64  "reinit"
65  , "Handles reinit call"
67  );
68 
69 
70  static DestFinfo addTable(
71  "addTable"
72  , "Add a table to Streamer"
74  );
75 
76  static DestFinfo addTables(
77  "addTables"
78  , "Add many tables to Streamer"
79  , new OpFunc1<Streamer, vector<Id> >( &Streamer::addTables )
80  );
81 
82  static DestFinfo removeTable(
83  "removeTable"
84  , "Remove a table from Streamer"
86  );
87 
88  static DestFinfo removeTables(
89  "removeTables"
90  , "Remove tables -- if found -- from Streamer"
91  , new OpFunc1<Streamer, vector<Id> >( &Streamer::removeTables )
92  );
93 
94  /*-----------------------------------------------------------------------------
95  * ShareMsg definitions.
96  *-----------------------------------------------------------------------------*/
97  static Finfo* procShared[] =
98  {
99  &process , &reinit , &addTable, &addTables, &removeTable, &removeTables
100  };
101 
102  static SharedFinfo proc(
103  "proc",
104  "Shared message for process and reinit",
105  procShared, sizeof( procShared ) / sizeof( const Finfo* )
106  );
107 
108  static Finfo * tableStreamFinfos[] =
109  {
110  &outfile, &format, &proc, &numTables
111  };
112 
113  static string doc[] =
114  {
115  "Name", "Streamer",
116  "Author", "Dilawar Singh, 2016, NCBS, Bangalore.",
117  "Description", "Streamer: Stream moose.Table data to out-streams\n"
118  };
119 
120  static Dinfo< Streamer > dinfo;
121 
122  static Cinfo tableStreamCinfo(
123  "Streamer",
125  tableStreamFinfos,
126  sizeof( tableStreamFinfos )/sizeof(Finfo *),
127  &dinfo,
128  doc,
129  sizeof(doc) / sizeof(string)
130  );
131 
132  return &tableStreamCinfo;
133 }
134 
136 
137 // Class function definitions
138 
140 {
141  // Not all compilers allow initialization during the declaration of class
142  // methods.
143  format_ = "npy";
144  columns_.push_back( "time" ); /* First column is time. */
145  tables_.resize(0);
146  tableIds_.resize(0);
147  tableTick_.resize(0);
148  tableDt_.resize(0);
149  data_.resize(0);
150 }
151 
153 {
154  return *this;
155 }
156 
157 
159 {
160 }
161 
168 void Streamer::reinit(const Eref& e, ProcPtr p)
169 {
170 
171  if( tables_.size() == 0 )
172  {
173  moose::showWarn( "Zero tables in streamer. Disabling Streamer" );
174  e.element()->setTick( -2 ); /* Disable process */
175  return;
176  }
177 
178  Clock* clk = reinterpret_cast<Clock*>( Id(1).eref().data() );
179  for (size_t i = 0; i < tableIds_.size(); i++)
180  {
181  int tickNum = tableIds_[i].element()->getTick();
182  double tick = clk->getTickDt( tickNum );
183  tableDt_.push_back( tick );
184  // Make sure that all tables have the same tick.
185  if( i > 0 )
186  {
187  if( tick != tableDt_[0] )
188  {
189  moose::showWarn( "Table " + tableIds_[i].path() + " has "
190  " different clock dt. "
191  " Make sure all tables added to Streamer have the same "
192  " dt value."
193  );
194  }
195  }
196  }
197 
198 
199  // Push each table dt_ into vector of dt
200  for( size_t i = 0; i < tables_.size(); i++)
201  {
202  Id tId = tableIds_[i];
203  int tickNum = tId.element()->getTick();
204  tableDt_.push_back( clk->getTickDt( tickNum ) );
205  }
206 
207  // Make sure all tables have same dt_ else disable the streamer.
208  vector<unsigned int> invalidTables;
209  for (size_t i = 1; i < tableTick_.size(); i++)
210  {
211  if( tableTick_[i] != tableTick_[0] )
212  {
214  , "Table " << tableIds_[i].path()
215  << " has tick (dt) which is different than the first table."
216  << endl
217  << " Got " << tableTick_[i] << " expected " << tableTick_[0]
218  << endl << " Disabling this table."
219  );
220  invalidTables.push_back( i );
221  }
222  }
223 
224  for (size_t i = 0; i < invalidTables.size(); i++)
225  {
226  tables_.erase( tables_.begin() + i );
227  tableDt_.erase( tableDt_.begin() + i );
228  tableIds_.erase( tableIds_.begin() + i );
229  }
230 
231  if( ! isOutfilePathSet_ )
232  {
233  string defaultPath = "_tables/" + moose::moosePathToUserPath( e.id().path() );
234  setOutFilepath( defaultPath );
235  }
236 
237  // Prepare data. Add columns names and write whatever values are available
238  // write now.
239  currTime_ = 0.0;
240  zipWithTime( );
242  data_.clear( );
243 }
244 
250 {
251  zipWithTime( );
253  data_.clear( );
254 }
255 
262 void Streamer::process(const Eref& e, ProcPtr p)
263 {
264  //LOG( moose::debug, "Writing to table" );
265  zipWithTime( );
266 
267  // Write only if there are more than 100 entry in first table.
268  if( tables_[0]->getVecSize() > 100 )
269  {
271  data_.clear( );
272  }
273 }
274 
275 
281 void Streamer::addTable( Id table )
282 {
283  // If this table is not already in the vector, add it.
284  for( size_t i = 0; i < tableIds_.size(); i++)
285  if( table.path() == tableIds_[i].path() )
286  return; /* Already added. */
287 
288  Table* t = reinterpret_cast<Table*>(table.eref().data());
289  tableIds_.push_back( table );
290  tables_.push_back( t );
291  tableTick_.push_back( table.element()->getTick() );
292 
293  // NOTE: If user can make sure that names are unique in table, using name is
294  // better than using the full path.
295  if( t->getColumnName().size() > 0 )
296  columns_.push_back( t->getColumnName( ) );
297  else
298  columns_.push_back( moose::moosePathToUserPath( table.path() ) );
299 }
300 
306 void Streamer::addTables( vector<Id> tables )
307 {
308  if( tables.size() == 0 )
309  return;
310  for( vector<Id>::const_iterator it = tables.begin(); it != tables.end(); it++)
311  addTable( *it );
312 }
313 
314 
321 {
322  int matchIndex = -1;
323  for (size_t i = 0; i < tableIds_.size(); i++)
324  if( table.path() == tableIds_[i].path() )
325  {
326  matchIndex = i;
327  break;
328  }
329 
330  if( matchIndex > -1 )
331  {
332  tableIds_.erase( tableIds_.begin() + matchIndex );
333  tables_.erase( tables_.begin() + matchIndex );
334  columns_.erase( columns_.begin() + matchIndex );
335  }
336 }
337 
343 void Streamer::removeTables( vector<Id> tables )
344 {
345  for( vector<Id>::const_iterator it = tables.begin(); it != tables.end(); it++)
346  removeTable( *it );
347 }
348 
354 size_t Streamer::getNumTables( void ) const
355 {
356  return tables_.size();
357 }
358 
359 
360 string Streamer::getOutFilepath( void ) const
361 {
362  return outfilePath_;
363 }
364 
365 void Streamer::setOutFilepath( string filepath )
366 {
367  outfilePath_ = filepath;
368  isOutfilePathSet_ = true;
369  if( ! moose::createParentDirs( filepath ) )
371 
372  string format = moose::getExtension( outfilePath_, true );
373  if( format.size() > 0)
374  setFormat( format );
375  else
376  setFormat( "csv" );
377 }
378 
379 /* Set the format of all Tables */
380 void Streamer::setFormat( string fmt )
381 {
382  format_ = fmt;
383 }
384 
385 /* Get the format of all tables. */
386 string Streamer::getFormat( void ) const
387 {
388  return format_;
389 }
390 
395 {
396  size_t numEntriesInEachTable = tables_[0]->getVecSize( );
397 
398  //LOG( moose::debug, "Entries in each table " << numEntriesInEachTable );
399 
400  // Collect data from all table. If some table does not have enough data,
401  // fill it with nan
402  vector< vector< double > > collectedData;
403  for( size_t i = 0; i < tables_.size( ); i++ )
404  {
405  vector<double> tVec( tables_[i]->getVec( ) );
406  if( tVec.size( ) <= numEntriesInEachTable )
407  {
408 #if 0
410  , "Table " << tables_[i]->getName( ) << " is not functional. Filling with zero "
411  );
412 #endif
413  tVec.resize( numEntriesInEachTable, 0 );
414  }
415  collectedData.push_back( tVec );
416  }
417 
418  // Turn it into a table format. Its like taking a transpose of vector<
419  // vector >.
420  double allTableDt = tableDt_[ 0 ];
421  for( size_t i = 0; i < collectedData[0].size( ); i++ )
422  {
423  data_.push_back( currTime_ );
424  currTime_ += allTableDt;
425  for( size_t ii = 0; ii < collectedData.size(); ii++ )
426  data_.push_back( collectedData[ ii ][ i ] );
427  }
428 
429  // After collection data from table, clear tables.
430  for(size_t i = 0; i < tables_.size(); i++ )
431  tables_[i]->clearVec( );
432 
433  return;
434 }
Id id() const
Definition: Eref.cpp:62
string format_
Definition: Streamer.h:76
char * data() const
Definition: Eref.cpp:41
void cleanUp(void)
This function is called from Shell when simulation is called to write the left-over data to streamer ...
Definition: Streamer.cpp:249
vector< Id > tableIds_
Definition: Streamer.h:88
Definition: Clock.h:25
Element * element() const
Synonym for Id::operator()()
Definition: Id.cpp:113
vector< Table * > tables_
Definition: Streamer.h:89
string getFormat(void) const
Definition: Streamer.cpp:386
std::string path(const std::string &separator="/") const
Definition: Id.cpp:76
vector< double > tableDt_
Definition: Streamer.h:80
Definition: Dinfo.h:60
void setFormat(string format)
Definition: Streamer.cpp:380
vector< double > getVec() const
Definition: TableBase.cpp:482
void removeTable(Id table)
Remove a table from Streamer.
Definition: Streamer.cpp:320
bool createParentDirs(const string &path)
Create directories recursively needed to open the given file p.
Definition: global.cpp:122
void clearVec()
Definition: TableBase.cpp:414
static const Cinfo * initCinfo()
Definition: Streamer.cpp:28
double getTickDt(unsigned int i) const
Definition: Clock.cpp:621
Eref eref() const
Definition: Id.cpp:125
Element * element() const
Definition: Eref.h:42
string getExtension(const string &path, bool without_dot)
Get the extension of a given filepath.
Definition: global.cpp:170
vector< double > data_
Definition: Streamer.h:93
string moosePathToUserPath(string path)
When user gives a path /a/b/c, moose creates a path /a[0]/b[0]/c[0]. This is helpful in cases where o...
Definition: global.cpp:189
int getTick() const
Definition: Element.cpp:186
static const Cinfo * tableStreamCinfo
Definition: Streamer.cpp:135
unsigned int getVecSize() const
Definition: TableBase.cpp:477
void setOutFilepath(string path)
Definition: Streamer.cpp:365
Streamer & operator=(const Streamer &st)
Definition: Streamer.cpp:152
vector< string > columns_
Definition: Streamer.h:90
static const Cinfo * initCinfo()
Definition: TableBase.cpp:15
string outfilePath_
Definition: Streamer.h:75
void process(const Eref &e, ProcPtr p)
This function is called at its clock tick.
Definition: Streamer.cpp:262
void addTable(Id table)
Add a table to streamer.
Definition: Streamer.cpp:281
double currTime_
Definition: Streamer.h:85
string getOutFilepath(void) const
Definition: Streamer.cpp:360
Definition: OpFunc.h:27
Definition: Eref.h:26
void removeTables(vector< Id > table)
Remove multiple tables – if found – from Streamer.
Definition: Streamer.cpp:343
void addTables(vector< Id > tables)
Add multiple tables to Streamer.
Definition: Streamer.cpp:306
string getColumnName() const
Definition: Table.cpp:389
string toFilename(const string &path)
Replace all directory sepearator with _. This creates a filepath which can be created in current dire...
Definition: global.cpp:161
void zipWithTime()
This function prepares data to be written to a file.
Definition: Streamer.cpp:394
vector< unsigned int > tableTick_
Definition: Streamer.h:81
bool isOutfilePathSet_
Definition: Streamer.h:77
Definition: Id.h:17
void setTick(int t)
Definition: Element.cpp:251
size_t getNumTables(void) const
Get the number of tables handled by Streamer.
Definition: Streamer.cpp:354
Definition: Table.h:18
void showWarn(string msg)
void reinit(const Eref &e, ProcPtr p)
Reinit.
Definition: Streamer.cpp:168
static void writeToOutFile(const string &filepath, const string &format, const string &openmode, const vector< double > &data, const vector< string > &columns)
Write to a output file in given format.
Definition: Cinfo.h:18
static char path[]
Definition: mfield.cpp:403
Definition: Finfo.h:12