UltraScan III
us_run_details2.cpp
Go to the documentation of this file.
1 
3 #include "us_run_details2.h"
4 #include "us_settings.h"
5 #include "us_gui_settings.h"
6 #include "us_math2.h"
7 #include "us_constants.h"
8 #include "us_util.h"
9 #include "us_gui_util.h"
10 
11 #include <qwt_legend.h>
12 
14 #define round(x) floor( (x) + 0.5 )
15 
16 US_RunDetails2::US_RunDetails2( const QVector< US_DataIO::RawData >& data,
17  const QString& runID,
18  const QString& dataDir,
19  const QStringList& cell_ch_wl )
20  : US_WidgetsDialog( 0, 0 ), dataList( data ), triples( cell_ch_wl )
21 {
22  setWindowTitle( tr( "Details for Raw Data" ) );
23  setPalette( US_GuiSettings::frameColor() );
24 
25  QGridLayout* main = new QGridLayout( this );
26  main->setSpacing ( 2 );
27  main->setContentsMargins( 2, 2, 2, 2 );
28 
30  temp_warn = true;
31  int row = 0;
32 
33  // Plot Rows
34  QBoxLayout* plot = new US_Plot( data_plot,
35  tr( "Parameter Variation Throughout Run" ),
36  tr( "Scan Number" ),
37  tr( "RPM * 1000 / Temperature " ) + DEGC );
38 
39  data_plot->setMinimumSize( 400, 200 );
40  data_plot->enableAxis( QwtPlot::yRight );
41 
42  // Copy font for right axis from left axis
43  QwtText axisTitle = data_plot->axisTitle( QwtPlot::yLeft );
44  axisTitle.setText( tr( "Time between Scans (min)" ) );
45  data_plot->setAxisTitle( QwtPlot::yRight, axisTitle );
46 
47  QwtPlotGrid* grid = us_grid( data_plot );
48  grid->enableXMin( false );
49 
50  main->addLayout( plot, row, 0, 5, 6 );
51  row += 6;
52 
53  // Row
54  QLabel* lb_dir = us_label( tr( "Data Directory:" ) );
55  main->addWidget( lb_dir, row, 0 );
56 
57  QLineEdit* le_dir = us_lineedit();
58  le_dir->setReadOnly( true );
59  le_dir->setText( dataDir );
60  main->addWidget( le_dir, row++, 1, 1, 5 );
61 
62  // Row
63  QLabel* lb_desc = us_label( tr( "Description:" ) );
64  main->addWidget( lb_desc, row, 0 );
65 
66  le_desc = us_lineedit();
67  le_desc->setReadOnly( true );
68  le_desc->setText( dataDir );
69  main->addWidget( le_desc, row++, 1, 1, 5 );
70 
71  // Row
72  QLabel* lb_runID = us_label( tr( "Run Identification:" ) );
73  main->addWidget( lb_runID, row, 0 );
74 
76  lw_rpm->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
77  lw_rpm->setMinimumSize( 100, 50 );
78  main->addWidget( lw_rpm, row, 2, 5, 2 );
79 
81  lw_triples->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum );
82  lw_triples->setMinimumSize( 100, 50 );
83  main->addWidget( lw_triples, row, 4, 5, 2 );
84 
86  le_runID->setReadOnly( true );
87  le_runID->setText( runID );
88  main->addWidget( le_runID, row++, 1 );
89 
90  // Row
91  QLabel* lb_runLen = us_label( tr( "Length of Run:" ) );
92  main->addWidget( lb_runLen, row, 0 );
93 
95  le_runLen->setReadOnly( true );
96  main->addWidget( le_runLen, row++, 1 );
97 
98  // Row
99  QLabel* lb_timeCorr = us_label( tr( "Time Correction:" ) );
100  main->addWidget( lb_timeCorr, row, 0 );
101 
103  le_timeCorr->setReadOnly( true );
104  main->addWidget( le_timeCorr, row++, 1 );
105 
106  // Row
107  QLabel* lb_rotorSpeed = us_label( tr( "Avg. Rotor Speed:" ) );
108  main->addWidget( lb_rotorSpeed, row, 0 );
109 
111  le_rotorSpeed->setReadOnly( true );
112  main->addWidget( le_rotorSpeed, row++, 1 );
113 
114  // Row
115  QLabel* lb_avgTemp = us_label( tr( "Avg. Temperature:" ) );
116  main->addWidget( lb_avgTemp, row, 0 );
117 
119  le_avgTemp->setReadOnly( true );
120  main->addWidget( le_avgTemp, row++, 1 );
121 
122  // Row
123  QLabel* lb_tempCheck = us_label( tr( "Temperature Check:" ) );
124  main->addWidget( lb_tempCheck, row, 0 );
125 
126  QHBoxLayout* box1 = new QHBoxLayout;
127  box1->setAlignment( Qt::AlignCenter );
128 
129  QHBoxLayout* box2 = new QHBoxLayout;
130  box2->setAlignment( Qt::AlignCenter );
131  box2->setSpacing( 10 );
132 
133  lb_green = new QLabel();
134  lb_green->setFixedSize(20, 16);
135  lb_green->setPalette( QPalette( QColor( 0, 0x44, 0 ) ) ); // Dark Green
136  lb_green->setAutoFillBackground( true );
137  lb_green->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
138 
139  lb_red = new QLabel();
140  lb_red->setFixedSize(20, 16);
141  lb_red->setPalette( QPalette( QColor( 0x55, 0, 0 ) ) ); // Dark Red
142  lb_red->setAutoFillBackground( true );
143  lb_red->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
144 
145  box2->addWidget( lb_green );
146  box2->addWidget( lb_red );
147  box1->addLayout( box2 );
148 
149  main->addLayout( box1, row, 1 );
150 
151  QHBoxLayout* buttons = new QHBoxLayout();
152 
153  QPushButton* pb_temp = us_pushbutton( tr( "Temperature" ) );
154  connect( pb_temp, SIGNAL( clicked() ), SLOT( plot_temp() ) );
155  buttons->addWidget( pb_temp );
156 
157  QPushButton* pb_rpm = us_pushbutton( tr( "RPM" ) );
158  connect( pb_rpm, SIGNAL( clicked() ), SLOT( plot_rpm() ) );
159  buttons->addWidget( pb_rpm );
160 
161  QPushButton* pb_interval = us_pushbutton( tr( "Interval" ) );
162  connect( pb_interval, SIGNAL( clicked() ), SLOT( plot_interval() ) );
163  buttons->addWidget( pb_interval );
164 
165  QPushButton* pb_all = us_pushbutton( tr( "Combined" ) );
166  connect( pb_all, SIGNAL( clicked() ), SLOT( plot_combined() ) );
167  buttons->addWidget( pb_all );
168 
169  QPushButton* pb_close = us_pushbutton( tr( "Close" ) );
170  connect( pb_close, SIGNAL( clicked() ), SLOT( close() ) );
171  buttons->addWidget( pb_close );
172 
173  main->addLayout( buttons, row++, 2, 1, 4 );
174 
175  timer = new QTimer();
176  connect( timer, SIGNAL( timeout() ), SLOT( update_timer() ) );
177 
178  setup();
179  connect( lw_triples, SIGNAL( currentRowChanged( int ) ),
180  SLOT ( update ( int ) ) );
181 
182  connect( lw_rpm, SIGNAL( itemClicked ( QListWidgetItem* ) ),
183  this, SLOT ( show_rpm_details( QListWidgetItem* ) ) );
184 }
185 
187 {
188  // Before leaving, save a combined plot for each triple automatically
189  plotType = COMBINED;
190  QString dir = US_Settings::reportDir() + "/" + le_runID->text();
191  if ( ! QDir( dir ).exists() ) // make sure the directory exists
192  QDir().mkdir( dir );
193  // int save_currentRow = lw_triples->currentRow();
194  data_plot->setVisible( false );
195  for ( int i = 0; i < triples.size(); i++ )
196  {
197  QString triple = US_Util::compressed_triple( triples[ i ] );
198  QString filename = dir + "/rundetail." + triple + ".rundetail.svgz";
199 
200  // Calculate the current plot and write it to a file
201  lw_triples->setCurrentRow( i );
202  update( i );
203  int status = US_GuiUtil::save_plot( filename, data_plot );
204  if ( status != 0 )
205  qDebug() << filename << "plot not saved";
206  }
207 
208  // Don't need to restore original view because we're leaving
209 }
210 
212 {
213  // Set length of run
214  double last = 0.0;
215  US_DataIO::RawData data;
216 
217  foreach( data, dataList )
218  last = max( last, data.scanData.last().seconds );
219 
220  last = round( last );
221  int hours = (int)floor( last / 3600.0 );
222  int mins = (int) round( ( last - hours * 3600.0 ) / 60.0 );
223 
224  QString s;
225  QString h = ( hours == 1 ) ? tr( "hour" ) : tr( "hours" );
226 
227  le_runLen->setText(
228  s.sprintf( "%d %s %02d min", hours, h.toAscii().data(), mins ) );
229 
230  // Set Time Correction
231  double correction = 0.0;
232  int scanCount = 0;
233 
234  US_DataIO::Scan scan;
235 
236  foreach( data, dataList )
237  {
238  foreach( scan, data.scanData )
239  {
240  double omega = ( M_PI / 30.0 ) * scan.rpm;
241  correction += scan.seconds - scan.omega2t / sq( omega );
242  scanCount++;
243  }
244  }
245 
246  correction /= scanCount;
247  int minutes = (int) correction / 60;
248  int seconds = (int) correction % 60;
249 
250  le_timeCorr->setText( s.sprintf( "%d min %02d sec", minutes, seconds ) );
251 
252  // Set rpm list widget
253  int i = 0;
254 
255  foreach( data, dataList )
256  {
257  int scanNumber = 1;
258  foreach( scan, data.scanData )
259  {
260  // Round to closest 100 rpm
261  int rpm = (int)round( scan.rpm / 100.0 ) * 100;
262  map.insert( rpm, triples[ i ] + " / " + QString::number( scanNumber ) );
263  scanNumber++;
264  }
265 
266  i++;
267  }
268 
269  QList< int > rpms = map.uniqueKeys();
270  qSort( rpms );
271  QStringList s_rpms;
272  int rpm;
273 
274  foreach( rpm, rpms ) s_rpms << QString::number( rpm ) + " RPM";
275  lw_rpm->addItems( s_rpms );
276 
277  // Set triples + scans
278  for ( int i = 0; i < triples.size(); i++ )
279  {
280  int scans = dataList[ i ].scanData.size();
281  lw_triples->addItem( triples[ i ] + s.sprintf( " -- %d scans", scans ) );
282  }
283 
284  lw_triples->addItem( s.sprintf( "All scans -- %d scans", scanCount ) );
285 
286  // Set triple to indicate All Data
287  lw_triples->setCurrentRow( triples.size() );
288 
289  show_all_data();
290 }
291 
293 {
294  le_desc->setText( "" );
295 
296  US_DataIO::RawData triple;
297  US_DataIO::Scan scan;
298  double temp = 0.0;
299  double rpm = 0.0;
300  int scanCount = 0;
301 
302  // Note that these are not weighted averages
303  foreach( triple, dataList )
304  {
305  foreach( scan, triple.scanData )
306  {
307  temp += scan.temperature;
308  rpm += scan.rpm;
309  scanCount++;
310  }
311  }
312 
313  // Set average temperature
314  le_avgTemp->setText( QString::number( temp / scanCount, 'f', 1 )
315  + " " + DEGC );
316 
317  // Set average rpm
318  rpm /= scanCount; // Get average
319  rpm = round( rpm / 100.0 ); // Round to closest 100 rpm
320  le_rotorSpeed->setText( QString::number( (int)rpm * 100 ) + " RPM" );
321 
322  // Determine temperature variation
323  double dt = 0.0;
324 
325  foreach( triple, dataList )
326  {
327  double temp_spread = triple.temperature_spread();
328  dt = ( temp_spread > dt ) ? temp_spread : dt;
329  }
330 
331  check_temp( dt );
332 
333  // Plot the data
334  // First, put all data in a list and sort by time
335  QList< graphValue > values;
336 
337  foreach( triple, dataList )
338  {
339  foreach( scan, triple.scanData )
340  {
341  values << graphValue( scan.seconds, scan.rpm, scan.temperature );
342  }
343  }
344 
345  qSort( values );
346 
347  QVector< double > x( scanCount );
348  QVector< double > t( scanCount );
349  QVector< double > r( scanCount );
350  QVector< double > m( scanCount );
351  double prior_seconds = 0.0;
352 
353  for ( int i = 0; i < scanCount; i++ )
354  {
355  x[ i ] = i + 1;
356  t[ i ] = values[ i ].temperature;
357  r[ i ] = values[ i ].rpm / 1000.0;
358 
359 
360  if ( i > 0 )
361  m[ i ] = ( values[ i ].seconds - prior_seconds ) / 60.0;
362 
363  prior_seconds = values[ i ].seconds;
364  }
365 
366  draw_plot( x.constData(), t.constData(), r.constData(), m.constData(), scanCount );
367 }
368 
369 void US_RunDetails2::check_temp( double dt )
370 {
371  if ( dt <= US_Settings::tempTolerance() )
372  {
373  lb_red ->setPalette( QPalette( QColor( 0x55, 0, 0 ) ) ); // Dark Red
374  lb_green->setPalette( QPalette( Qt::green ) );
375  }
376  else
377  {
378  lb_red ->setPalette( QPalette( Qt::red ) );
379  lb_green->setPalette( QPalette( QColor( 0, 0x44, 0 ) ) ); // Dark Green
380 
381  if ( ! timer->isActive() ) timer->start( 1000 );
382  }
383 }
384 
386 {
387  static bool bright = true;
388  static const QPalette red( Qt::red );
389  static const QPalette darkRed( QColor( 0x55, 0, 0 ) );
390 
391  if ( bright )
392  lb_red->setPalette( darkRed );
393  else
394  lb_red->setPalette( red );
395 
396  bright = ! bright;
397 }
398 
399 void US_RunDetails2::draw_plot( const double* x, const double* t,
400  const double* r, const double* m, int count )
401 {
402  // Set up the axes and titles
403  QwtText axisTitle = data_plot->axisTitle( QwtPlot::yLeft );
404 
405  data_plot->setAxisTitle ( QwtPlot::yRight, axisTitle );
406  data_plot->enableAxis ( QwtPlot::yRight, false );
407  data_plot->setAxisAutoScale( QwtPlot::yLeft );
408  data_plot->setAxisScale ( QwtPlot::xBottom, 1.0, count );
409  data_plot->setAxisMaxMinor ( QwtPlot::xBottom, 0 );
410 
411  switch( plotType )
412  {
413  case TEMPERATURE:
414  axisTitle.setText( tr( "Temperature " ) + DEGC );
415  data_plot->setAxisTitle( QwtPlot::yLeft, axisTitle );
416  break;
417 
418  case RPM:
419  axisTitle.setText( tr( "RPM * 1000" ) );
420  data_plot->setAxisTitle( QwtPlot::yLeft, axisTitle );
421  break;
422 
423  case INTERVAL:
424  axisTitle.setText( tr( "Time between Scans (min)" ) );
425  data_plot->setAxisTitle( QwtPlot::yLeft, axisTitle );
426  break;
427 
428  default:
429  axisTitle.setText(
430  tr( "RPM * 1000 / Temperature " ) + DEGC );
431  data_plot->setAxisTitle( QwtPlot::yLeft, axisTitle );
432 
433  axisTitle.setText( tr( "Time between Scans (min)" ) );
434  data_plot->setAxisTitle( QwtPlot::yRight, axisTitle );
435 
436  data_plot->enableAxis ( QwtPlot::yRight, true );
437  data_plot->setAxisScale( QwtPlot::yLeft, 0.0, 60.0 );
438  break;
439 
440  }
441 
442  data_plot->detachItems( QwtPlotItem::Rtti_PlotCurve );
443 
444  QwtSymbol sym;
445 
446  sym.setStyle( QwtSymbol::Ellipse );
447  sym.setPen ( QPen( Qt::yellow ) );
448  sym.setBrush( Qt::white );
449  sym.setSize ( 6 );
450 
451  if ( plotType == TEMPERATURE || plotType == COMBINED )
452  {
453  QwtPlotCurve* c1 = us_curve( data_plot, tr( "Temperature" ) );
454  c1->setPen ( QPen( QBrush( Qt::yellow ), 2 ) );
455  c1->setSymbol( sym );
456  c1->setData ( x, t, count );
457  }
458 
459  sym.setPen( QColor( Qt::green ) );
460 
461  if ( plotType == RPM || plotType == COMBINED )
462  {
463  QwtPlotCurve* c2 = us_curve( data_plot, tr( "RPM" ) );
464  c2->setPen ( QPen( QBrush( Qt::green ), 2 ) );
465  c2->setSymbol ( sym );
466  c2->setData ( x, r, count );
467  }
468 
469  sym.setPen( QColor( Qt::red ) );
470 
471  if ( plotType == INTERVAL || plotType == COMBINED )
472  {
473  QwtPlotCurve* c3 = us_curve( data_plot, tr( "Scan Time Deltas" ) );
474  if ( plotType == COMBINED ) c3->setYAxis( QwtPlot::yRight );
475  c3->setPen ( QPen( QBrush( Qt::red ), 2 ) );
476  c3->setSymbol ( sym );
477  c3->setData ( &x[ 1 ], &m[ 1 ], count - 1 );
478  }
479 
480  if ( data_plot->legend() == NULL )
481  {
482  QwtLegend* legend = new QwtLegend;
483  data_plot->insertLegend( legend, QwtPlot::BottomLegend );
484  legend->setFrameStyle( QFrame::Box | QFrame::Sunken );
485 
486  QList< QWidget* > items = legend->legendItems();
487 
488  QFont font = items[ 0 ]->font();
489  font.setPointSize( US_GuiSettings::fontSize() );
490 
491  QWidget* item;
492  foreach( item, items ) item->setFont( font );
493 
494  data_plot->insertLegend( legend, QwtPlot::BottomLegend );
495  }
496 
497  data_plot->replot();
498 }
499 
500 void US_RunDetails2::update( int index )
501 {
502  lw_rpm->clearSelection();
503 
504  if ( lw_triples->currentItem()->text().contains( tr( "All" ) ) )
505  {
506  show_all_data();
507  return;
508  }
509 
510  const US_DataIO::RawData* data = &dataList[ index ];
511  int scanCount = data->scanData.size();
512 
513  le_desc->setText( data->description );
514 
515  double temp = 0.0;
516  double rpm = 0.0;
517 
518  for ( int i = 0; i < scanCount; i++ )
519  {
520  temp += data->scanData[ i ].temperature;
521  rpm += data->scanData[ i ].rpm;
522  }
523 
524  // Set average temperature
525  le_avgTemp->setText( QString::number( temp / scanCount, 'f', 1 )
526  + " " + DEGC );
527 
528  // Set average rpm
529  rpm /= scanCount; // Get average
530  rpm = round( rpm / 100.0 ); // Round to closest 100 rpm
531  le_rotorSpeed->setText( QString::number( (int)rpm * 100 ) + " RPM" );
532 
533  double maxTemp = -1.0e99;
534  double minTemp = 1.0e99;
535 
536  QVector< double > x( scanCount );
537  QVector< double > t( scanCount );
538  QVector< double > r( scanCount );
539  QVector< double > m( scanCount );
540  double prior_seconds = 0.0;
541 
542  for ( int i = 0; i < scanCount; i++ )
543  {
544  const US_DataIO::Scan* s = &data->scanData[ i ];
545 
546  x[ i ] = i + 1;
547  t[ i ] = s->temperature;
548  maxTemp = max( maxTemp, s->temperature );
549  minTemp = min( minTemp, s->temperature );
550 
551  r[ i ] = s->rpm / 1000.0;
552 
553  if ( i > 0 ) m[ i ] = ( s->seconds - prior_seconds ) / 60.0;
554 
555  prior_seconds = s->seconds;
556  }
557 
558  // Determine temperature variation
559  double dt = data->temperature_spread();;
560 
561  check_temp( dt );
562 
563  draw_plot( x.constData(), t.constData(), r.constData(), m.constData(), scanCount );
564 }
565 
566 void US_RunDetails2::show_rpm_details( QListWidgetItem* item )
567 {
568 qDebug() << "show_rpm_details";
569  QString sspeed = item->text();
570  QString msg = tr( "The following scans have been measured at " )
571  + sspeed + ":\n\n";
572 
573 qDebug() << " srd: msg" << msg;
574  QStringList sl = sspeed.split( " " );
575  sspeed = sl[ 0 ];
576  int rpm = sspeed.toInt();
577 qDebug() << " srd: sl" << sl << "rpm" << rpm << "np" << sl.count();
578 
579  sl = map.values( rpm );
580  qSort( sl ); // contains cell / channel / wavelength / scan
581  // ( or cell / channel / scan for MWL data )
582 
583  QString triple = triples[ 0 ];
584  bool isMwl = triple.split( " / " ).size() < 3;
585  QString pcellCh = "0/Z";
586 
587  foreach( triple, triples )
588  {
589  QList< int > scans;
590  QString value;
591 
592  foreach( value, sl )
593  {
594 //qDebug() << " srd: triple" << triple << "value" << value;
595  if ( value.startsWith( triple ) )
596  {
597  QStringList components = value.split( " / " );
598  int lvx = components.size() - 1;
599  scans << components[ lvx ].toInt();
600  }
601  }
602 
603  if ( scans.size() == 0 ) continue;
604 
605  QStringList cellChWl = triple.split( " / " );
606  QString cellCh = cellChWl[ 0 ] + "/" + cellChWl[ 1 ];
607 qDebug() << " srd: ccw" << cellChWl << "ccwsz" << cellChWl.count();
608 qDebug() << " srd: pcellCh cellCh isMwl" << pcellCh << cellCh << isMwl;
609 
610  if ( cellChWl.size() > 2 )
611  { // Normal (c/c/w/s) data
612  msg += tr( "Cell: " ) + cellChWl[ 0 ]
613  + tr( ", Channel: " ) + cellChWl[ 1 ]
614  + tr( ", Wavelength: " ) + cellChWl[ 2 ]
615  + tr( ", Scan Count: " );
616  isMwl = ( isMwl || cellCh == pcellCh );
617 qDebug() << " srd: isMwl" << isMwl;
618  }
619 
620  else
621  { // MWL (c/c/s) data
622  msg += tr( "Cell: " ) + cellChWl[ 0 ]
623  + tr( ", Channel: " ) + cellChWl[ 1 ]
624  + tr( ", Scan Count: " );
625  }
626 
627  msg += QString::number( scans.size() ) + "\n";
628  pcellCh = cellCh;
629  }
630 
631  bool have_avg = false;
632  QString runID = le_runID->text();
633  QString fname = US_Settings::resultDir() + "/" + runID + "/"
634  + runID + ".RI.xml";
635  QFile filei( fname );
636  if ( filei.open( QIODevice::ReadOnly | QIODevice::Text ) )
637  {
638  QTextStream texti( &filei );
639  QString xtext = texti.readAll();
640  have_avg = xtext.contains( "avg_speed" );
641  filei.close();
642  }
643 
644  if ( have_avg )
645  {
646  msg += moreSpeedInfo( rpm );
647  }
648 
649 #if 1
650  QMessageBox::information( this,
651  tr( "Speed Information" ), msg );
652 #endif
653 #if 0
654  msg += tr( "\nYou may \"Close\" this dialog or click \"Details\""
655  " to open a text dialog showing speed details"
656  " for all scans" );
657  QMessageBox msgbox;
658  msgbox.setIcon( QMessageBox::Information );
659  msgbox.setText( tr( "Speed Information" ) );
660  msgbox.setInformativeText( msg );
661  msgbox.addButton( tr( "Details" ), QMessageBox::AcceptRole );
662  msgbox.addButton( tr( "Close" ), QMessageBox::RejectRole );
663  msgbox.adjustSize();
664  int sbutton = msgbox.exec();
665 qDebug() << "select button" << sbutton << "Rej(C) Acc(D)"
666  << QMessageBox::RejectRole << QMessageBox::AcceptRole;
667 
668  if ( sbutton == QMessageBox::AcceptRole )
669  {
670 QMessageBox::information( this, "DEBUG", "you clicked DETAILS" );
671  }
672 else
673 QMessageBox::information( this, "DEBUG", "you clicked CLOSE" );
674 #endif
675  lw_rpm->clearSelection();
676 }
677 
679 {
681  update( lw_triples->currentRow() );
682 }
683 
685 {
686  plotType = RPM;
687  update( lw_triples->currentRow() );
688 }
689 
691 {
692  plotType = INTERVAL;
693  update( lw_triples->currentRow() );
694 }
695 
697 {
698  plotType = COMBINED;
699  update( lw_triples->currentRow() );
700 }
701 
702 // Read any speedsteps from run xml and create speed details message
703 QString US_RunDetails2::moreSpeedInfo( double rpm )
704 {
705  QString msg = "";
706  QString runID = le_runID->text();
707  QString fname = US_Settings::resultDir() + "/" + runID + "/"
708  + runID + ".RI.xml";
709  QFile filei( fname );
710 qDebug() << " srd:mSI: rpm fname" << rpm << fname;
711  double rpm_s = 0.0;
712  double rpm_a = 0.0;
713  double rpm_d = 0.0;
714 
715  if ( filei.open( QIODevice::ReadOnly | QIODevice::Text ) )
716  {
717  QXmlStreamReader xmli( &filei );
718 
719  while ( ! xmli.atEnd() )
720  {
721  xmli.readNext();
722 qDebug() << " srd:mSI: xml name" << xmli.name();
723 
724  if ( xmli.isStartElement() && xmli.name() == "speedstep" )
725  {
726  QXmlStreamAttributes attr = xmli.attributes();
727  double rpm_x = attr.value( "rotorspeed" ).toString().toDouble();
728  QString msg = "";
729 qDebug() << " srd:mSI: rpm_x" << rpm_x;
730 
731  if ( qAbs( rpm_x - rpm ) < 200.0 )
732  {
733  rpm_s = attr.value( "set_speed" ).toString().toDouble();
734  rpm_a = attr.value( "avg_speed" ).toString().toDouble();
735  rpm_d = attr.value( "speed_stddev" ).toString().toDouble();
736 qDebug() << " srd:mSI:M: rpm_s rpm_a rpm_d" << rpm_s << rpm_a << rpm_d;
737  break;
738  }
739  }
740  }
741 
742  filei.close();
743  }
744 qDebug() << " srd:mSI: rpm_s rpm_a rpm_d" << rpm_s << rpm_a << rpm_d;
745 
746  if ( rpm_a != 0.0 )
747  {
748  int rpm_fe = qRound( rpm_a );
749  msg = tr( "\nSpeed step additional information:"
750  "\n Set Speed = %1 ;"
751  "\n Average Speed = %2 ;"
752  "\n Speed Standard Deviation = %3 ;"
753  "\n Finite Element Rotor Speed = %4 ." )
754  .arg( rpm_s ).arg( rpm_a ).arg( rpm_d ).arg( rpm_fe );
755  }
756 else
757  msg="\n*** MWL but no extended speedstep values ***";
758 
759  return msg;
760 }
761