Monarch  v3.8.2
Project 8 Data File Format Library
M3ReadTest.cc
Go to the documentation of this file.
1 #ifdef _WIN32
2 #define NOMINMAX
3 #endif
4 
5 #include "M3DataInterface.hh"
6 #include "M3Monarch.hh"
7 #include "application.hh"
8 #include "logger.hh"
9 #include "M3Record.hh"
10 
11 #include <algorithm>
12 #include <cstring> // for strcmp
13 #include <sstream>
14 
15 using namespace monarch3;
16 using std::stringstream;
17 
18 LOGGER( mlog, "M3ReadTest" );
19 
20 bool ReadRecordCheck( const M3Stream* aStream, int aOffset, unsigned aDataFormat );
21 bool PrintChannelsUInt( const M3Stream* aStream );
22 bool PrintChannelsInt( const M3Stream* aStream );
23 bool PrintChannelsFloat( const M3Stream* aStream );
24 bool PrintChannelsFloatComplex( const M3Stream* aStream );
25 
26 int main( const int argc, const char** argv )
27 {
28  scarab::main_app theMain( false );
29 
30  bool tHeaderOnly;
31  std::string tFilename;
32  theMain.add_flag( "-H,--header-only", tHeaderOnly, "Only look at header information; does not check number of records" );
33  theMain.add_option( "Filename", tFilename, "File to read" )->required();
34 
35  CLI11_PARSE( theMain, argc, argv );
36 
37  try
38  {
39  LINFO( mlog, "Opening file <" << tFilename );
40  std::shared_ptr< const Monarch3 > tReadTest( Monarch3::OpenForReading( tFilename ) );
41 
42  LINFO( mlog, "Reading header" );
43  tReadTest->ReadHeader();
44 
45  const M3Header* tReadHeader = tReadTest->GetHeader();
46  LINFO( mlog, *tReadHeader );
47 
48  if( tHeaderOnly )
49  {
50  tReadTest->FinishReading();
51  return RETURN_SUCCESS;
52  }
53 
54  LINFO( mlog, "Reading data" );
55 
56  LINFO( mlog, "Test 1: reading 2 sequential 1-channel records from stream 0");
57  LINFO( mlog, "\tRecord 0 has values '1'" );
58  LINFO( mlog, "\tRecord 1 has values '10'" );
59 
60  const M3Stream* tStream0 = tReadTest->GetStream( 0 );
61  unsigned tNAcquisitions0 = tStream0->GetNAcquisitions();
62  unsigned tNRecords0 = tStream0->GetNRecordsInFile();
63  LINFO( mlog, "Stream 0 has " << tNAcquisitions0 << " acquisitions and " << tNRecords0 << " records" );
64  const M3StreamHeader& tStrHeader0 = tReadHeader->StreamHeaders().at( 0 );
65  unsigned tNChannels0 = tStrHeader0.GetNChannels();
66  //unsigned tRecSize0 = tStrHeader0.GetRecordSize();
67  LINFO( mlog, "Stream 0 has " << tNChannels0 << " channel(s) stored in format mode " << tStrHeader0.GetChannelFormat() );
68  if( tNAcquisitions0 != 1 || tNChannels0 != 1 || tNRecords0 != 2 )
69  {
70  LERROR( mlog, "Invalid number of acquisitions (1 expected), channels (1 expected), or records (2 expected)" );
71  return RETURN_ERROR;
72  }
73 
74  for( unsigned iRec = 0; iRec < tNRecords0; ++iRec )
75  {
76  LINFO( mlog, "Checking record " << iRec );
77  if( ! ReadRecordCheck( tStream0, 0, tStrHeader0.GetDataFormat() ) )
78  {
79  LERROR( mlog, "Failed read record check" );
80  return RETURN_ERROR;
81  }
82  }
83 
84  LINFO( mlog, "Test 1 complete\n" );
85 
86 
87 
88  LINFO( mlog, "Test 2: using non-zero reading offsets");
89  LINFO( mlog, "\tRecord 0 has values '1' and '2'" );
90  LINFO( mlog, "\tRecord 1 has values '1000' and '2000'" );
91  LINFO( mlog, "\tRecord 2 has values '10000' and '20000'" );
92 
93  const M3Stream* tStream1 = tReadTest->GetStream( 1 );
94  unsigned tNAcquisitions1 = tStream1->GetNAcquisitions();
95  unsigned tNRecords1 = tStream1->GetNRecordsInFile();
96  LINFO( mlog, "Stream 1 has " << tNAcquisitions1 << " acquisitions and " << tNRecords1 << " records" );
97  const M3StreamHeader& tStrHeader1 = tReadHeader->StreamHeaders().at( 1 );
98  unsigned tNChannels1 = tStrHeader1.GetNChannels();
99  //unsigned tRecSize1 = tStrHeader1.GetRecordSize();
100  LINFO( mlog, "Stream 1 has " << tNChannels1 << " channel(s) stored in format mode " << tStrHeader1.GetChannelFormat() );
101  if( tNAcquisitions1 != 2 || tNChannels1 != 2 || tNRecords1 != 3 )
102  {
103  LERROR( mlog, "Invalid number of acquisitions (2 expected), channels (2 expected), or records (3 expected)" );
104  return RETURN_ERROR;
105  }
106 
107  LINFO( mlog, "Read the first record (record 0)" );
108  if( ! ReadRecordCheck( tStream1, 0, tStrHeader1.GetDataFormat() ) )
109  {
110  LERROR( mlog, "Failed read record check" );
111  return RETURN_ERROR;
112  }
113 
114  LINFO( mlog, "Skip to the third record, crossing to the next acquisition (record 2; acquisition 1)" );
115  if( ! ReadRecordCheck( tStream1, 1, tStrHeader1.GetDataFormat() ) )
116  {
117  LERROR( mlog, "Failed read record check" );
118  return RETURN_ERROR;
119  }
120 
121  LINFO( mlog, "Reread the third record (record 2; acquisition 1)" );
122  if( ! ReadRecordCheck( tStream1, -1, tStrHeader1.GetDataFormat() ) )
123  {
124  LERROR( mlog, "Failed read record check" );
125  return RETURN_ERROR;
126  }
127 
128  LINFO( mlog, "Go backwards to the second record (record 1; acquisition 1)" );
129  if( ! ReadRecordCheck( tStream1, -2, tStrHeader1.GetDataFormat() ) )
130  {
131  LERROR( mlog, "Failed read record check" );
132  return RETURN_ERROR;
133  }
134 
135  LINFO( mlog, "Go backwards to the first record (record 1; acquisition 0)" );
136  if( ! ReadRecordCheck( tStream1, -2, tStrHeader1.GetDataFormat() ) )
137  {
138  LERROR( mlog, "Failed read record check" );
139  return RETURN_ERROR;
140  }
141 
142  LINFO( mlog, "Reread the first record (record 1; acquisition 0)" );
143  if( ! ReadRecordCheck( tStream1, -1, tStrHeader1.GetDataFormat() ) )
144  {
145  LERROR( mlog, "Failed read record check" );
146  return RETURN_ERROR;
147  }
148 
149  LINFO( mlog, "Request record beyond the end of the file" );
150  if( tStream1->ReadRecord( 5 ) )
151  {
152  LERROR( mlog, "Record read did not fail" );
153  return RETURN_ERROR;
154  }
155 
156  LINFO( mlog, "Test 2 complete\n" );
157 
158 
159 
160  LINFO( mlog, "Test 3: using non-zero reading offset to skip the first record");
161  LINFO( mlog, "\tRecord 0 has values '1', '2', and '3'" );
162  LINFO( mlog, "\tRecord 1 has values '10', '20', and '30'" );
163 
164  const M3Stream* tStream2 = tReadTest->GetStream( 2 );
165  unsigned tNAcquisitions2 = tStream2->GetNAcquisitions();
166  unsigned tNRecords2 = tStream2->GetNRecordsInFile();
167  LINFO( mlog, "Stream 2 has " << tNAcquisitions2 << " acquisitions and " << tNRecords2 << " records" );
168  const M3StreamHeader& tStrHeader2 = tReadHeader->StreamHeaders().at( 2 );
169  unsigned tNChannels2 = tStrHeader2.GetNChannels();
170  //unsigned tRecSize2 = tStrHeader2.GetRecordSize();
171  LINFO( mlog, "Stream 2 has " << tNChannels2 << " channel(s) stored in format mode " << tStrHeader2.GetChannelFormat() );
172  if( tNAcquisitions2 != 1 || tNChannels2 != 3 || tNRecords2 != 2 )
173  {
174  LERROR( mlog, "Invalid number of acquisitions (1 expected), channels (3 expected), or records (2 expected)" );
175  return RETURN_ERROR;
176  }
177 
178  LINFO( mlog, "Skipping immediately to the second record (record 1)" );
179  if( ! ReadRecordCheck( tStream2, 1, tStrHeader2.GetDataFormat() ) )
180  {
181  LERROR( mlog, "Failed read record check" );
182  return RETURN_ERROR;
183  }
184 
185  LINFO( mlog, "Request record before the beginning of the file" );
186  if( tStream2->ReadRecord( -3 ) )
187  {
188  LERROR( mlog, "Record read did not fail" );
189  return RETURN_ERROR;
190  }
191 
192  LINFO( mlog, "Test 3 complete\n" );
193 
194 
195  LINFO( mlog, "Test 4: reading 2 sequential 1-channel floating-point records from stream 3");
196  LINFO( mlog, "\tRecord 0 has values '3.1415926535898'" );
197  LINFO( mlog, "\tRecord 1 has values '2.71828182846'" );
198 
199  const M3Stream* tStream3 = tReadTest->GetStream( 3 );
200  unsigned tNAcquisitions3 = tStream3->GetNAcquisitions();
201  unsigned tNRecords3 = tStream3->GetNRecordsInFile();
202  LINFO( mlog, "Stream 3 has " << tNAcquisitions3 << " acquisitions and " << tNRecords3 << " records" );
203  const M3StreamHeader& tStrHeader3 = tReadHeader->StreamHeaders().at( 3 );
204  unsigned tNChannels3 = tStrHeader3.GetNChannels();
205  //unsigned tRecSize3 = tStrHeader3.GetRecordSize();
206  LINFO( mlog, "Stream 3 has " << tNChannels3 << " channel(s) stored in format mode " << tStrHeader3.GetChannelFormat() );
207  if( tNAcquisitions3 != 2 || tNChannels3 != 1 || tNRecords3 != 2 )
208  {
209  LERROR( mlog, "Invalid number of acquisitions (2 expected), channels (1 expected), or records (2 expected)" );
210  return RETURN_ERROR;
211  }
212 
213  for( unsigned iRec = 0; iRec < tNRecords3; ++iRec )
214  {
215  LINFO( mlog, "Checking record " << iRec );
216  if( ! ReadRecordCheck( tStream3, 0, tStrHeader3.GetDataFormat() ) )
217  {
218  LERROR( mlog, "Failed read record check" );
219  return RETURN_ERROR;
220  }
221  }
222 
223  LINFO( mlog, "Test 4 complete\n" );
224 
225 /*
226  LINFO( mlog, "Test 5: reading 2 sequential 5-channel interleaved complex floating-point records from stream 4");
227  LINFO( mlog, "\tRecord 0 always has values '(0, 0)'" );
228  LINFO( mlog, "\tRecord 1 has values '(1.1, 1.001) and (-1.1, -1.001)'" );
229  LINFO( mlog, "\tRecord 2 has values '(2.2, 2.002) and (-2.2, -2.002)'" );
230  LINFO( mlog, "\tRecord 3 has values '(3.3, 3.003) and (-3.3, -3.003)'" );
231  LINFO( mlog, "\tRecord 4 has values '(4.4, 4.004) and (-4.4, -4.004)'" );
232 
233  const M3Stream* tStream4 = tReadTest->GetStream( 4 );
234  unsigned tNAcquisitions4 = tStream4->GetNAcquisitions();
235  unsigned tNRecords4 = tStream4->GetNRecordsInFile();
236  LINFO( mlog, "Stream 4 has " << tNAcquisitions4 << " acquisitions and " << tNRecords4 << " records" );
237  const M3StreamHeader& tStrHeader4 = tReadHeader->GetStreamHeaders().at( 3 );
238  unsigned tNChannels4 = tStrHeader4.GetNChannels();
239  //unsigned tRecSize4 = tStrHeader4.GetRecordSize();
240  LINFO( mlog, "Stream 4 has " << tNChannels4 << " channel(s) stored in format mode " << tStrHeader4.GetChannelFormat() );
241  if( tNAcquisitions4 != 1 || tNChannels4 != 5 || tNRecords4 != 2 )
242  {
243  LERROR( mlog, "Invalid number of acquisitions (1 expected), channels (5 expected), or records (2 expected)" );
244  return RETURN_ERROR;
245  }
246 
247  for( unsigned iRec = 0; iRec < tNRecords4; ++iRec )
248  {
249  LINFO( mlog, "Checking record " << iRec );
250  if( ! ReadRecordCheck( tStream4, 0, tStrHeader4.GetDataFormat() ) )
251  {
252  LERROR( mlog, "Failed read record check" );
253  return RETURN_ERROR;
254  }
255  }
256 
257  LINFO( mlog, "Test 5 complete\n" );
258 */
259 
260 
261 
262  tReadTest->FinishReading();
263  }
264  catch( M3Exception& e )
265  {
266  LERROR( mlog, "Exception thrown during file reading:\n" << e.what() );
267  return RETURN_ERROR;
268  }
269 
270  return RETURN_SUCCESS;
271 }
272 
273 bool ReadRecordCheck( const M3Stream* aStream, int aOffset, unsigned aDataFormat )
274 {
275  if( ! aStream->ReadRecord( aOffset ) )
276  {
277  LERROR( mlog, "Failed to read record" );
278  return false;
279  }
280 
281  switch( aDataFormat )
282  {
283  case sDigitizedUS:
284  if( ! PrintChannelsUInt( aStream ) )
285  {
286  LERROR( mlog, "Failed to print channels (digitized)" );
287  return false;
288  }
289  break;
290  case sDigitizedS:
291  if( ! PrintChannelsUInt( aStream ) )
292  {
293  LERROR( mlog, "Failed to print channels (digitized)" );
294  return false;
295  }
296  break;
297  case sAnalog:
298  switch( aStream->GetSampleSize() )
299  {
300  case 1:
301  if( ! PrintChannelsFloat( aStream ) )
302  {
303  LERROR( mlog, "Problem printing channels (float)" );
304  return 0;
305  }
306  break;
307  default:
308  if( ! PrintChannelsFloatComplex( aStream ) )
309  {
310  LERROR( mlog, "Problem printing channels (float-complex)" );
311  return 0;
312  }
313  break;
314  }
315  break;
316  default:
317  LERROR( mlog, "Invalid data format" );
318  return false;
319  }
320 
321  return true;
322 }
323 
324 bool PrintChannelsUInt( const M3Stream* aStream )
325 {
326  unsigned tRecSize = aStream->GetChannelRecordSize();
327  const unsigned tMaxSamples = 30;
328  for( unsigned iChan = 0; iChan < aStream->GetNChannels(); ++iChan )
329  {
330  const M3DataReader< uint64_t > tDataInterface( aStream->GetChannelRecord( iChan )->GetData(),
331  aStream->GetDataTypeSize(), sDigitizedUS );
332  stringstream tDataOut;
333  for( unsigned iSample = 0; iSample < std::min( tMaxSamples, tRecSize ); ++iSample )
334  {
335  tDataOut << tDataInterface.at( iSample );
336  if( iSample != tRecSize - 1 ) tDataOut << ", ";
337  }
338  if( tRecSize > tMaxSamples ) tDataOut << " . . .";
339  LINFO( mlog, "\tChannel " << iChan << ": " << tDataOut.str() );
340  }
341  return true;
342 }
343 
344 bool PrintChannelsInt( const M3Stream* aStream )
345 {
346  unsigned tRecSize = aStream->GetChannelRecordSize();
347  const unsigned tMaxSamples = 30;
348  for( unsigned iChan = 0; iChan < aStream->GetNChannels(); ++iChan )
349  {
350  const M3DataReader< int64_t > tDataInterface( aStream->GetChannelRecord( iChan )->GetData(),
351  aStream->GetDataTypeSize(), sDigitizedS );
352  stringstream tDataOut;
353  for( unsigned iSample = 0; iSample < std::min( tMaxSamples, tRecSize ); ++iSample )
354  {
355  tDataOut << tDataInterface.at( iSample );
356  if( iSample != tRecSize - 1 ) tDataOut << ", ";
357  }
358  if( tRecSize > tMaxSamples ) tDataOut << " . . .";
359  LINFO( mlog, "\tChannel " << iChan << ": " << tDataOut.str() );
360  }
361  return true;
362 }
363 
364 bool PrintChannelsFloat( const M3Stream* aStream )
365 {
366  unsigned tRecSize = aStream->GetChannelRecordSize();
367  const unsigned tMaxSamples = 30;
368  for( unsigned iChan = 0; iChan < aStream->GetNChannels(); ++iChan )
369  {
370  const M3DataReader< double > tDataInterface( aStream->GetChannelRecord( iChan )->GetData(),
371  aStream->GetDataTypeSize(), sAnalog );
372  stringstream tDataOut;
373  for( unsigned iSample = 0; iSample < std::min( tMaxSamples, tRecSize ); ++iSample )
374  {
375  tDataOut << tDataInterface.at( iSample );
376  if( iSample != tRecSize - 1 ) tDataOut << ", ";
377  }
378  if( tRecSize > tMaxSamples ) tDataOut << " . . .";
379  LINFO( mlog, "\tChannel " << iChan << ": " << tDataOut.str() );
380  }
381  return true;
382 }
383 
384 bool PrintChannelsFloatComplex( const M3Stream* aStream )
385 {
386  // NOTE: this implementation is specific to f4_complex and f8_complex, and therefore assumes only 2 elements in each sample
387  const unsigned tMaxSamples = 30;
388  unsigned tRecSize = aStream->GetChannelRecordSize();
389  switch( aStream->GetDataTypeSize() )
390  {
391  case 4:
392  for( unsigned iChan = 0; iChan < aStream->GetNChannels(); ++iChan )
393  {
394  const M3ComplexDataReader< f4_complex > tDataInterface( aStream->GetChannelRecord( iChan )->GetData(),
395  aStream->GetDataTypeSize(), sAnalog, aStream->GetSampleSize() );
396  stringstream tDataOut;
397  for( unsigned iSample = 0; iSample < std::min( tMaxSamples, tRecSize ); ++iSample )
398  {
399  tDataOut << "(" << tDataInterface.at( iSample )[ 0 ] << ", " << tDataInterface.at( iSample )[ 1 ] << ")";
400  if( iSample != tRecSize - 1 ) tDataOut << ", ";
401  }
402  if( tRecSize > tMaxSamples ) tDataOut << " . . .";
403  LINFO( mlog, "\tChannel " << iChan << ": " << tDataOut.str() );
404  }
405  break;
406  case 8:
407  for( unsigned iChan = 0; iChan < aStream->GetNChannels(); ++iChan )
408  {
409  const M3ComplexDataReader< f8_complex > tDataInterface( aStream->GetChannelRecord( iChan )->GetData(),
410  aStream->GetDataTypeSize(), sAnalog, aStream->GetSampleSize() );
411  stringstream tDataOut;
412  for( unsigned iSample = 0; iSample < std::min( tMaxSamples, tRecSize ); ++iSample )
413  {
414  tDataOut << "(" << tDataInterface.at( iSample )[ 0 ] << ", " << tDataInterface.at( iSample )[ 1 ] << ")";
415  if( iSample != tRecSize - 1 ) tDataOut << ", ";
416  }
417  if( tRecSize > tMaxSamples ) tDataOut << " . . .";
418  LINFO( mlog, "\tChannel " << iChan << ": " << tDataOut.str() );
419  }
420  break;
421  default:
422  LERROR( mlog, "Cannot print channels for complex floating-point data with type size " << aStream->GetDataTypeSize() );
423  return false;
424  break;
425  }
426  return true;
427 }
const ReturnType & at(unsigned index) const
unsigned GetNRecordsInFile() const
Definition: M3Stream.hh:134
static const Monarch3 * OpenForReading(const std::string &filename)
Definition: M3Monarch.cc:56
static const uint32_t sDigitizedUS
Definition: M3Constants.hh:38
unsigned GetSampleSize() const
Definition: M3Stream.hh:119
unsigned GetChannelRecordSize() const
Definition: M3Stream.hh:123
unsigned GetNChannels() const
Definition: M3Stream.hh:124
virtual const char * what() const
Definition: M3Exception.cc:34
int main(const int argc, const char **argv)
Definition: M3ReadTest.cc:26
Egg file header information.
Definition: M3Header.hh:152
ReturnType at(unsigned index) const
bool PrintChannelsUInt(const M3Stream *aStream)
Definition: M3ReadTest.cc:324
bool PrintChannelsFloatComplex(const M3Stream *aStream)
Definition: M3ReadTest.cc:384
bool ReadRecord(int anOffset=0, bool aIfNewAcqStartAtFirstRec=true) const
Read the next record from the file.
Definition: M3Stream.cc:313
unsigned GetNAcquisitions() const
Definition: M3Stream.hh:125
static const uint32_t sDigitizedS
Definition: M3Constants.hh:39
Read/write access for a data stream.
Definition: M3Stream.hh:41
bool PrintChannelsInt(const M3Stream *aStream)
Definition: M3ReadTest.cc:344
const byte_type * GetData() const
Definition: M3Record.hh:111
Specialized exception class for Monarch3.
Definition: M3Exception.hh:28
Single-stream header information.
Definition: M3Header.hh:33
static scarab::logger mlog("M3Header")
const M3Record * GetChannelRecord(unsigned aChannel) const
Get the pointer to a particular channel record.
Definition: M3Stream.cc:304
bool ReadRecordCheck(const M3Stream *aStream, int aOffset, unsigned aDataFormat)
Definition: M3ReadTest.cc:273
Interface class for complex data types.
Interface class for a variety of data types.
static const uint32_t sAnalog
Definition: M3Constants.hh:40
bool PrintChannelsFloat(const M3Stream *aStream)
Definition: M3ReadTest.cc:364
unsigned GetDataTypeSize() const
Definition: M3Stream.hh:118