UltraScan III
us_mwl_data.cpp
Go to the documentation of this file.
1 
3 #include <QtGui>
4 #include "us_mwl_data.h"
5 #include "us_util.h"
6 #include "us_settings.h"
7 #include "us_math2.h"
8 #include "us_memory.h"
9 
10 // Hold data read in and selected from a raw MWL data directory
12 {
13  clear(); // Clear internal vectors
14 
16 DbgLv(0) << "MwDa: dbg_level" << dbg_level;
17 }
18 
19 // Import MWL data from a selected local directory
20 bool US_MwlData::import_data( QString& mwldir, QLineEdit* lestat )
21 {
22  bool status = true;
23  int nlmb_dup = 0;
24  cur_dir = mwldir;
25  le_status = lestat;
26  evers = 0.0;
27  is_absorb = false;
28 DbgLv(1) << "MwDa: cur_dir" << cur_dir;
29 
30  QDir ddir( cur_dir, "*", QDir::Name, QDir::Files | QDir::Readable );
31  ddir.makeAbsolute();
32  if ( cur_dir.right( 1 ) != "/" ) cur_dir += "/";
33 
34  read_runxml( ddir, cur_dir );
35 DbgLv(1) << "MwDa: evers" << evers << "is_absorb" << is_absorb;
36 
37  int kcelchn = cellchans.count();
38 
39  if ( kcelchn == 0 )
40  {
41  QMessageBox::critical( 0,
42  tr( "No mwrs XML File Found" ),
43  tr( "No proper mwrs XML file was found in directory \"%1\".\n"
44  "No import of MWRS data is possible without"
45  " such a file." ).arg( cur_dir ) );
46  return false;
47  }
48 
49  cellchans.clear();
50  QString old_runID = runID;
51 
52  runID.replace( QRegExp( "![A-Za-z0-9_-]" ), "_" );
53 
54  if ( runID != old_runID )
55  {
56  QMessageBox::warning( 0,
57  tr( "RunID Name Changed" ),
58  tr( "The runID name has been changed. It may consist only\n"
59  "of alphanumeric characters, underscore, or hyphen.\n"
60  " New runID: " ) + runID );
61  }
62 
63  // Read in the data
64  QStringList mwrfs = ddir.entryList( QStringList( "*.mwrs" ),
65  QDir::Files, QDir::Name );
66  QStringList chans;
67  QVector< int > ccscans;
68  cells .clear();
69  cellchans.clear();
70  nscan = -1;
71  int scnmin = 99999;
72  mwrfs.sort();
73  nfile = mwrfs.size();
74  ccscans.fill( 0, nfile );
75  le_status->setText( QString( "%1 files from %2 ..." )
76  .arg( nfile ).arg( runID ) );
77  qApp->processEvents();
78 DbgLv(1) << "MwDa: nfile" << nfile;
79 
80  for ( int ii = 0; ii < nfile; ii++ )
81  {
82  QString fname = mwrfs.at( ii );
83  QString fpath = cur_dir + fname;
84  QString acell = fname.section( ".", -5, -5 );
85  QString chann = fname.section( ".", -4, -4 );
86  QString adesc = fname.section( ".", -3, -3 );
87  QString ascan = fname.section( ".", -2, -2 );
88 
89  if ( !cells.contains( acell ) ) cells << acell;
90  if ( !chans.contains( chann ) ) chans << chann;
91 
92  int scann = ascan.toInt();
93  nscan = qMax( nscan, scann );
94  scnmin = qMin( scnmin, scann );
95 
96  fnames << fname;
97  fpaths << fpath;
98 
99  QString celchn = acell + "." + chann;
100 
101  int ccx = cellchans.indexOf( celchn );
102  if ( ccx < 0 )
103  {
104  ccx = cellchans.size();
105  cellchans << celchn;
106  }
107 
108  ccscans[ ccx ] = qMax( ccscans[ ccx ], scann );
109  }
110 
111  nscan = ( nscan - scnmin ) + 1;
112  ncell = cells.size();
113  nchan = chans.size();
114 DbgLv(1) << "MwDa: nscan ncell nchan" << nscan << ncell << nchan;
115  ncelchn = ncell * nchan;
116  if ( ncelchn != kcelchn )
117  {
118  qDebug() << "kcelchn ncelchn" << kcelchn << ncelchn;
119  }
120  cells .sort();
121  chans .sort();
122 
123  if ( ( ncelchn * nscan ) != nfile )
124  {
125  qDebug() << "*** nfile" << nfile << "ncelchn*nscn" << ncelchn*nscan;
126  int scn_lo = ccscans[ 0 ];
127  int scn_hi = scn_lo;
128 
129  for ( int ii = 1; ii < cellchans.size(); ii++ )
130  {
131  scn_lo = qMin( scn_lo, ccscans[ ii ] );
132  scn_hi = qMax( scn_hi, ccscans[ ii ] );
133  }
134 
135  scn_lo = ( scn_lo - scnmin ) + 1;
136  scn_hi = ( scn_hi - scnmin ) + 1;
137 
138  if ( scn_lo != scn_hi )
139  {
140  QApplication::restoreOverrideCursor();
141  QApplication::restoreOverrideCursor();
142 
143  int response = QMessageBox::warning( 0,
144  tr( "Varying Number of Scans" ),
145  tr( "The number of scans in each cell varies"
146  " from %1 to %2.<br/><br/>Select <b>[ Cancel ]</b>"
147  " to abort the import<br/>or <b>[ OK ]</b> to"
148  " process only the first %3 scans of each cell." )
149  .arg( scn_lo ).arg( scn_hi ).arg( scn_lo ),
150  QMessageBox::Cancel|QMessageBox::Ok, QMessageBox::Ok );
151 
152  if ( response == QMessageBox::Cancel )
153  return false;
154 
155  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
156  }
157  nscan = scn_lo;
158  }
159 
160  cellchans.clear();
161  le_status->setText( QString( "%1 cells and %2 channels ..." )
162  .arg( ncell ).arg( nchan ) );
163  qApp->processEvents();
164 
165  for ( int ii = 0; ii < ncell; ii++ )
166  {
167  for ( int jj = 0; jj < nchan; jj++ )
168  {
169  QString celchn = cells[ ii ] + " / " + chans[ jj ];
170  cellchans << celchn;
171  }
172  }
173 
174  // Read in all the headers
175  for ( int ii = 0; ii < nfile; ii++ )
176  {
177  QString fname = fnames[ ii ];
178  QString fpath = fpaths[ ii ];
179  QString acell = fname.section( ".", -5, -5 );
180  QString chann = fname.section( ".", -4, -4 );
181  QString ascan = fname.section( ".", -2, -2 );
182  int scann = ascan.toInt() - scnmin + 1;
183  QString celchn = acell + " / " + chann;
184 
185  if ( scann > nscan ) continue;
186 
187  QFile fi( fpath );
188  if ( ! fi.open( QIODevice::ReadOnly ) )
189  {
190  qDebug() << "*ERROR* Unable to open" << fname;
191  qDebug() << fpath;
192  status = false;
193  break;
194  }
195 
196  QDataStream ds( &fi );
197  DataHdr hd;
198 
199  read_header( ds, hd );
200 
201  headers << hd;
202 
203  if ( ii == 0 )
204  { // At the first file, read in the wavelengths
205  nlamb_i = hd.nlambda;
206  ntrip_i = nlamb_i * ncelchn;
207  nlambda = nlamb_i;
208  ntriple = ntrip_i;
209  npoint = hd.npoint;
210  npointt = npoint * nscan;
211  slambda = 0;
212 DbgLv(1) << "MwDa: npoint nlambda" << npoint << nlambda;
213 
215 
216  // Test for duplicate wavelengths
217  for ( int jj = 1; jj < nlamb_i; jj++ )
218  {
219  if ( ri_wavelns[ jj ] == ri_wavelns[ jj - 1 ] )
220  { // Mark dup with zero value for now; and bump dupl. count
221  ri_wavelns[ jj - 1 ] = 0;
222  nlmb_dup++;
223 DbgLv(1) << "MwDa: jj" << jj << "ndup lmb" << nlmb_dup << ri_wavelns[jj];
224  }
225  else if ( slambda == 0 )
226  { // Save start non-duplicate lambda
227  slambda = ri_wavelns[ jj - 1 ];
228  }
229  }
230 DbgLv(1) << "MwDa: read_lambdas COMPLETE";
231  slambda = ( slambda == 0 ) ? ri_wavelns[ 0 ] : slambda;
232  elambda = ri_wavelns[ nlamb_i - 1 ];
233  nlambda = nlamb_i - nlmb_dup;
234  ntriple = nlambda * ncelchn;
235 int ww=nlamb_i-1;
236 DbgLv(1) << "MwDa: w0 w1 w3 wi wj wk" << ri_wavelns[0] << ri_wavelns[1]
237  << ri_wavelns[2] << ri_wavelns[ww-2] << ri_wavelns[ww-1] << ri_wavelns[ww];
238  if ( nlmb_dup == 0 )
239  {
240  le_status->setText( tr( "%1 wavelengths ..." )
241  .arg( nlamb_i ) );
242  }
243  else
244  {
245  le_status->setText( tr( "%1 wavelengths ..."
246  " (%2 duplicate(s) removed)" )
247  .arg( nlambda ).arg( nlmb_dup ) );
248  }
249  qApp->processEvents();
250 
251  // And initialize the data vector
252  QVector< double > wave_reads( npointt, 0.0 );
253  ri_readings.clear ();
254  ri_readings.reserve( ntriple );
255 
256  for ( int tx = 0; tx < ntriple; tx++ )
257  {
258  ri_readings << wave_reads;
259  }
260 DbgLv(1) << "MwDa: ri_readings CREATED size" << ri_readings.size();
261  }
262  else
263  { // Otherwise, skip past wavelengths
264  ds.skipRawData( nlamb_i * 2 );
265  }
266 
267  int ccx = cellchans.indexOf( celchn );
268 DbgLv(1) << "MwDa: cell chann celchn ccx" << acell << chann << celchn << ccx;
269 DbgLv(1) << "MwDa: celchn size cc0 ccn" << cellchans.size()
270  << cellchans[0] << cellchans[cellchans.size()-1];
271  ccscans[ ccx ] = ccscans[ ccx ] + 1;
272  int tripx = ccx * nlambda;
273  int scnx = ( fname.section( ".", -2, -2 ).toInt() - scnmin ) * npoint;
274 DbgLv(1) << "MwDa: PREPARE rdata ccx tripx scnx" << ccx << tripx << scnx;
275 DbgLv(1) << "MwDa: PREPARE icell ichan nchan" << hd.icell << hd.ichan
276  << nchan << "channel" << hd.channel;
277 
278  // Read in the radius point data
279  for ( int wavx = 0; wavx < nlamb_i; wavx++ )
280  {
281  if ( ri_wavelns[ wavx ] > 0 )
282  read_rdata( ds, ri_readings[ tripx++ ], scnx, npoint );
283  else
284  ds.skipRawData( npoint * 4 );
285  }
286 
287  le_status->setText( QString( "Data in for triple %1, scan %2 ..." )
288  .arg( tripx + 1 ).arg( scnx + 1 ) );
289  qApp->processEvents();
290 //DbgLv(1) << "MwDa: read_data COMPLETE";
291  } // END: header read loop
292 
293 DbgLv(1) << "MwDa: wv0 wvm wvn" << ri_wavelns[0]
294  << ri_wavelns[nlamb_i/2] << ri_wavelns[nlamb_i-1];
295 #if 0
296 DbgLv(1) << "MwDa: da20,40" << ri_readings[20][40] << "m+40 n-40"
297  << ri_readings[20][npointt/2+40] << ri_readings[20][npointt-41];
298 #endif
299  if ( nlmb_dup == 0 )
300  {
301  le_status->setText( tr( "Initial MWL import from %1 files is complete." )
302  .arg( nfile ) );
303  }
304  else
305  {
306  le_status->setText( tr( "Initial MWL import from %1 files is complete."
307  " (%2 duplicate(s) encountered!)" )
308  .arg( nfile ).arg( nlmb_dup ) );
309  int kk = 0;
310 
311  for ( int ii = 0; ii < nlamb_i; ii++ )
312  {
313  if ( ri_wavelns[ ii ] > 0 )
314  ri_wavelns[ kk++ ] = ri_wavelns[ ii ];
315  }
316 
317  ri_wavelns.resize( nlambda );
318  nlamb_i = nlambda;
319  ntrip_i = ntriple;
320  status = false;
321  }
322  qApp->processEvents();
323 
324  // Initialize the wavelengths lists for all channels
325  ex_wavelns.clear();
326 
327  for ( int cc = 0; cc < ncelchn; cc++ )
328  {
330  }
331 
332 DbgLv(1) << "MwDa: status" << status << " stat_text" << le_status->text();
333  return status;
334 }
335 
336 // Load internal values from a vector of loaded rawDatas
337 void US_MwlData::load_mwl( QVector< US_DataIO::RawData >& allData )
338 {
339  QStringList chans;
340  nfile = allData.size();
341  ntriple = nfile;
342  ntrip_i = nfile;
343  ntriple = ntrip_i;
344  nscan = allData[ 0 ].scanCount();
345  npoint = allData[ 0 ].pointCount();
346  npointt = npoint * nscan;
347 DbgLv(1) << "MwDa:LdMw: nfile" << nfile << "nscan npoint" << nscan << npoint;
348 
349  ri_readings.clear();
350  ri_wavelns .clear();
351  ex_wavelns .clear();
352  cells .clear();
353  cellchans .clear();
354  ccdescs .clear();
355  triples .clear();
356 #if 0
357  QString cech_p = "";
358  int iwvl_p = 0;
359 #endif
360 
361  for ( int trx = 0; trx < nfile; trx++ )
362  {
363  US_DataIO::RawData* edata = &allData[ trx ];
364 
365  int icell = edata->cell;
366  QString cell = QString::number( icell );
367  QString chan = QString( edata->channel );
368  QString celchn = cell + " / " + chan;
369  int iwvl = qRound( edata->scanData[ 0 ].wavelength );
370 #if 0
371  int kwvl = iwvl;
372 
373  if ( iwvl < 300 && iwvl_p > 655 && celchn == cech_p )
374  { // Handle wavelength wrap-around for values > 835
375  iwvl += 655;
376 DbgLv(1) << "MwDa:L trx" << trx << "kwvl iwvl_p iwvl cech cech_p"
377  << kwvl << iwvl_p << iwvl << celchn << cech_p;
378  double wvlen = (double)iwvl;
379 
380  for ( int jj = 0; jj < edata->scanCount(); jj++ )
381  {
382  edata->scanData[ jj ].wavelength = wvlen;
383  }
384  }
385 
386  cech_p = celchn;
387  iwvl_p = iwvl;
388 #endif
389  QString wavl = QString::number( iwvl );
390  QString triple = celchn + " / " + wavl;
391 
392  if ( ! cells.contains( cell ) )
393  cells << cell;
394 
395  if ( ! chans.contains( chan ) )
396  chans << chan;
397 
398  if ( ! cellchans.contains( celchn ) )
399  {
400  cellchans << celchn;
401  ccdescs << edata->description;
402  }
403 
404  if ( ! triples.contains( triple ) )
405  triples << triple;
406 
407  if ( ! ri_wavelns.contains( iwvl ) )
408  {
409  ri_wavelns << iwvl;
410  }
411 else if ( chans.size() < 2 )
412 {
413 int wx=ri_wavelns.indexOf(iwvl);
414 QString tripd=triples[wx];
415 DbgLv(1) << "MwDa:L trx" << trx << "duplicate iwvl" << iwvl << triple
416  << "dup wx" << wx << "trip[wx]" << tripd;
417 }
418 
419  for ( int ss = 0; ss < nscan; ss++ )
420  {
421  ri_readings << edata->scanData[ ss ].rvalues;
422  }
423  }
424 
425  ncell = cells.size();
426  nchan = chans.size();
427  ncelchn = cellchans.size();
428  nlamb_i = ri_wavelns.size();;
429  nlambda = nlamb_i;
430  slambda = ri_wavelns[ 0 ];
431 DbgLv(1) << "MwDa:LdMw: ncell nchan nlambda" << ncell << nchan << nlambda;
432 DbgLv(1) << "MwDa:LdMw: ncelchn ntriple" << ncelchn << ntriple;
433 int klam=ntriple/ncelchn;
434 if(nlambda>(klam+2))
435  DbgLv(1) << "MwDa:LdMw: wl k.."
436  << ri_wavelns[klam-2]
437  << ri_wavelns[klam-1]
438  << ri_wavelns[klam ]
439  << ri_wavelns[klam+1]
440  << ri_wavelns[klam+2];
441 
442  if ( ( nlambda * ncelchn ) == ntriple )
443  { // If all cells have same wavelengths, just duplicate list
444 DbgLv(1) << "MwDa:LdMw: All Cells Same #Wavelengths";
445 DbgLv(1) << "MwDa:LdMw: ri_wavelns size" << ri_wavelns.size();
446  for ( int ccx = 0; ccx < ncelchn; ccx++ )
447  {
449  }
450  }
451 
452  else
453  { // If wavelength lists vary, we must build them carefully
454  QVector< int > wvs;
455 DbgLv(1) << "MwDa:LdMw: All Cells NOT Same #Wavelengths";
456 
457  for ( int ccx = 0; ccx < ncelchn; ccx++ )
458  { // First fill with empty vectors
459  ex_wavelns << wvs;
460  }
461 
462  for ( int trx = 0; trx < ntriple; trx++ )
463  { // Fill each cells list with only the wavelengths it has
464  QString triple = triples[ trx ];
465  QString celchn = triple.section( " / ", 0, 1 );
466  int iwvl = triple.section( " / ", 2, 2 ).toInt();
467  int ccx = cellchans.indexOf( celchn );
468 //DbgLv(1) << "MwDa:LdMw: trx" << trx << "ccx" << ccx << "celchn" << celchn;
469 
470  if ( ccx < 0 )
471  {
472  qDebug() << "load_mwl:*ERROR* unexpected missing cell" << celchn;
473  continue;
474  }
475 
476  ex_wavelns[ ccx ] << iwvl;
477  }
478  }
479 DbgLv(1) << "MwDa:LdMw: wlns size" << ex_wavelns.size();
480 }
481 
482 // Return a readings values vector for a given triple, scan
483 int US_MwlData::rvalues( int& tripx, int& scanx, QVector< double >& rvs )
484 {
485  int jj = scanx * npoint;
486  rvs.clear();
487  rvs.reserve( npoint );
488 
489  for ( int ii = 0; ii < npoint; ii++ )
490  {
491  rvs << ri_readings[ tripx ][ jj++ ];
492  }
493 
494  return jj;
495 }
496 
497 // Return the lambdas vector for the data
498 int US_MwlData::lambdas( QVector< int >& wls, int ccx )
499 {
500  set_celchnx( ccx );
501  nlambda = ex_wavelns[ curccx ].count();
502 
503  wls.clear();
504  wls.reserve( nlambda );
505 
506  for ( int ii = 0; ii < nlambda; ii++ )
507  {
508  wls << ex_wavelns[ curccx ][ ii ];
509  }
510 
511  return nlambda;
512 }
513 
514 // Return the input raw lambdas vector for the data
515 int US_MwlData::lambdas_raw( QVector< int >& wls )
516 {
517  wls.clear();
518  wls.reserve( nlamb_i );
519 
520  for ( int ii = 0; ii < nlamb_i; ii++ )
521  {
522  wls << ri_wavelns[ ii ];
523  }
524 
525  return nlamb_i;
526 }
527 
528 // Private slot to clear arrays
530 {
531  ri_readings.clear(); // Raw input readings
532  ri_wavelns .clear(); // Raw input wavelengths
533  ex_wavelns .clear(); // Export wavelengths
534  headers .clear(); // MWL file headers
535 
536  fpaths .clear();
537  fnames .clear();
538  cells .clear();
539  cellchans .clear();
540  ccdescs .clear();
541  triples .clear();
542  trnodes .clear();
543 
544  nfile = 0;
545  nscan = 0;
546  ncell = 0;
547  nchan = 0;
548  ncelchn = 0;
549  nlamb_i = 0;
550  ntrip_i = 0;
551  nlambda = 0;
552  ntriple = 0;
553  npoint = 0;
554  npointt = 0;
555  slambda = 0;
556  elambda = 0;
557 
558  mapCounts();
559 }
560 
561 // Utility to extract a half-word (2-byte) from a character buffer
562 int US_MwlData::hword( char* cc )
563 {
564  unsigned char* cbuf = (unsigned char*)cc;
565  int j0 = (int)cbuf[ 0 ] & 255;
566  int j1 = (int)cbuf[ 1 ] & 255;
567  return ( ( j0 << 8 ) | j1 );
568 }
569 
570 // Utility to extract a full-word (4-byte) from a character buffer
571 int US_MwlData::iword( char* cbuf )
572 {
573  int j0 = hword( cbuf );
574  int j1 = hword( cbuf + 2 );
575  return ( ( j0 << 16 ) | j1 );
576 }
577 
578 // Utility to extract a float from a character buffer (4-byte)
579 float US_MwlData::fword( char* cbuf )
580 {
581  int ival = iword( cbuf );
582  int* iptr = &ival;
583  float* fptr = (float*)iptr;
584 #ifdef Q_WS_X11
585 // The following code is necessary to counter a compiler bug on 64-bit Linux
586 if(sizeof(long)==8)
587 {
588 static int kk=0;
589 if(((++kk)%1000)==1)
590 qDebug() << "fval" << *fptr << " kk" << kk;
591 }
592 #endif
593  return *fptr;
594 }
595 
596 // Utility to extract a double from a character buffer (4-byte)
597 double US_MwlData::dword( char* cbuf )
598 {
599  float fval = fword( cbuf );
600  return (double)fval;
601 }
602 
603 // Utility to read an MWL header from a data stream
604 void US_MwlData::read_header( QDataStream& ds, DataHdr& hd )
605 {
606  char chary[ 28 ];
607  char* cbuf = (char*)chary;
608 
609  int nhbyte = ( evers == 1.0 ) ? 24 : 26;
610  ds.readRawData( cbuf, nhbyte );
611 
612  hd.cell = QChar( '0' | cbuf[ 0 ] );
613  hd.channel = QChar( cbuf[ 1 ] );
614  hd.icell = cells.indexOf( QString( hd.cell ) );
615  hd.ichan = QString( "ABCDEFGH" ).indexOf( hd.channel );
616  hd.iscan = hword( cbuf + 2 );
617  hd.set_speed = hword( cbuf + 4 );
618 
619  if ( evers > 1.0 )
620  { // Current version that includes both set_speed and rotor_speed
621  hd.rotor_speed = hword( cbuf + 6 );
622  hd.temperature = (double)( hword( cbuf + 8 ) ) / 10.0;
623  hd.omega2t = dword( cbuf + 10 );
624  hd.elaps_time = iword( cbuf + 14 );
625  hd.npoint = hword( cbuf + 18 );
626  hd.radius_start = (double)( hword( cbuf + 20 ) ) / 1000.0;
627  hd.radius_step = (double)( hword( cbuf + 22 ) ) / 10000.0;
628  hd.nlambda = hword( cbuf + 24 );
629  }
630 
631  else
632  { // Older version with only rotor_speed (use that as set_speed)
633  hd.rotor_speed = hd.set_speed;
634  hd.temperature = (double)( hword( cbuf + 6 ) ) / 10.0;
635  hd.omega2t = dword( cbuf + 8 );
636  hd.elaps_time = iword( cbuf + 12 );
637  hd.npoint = hword( cbuf + 16 );
638  hd.radius_start = (double)( hword( cbuf + 18 ) ) / 1000.0;
639  hd.radius_step = (double)( hword( cbuf + 20 ) ) / 10000.0;
640  hd.nlambda = hword( cbuf + 22 );
641  }
642 }
643 
644 // Utility to read the lambdas from a data stream
645 void US_MwlData::read_lambdas( QDataStream& ds, QVector< int >& wvs,
646  int& klambda )
647 {
648  char cbuf[ 4 ];
649 
650  wvs.reserve( klambda );
651 
652  for ( int ii = 0; ii < klambda; ii++ )
653  { // Pick up each 2-byte value and store as integer
654  ds.readRawData( cbuf, 2 );
655  int wvv = hword( cbuf );
656  wvs << wvv;
657  }
658 }
659 
660 // Utility to read the radius point data from a data stream
661 void US_MwlData::read_rdata( QDataStream& ds, QVector< double >& rvs,
662  int& scnx, int& npoint )
663 {
664  char cbuf[ 4 ];
665  int kk = scnx;
666  // Scale by 1.0 or 1/1000 depending on version
667  double rscl = ( evers > 1.2 ) ? 1.0 : 0.001;
668  // In latest versions, scale by 1/10000 if Absorbance
669  rscl = ( ( evers > 1.3 ) && is_absorb ) ? 0.0001 : rscl;
670 
671  for ( int ii = 0; ii < npoint; ii++ )
672  { // Pick up each 4-byte value, convert to double and possibly scale
673  ds.readRawData( cbuf, 4 );
674  int ival = iword( cbuf );
675  double rvv = (double)ival * rscl;
676  rvs[ kk++ ] = rvv;
677  }
678 //if(scnx<1)
679 //DbgLv(1) << "MwDa:ReadRdata evers absorb" << evers << is_absorb
680 // << "rscl ival rvv" << rscl << iword(cbuf) << rvs[kk-1];
681 }
682 
683 // Set Lambda ranges for export
684 int US_MwlData::set_lambdas( int start, int end, int ccx )
685 {
686  set_celchnx( ccx );
687 DbgLv(1) << "MwDa:SetLamb s/e" << start << end;
688  if ( ex_wavelns[ curccx ].count() == 0 )
689  { // If out list is empty, build from input
690  slambda = ( start > 0 ) ? start : ri_wavelns[ 0 ];
691  elambda = ( end > 0 ) ? end : ri_wavelns[ nlamb_i - 1 ];
692  ex_wavelns[ curccx ].clear();
693 
694  // Set up export lambdas
695  int wvxs = indexOfLambda( slambda );
696  int wvxe = indexOfLambda( elambda );
697  nlambda = wvxe - wvxs + 1;
698  int wvx = wvxs;
699 
700  while ( wvx <= wvxe )
701  { // Duplicate lambdas from the range of raw lambdas
702  ex_wavelns[ curccx ] << ri_wavelns[ wvx++ ];
703  }
704 DbgLv(1) << "SetLamb (2)n" << nlambda << wvxs << wvxe << wvx;
705  }
706 
707  else
708  { // If out list exists, pair it down to the new range
709  QVector< int > wkwaves = ex_wavelns[ curccx ];
710  nlambda = wkwaves.count();
711  int old_start = wkwaves[ 0 ];
712  int old_end = wkwaves[ nlambda - 1 ];
713  slambda = ( start > 0 ) ? start : old_start;
714  elambda = ( end > 0 ) ? end : old_end;
715  ex_wavelns[ curccx ].clear();
716 DbgLv(1) << "SetLamb (3)n" << nlambda << slambda << elambda << "ccx" << curccx;
717 
718  // Set up export lambdas
719  int wvxs = wkwaves.indexOf( slambda );
720  int wvxe = wkwaves.indexOf( elambda );
721  wvxe = ( wvxe < 0 ) ? ( nlambda - 1 ) : wvxe;
722  int wvx = wvxs;
723 DbgLv(1) << "SetLamb wvxs wvxe" << wvxs << wvxe;
724 
725  if ( slambda < old_start )
726  { // If start is before old list, grab some from the original input
727  wvxs = indexOfLambda( slambda );
728  slambda = ri_wavelns[ wvxs++ ];
729 
730  while ( slambda < old_start && wvxs < nlamb_i )
731  {
732  ex_wavelns[ curccx ] << slambda;
733  slambda = ri_wavelns[ wvxs++ ];
734  }
735  wvx = 0;
736  }
737 
738  while ( wvx <= wvxe )
739  { // Duplicate lambdas from the range of previous lambdas
740  ex_wavelns[ curccx ] << wkwaves[ wvx++ ];
741  }
742 
743 DbgLv(1) << "SetLamb elambda old_end" << elambda << old_end;
744  if ( elambda > old_end )
745  { // If end is after old list, append some from the original list
746  wvxs = indexOfLambda( old_end ) + 1;
747  wvxe = indexOfLambda( elambda );
748  old_end = ri_wavelns[ wvxs++ ];
749 DbgLv(1) << "SetLamb wvx s,e" << wvxs << wvxe << "old_end" << old_end;
750 
751  while ( old_end <= elambda )
752  {
753  ex_wavelns[ curccx ] << old_end;
754  if ( wvxs >= nlamb_i ) break;
755  old_end = ri_wavelns[ wvxs++ ];
756  }
757  }
758 
759 DbgLv(1) << "SetLamb (4)n" << nlambda << wvxs << wvxe << wvx;
760  }
761 
762  nlambda = ex_wavelns[ curccx ].count();
763  slambda = ex_wavelns[ curccx ][ 0 ];
764  elambda = ex_wavelns[ curccx ][ nlambda - 1 ];
765  ntriple = nlambda * ncelchn;
766 DbgLv(1) << "SetLamb s/e/n" << slambda << elambda << nlambda;
767  return nlambda;
768 }
769 
770 // Set a new lambdas vector for a channel
771 int US_MwlData::set_lambdas( QVector< int >& wls, int ccx )
772 {
773  set_celchnx( ccx );
774  ex_wavelns[ curccx ] = wls;
775  nlambda = wls.count();
776  slambda = wls[ 0 ];
777  elambda = wls[ nlambda - 1 ];
778 
779  return nlambda;
780 }
781 
782 // Find the index of a lambda value in the input raw list of lambdas
783 int US_MwlData::indexOfLambda( int lambda )
784 {
785  int wvx = ri_wavelns.indexOf( lambda ); // Try exact match
786 
787  if ( wvx < 0 )
788  { // If lambda is not in the list, find the nearest to a match
789  int diflow = 9999;
790 
791  for ( int ii = 0; ii < nlamb_i; ii++ )
792  {
793  int difval = qAbs( lambda - ri_wavelns[ ii ] );
794 
795  if ( difval < diflow )
796  { // New low difference, so save index and new low
797  wvx = ii;
798  diflow = difval;
799  }
800  }
801  }
802 
803  return wvx;
804 }
805 
806 // Return the list of cell/channel strings
807 int US_MwlData::cellchannels( QStringList& celchns )
808 {
809  celchns = cellchans;
810  return ncelchn;
811 }
812 
813 // Populate the list of RawData objects from raw input MWL data
814 int US_MwlData::build_rawData( QVector< US_DataIO::RawData >& allData )
815 {
816  const double signif_dif=100.0;
817  const int low_memApc=20;
818 
819  allData.clear();
820 
821  // Build the radius vector that is constant
822  QVector< double > xout;
823  double rad_val = headers[ 0 ].radius_start;
824  double rad_inc = headers[ 0 ].radius_step;
825  r_rpms.clear();
826  s_rpms.clear();
827  a_rpms.clear();
828  d_rpms.clear();
829 DbgLv(1) << "BldRawD radv radi" << rad_val << rad_inc << "npoint" << npoint
830  << " evers" << evers;
831 
832  for ( int ii = 0; ii < npoint; ii++ )
833  {
834  xout << rad_val;
835  rad_val += rad_inc;
836  }
837 DbgLv(1) << "BldRawD xout size ntrip" << xout.size() << npoint << ntrip_i;
838 
839  // Set up the interpolated byte array (all zeroes)
840  int nbytei = ( npoint + 7 ) / 8;
841  QByteArray interpo( nbytei, '\0' );
842 
843  // Build a raw data set for each triple
844  char dtype0 = 'R';
845  char dtype1 = is_absorb ? 'A' : 'I';
846  int ccx = 0;
847  int wvx = 0;
848  int hdx = 0;
849 DbgLv(1) << "BldRawD szs: ccd" << ccdescs.size() << "hdrs" << headers.size()
850  << "rds" << ri_readings.size() << ri_readings[0].size()
851  << "wvs" << ri_wavelns.size() << "nli nlo" << nlamb_i << nlambda;
852 
853  for ( int trx = 0; trx < ntrip_i; trx++ )
854  {
855 DbgLv(1) << "BldRawD trx" << trx << " building scans... ccx" << ccx;
856  US_DataIO::RawData rdata;
857  QString uuid_str = US_Util::new_guid();
858  US_Util::uuid_parse( uuid_str, (unsigned char*)rdata.rawGUID );
859  // Set triple values
860  rdata.type[ 0 ] = dtype0;
861  rdata.type[ 1 ] = dtype1;
862  rdata.cell = QString( headers[ hdx ].cell ).toInt();
863  rdata.channel = headers[ hdx ].channel.toAscii();
864  rdata.xvalues = xout;
865  int jhx = hdx;
866  int rdx = 0;
867  int kspstep = 1;
868  int kscx = 0;
869  int nspstep = 0;
870  int kscan = 0;
871  double rpm_min = 1e+9;
872  double rpm_max = 1e-9;
873  double rpm_sum = 0.0;
874  double rpm_setp = 0.0;
875  double rpm_set = headers[ jhx ].set_speed;
876  double rpm_avg = 0.0;
877  double rpm_stdd = 0.0;
878  rdata.description = ccdescs.at( ccx );
879 DbgLv(1) << "BldRawD hdx" << hdx << "hdsize" << headers.size();
880 
881  for ( int scx = 0; scx < nscan; scx++ )
882  { // Set scan values
883  US_DataIO::Scan scan;
884 if(scx<3 || (scx+4)>nscan)
885 DbgLv(1) << "BldRawD scx" << scx << "jhx" << jhx << "wvx" << wvx;
886  scan.temperature = headers[ jhx ].temperature;
887  rpm_setp = rpm_set;
888  rpm_set = headers[ jhx ].set_speed;
889  scan.rpm = headers[ jhx ].rotor_speed;
890  scan.seconds = headers[ jhx ].elaps_time;
891  scan.omega2t = headers[ jhx ].omega2t;
892  scan.wavelength = ri_wavelns[ wvx ];
893  scan.delta_r = rad_inc;
894  scan.rvalues.reserve( npoint );
895  scan.interpolated = interpo;
896 
897  if ( scx > 0 && scan.rpm != r_rpms[ scx - 1 ] )
898  kspstep++;
899 
900 if(scx<3 || (scx+4)>nscan)
901 DbgLv(1) << "BldRawD rpm_set rpm_setp" << rpm_set << rpm_setp;
902  if ( rpm_set != rpm_setp )
903  { // A new speed step is reached, re-do speeds in the previous one
904  nspstep++;
905  rpm_avg = rpm_sum / (double)kscan;
906  rpm_stdd = 0.0;
907 
908  for ( int jsx = kscx; jsx < scx; jsx++ )
909  {
910  // Store the average over the speed step as the scan speed
911  rdata.scanData[ jsx ].rpm = (double)qRound( rpm_avg );
912 
913  // Compute chi-squared sum
914  rpm_stdd += sq( r_rpms[ jsx ] - rpm_avg );
915  }
916 
917  // Compute standard deviation of speeds and save step values
918  rpm_stdd = sqrt( rpm_stdd ) / (double)kscan;
919  if ( trx == 0 )
920  {
921  a_rpms << rpm_avg;
922  s_rpms << rpm_setp;
923  d_rpms << rpm_stdd;
924  }
925 
926  // Reinitialize for next speed step
927  kscx = scx;
928  kscan = 1;
929  rpm_sum = 0.0;
930  }
931  else
932  { // Bump scan count in a speed step
933  kscan++;
934  }
935 
936  // Accumulate rpm min,max,sum
937  rpm_min = qMin( rpm_min, scan.rpm );
938  rpm_max = qMax( rpm_max, scan.rpm );
939  rpm_sum += scan.rpm;
940 //*DEBUG*
941 if(trx==0) {
942 DbgLv(1) << "BldRawD scx" << scx << "jhx" << jhx
943  << "seconds" << scan.seconds << "rpm" << scan.rpm << "ss" << rpm_set
944  << "speed step" << kspstep << nspstep+1;
945 }
946 //*DEBUG*
947  if ( trx == 0 )
948  r_rpms << scan.rpm;
949  jhx++;
950 if(scx<3 || (scx+4)>nscan)
951 DbgLv(1) << "BldRawD trx jhx rdx" << trx << jhx << rdx;
952 if(scx<3 || (scx+4)>nscan)
953 DbgLv(1) << "BldRawD riread[trx] size" << ri_readings[trx].size();
954 
955  for ( int kk = 0; kk < npoint; kk++ )
956  { // Set readings values
957  scan.rvalues << ri_readings[ trx ][ rdx++ ];
958  } // END: radius points loop
959 
960  rdata.scanData << scan; // Append a scan to a triple
961  } // END: scan loop
962 DbgLv(1) << "BldRawD EoSl: trx rdx" << trx << rdx;
963 
964  if ( evers < 1.2 )
965  { // For an old data version, get the average of all scans
966  rpm_min = 1.e+9;
967  rpm_max = 1.e-9;
968  rpm_sum = 0.0;
969 
970  for ( int scx = 0; scx < nscan; scx++ )
971  {
972  double srpm = rdata.scanData[ scx ].rpm;
973  rpm_min = qMin( rpm_min, srpm );
974  rpm_max = qMax( rpm_max, srpm );
975  rpm_sum += srpm;
976  }
977 
978  kscan = nscan;
979  nspstep = 0;
980  kscx = 0;
981  rpm_set = (double)qRound( ( rpm_min + rpm_max ) * 0.5 );
982  }
983 
984  // Set the average speed for the final/only speed step
985  nspstep++;
986  rpm_stdd = 0.0;
987  rpm_avg = rpm_sum / (double)kscan;
988 DbgLv(1) << "BldRawD kscx" << kscx;
989 
990  for ( int scx = kscx; scx < nscan; scx++ )
991  {
992  // Store the average over the speed step as the scan speed
993  rdata.scanData[ scx ].rpm = (double)qRound( rpm_avg );
994 
995  // Compute the chi-squared sum
996  rpm_stdd += sq( r_rpms[ scx ] - rpm_avg );
997  }
998 
999  // Compute standard deviation of speeds and update step values
1000  rpm_stdd = sqrt( rpm_stdd ) / (double)kscan;
1001 DbgLv(1) << "BldRawD rpm_stdd" << rpm_stdd;
1002 
1003  if ( trx == 0 )
1004  {
1005  a_rpms << rpm_avg;
1006  s_rpms << rpm_set;
1007  d_rpms << rpm_stdd;
1008 
1009  if ( evers > 1.0 )
1010  { // In newer data, a set_speed may differ from the average
1011  if ( qAbs( rpm_avg - rpm_set ) > signif_dif )
1012  {
1013  QMessageBox::warning( 0,
1014  tr( "Set/Average Speed Difference" ),
1015  tr( "The stored set_speed (%1) and the average of"
1016  " recorded rotor_speeds (%2) differ"
1017  " significantly!" ).arg( rpm_set ).arg( rpm_avg ) );
1018  }
1019  }
1020  }
1021 //*DEBUG*
1022 if(trx==0) {
1023  DbgLv(1) << "BldRawD trx=" << trx << "rpm_min rpm_max rpm_avg rpm_set"
1024  << rpm_min << rpm_max << rpm_avg << rpm_set << "speed steps" << nspstep;
1025 }
1026 //*DEBUG*
1027 
1028 DbgLv(1) << "BldRawD trx" << trx << " saving allData...";
1029  allData << rdata; // Append triple data to the array
1030  le_status->setText( tr( "Of %1 raw AUCs, built %2" )
1031  .arg( ntriple ).arg( trx + 1 ) );
1032  qApp->processEvents();
1033  wvx++;
1034 
1035  if ( wvx >= nlambda )
1036  { // After final wavelength, reset at next cell/channel
1037  ccx++;
1038  wvx = 0;
1039  hdx = ccx * nscan;
1040 
1041  // Free up some memory if it is getting tight
1042  int memAv = US_Memory::memory_profile();
1043 
1044  if ( memAv < low_memApc )
1045  {
1046  for ( int rr = ( trx - nlambda + 1 ); rr < ( trx + 1 ); rr++ )
1047  ri_readings[ rr ].clear();
1048 int memAv2 = US_Memory::memory_profile();
1049 DbgLv(1) << "BldRawD memfree %: 1memAV" << memAv << "2memAV" << memAv2;
1050  }
1051  }
1052 DbgLv(1) << "BldRawD ccx wvx hdx" << ccx << wvx << hdx << headers.size();
1053  } // END: triple loop
1054 
1055  le_status->setText( tr( "All %1 raw AUCs have been build." )
1056  .arg( ntriple ) );
1057  qApp->processEvents();
1058 
1059 DbgLv(1) << "BldRawD DONE ntriple" << ntriple << ntrip_i;
1060  return ntriple;
1061 }
1062 
1063 // Return a count of a specified type
1064 int US_MwlData::countOf( QString key )
1065 {
1066  mapCounts();
1067 
1068  return counts[ key ];
1069 }
1070 
1071 // Return the channel description string for a given cell/channel
1072 QString US_MwlData::cc_description( QString celchn )
1073 {
1074  int ccx = cellchans.indexOf( celchn );
1075  return ( ccx < 0 ? "" : ccdescs.at( ccx ) );
1076 }
1077 
1078 // Return the runID and runType strings for the data
1079 void US_MwlData::run_values( QString& arunid, QString& aruntype )
1080 {
1081  arunid = runID;
1082  aruntype = is_absorb ? "RA" : "RI";
1083 }
1084 
1085 // Private slot to map counts and sizes
1087 {
1088  counts[ "file" ] = nfile;
1089  counts[ "scan" ] = nscan;
1090  counts[ "cell" ] = ncell;
1091  counts[ "channel" ] = nchan;
1092  counts[ "cellchann" ] = ncelchn;
1093  counts[ "lambda" ] = nlambda;
1094  counts[ "triple" ] = ntriple;
1095  counts[ "lamb_i" ] = nlamb_i;
1096  counts[ "trip_i" ] = ntrip_i;
1097  counts[ "point" ] = npoint;
1098  counts[ "point_all" ] = npointt;
1099  counts[ "slambda" ] = slambda;
1100  counts[ "elambda" ] = elambda;
1101 }
1102 
1103 // Read the run XML file and return its values
1104 void US_MwlData::read_runxml( QDir ddir, QString curdir )
1105 {
1106  QStringList mwrfs = ddir.entryList( QStringList( "*.mwrs.xml" ),
1107  QDir::Files, QDir::Name );
1108  int nxfile = mwrfs.count();
1109 
1110  if ( nxfile > 1 )
1111  {
1112  qDebug() << "*ERROR* '*.mwrs.xml' count > 1" << nxfile << curdir;
1113  return;
1114  }
1115 
1116  else if ( nxfile == 0 )
1117  {
1118  qDebug() << "*ERROR* '*.mwrs.xml' does not exist in " << curdir;
1119  return;
1120  }
1121 
1122  QString fname = mwrfs.at( 0 );
1123  QString fpath = cur_dir + fname;
1124  QFile xfi( fpath );
1125 
1126  if ( ! xfi.open( QIODevice::ReadOnly ) )
1127  {
1128  qDebug() << "*ERROR* Unable to open" << fname;
1129  qDebug() << fpath;
1130  return;
1131  }
1132 
1133  QXmlStreamReader xml( &xfi );
1134  QString celi;
1135  QString chni;
1136  QString cech;
1137  cellchans.clear();
1138 
1139  while( ! xml.atEnd() )
1140  {
1141  xml.readNext();
1142  if ( xml.isStartElement() )
1143  {
1144  QXmlStreamAttributes att = xml.attributes();
1145  if ( xml.name() == "runID" )
1146  {
1147  runID = att.value( "name" ).toString();
1148  is_absorb = att.value( "take_intensity" ).toString() == "N";
1149 DbgLv(1) << "MwDa:RdXML take_i" << att.value( "take_intensity" ).toString()
1150  << "evers absorb" << evers << is_absorb;
1151  }
1152  else if ( xml.name() == "cell" )
1153  {
1154  celi = att.value( "id" ).toString();
1155  celi = QString::number( celi.toInt() );
1156  }
1157  else if ( xml.name() == "channel" )
1158  {
1159  chni = att.value( "id" ).toString();
1160  cech = celi + " / " + chni;
1161  QString desc = att.value( "sample" ).toString();
1162 
1163  if ( ! cellchans.contains( cech ) )
1164  {
1165  cellchans << cech;
1166  ccdescs << desc;
1167  }
1168  }
1169  else if ( xml.name() == "settings_mwrs_experiment" )
1170  {
1171  evers = att.value( "version" ).toString().toDouble();
1172  }
1173  }
1174  }
1175 
1176  is_absorb = ( evers > 1.3 ) ? is_absorb : false;
1177  xfi.close();
1178 }
1179 
1180 // Set the current cell/channel index
1182 {
1183 //DbgLv(1) << "SetCCX" << ccx;
1184  curccx = qMax( 0, qMin( ccx, ( ncelchn - 1 ) ) );
1185 
1186  return curccx;
1187 }
1188 
1189 // Return the output data index of a wavelength in a channel
1190 int US_MwlData::data_index( int waveln, int ccx )
1191 {
1192  // Set the current cell/channel index
1193  set_celchnx( ccx );
1194 
1195  // Initially, data index is wavelength index in current cell/channel
1196  int datax = qMax( 0, ex_wavelns[ curccx ].indexOf( waveln ) );
1197 
1198  // Bump the data index by the sum of wavelengths preceding the channel
1199  for ( int ii = 0; ii < curccx; ii++ )
1200  datax += ex_wavelns[ ii ].count();
1201 
1202  return datax;
1203 }
1204 
1205 // Return the output data index of a wavelength in a channel
1206 int US_MwlData::data_index( QString clambda, int ccx )
1207 {
1208  return data_index( clambda.toInt(), ccx );
1209 }
1210 
1211 // Return the output data index of a wavelength in a channel
1212 int US_MwlData::data_index( QString clambda, QString celchn )
1213 {
1214  int ccx = cellchans.indexOf( celchn );
1215  return data_index( clambda.toInt(), ccx );
1216 }
1217 
1218 // Update the speed profile for the current MWL data
1219 int US_MwlData::update_speedsteps( QVector< SP_SPEEDPROFILE >& speedsteps )
1220 {
1221 // int nsteps = qMin( speedsteps.size(), s_rpms.size() );
1222  int nsteps = s_rpms.size();
1223 DbgLv(1) << "MwDa:uSS: nsteps" << nsteps << speedsteps.size() << s_rpms.size();
1224  if ( nsteps > 0 )
1225  {
1226  int kdecr = 0;
1227  const int mxstep = 10;
1228  speedsteps.resize( nsteps );
1229 
1230  for ( int jj = 0; jj < nsteps; jj++ )
1231  {
1232  speedsteps[ jj ].set_speed = (int)s_rpms[ jj ];
1233  speedsteps[ jj ].avg_speed = a_rpms[ jj ];
1234  speedsteps[ jj ].speed_stddev = d_rpms[ jj ];
1235  speedsteps[ jj ].rotorspeed = qRound( a_rpms[ jj ] );
1236 DbgLv(1) << "MwDa:uSS: jj" << jj << "set_speed avg_speed speed_stddev"
1237  << s_rpms[ jj ] << a_rpms[ jj ] << d_rpms[ jj ];
1238  if ( jj > 0 &&
1239  speedsteps[ jj ].set_speed < speedsteps[ jj - 1 ].set_speed )
1240  kdecr++;
1241  }
1242 
1243  if ( kdecr > 0 )
1244  nsteps = -1;
1245  if ( nsteps > mxstep )
1246  nsteps = -2;
1247  }
1248 
1249  return nsteps;
1250 }
1251 
1252 // Return a vector of raw speeds for all MWL data scans
1253 int US_MwlData::raw_speeds( QVector< double >& rrpms )
1254 {
1255  int nscans = r_rpms.size();
1256  rrpms = r_rpms;
1257  return nscans;
1258 }
1259