DATRW++ library: seismic data I/O with multiple formats

◆ read()

void datrw::mseed::MiniSEEDRecord::read ( std::istream &  is)

read a full MiniSEED record including data samples

Big effort of decoding a MiniSEED record.

Read all blocks belonging to one record in sequence. Extract all frames in all blocks in sequence (within the outer loop of reading blocks). Reading stops, if all blocks of the record are read or all frames (as indicated in the header of the record) are extracted are all expected samples are extracted. Extraction of samples stops when all samples (as indicated by the record header) are extracted.

It may appear in normal operation that the capacity of a data record is not completely used to store samples.

Definition at line 78 of file mseedread_mseedrecord_read.cc.

References datrw::mseed::MiniSEEDblock::block(), datrw::mseed::SEED::SteimFrame::blocksize, datrw::mseed::SEED::DataOnlySEEDBlockette::bytesex, datrw::mseed::MiniSEEDblock::bytesize(), datrw::mseed::SEED::SteimFrame::ctrl(), datrw::mseed::key::data, datrw::mseed::ConsistencyChecks::data, DATRW_abort, DATRW_assert, DATRW_nonfatal_assert, DATRW_value, DATRW_warning, datrw::mseed::SEED::FixedDataRecordHeader::dbeg, datrw::mseed::SEED::SteimFrame::diff(), datrw::mseed::ConsistencyCheckControl::docheck, datrw::mseed::ConsistencyCheckControl::fatal, datrw::mseed::SEED::SteimFrame::Fspecial, datrw::mseed::SEED::DataExtensionBlockette::ifcount(), datrw::mseed::SEED::DataOnlySEEDBlockette::iformat(), datrw::mseed::Debug::inconsistencies_are_not_fatal, datrw::mseed::SEED::DataExtensionBlockette::iusec(), Mblockette1000, Mblockette1001, Mchecks, Mdata, Mdebug, MestimateNframes, Mhasblockette1001, Mrecordheader, Mvalid, Mxm1, datrw::mseed::needswap(), datrw::mseed::SEED::SteimFrame::next(), datrw::mseed::key::nframes, datrw::mseed::ConsistencyChecks::nframes, datrw::mseed::key::nonfatal, datrw::mseed::SEED::FixedDataRecordHeader::nsamp, datrw::mseed::key::nsamples, datrw::mseed::ConsistencyChecks::nsamples, nsamples(), readheader(), datrw::mseed::SEED::DataOnlySEEDBlockette::reclenbytes(), datrw::mseed::key::skipcheck, datrw::mseed::SEED::steim1, datrw::mseed::SEED::steim2, datrw::mseed::ConsistencyChecks::usec, and datrw::mseed::SEED::SteimFrame::valid().

Referenced by datrw::mseed::operator>>().

79  {
80  // create block to read MiniSEED
81  MiniSEEDblock block=this->readheader(is);
82  // count blocks
83  int iblock=0;
84  // count frames
85  int iframe=0;
86 
87  if (Mvalid)
88  {
89  // data header is present
90  ++iblock;
91 
92  // For SEED data (not header fields) the byte order my differ from
93  // file to file. Use the byte order defined in the Data Only SEED
94  // Blockette.
95  bool doswap=needswap(Mblockette1000.bytesex);
96 
97  // extract essential header data
98  // -----------------------------
99  //
100  // number of samples to extract
102  // beginning of first frame
103  int pdata=Mrecordheader.dbeg;
104  // size of record in bytes
105  int reclen=Mblockette1000.reclenbytes();
106  // number of blocks to read for full record
107  int nblocks=reclen/block.bytesize();
108  // number of frames to be expected
109  int nframes=(reclen-pdata)/SEED::SteimFrame::blocksize;
110  // is number of frames read from file?
111  bool filetellsnframes=false;
113  {
114  filetellsnframes=true;
116  if (nframes < 1)
117  {
118  DATRW_warning("MiniSEEDRecord::read",
119  "unreasonable number of frames ("
120  << nframes <<
121  ") given in blockette1001\n"
122  << " consider to use format modifier \"estimateNframes\"");
123  }
124  }
125  // check Steim 1 encoding
128  "ERROR (reading MiniSEED record): "
129  "Can only decode Steim (1) or Steim (2) compression");
130  // check size of sample buffer
131  if (int(Mdata.size())<nsamples)
132  { Mdata=Tseries(nsamples); }
133  int isample=0;
134  // x0, xn, d1
135  int x0, xn, d1, sum;
136  // x0 and xn are not read yet
137  bool waitingforxn=true;
138 
139  // extract samples
140  // ---------------
141  // loop over blocks in record
142  while ((iblock <= nblocks) &&
143  (isample < nsamples) &&
144  ((iframe < nframes) || (!filetellsnframes)))
145  {
146  // extract
147  // (loop over frames in block)
148  while (pdata < int(block.bytesize()) &&
149  (isample < nsamples) &&
150  ((iframe < nframes) || (!filetellsnframes)))
151  {
152  SEED::SteimFrame* pframe;
153  switch (Mblockette1000.iformat())
154  {
155  case SEED::steim1:
156  pframe= new SEED::Steim1Frame(block.block(pdata), doswap);
157  break;
158  case SEED::steim2:
159  pframe= new SEED::Steim2Frame(block.block(pdata), doswap);
160  break;
161  default:
162  DATRW_abort("ERROR (reading MiniSEED record): "
163  "compression format not supported");
164  }
165  ++iframe;
166  SEED::SteimFrame& rframe(*pframe);
167 
168  if (waitingforxn) {
169  DATRW_assert((rframe.ctrl()==SEED::SteimFrame::Fspecial),
170  "ERROR (reading MiniSEED record): "
171  "missing X0");
172  x0=rframe.diff();
173  rframe.next();
174  DATRW_assert((rframe.ctrl()==SEED::SteimFrame::Fspecial),
175  "ERROR (reading MiniSEED record): "
176  "missing XN");
177  xn=rframe.diff();
178  rframe.next();
179  d1=rframe.diff();
180  rframe.next();
181  waitingforxn=false;
182  Mdata(isample)=x0;
183  ++isample;
184  sum=x0;
185  /*
186  * Calculate value of last sample of previous record in order to
187  * provide means for a continuous stream of sample values.
188  */
189  Mxm1=x0-d1;
190  }
191  while (rframe.valid() && (isample < nsamples))
192  {
193  if (rframe.ctrl() != SEED::SteimFrame::Fspecial)
194  {
195  sum += rframe.diff();
196  Mdata(isample)=sum;
197  ++isample;
198  }
199  rframe.next();
200  }
202  delete pframe;
203  } // while (pdata < int(block.bytesize()))
204 
205  // read next block
206  if (iblock < nblocks)
207  {
208  is >> block;
209  if (is.bad())
210  {
211  DATRW_warning("MiniSEEDRecord::read",
212  "input stream is bad!");
213  }
214  pdata=0;
215  ++iblock;
216  }
217  } // while ((iblock <= nblocks) &&
218  // (isample < nsamples) &&
219  // ((iframe < nframes) || (!filetellsnframes)))
220  // skip rest of blocks in record
221  while (iblock < nblocks)
222  {
223  // read next block
224  is >> block;
225  if (is.bad())
226  {
227  DATRW_warning("MiniSEEDRecord::read",
228  "input stream is bad!");
229  }
230  ++iblock;
231  }
232 
233  /* consistency checks
234  * ==================
235  * Check for data integrity, consistency, plausibility,...
236  */
237 
238  /* string constant containing hint to format modifiers
239  * (this is a very local constant, defined here becausing being used
240  * three times)
241  */
242  const std::string CHintToFormatModifiers(
243  "consider to use format modifiers \""
244  + std::string(key::nonfatal) + "\" or \""
245  + std::string(key::skipcheck) + "\"\n"
246  "if you like to ignore this inconsistency");
247 
248  /* Check for usec field being in specified range
249  * ---------------------------------------------
250  *
251  * On page 124 of "SEED Reference Manual, Standard for the Exchange of
252  * Earthquake Data, SEED Format Version 2.4, August, 2012" with
253  * respect to [1001] Data Extension Blockette (8 bytes):
254  *
255  * > field 4: BYTE: µsec has the data start time down to the
256  * > microsecond. The SEED format handles down to 100µsecs. This
257  * > field is an offset from that value. The recommended value is
258  * > from -50 to +49µsecs. At the users option, this value may be
259  * > from 0 to +99µsecs.
260  */
262  {
264  || (!Mchecks.usec.fatal),
265  (Mblockette1001.iusec()>=-50)
266  && (Mblockette1001.iusec()<=99),
267  "usec-value in MiniSEED record is out of specified range\n"
268  "consistency check \"" << key::nsamples << "\" complains:\n"
269  "usec-value in [1001] Data Extension Blockette: "
270  << DATRW_value(Mblockette1001.iusec()) << "\n"
271  "specified range SEED Reference Manual, "
272  "Version 2.4, August, 2012 (page 124):\n"
273  "The recommended value is from -50 to +49 usecs.\n"
274  "At the users option, this value may be from 0 to +99 usecs.\n"
275  << CHintToFormatModifiers);
276  }
277 
278  /* Check for consistent number of samples.
279  * ---------------------------------------
280  *
281  * Number of samples to be expected is provided in the header in
282  * the fixed section data header. This value will be compared against
283  * the number of samples actually provided in the logical record.
284  */
286  {
288  || (!Mchecks.nsamples.fatal),
289  (isample==nsamples),
290  "number of samples in MiniSEED record is inconsistent\n"
291  "consistency check \"" << key::nsamples << "\" complains:\n"
292  "number of samples announced in header: "
293  << DATRW_value(nsamples) << "\n"
294  "number of samples actually used: "
295  << DATRW_value(isample) << "\n"
296  << CHintToFormatModifiers);
297  }
298 
299  /* Check for consistent data values.
300  * ---------------------------------
301  *
302  * Page 142 of "SEED Reference Manual, Standard for the Exchange of
303  * Earthquake Data, SEED Format Version 2.4, August, 2012":
304  *
305  * > The reverse integrating constant also provides for a quick data
306  * > integrity check when compared with the last computed
307  * > sample. A discrepancy indicates that the contents of the data are
308  * > garbled.
309  *
310  * The sample value of the last sample in the record is compared against
311  * the value of the reverse integration constant as provided in the
312  * first data frame of the record.
313  */
314  if (Mchecks.data.docheck)
315  {
317  || (!Mchecks.data.fatal),
318  (Mdata(isample-1)==xn),
319  "data in MiniSEED record are inconsistent\n"
320  "consistency check \"" << key::data << "\" complains:\n"
321  "expected value of last sample "
322  "(i.e. reverse integration constant): "
323  << DATRW_value(xn) << "\n"
324  "value of last sample ("
325  << DATRW_value(isample) << ") actually read: "
326  << DATRW_value(Mdata(isample-1)) << "\n"
327  << CHintToFormatModifiers);
328  }
329 
330  /* Check for consistent number of frames.
331  * --------------------------------------
332  *
333  * Number of frames to be expected is provided in the header in
334  * Blockette 1001. This value will be compared against the number of
335  * frames actually used to store data.
336  *
337  * Skip this test if data file does not specify number of frames. If
338  * data records are not completely filled with samples, there is no
339  * reason, why we should have guessed the correct number of frames.
340  */
341  if (filetellsnframes && Mchecks.nframes.docheck)
342  {
344  || (!Mchecks.nframes.fatal),
345  (iframe==nframes),
346  "number of frames in MiniSEED record is inconsistent\n"
347  "consistency check \"" << key::nframes << "\" complains:\n"
348  "number of frames announced in header: "
349  << DATRW_value(nframes) << "\n"
350  "number of frames actually used: "
351  << DATRW_value(iframe) << "\n"
352  << CHintToFormatModifiers);
353  }
354 
355  // finished successfully
356  if (is.good()) { Mvalid=true; }
357  }
358  } // void MiniSEEDRecord::read(std::istream& is)
ConsistencyChecks Mchecks
flags controlling consistency checks
Definition: mseedread.h:235
bool fatal
Consequences of check.
Definition: mseed.h:77
#define DATRW_assert(C, M)
Check an assertion and report by throwing an exception.
Definition: error.h:92
ConsistencyCheckControl nsamples
Check for consistent number of samples.
Definition: mseed.h:106
MiniSEEDblock readheader(std::istream &is)
read header and return block
static const int blocksize
size of frame in bytes
Definition: seedstructs.h:465
ConsistencyCheckControl data
Check for consistent data values.
Definition: mseed.h:121
Steim (1) compression.
Definition: seedstructs.h:102
SEED::DataExtensionBlockette Mblockette1001
Data Extension Blockette.
Definition: mseedread.h:241
unsigned short int dbeg
beginning of data
Definition: seedstructs.h:320
const char *const nframes
keywords for consistency checks
unsigned short int nsamp
number of samples
Definition: seedstructs.h:311
bool Mhasblockette1001
Data Extension Blockette is present.
Definition: mseedread.h:231
int Mxm1
Expected value of last sample in previous block.
Definition: mseedread.h:243
bool MestimateNframes
estimate number of frames
Definition: mseedread.h:233
ConsistencyCheckControl usec
Check for usec field being in specified range.
Definition: mseed.h:134
const char *const data
keywords for consistency checks
bool needswap(const unsigned char &bytesex)
check bytesex
Definition: mseedread.cc:192
aff::Series< Tvalue > Tseries
type of container for sample data
Definition: mseedread.h:159
#define DATRW_warning(N, M)
Report a warning.
Definition: error.h:148
bool docheck
Activation of check.
Definition: mseed.h:72
Steim (2) compression.
Definition: seedstructs.h:103
const char *const skipcheck
keywords for format modifiers
#define DATRW_abort(M)
Abort and give a message.
Definition: error.h:101
contains non-data information, like headers
Definition: seedstructs.h:469
bool inconsistencies_are_not_fatal
make inconsistencies non fatal
Definition: mseedread.h:134
SEED::FixedDataRecordHeader Mrecordheader
Fixed Data Record Header.
Definition: mseedread.h:237
#define DATRW_nonfatal_assert(F, C, M)
Macro to distinguish between fatal and non fatal assertions.
Definition: error.h:138
Tseries Mdata
Container for sample data.
Definition: mseedread.h:245
unsigned int nsamples() const
number of samples
Definition: mseedread.h:197
const char *const nsamples
number of samples per minute block and channel
SEED::DataOnlySEEDBlockette Mblockette1000
Data Only SEED Blockette.
Definition: mseedread.h:239
#define DATRW_value(V)
report value
Definition: debug.h:65
Debug Mdebug
debug options
Definition: mseedread.h:225
bool Mvalid
contains valid data
Definition: mseedread.h:227
ConsistencyCheckControl nframes
Check for consistent number of frames.
Definition: mseed.h:98
unsigned char bytesex
Word order.
Definition: seedstructs.h:356
const char *const nonfatal
keywords for format modifiers
Here is the call graph for this function:
Here is the caller graph for this function: