UltraScan III
us_analysis_base2.cpp
Go to the documentation of this file.
1 
3 #include <QtSvg>
4 
5 #include "us_analysis_base2.h"
6 #include "us_settings.h"
7 #include "us_gui_settings.h"
8 #include "us_run_details2.h"
9 #include "us_analyte_gui.h"
10 #include "us_buffer_gui.h"
11 #include "us_data_loader.h"
12 #include "us_noise_loader.h"
13 #include "us_loadable_noise.h"
14 #include "us_db2.h"
15 #include "us_passwd.h"
16 #include "us_solution_vals.h"
17 #include "us_solution_gui.h"
18 #include "us_report.h"
19 
21 {
22  setPalette( US_GuiSettings::frameColor() );
23 
24  mainLayout = new QGridLayout( this );
25  mainLayout->setSpacing ( 2 );
26  mainLayout->setContentsMargins( 2, 2, 2, 2 );
27 
28  leftLayout = new QVBoxLayout();
29  rightLayout = new QVBoxLayout();
30 
31  analysisLayout = new QGridLayout();
32  runInfoLayout = new QGridLayout();
33  parameterLayout = new QGridLayout();
34  controlsLayout = new QGridLayout();
35  buttonLayout = new QHBoxLayout();
36 
37  leftLayout->addLayout( analysisLayout );
38  leftLayout->addLayout( runInfoLayout );
39  leftLayout->addLayout( parameterLayout );
40  leftLayout->addLayout( controlsLayout );
41  leftLayout->addStretch();
42  leftLayout->addLayout( buttonLayout );
43 
44  // Plots
46  tr( "Plot 1 Title" ),
47  tr( "X-Axis Title" ),
48  tr( "Y-Axis Title" ) );
49 
50  data_plot1->setMinimumSize( 600, 150 );
51 
53  tr( "Plot 2 Title" ),
54  tr( "X-Axis Title" ),
55  tr( "Y-Axis Title" ) );
56 
57  data_plot2->setMinimumSize( 600, 150 );
58 
59  rightLayout->addLayout( plotLayout1 );
60  rightLayout->addLayout( plotLayout2 );
61 
62  mainLayout->addLayout( leftLayout, 0, 0 );
63  mainLayout->addLayout( rightLayout, 0, 1 );
64  mainLayout->setColumnStretch( 0, 0 );
65  mainLayout->setColumnStretch( 1, 99 );
66 
67  // Analysis buttons
68  pb_load = us_pushbutton( tr( "Load Experiment" ) );
69  connect( pb_load, SIGNAL( clicked() ), SLOT( load() ) );
70  pb_details = us_pushbutton( tr( "Run Details" ) );
71  QLayout* lo_edlast =
72  us_checkbox( tr( "Latest Data Edit" ), ck_edlast, true );
73  connect( pb_details, SIGNAL( clicked() ), SLOT( details() ) );
74 
76 
77  pb_view = us_pushbutton( tr( "View Data Report" ) );
78  pb_save = us_pushbutton( tr( "Save Data" ) );
79 
80  pb_details->setEnabled( false );
81  pb_view ->setEnabled( false );
82  pb_save ->setEnabled( false );
83 
84  int row = 0;
85  analysisLayout->addWidget( pb_load, row, 0, 1, 1 );
86  analysisLayout->addWidget( pb_details, row++, 1, 1, 1 );
87  analysisLayout->addLayout( lo_edlast, row, 0, 1, 1 );
88  analysisLayout->addLayout( disk_controls, row++, 1, 1, 1 );
89  analysisLayout->addWidget( pb_view, row, 0, 1, 1 );
90  analysisLayout->addWidget( pb_save, row++, 1, 1, 1 );
91 
92  // Standard buttons
93  pb_reset = us_pushbutton( tr( "Reset" ) );
94  pb_help = us_pushbutton( tr( "Help" ) );
95  pb_close = us_pushbutton( tr( "Close" ) );
96 
97  buttonLayout->addWidget( pb_reset );
98  connect( pb_reset, SIGNAL( clicked() ), SLOT( reset() ) );
99  buttonLayout->addWidget( pb_help );
100  buttonLayout->addWidget( pb_close );
101  connect( pb_close, SIGNAL( clicked() ), SLOT( close() ) );
102 
103  // Run info
104  QLabel* lb_info = us_banner( tr( "Information for this Run" ) );
105  QLabel* lb_triples = us_banner( tr( "Cell / Channel / Wavelength" ) );
106  QLabel* lb_id = us_label ( tr( "Run ID / Edit ID:" ) );
107  QLabel* lb_temp = us_label ( tr( "Avg Temperature:" ) );
108 
109  le_id = us_lineedit( "", 0, true );
110  le_temp = us_lineedit( "", 0, true );
111 
112  te_desc = us_textedit();
114 
115  QFont font( US_GuiSettings::fontFamily(),
117  QFontMetrics fm ( font );
118 
119  int fontHeight = fm.lineSpacing();
120 
121  te_desc ->setMaximumHeight( fontHeight * 2 + 12 ); // Add for border
122  lw_triples->setMaximumHeight( fontHeight * 6 + 12 );
123 
124  us_setReadOnly( te_desc, true );
125 
126  row = 0;
127  runInfoLayout->addWidget( lb_info , row++, 0, 1, 2 );
128  runInfoLayout->addWidget( lb_id , row, 0 );
129  runInfoLayout->addWidget( le_id , row++, 1 );
130  runInfoLayout->addWidget( lb_temp , row, 0 );
131  runInfoLayout->addWidget( le_temp , row++, 1 );
132  runInfoLayout->addWidget( te_desc , row, 0, 2, 2 );
133  row += 2;
134  runInfoLayout->addWidget( lb_triples, row++, 0, 1, 2 );
135  runInfoLayout->addWidget( lw_triples, row++, 0, 4, 2 );
136 
137  // Parameters
138 
139  pb_solution = us_pushbutton( tr( "Solution" ) );
140  connect( pb_solution, SIGNAL( clicked() ), SLOT( get_solution() ) );
141 
142  QLabel* lb_density = us_label( tr( "Density (20" ) + DEGC + ")" );
143  QLabel* lb_viscosity = us_label( tr( "Viscosity (20" ) + DEGC + ")" );
144  QLabel* lb_vbar = us_label( tr( "Vbar (20" ) + DEGC + ")" );
145  QLabel* lb_skipped = us_label( tr( "Skipped:" ) );
146 
147  density = DENS_20W;
149  vbar = TYPICAL_VBAR;
150  manual = false;
151 
152  le_solution = us_lineedit( tr( "(Experiment's solution)" ), 0, true );
153  le_density = us_lineedit( QString::number( density, 'f', 6 ), 0, true );
154  le_viscosity = us_lineedit( QString::number( viscosity, 'f', 5 ), 0, true );
155  le_vbar = us_lineedit( QString::number( vbar, 'f', 5 ), 0, true );
156  le_skipped = us_lineedit( "0", 0, true );
157 
158  pb_solution ->setEnabled ( false );
159 
160  row = 0;
161  parameterLayout->addWidget( pb_solution , row, 0 );
162  parameterLayout->addWidget( le_solution , row++, 1, 1, 3 );
163  parameterLayout->addWidget( lb_density , row, 0 );
164  parameterLayout->addWidget( le_density , row, 1 );
165  parameterLayout->addWidget( lb_viscosity, row, 2 );
166  parameterLayout->addWidget( le_viscosity, row++, 3 );
167  parameterLayout->addWidget( lb_vbar , row, 0 );
168  parameterLayout->addWidget( le_vbar , row, 1 );
169  parameterLayout->addWidget( lb_skipped , row, 2 );
170  parameterLayout->addWidget( le_skipped , row++, 3 );
171 
172  // Analysis Controls
173  QLabel* lb_analysis = us_banner( tr( "Analysis Controls" ) );
174  QLabel* lb_smoothing = us_label ( tr( "Data Smoothing:" ) );
175  QLabel* lb_boundPercent = us_label ( tr( "% of Boundary:" ) );
176  QLabel* lb_boundPos = us_label ( tr( "Boundary Pos. (%):" ) );
177 
178  QLabel* lb_from = us_label ( tr( "Scan focus from:" ) );
179  QLabel* lb_to = us_label ( tr( "to:" ) );
180 
181  pb_exclude = us_pushbutton( tr( "Exclude Scan Range" ) );
182  pb_exclude->setEnabled( false );
183  connect( pb_exclude, SIGNAL( clicked() ), SLOT( exclude() ) );
184 
185  pb_reset_exclude = us_pushbutton( tr( "Reset Scan Range" ) );
186  pb_reset_exclude->setEnabled( false );
187  connect( pb_reset_exclude, SIGNAL( clicked() ), SLOT( reset_excludes() ) );
188 
189  ct_smoothing = us_counter( 2, 1, 50, 1 );
190  ct_smoothing->setStep( 1.0 );
191  connect( ct_smoothing, SIGNAL( valueChanged( double ) ),
192  SLOT ( smoothing ( double ) ) );
193 
194  ct_boundaryPercent = us_counter( 3, 10, 100, 90 );
195  ct_boundaryPos = us_counter( 3, 0, 10, 5 );
196  ct_boundaryPercent->setStep( 0.1 );
197  ct_boundaryPos ->setStep( 0.1 );
198  connect( ct_boundaryPercent, SIGNAL( valueChanged( double ) ),
199  SLOT ( boundary_pct( double ) ) );
200  connect( ct_boundaryPos, SIGNAL( valueChanged( double ) ),
201  SLOT ( boundary_pos( double ) ) );
202 
203  ct_from = us_counter( 3, 0, 0 );
204  ct_to = us_counter( 3, 0, 0 );
205 
206  connect( ct_from, SIGNAL( valueChanged( double ) ),
207  SLOT ( exclude_from( double ) ) );
208  connect( ct_to, SIGNAL( valueChanged( double ) ),
209  SLOT ( exclude_to ( double ) ) );
210 
211  row = 0;
212  controlsLayout->addWidget( lb_from , row, 0, 1, 1 );
213  controlsLayout->addWidget( ct_from , row++, 1, 1, 1 );
214  controlsLayout->addWidget( lb_to , row, 0, 1, 1 );
215  controlsLayout->addWidget( ct_to , row++, 1, 1, 1 );
216  controlsLayout->addWidget( pb_exclude , row, 0, 1, 1 );
217  controlsLayout->addWidget( pb_reset_exclude , row++, 1, 1, 1 );
218  controlsLayout->addWidget( lb_analysis , row++, 0, 1, 2 );
219  controlsLayout->addWidget( lb_smoothing , row, 0, 1, 1 );
220  controlsLayout->addWidget( ct_smoothing , row++, 1, 1, 1 );
221  controlsLayout->addWidget( lb_boundPercent , row, 0, 1, 1 );
222  controlsLayout->addWidget( ct_boundaryPercent, row++, 1, 1, 1 );
223  controlsLayout->addWidget( lb_boundPos , row, 0, 1, 1 );
224  controlsLayout->addWidget( ct_boundaryPos , row++, 1, 1, 1 );
225 
226  dataLoaded = false;
227  buffLoaded = false;
228 
229  dfilter = "";
230  etype_filt = "velocity";
231 
232  setMaximumSize( qApp->desktop()->size() - QSize( 60, 60 ) );
233  reset();
234 //qDebug() << "AB2: desktop size" << qApp->desktop()->size();
235 //qDebug() << "AB2: max main size" << maximumSize();
236 }
237 
239 {
240  ( db ) ? disk_controls->set_db() : disk_controls->set_disk();
241 }
242 
244 {
245  // Determine the edit ID
246  dataLoaded = false;
247  dataList .clear();
248  rawList .clear();
249  excludedScans.clear();
250  triples .clear();
251  savedValues .clear();
252 
253  lw_triples->disconnect();
254  lw_triples->clear();
255  ct_from ->disconnect();
256  ct_from ->setValue( 0 );
257 
258 
259  bool edlast = ck_edlast->isChecked();
260  int dbdisk = ( disk_controls->db() ) ? US_Disk_DB_Controls::DB
262  QString description;
263 
264  US_DataLoader* dialog = new US_DataLoader(
265  edlast, dbdisk, rawList, dataList, triples, description, etype_filt );
266 
267  connect( dialog, SIGNAL( changed( bool ) ), SLOT( update_disk_db( bool ) ) );
268  connect( dialog, SIGNAL( progress ( const QString ) ),
269  SLOT ( set_progress( const QString ) ) );
270 
271  if ( dialog->exec() != QDialog::Accepted ) return;
272 
273  if ( disk_controls->db() )
274  directory = tr( "(database)" );
275 
276  else
277  {
278  directory = description.section( description.left( 1 ), 4, 4 );
279  directory = directory.left( directory.lastIndexOf( "/" ) );
280  }
281 
282  for ( int ii=0; ii < triples.size(); ii++ )
283  lw_triples->addItem( triples.at( ii ) );
284 
285  int nscans = dataList[ 0 ].scanCount();
286 
287  // Save original readings values for each scan
288  for ( int ii = 0; ii < nscans; ii++ )
289  savedValues << dataList[ 0 ].scanData[ ii ].rvalues;
290 
291  noiflags.fill( -1, dataList.size() );
292  allExcls.fill( excludedScans, dataList.size() );
293  rinoises.fill( US_Noise(), dataList.size() );
294  tinoises.fill( US_Noise(), dataList.size() );
295 
296  connect( lw_triples, SIGNAL( currentRowChanged( int ) ),
297  SLOT ( new_triple ( int ) ) );
298  lw_triples->setCurrentRow( 0 );
299 
300  // Enable other buttons
301  pb_solution->setEnabled( true );
302  pb_details ->setEnabled( true );
303  pb_view ->setEnabled( true );
304  pb_save ->setEnabled( true );
305  pb_exclude ->setEnabled( true );
306 
307  connect( ct_from, SIGNAL( valueChanged( double ) ),
308  SLOT ( exclude_from( double ) ) );
309 
310  dataLoaded = true;
311  emit dataAreLoaded();
312  qApp->processEvents();
313 }
314 
315 void US_AnalysisBase2::update( int selection )
316 {
317  US_DataIO::EditedData* d = &dataList[ selection ];
318  int scanCount = d->scanData.size();
319  runID = d->runID;
320  le_id->setText( runID + " / " + d->editID );
321 
322  double avTemp = d->average_temperature();
323 
324  le_temp->setText( QString::number( avTemp, 'f', 1 ) + " " + DEGC );
325 
326  te_desc->setText( d->description );
327 
328  excludedScans = allExcls[ selection ];
329 
330  ct_from->setMaxValue( scanCount - excludedScans.size() );
331  ct_from->setStep( 1.0 );
332  ct_to ->setMaxValue( scanCount - excludedScans.size() );
333  ct_to ->setStep( 1.0 );
334 
335  // Set up solution/buffer values implied from experimental data
336  QString solID;
337  QString bufID;
338  QString bguid;
339  QString bdesc;
340  QString bdens = le_density ->text();
341  QString bvisc = le_viscosity->text();
342  QString svbar = le_vbar ->text();
343  QString bcomp = "";
344  QString bmanu = "0";
345  QString errmsg = "";
346  US_Passwd pw;
347  US_DB2* dbP = ( disk_controls->db() ) ?
348  new US_DB2( pw.getPasswd() ) : 0;
349 
350  bool bufin = US_SolutionVals::values( dbP, d, solID, svbar, bdens,
351  bvisc, bcomp, bmanu, errmsg );
352 
353  if ( bufin )
354  {
355  buffLoaded = false;
356 
357  le_density ->setText( bdens );
358  le_viscosity->setText( bvisc );
359  density = bdens.toDouble();
360  viscosity = bvisc.toDouble();
361  manual = ( !bmanu.isEmpty() && bmanu == "1" );
362  buffLoaded = true;
364 
365  if ( solID.isEmpty() )
366  {
367  QMessageBox::warning( this, tr( "Solution/Buffer Values Fetch" ),
368  tr( "Empty solution ID value!" ) );
369  }
370 
371  else if ( solID.length() < 36 && dbP != NULL )
372  { // Have DB solution ID
373  solution_rec.readFromDB( solID.toInt(), dbP );
374  }
375 
376  else
377  { // Have Local solution GUID
378  solution_rec.readFromDisk( solID );
379  }
380 
383  svbar = QString::number( vbar );
384  le_vbar ->setText( svbar );
385  }
386 
387  else
388  {
389  QMessageBox::warning( this, tr( "Solution/Buffer Values Fetch" ),
390  errmsg );
392  le_solution ->setText( tr( "( ***Undefined*** )" ) );
393  }
394 
395  if ( dbP != NULL )
396  {
397  delete dbP;
398  }
399 
400  data_plot();
401 }
402 
403 // Report data set details
405 {
406  US_RunDetails2* dialog
408  dialog->exec();
409  qApp->processEvents();
410  delete dialog;
411 }
412 
414 {
415  int row = lw_triples->currentRow();
416  US_DataIO::EditedData* d = &dataList[ row ];
417 
418  QString dataType = tr( "Absorbance" );
419  if ( d->dataType == "RI" ) dataType = tr( "Intensity" );
420  if ( d->dataType == "WI" ) dataType = tr( "Intensity" );
421  if ( d->dataType == "IP" ) dataType = tr( "Interference" );
422  if ( d->dataType == "FI" ) dataType = tr( "Fluorescence" );
423 
424  QString header = tr( "Velocity Data for\n") + d->runID + " ("
425  + d->cell + "/" + d->channel + "/" + d->wavelength + ")";
426  data_plot2->setTitle( header );
427 
428  header = dataType + tr( " at " ) + d->wavelength + tr( " nm" );
429  data_plot2->setAxisTitle( QwtPlot::yLeft, header );
430 
431  header = tr( "Radius (cm) " );
432  data_plot2->setAxisTitle( QwtPlot::xBottom, header );
433 
434  data_plot2->clear();
435  us_grid( data_plot2 );
436 
437  int scan_number = 0;
438  int from = (int)ct_from->value();
439  int to = (int)ct_to ->value();
440 
441  int scanCount = d->scanCount();
442  int points = d->pointCount();
443  double boundaryPct = ct_boundaryPercent->value() / 100.0;
444  boundaryPct = ct_boundaryPercent->isEnabled() ? boundaryPct : 9.0;
445  double positionPct = ct_boundaryPos ->value() / 100.0;
446  double baseline = calc_baseline();
447 
448  QVector< double > rvec( points );
449  QVector< double > vvec( points );
450  double* r = rvec.data();
451  double* v = vvec.data();
452 
453  // Calculate basic parameters for other functions
455 
456  solution.density = le_density ->text().toDouble();
457  solution.viscosity = le_viscosity->text().toDouble();
458  solution.vbar20 = le_vbar ->text().toDouble();
460  double avgTemp = d->average_temperature();
462 
464 
465  // Draw curves
466  for ( int i = 0; i < scanCount; i++ )
467  {
468  if ( excludedScans.contains( i ) ) continue;
469 
470  scan_number++;
471  bool highlight = scan_number >= from && scan_number <= to;
472 
473  US_DataIO::Scan* s = &d->scanData[ i ];
474 
475  double range = s->plateau - baseline;
476  double lower_limit = baseline + range * positionPct;
477  double upper_limit = lower_limit + range * boundaryPct;
478 
479  int j = 0;
480  int count = 0;
481 
482  // Plot each scan in (up to) three segments: below, in, and above
483  // the specified boundaries
484  while ( j < points && s->rvalues[ j ] < lower_limit )
485  {
486  r[ count ] = d->xvalues[ j ];
487  v[ count ] = s->rvalues[ j ];
488  j++;
489  count++;
490  }
491 
492  QString title;
493  QwtPlotCurve* c;
494 
495  if ( count > 1 )
496  {
497  title = tr( "Curve " ) + QString::number( i ) + tr( " below range" );
498  c = us_curve( data_plot2, title );
499 
500  if ( highlight )
501  c->setPen( QPen( Qt::red ) );
502  else
503  c->setPen( QPen( Qt::cyan ) );
504 
505  c->setData( r, v, count );
506  }
507 
508  count = 0;
509 
510  while ( j < points && s->rvalues[ j ] < upper_limit )
511  {
512  r[ count ] = d->xvalues[ j ];
513  v[ count ] = s->rvalues[ j ];
514  j++;
515  count++;
516  }
517 
518  if ( count > 1 )
519  {
520  title = tr( "Curve " ) + QString::number( i ) + tr( " in range" );
521  c = us_curve( data_plot2, title );
522 
523  if ( highlight )
524  c->setPen( QPen( Qt::red ) );
525  else
526  c->setPen( QPen( US_GuiSettings::plotCurve() ) );
527 
528  c->setData( r, v, count );
529  }
530 
531  count = 0;
532 
533  while ( j < points )
534  {
535  r[ count ] = d->xvalues[ j ];
536  v[ count ] = s->rvalues[ j ];
537  j++;
538  count++;
539  }
540 
541  if ( count > 1 )
542  {
543  title = tr( "Curve " ) + QString::number( i ) + tr( " above range" );
544  c = us_curve( data_plot2, title );
545 
546  if ( highlight )
547  c->setPen( QPen( Qt::red ) );
548  else
549  c->setPen( QPen( Qt::cyan ) );
550 
551  c->setData( r, v, count );
552  }
553  }
554 
555  data_plot2->replot();
556 
557  return;
558 }
559 
560 void US_AnalysisBase2::boundary_pct( double percent )
561 {
562  ct_boundaryPos->disconnect();
563  ct_boundaryPos->setMaxValue( 100.0 - percent );
564 
565  ct_boundaryPos->setValue( ( 100.0 - percent ) / 2.0 );
566 
567  connect( ct_boundaryPos, SIGNAL( valueChanged( double ) ),
568  SLOT ( boundary_pos( double ) ) );
569  data_plot();
570 }
571 
572 void US_AnalysisBase2::boundary_pos( double percent )
573 {
574  ct_boundaryPercent->disconnect();
575  ct_boundaryPercent->setMaxValue( 100.0 - percent );
576 
577  connect( ct_boundaryPercent, SIGNAL( valueChanged( double ) ),
578  SLOT ( boundary_pct( double ) ) );
579  data_plot();
580 }
581 
583 {
584  double to = ct_to->value();
585 
586  if ( to < from )
587  {
588  ct_to->disconnect();
589  ct_to->setValue( from );
590 
591  connect( ct_to, SIGNAL( valueChanged( double ) ),
592  SLOT ( exclude_to ( double ) ) );
593  }
594 
595  data_plot();
596 }
597 
599 {
600  double from = ct_from->value();
601 
602  if ( from > to )
603  {
604  ct_from->disconnect();
605  ct_from->setValue( to );
606 
607  connect( ct_from, SIGNAL( valueChanged( double ) ),
608  SLOT ( exclude_from( double ) ) );
609  }
610 
611  data_plot();
612 }
613 
615 {
616  double from = ct_from->value();
617  double to = ct_to ->value();
618 
619  int displayedScan = 1;
620  int index = lw_triples->currentRow();
621  US_DataIO::EditedData* d = &dataList[ index ];
622  int totalScans = d->scanData.size();
623 
624  for( int i = 0; i < totalScans; i++ )
625  {
626  if ( excludedScans.contains( i ) ) continue;
627 
628  if ( displayedScan >= from && displayedScan <= to ) excludedScans << i;
629 
630  displayedScan++;
631  }
632 
633  ct_to->setValue( 0 ); // Resets both counters and replots
634 
635  ct_from->setMaxValue( totalScans - excludedScans.size() );
636  ct_to ->setMaxValue( totalScans - excludedScans.size() );
637 
638  allExcls[ index ] = excludedScans;
639  pb_reset_exclude->setEnabled( true );
640 }
641 
643 {
644  int index = lw_triples->currentRow();
645  US_DataIO::EditedData* d = &dataList[ index ];
646  int totalScans = d->scanData.size();
647 
648  excludedScans.clear();
649  le_skipped->setText( "0" );
650 
651  ct_from->setMaxValue( totalScans );
652  ct_to ->setMaxValue( totalScans );
653 
654  if ( ct_to->value() != 0 )
655  ct_to ->setValue( 0 );
656  else
657  data_plot();
658 
659  pb_reset_exclude->setEnabled( false );
660  allExcls[ index ] = excludedScans;
661 }
662 
663 void US_AnalysisBase2::smoothing( double smoothCount )
664 {
665  if ( ! dataLoaded ) return;
666 
667  int smoothPoints = (int) smoothCount;
668 
669  // Restore saved data
670  int index = lw_triples->currentRow();
671  US_DataIO::EditedData* dat = &dataList[ index ];
672 
673  for ( int ii = 0; ii < dat->scanCount(); ii++ )
674  dat->scanData[ ii ].rvalues = savedValues[ ii ];
675 
676  // Smooth the data
677  if ( smoothPoints > 1 )
678  {
679  QVector< double > xwvec( smoothPoints );
680  QVector< double > ywvec( smoothPoints );
681  x_weights = xwvec.data();
682  y_weights = ywvec.data();
683 
684  // Divide the count into 2 standard deviations
685  double increment = 2.0 / smoothCount;
686  int scanPoints = dat->pointCount();
687 
688  // Only calculate half a Gaussian curve, since the other side is symmetric
689  for ( int jj = 0; jj < smoothPoints; jj++ )
690  {
691  x_weights[ jj ] = increment * jj;
692 
693  // Use a standard deviation of 0.7 to narrow the spread and multiply
694  // by 0.7 to scale the result as an empirical weighting factor
695 
696  // Standard deviation = 0.7, mean = 0.0, point = 0.0;
697  y_weights[ jj ] =
698  0.7 * US_Math2::normal_distribution( 0.7, 0.0, x_weights[ jj ] );
699  }
700 
701  // For each scan
702  for ( int ii = 0; ii < dat->scanData.size(); ii++ )
703  {
704  US_DataIO::Scan* scn = &dat->scanData[ ii ];
705 
706  // Loop over all border point centers
707  for ( int jj = 0; jj < smoothPoints; jj++ )
708  {
709  scn->rvalues[ jj ] = smooth_point( ii, jj, -1, smoothPoints );
710  }
711 
712  // Now deal with all non-border points
713  for ( int jj = smoothPoints; jj < scanPoints - smoothPoints - 1; jj++ )
714  {
715  scn->rvalues[ jj ] = smooth_point( ii, jj, 0, smoothPoints );
716  }
717 
718  // Finally the points on the right border
719  for ( int jj = scanPoints - smoothPoints - 1; jj < scanPoints; jj++ )
720  {
721  scn->rvalues[ jj ]
722  = smooth_point( ii, jj, 1, smoothPoints, scanPoints );
723  }
724  } // END: scan loop
725 
726  } // END: smoothPoints > 1
727 
728  data_plot();
729 }
730 
732  int scan, int point, int type, int smoothPoints, int scanPoints )
733 {
734  // type == 0 means no reflection
735  // type == 1 means to reflect on the right
736  // type == -1 means to reflect on the left
737 
738  double sum = 0.0;
739  double sum_y = 0.0;
740  int start;
741  int stop;
742  int direction;
743 
744  // Sum all applicable points left of center
745  if ( type == -1 ) // reflect left
746  {
747  start = point + 1;
748  stop = point + smoothPoints;
749  direction = 1;
750  }
751  else
752  {
753  start = point - 1;
754  stop = point - smoothPoints;
755  direction = -1;
756  }
757 
758  // This is a bit complex because the test for leaving the loop
759  // is different if we are incrementing or decrementing.
760 
761  int position = 0;
762  int k = start;
763 
764  while ( true )
765  {
766  position++;
767  double value = savedValues[ scan ][ k ];
768 
769  if ( type == -1 )
770  {
771  if ( point - position < 0 ) // we need a reflected value
772  {
773  double dy = savedValues[ scan ][ k ] - savedValues[ scan ][ point ];
774  value = savedValues[ scan ][ point ] - dy;
775  }
776  else
777  value = savedValues[ scan ][ point - position ];
778  }
779 
780  sum += value * y_weights[ position ];
781  sum_y += y_weights[ position ];
782 
783  if ( type == -1 )
784  {
785  if ( k > stop ) break;
786  }
787  else
788  {
789  if ( k <= stop ) break;
790  }
791 
792  k += direction;
793  }
794 
795  // Add the center point
796  sum += savedValues[ scan ][ point ] * y_weights[ 0 ];
797  sum_y += y_weights[ 0 ];
798 
799  // Sum all applicable points right of center
800  if ( type == 1 ) // reflect right
801  {
802  start = point - 1;
803  stop = point - smoothPoints;
804  direction = -1;
805  }
806  else
807  {
808  start = point + 1;
809  stop = point + smoothPoints;
810  direction = 1;
811  }
812 
813  position = 0;
814  k = start;
815 
816  while( true )
817  {
818  position++;
819  double value = savedValues[ scan ][ k ];
820 
821  if ( type == 1 )
822  {
823  if ( point + position >= scanPoints ) // Need reflection
824  {
825  double dy = savedValues[ scan ][ k ]
826  - savedValues[ scan ][ point ];
827  value = savedValues[ scan ][ point ] - dy;
828  }
829  else
830  value = savedValues[ scan ][ point + position ];
831  }
832 
833  sum += value * y_weights[ position ];
834  sum_y += y_weights[ position ];
835 
836  if ( type == 1 )
837  {
838  if ( k <= stop ) break;
839  }
840  else
841  {
842  if ( k > stop ) break;
843  }
844 
845  k += direction;
846  }
847 
848  // Normalize by the sum of all weights that were used
849  return sum / sum_y;
850 }
851 
853 {
854  if ( ! dataLoaded ) return;
855 
856  excludedScans.clear();
857 
858  int index = lw_triples->currentRow();
859  density = DENS_20W;
861  vbar = TYPICAL_VBAR;
862  manual = false;
863 
864  le_density ->setText( QString::number( density, 'f', 6 ) );
865  le_viscosity->setText( QString::number( viscosity, 'f', 5 ) );
866  le_vbar ->setText( QString::number( vbar, 'f', 5 ) );
867  le_skipped ->setText( "0" );
868 
869  // Restore saved data
870  if ( dataList.size() > 0 )
871  {
872  US_DataIO::EditedData* dat = &dataList[ index ];
873 
874  for ( int ii = 0; ii < dat->scanData.size(); ii++ )
875  {
876  dat->scanData[ ii ].rvalues = savedValues[ ii ];
877  }
878  }
879 
880  ct_from ->disconnect();
881  ct_to ->disconnect();
882  ct_smoothing ->disconnect();
883  ct_boundaryPercent->disconnect();
884  ct_boundaryPos ->disconnect();
885 
886  ct_from ->setValue( 0 );
887  ct_to ->setValue( 0 );
888  ct_smoothing ->setValue( 1 );
889  ct_boundaryPercent->setValue( 90 );
890  ct_boundaryPos ->setValue( 5 );
891 
892  connect( ct_from, SIGNAL( valueChanged( double ) ),
893  SLOT ( exclude_from( double ) ) );
894 
895  connect( ct_to, SIGNAL( valueChanged( double ) ),
896  SLOT ( exclude_to ( double ) ) );
897 
898  connect( ct_boundaryPercent, SIGNAL( valueChanged( double ) ),
899  SLOT ( boundary_pct( double ) ) );
900 
901  connect( ct_boundaryPos, SIGNAL( valueChanged( double ) ),
902  SLOT ( boundary_pos( double ) ) );
903 
904  connect( ct_smoothing, SIGNAL( valueChanged( double ) ),
905  SLOT ( smoothing ( double ) ) );
906 
907  allExcls[ index ] = excludedScans;
908 
909  update( index );
910 }
911 
913 {
914  // Save the data for the new triple
915  US_DataIO::EditedData* dat = &dataList[ index ];
916 
917  // Test for noise data to substract from the experiment; apply if any
918  load_noise( index );
919 
920  savedValues.clear();
921 
922  for ( int ii = 0; ii < dat->scanCount(); ii++ )
923  {
924  savedValues << dat->scanData[ ii ].rvalues;
925  }
926 
927  // Update GUI elements and plot for selected triple
928  update( index );
929 
930  // Make sure we have a reports directory for this runID
931  QString repdir = US_Settings::reportDir() + "/" + dat->runID;
932  QDir dir;
933  if ( ! dir.exists( repdir ) ) dir.mkpath( repdir );
934 }
935 
937 {
938  int row = lw_triples->currentRow();
939  const US_DataIO::Scan*
940  scan = &dataList[ row ].scanData.last();
941  int point = US_DataIO::index( dataList[ row ].xvalues,
942  dataList[ row ].baseline );
943  point = ( point < 5 ) ? 5 : point;
944  double sum = 0.0;
945 
946  for ( int j = point - 5; j < point + 6; j++ )
947  sum += scan->rvalues[ j ];
948 
949  return sum / 11.0;
950 }
951 
952 // String to accomplish line identation
953 QString US_AnalysisBase2::indent( const int spaces ) const
954 {
955  return QString( " " ).leftJustified( spaces, ' ' );
956 }
957 
958 // Table row HTML with 2 columns
959 QString US_AnalysisBase2::table_row( const QString& s1, const QString& s2 ) const
960 {
961  return ( indent( 6 ) + "<tr><td>" + s1 + "</td><td>" + s2 + "</td></tr>\n" );
962 }
963 
964 // Table row HTML with 3 columns
965 QString US_AnalysisBase2::table_row( const QString& s1, const QString& s2,
966  const QString& s3 ) const
967 {
968  return ( indent( 6 ) + "<tr><td>" + s1 + "</td><td>" + s2 + "</td><td>"
969  + s3 + "</td></tr>\n" );
970 }
971 
972 // Table row HTML with 5 columns
973 QString US_AnalysisBase2::table_row( const QString& s1, const QString& s2,
974  const QString& s3, const QString& s4,
975  const QString& s5 ) const
976 {
977  return ( indent( 6 ) + "<tr><td>" + s1 + "</td><td>" + s2 + "</td><td>"
978  + s3 + "</td><td>" + s4 + "</td><td>" + s5 + "</td></tr>\n" );
979 }
980 
981 // Table row HTML with 7 columns
982 QString US_AnalysisBase2::table_row( const QString& s1, const QString& s2,
983  const QString& s3, const QString& s4,
984  const QString& s5, const QString& s6,
985  const QString& s7 ) const
986 {
987  return ( indent( 6 ) + "<tr><td>" + s1 + "</td><td>" + s2 + "</td><td>"
988  + s3 + "</td><td>" + s4 + "</td><td>" + s5 + "</td><td>"
989  + s6 + "</td><td>" + s7 + "</td></tr>\n" );
990 }
991 
992 // Compose HTML header string
993 QString US_AnalysisBase2::html_header( const QString& title,
994  const QString& head1, US_DataIO::EditedData* edata ) const
995 {
996  QString ss = QString( "<?xml version=\"1.0\"?>\n" );
997  ss += "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
998  ss += " \"http://www.w3.org/TR/xhtml1/DTD"
999  "/xhtml1-strict.dtd\">\n";
1000  ss += "<html xmlns=\"http://www.w3.org/1999/xhtml\""
1001  " xml:lang=\"en\" lang=\"en\">\n";
1002  ss += " <head>\n";
1003  ss += " <title> " + title + " </title>\n";
1004  ss += " <meta http-equiv=\"Content-Type\" content="
1005  "\"text/html; charset=iso-8859-1\"/>\n";
1006  ss += " <style type=\"text/css\" >\n";
1007  ss += " td { padding-right: 1em; }\n";
1008  ss += " body { background-color: white; }\n";
1009  ss += " </style>\n";
1010  ss += " </head>\n <body>\n";
1011  ss += " <h1>" + head1 + "</h1>\n";
1012  ss += indent( 4 ) + tr( "<h2>Data Report for Run \"" ) + edata->runID;
1013  ss += "\",<br/>\n" + indent( 4 ) + "&nbsp;" + tr( " Cell " ) + edata->cell;
1014  ss += tr( ", Channel " ) + edata->channel;
1015  ss += tr( ", Wavelength " ) + edata->wavelength;
1016  ss += ",<br/>\n" + indent( 4 ) + "&nbsp;" + tr( " Edited Dataset " );
1017  ss += edata->editID + "</h2>\n";
1018 
1019  return ss;
1020 }
1021 
1022 QString US_AnalysisBase2::run_details( void ) const
1023 {
1024  int index = lw_triples->currentRow();
1025  const US_DataIO::EditedData* d = &dataList[ index ];
1026 
1027  QString s = "\n" + indent( 4 )
1028  + tr( "<h3>Detailed Run Information:</h3>\n" )
1029  + indent( 4 ) + "<table>\n"
1030  + table_row( tr( "Cell Description:" ), d->description )
1031  + table_row( tr( "Data Directory:" ), directory )
1032  + table_row( tr( "Rotor Speed:" ),
1033  QString::number( (int)d->scanData[ 0 ].rpm ) + " rpm" );
1034 
1035  // Temperature data
1036  double sum = 0.0;
1037  double maxTemp = -1.0e99;
1038  double minTemp = 1.0e99;
1039 
1040  for ( int i = 0; i < d->scanData.size(); i++ )
1041  {
1042  double t = d->scanData[ i ].temperature;
1043  sum += t;
1044  maxTemp = max( maxTemp, t );
1045  minTemp = min( minTemp, t );
1046  }
1047 
1048  QString average = QString::number( sum / d->scanData.size(), 'f', 1 );
1049 
1050  s += table_row( tr( "Average Temperature:" ), average + " " + MLDEGC );
1051 
1052  if ( maxTemp - minTemp <= US_Settings::tempTolerance() )
1053  s += table_row( tr( "Temperature Variation:" ), tr( "Within tolerance" ) );
1054  else
1055  s += table_row( tr( "Temperature Variation:" ),
1056  tr( "(!) OUTSIDE TOLERANCE (!)" ) );
1057 
1058  // Time data
1059  int minutes = (int)time_correction / 60;
1060  int seconds = (int)time_correction % 60;
1061 
1062  QString m = ( minutes == 1 ) ? tr( " minute " ) : tr( " minutes " );
1063  QString sec = ( seconds == 1 ) ? tr( " second" ) : tr( " seconds" );
1064 
1065  s += table_row( tr( "Time Correction:" ),
1066  QString::number( minutes ) + m +
1067  QString::number( seconds ) + sec );
1068 
1069  double duration = rawList.last().scanData.last().seconds;
1070 
1071  int hours = (int) duration / 3600;
1072  minutes = (int) duration / 60 - hours * 60;
1073  seconds = (int) duration % 60;
1074  QString dataType = tr( "Absorbance:" );
1075  if ( d->dataType == "RI" ) dataType = tr( "Intensity:" );
1076  if ( d->dataType == "WI" ) dataType = tr( "Intensity:" );
1077  if ( d->dataType == "IP" ) dataType = tr( "Interference:" );
1078  if ( d->dataType == "FI" ) dataType = tr( "Fluorescence:" );
1079 
1080  QString h;
1081  h = ( hours == 1 ) ? tr( " hour " ) : tr( " hours " );
1082  m = ( minutes == 1 ) ? tr( " minute " ) : tr( " minutes " );
1083  sec = ( seconds == 1 ) ? tr( " second" ) : tr( " seconds" );
1084 
1085  s += table_row( tr( "Run Duration:" ),
1086  QString::number( hours ) + h +
1087  QString::number( minutes ) + m +
1088  QString::number( seconds ) + sec );
1089 
1090  // Wavelength, baseline, meniscus, range
1091  s += table_row( tr( "Wavelength:" ), d->wavelength + " nm" ) +
1092  table_row( tr( "Baseline " ) + dataType,
1093  QString::number( calc_baseline(), 'f', 6 ) + " OD" ) +
1094  table_row( tr( "Meniscus Position:" ),
1095  QString::number( d->meniscus, 'f', 3 ) + " cm" );
1096 
1097  int rrx = d->xvalues.size() - 1;
1098  double left = d->xvalues[ 0 ];
1099  double right = d->xvalues[ rrx ];
1100 
1101  s += table_row( tr( "Edited Data starts at:" ),
1102  QString::number( left, 'f', 3 ) + " cm" ) +
1103  table_row( tr( "Edited Data stops at:" ),
1104  QString::number( right, 'f', 3 ) + " cm" );
1105  s += indent( 4 ) + "</table>\n";
1106  return s;
1107 }
1108 
1109 QString US_AnalysisBase2::hydrodynamics( void ) const
1110 {
1111  // Set up hydrodynamics values
1113  solution.vbar20 = le_vbar ->text().toDouble();
1114  solution.density = le_density ->text().toDouble();
1115  solution.viscosity = le_viscosity->text().toDouble();
1116  solution.manual = manual;
1117  double avgTemp = le_temp ->text().section( " ", 0, 0 ).toDouble();
1118  solution.vbar = US_Math2::calcCommonVbar( (US_Solution&)solution_rec, avgTemp );
1119  US_Math2::data_correction( avgTemp, solution );
1120 
1121  QString s = "\n" + indent( 4 ) + tr( "<h3>Hydrodynamic Settings:</h3>\n" )
1122  + indent( 4 ) + "<table>\n";
1123 
1124  s += table_row( tr( "Viscosity corrected:" ),
1125  QString::number( solution.viscosity, 'f', 5 ) ) +
1126  table_row( tr( "Viscosity (absolute):" ),
1127  QString::number( solution.viscosity_tb, 'f', 5 ) ) +
1128  table_row( tr( "Density corrected:" ),
1129  QString::number( solution.density, 'f', 6 ) + " g/ccm" ) +
1130  table_row( tr( "Density (absolute):" ),
1131  QString::number( solution.density_tb, 'f', 6 ) + " g/ccm" ) +
1132  table_row( tr( "Vbar:" ),
1133  QString::number( solution.vbar, 'f', 4 ) + " ccm/g" ) +
1134  table_row( tr( "Vbar corrected for 20 " ) + MLDEGC + ":",
1135  QString::number( solution.vbar20, 'f', 4 ) + " ccm/g" ) +
1136  table_row( tr( "Buoyancy (Water, 20 " ) + MLDEGC + "):",
1137  QString::number( solution.buoyancyw, 'f', 6 ) ) +
1138  table_row( tr( "Buoyancy (absolute):" ),
1139  QString::number( solution.buoyancyb, 'f', 6 ) ) +
1140  table_row( tr( "Correction Factor (s):" ),
1141  QString::number( solution.s20w_correction, 'f', 6 ) ) +
1142  table_row( tr( "Correction Factor (D):" ),
1143  QString::number( solution.D20w_correction, 'f', 6 ) ) +
1144  indent( 4 ) + "</table>\n";
1145 
1146  return s;
1147 }
1148 
1149 QString US_AnalysisBase2::analysis( const QString& extra ) const
1150 {
1151  QString s = "\n" + indent( 4 ) + tr( "<h3>Data Analysis Settings:</h3>\n" )
1152  + indent( 4 ) + "<table>\n";
1153 
1154  s += table_row( tr( "Smoothing Frame:" ),
1155  QString::number( (int)ct_smoothing->value() ) );
1156  s += table_row( tr( "Analyzed Boundary:" ),
1157  QString::number( (int)ct_boundaryPercent->value() ) + " %" );
1158  s += table_row( tr( "Boundary Position:" ),
1159  QString::number( (int)ct_boundaryPos->value() ) + " %" );
1160  s += table_row( tr( "Early Scans skipped:" ),
1161  le_skipped->text() + " scans" );
1162  s += extra;
1163 
1164  s += indent( 4 ) + "</table>\n";
1165 
1166  return s;
1167 }
1168 
1169 QString US_AnalysisBase2::scan_info( void ) const
1170 {
1171  int index = lw_triples->currentRow();
1172  const US_DataIO::EditedData* d = &dataList[ index ];
1173 
1174  QString s = "\n" + indent( 4 ) + tr( "<h3>Scan Information:</h3>\n" )
1175  + indent( 4 ) + "<table>\n";
1176 
1177  s += table_row( tr( "Scan" ), tr( "Corrected Time" ),
1178  tr( "Plateau Concentration" ) );
1179 
1180  for ( int i = 0; i < d->scanData.size(); i++ )
1181  {
1182  if ( excludedScans.contains( i ) ) continue;
1183 
1184  QString s1;
1185  QString s2;
1186  QString s3;
1187 
1188  double od = d->scanData[ i ].plateau;
1189  int time = (int)( d->scanData[ i ].seconds - time_correction );
1190 
1191  s1 = s1.sprintf( "%4d", i + 1 );
1192  s2 = s2.sprintf( "%4d min %2d sec", time / 60, time % 60 );
1193  s3 = s3.sprintf( "%.6f OD", od );
1194 
1195  s += table_row( s1, s2, s3 );
1196  }
1197 
1198  s += indent( 4 ) + "</table>\n";
1199 
1200  return s;
1201 }
1202 
1203 bool US_AnalysisBase2::mkdir( const QString& baseDir, const QString& subdir )
1204 {
1205  QDir folder( baseDir );
1206 
1207  if ( folder.exists( subdir ) ) return true;
1208 
1209  if ( folder.mkdir( subdir ) ) return true;
1210 
1211  QMessageBox::warning( this,
1212  tr( "File error" ),
1213  tr( "Could not create the directory:\n" ) + baseDir + "/" + subdir );
1214 
1215  return false;
1216 }
1217 
1218 // Slot to give load-data progress feedback
1219 void US_AnalysisBase2::set_progress( const QString message )
1220 {
1221  te_desc->setHtml( "<b>" + message + " ...</b>" );
1222  qApp->processEvents();
1223 }
1224 
1225 // Load noise record(s) if there are any and user so chooses, then apply
1227 {
1228  US_DataIO::EditedData* edata = &dataList[ index ];
1229 //qDebug() << "AB2: load_noise index noif" << index << noiflags[index];
1230 
1231  if ( noiflags[ index ] >= 0 )
1232  { // If noise already applied, ask user: retain? reselect?
1233  bool retain = query_noise_retain();
1234 
1235  if ( retain ) // Do nothing if user wants applied noise retained
1236  return;
1237  else // Otherwise, back out noise and fall thru to re-select
1238  back_out_noise( index );
1239  }
1240 
1241  noiflags[ index ] = 0; // Initially flag no noise to subtract
1242 
1243  QStringList mieGUIDs; // List of GUIDs of models-in-edit
1244  QStringList nieGUIDs; // List of GUIDS:type:index of noises-in-edit
1245 
1246  te_desc->setHtml( tr( "<b>Scanning noise for %1 ...</b>" )
1247  .arg( triples[ index ] ) );
1248  qApp->processEvents();
1249  US_LoadableNoise lnoise;
1250  bool loadDB = disk_controls->db();
1251  bool local = ! loadDB;
1252  int nenois = lnoise.count_noise( local, edata, NULL, mieGUIDs, nieGUIDs );
1253  te_desc->setHtml( tr( "<b>%1 noise(s) found for %2</b>" )
1254  .arg( nenois ).arg( triples[ index ] ) );
1255  qApp->processEvents();
1256 
1257 //for (int jj=0;jj<nenois;jj++)
1258 // qDebug() << " jj nieG" << jj << nieGUIDs.at(jj);
1259 
1260  if ( nenois > 0 )
1261  { // There is/are noise(s): ask user if she wants to load
1262  US_Passwd pw;
1263  US_DB2* dbP = local ? NULL : new US_DB2( pw.getPasswd() );
1264 
1265  if ( nenois > 1 )
1266  { // more than 1: get choice from noise loader dialog
1267  US_NoiseLoader* nldiag = new US_NoiseLoader( dbP,
1268  mieGUIDs, nieGUIDs, ti_noise, ri_noise, edata );
1269  nldiag->move( this->pos() + QPoint( 200, 200 ) );
1270  nldiag->exec();
1271  qApp->processEvents();
1272 
1273  delete nldiag;
1274  }
1275 
1276  else
1277  { // only 1: just load it
1278  QString noiID = nieGUIDs.at( 0 );
1279  QString typen = noiID.section( ":", 1, 1 );
1280  noiID = noiID.section( ":", 0, 0 );
1281 
1282  if ( typen == "ti" )
1283  ti_noise.load( loadDB, noiID, dbP );
1284 
1285  else
1286  ri_noise.load( loadDB, noiID, dbP );
1287  }
1288 
1289  // noise loaded: insure that counts jive with data
1290  int ntinois = ti_noise.values.size();
1291  int nrinois = ri_noise.values.size();
1292  int nscans = edata->scanCount();
1293  int npoints = edata->pointCount();
1294  int npadded = 0;
1295 
1296  if ( ntinois > 0 && ntinois < npoints )
1297  { // pad out ti noise values to radius count
1298  int jj = ntinois;
1299  while ( jj++ < npoints )
1300  ti_noise.values << 0.0;
1301  ti_noise.count = ti_noise.values.size();
1302  npadded++;
1303  }
1304 
1305  if ( nrinois > 0 && nrinois < nscans )
1306  { // pad out ri noise values to scan count
1307  int jj = nrinois;
1308  while ( jj++ < nscans )
1309  ri_noise.values << 0.0;
1310  ri_noise.count = ri_noise.values.size();
1311  npadded++;
1312  }
1313 
1314  if ( npadded > 0 )
1315  { // let user know that padding occurred
1316  QString pmsg;
1317 
1318  if ( npadded == 1 )
1319  pmsg = tr( "The noise file was padded out with zeroes\n"
1320  "in order to match the data range." );
1321  else
1322  pmsg = tr( "The noise files were padded out with zeroes\n"
1323  "in order to match the data ranges." );
1324 
1325  QMessageBox::information( this, tr( "Noise Padded Out" ), pmsg );
1326  }
1327 
1328  // Subtract noise from the experiment
1329 
1330  for ( int ii = 0; ii < nscans; ii++ )
1331  {
1332  int iin = min( ii, ( nrinois - 1 ) );
1333  double rinoi = ( nrinois > 0 ) ? ri_noise.values[ iin ] : 0.0;
1334  US_DataIO::Scan* escan = &edata->scanData[ ii ];
1335 
1336  for ( int jj = 0; jj < npoints; jj++ )
1337  {
1338  int jjn = min( jj, ( ntinois - 1 ) );
1339  double tinoi = ( ntinois > 0 ) ? ti_noise.values[ jjn ] : 0.0;
1340 
1341  escan->rvalues[ jj ] = edata->value( ii, jj ) - rinoi - tinoi;
1342  }
1343 
1344  int plx = US_DataIO::index( edata->xvalues, edata->plateau );
1345  escan->plateau = escan->rvalues[ plx ];
1346  }
1347 
1348  // Keep track of noise applied to this triple and save each
1349  noiflags[ index ] = min( nrinois, 1 ) + 2 * min( ntinois, 1 );
1350 
1351  rinoises[ index ] = nrinois > 0 ? ri_noise : US_Noise();
1352  tinoises[ index ] = ntinois > 0 ? ti_noise : US_Noise();
1353 
1354  if ( dbP != NULL )
1355  {
1356  delete dbP;
1357  }
1358  } // End: query for desired noise
1359 
1360  else // Flag that there was no noise to apply
1361  noiflags[ index ] = -1;
1362 }
1363 
1364 // Get solution parameters via US_SolutionGui
1366 {
1367  if ( ! dataLoaded )
1368  return;
1369 
1370  int dbdisk = ( disk_controls->db() ) ? US_Disk_DB_Controls::DB
1372  int expID = 0;
1373  QString runID = dataList[ lw_triples->currentRow() ].runID;
1374 
1375  if ( disk_controls->db() )
1376  {
1377  US_Passwd pw;
1378  US_DB2 db( pw.getPasswd() );
1379  QStringList query( "get_experiment_info_by_runID" );
1380  query << runID << QString::number( US_Settings::us_inv_ID() );
1381  db.query( query );
1382  if ( db.lastErrno() != US_DB2::NOROWS )
1383  {
1384  db.next();
1385  expID = db.value( 1 ).toString().toInt();
1386  }
1387  }
1388 
1389  US_SolutionGui* soluInfo = new US_SolutionGui( expID, 1, true, dbdisk,
1390  solution_rec, false );
1391 
1392  connect( soluInfo, SIGNAL( updateSolutionGuiSelection( US_Solution ) ),
1393  this, SLOT( updateSolution( US_Solution ) ) );
1394 
1395  soluInfo->exec();
1396 }
1397 
1398 // Update solution parameters after user has made selections
1400 {
1401  solution_rec = solution_sel;
1402 
1403  int bufID = solution_rec.buffer.bufferID.toInt();
1404  QString sbufID = QString::number( bufID );
1405  QString bufDesc = solution_rec.buffer.description;
1406  QString bdens = le_density ->text();
1407  QString bvisc = le_viscosity->text();
1408  QString svbar = le_vbar ->text();
1409  QString bcmpr = "";
1410  QString bmanu = solution_rec.buffer.manual ? "1" : "0";
1411  QString errmsg = "";
1412  QString bufGUID = solution_rec.buffer.GUID;
1413 qDebug() << "updSolu: manual" << bmanu;
1414 
1415  if ( disk_controls->db() )
1416  {
1417  US_Passwd pw;
1418  US_DB2 db( pw.getPasswd() );
1419 
1420  US_SolutionVals::bufvals_db( &db, sbufID, bufGUID, bufDesc,
1421  bdens, bvisc, bcmpr, bmanu, errmsg );
1422  }
1423 
1424  else
1425  {
1426  US_SolutionVals::bufvals_disk( sbufID, bufGUID, bufDesc,
1427  bdens, bvisc, bcmpr, bmanu, errmsg );
1428  }
1429 
1430  density = bdens.toDouble();
1431  viscosity = bvisc.toDouble();
1433  svbar = QString::number( vbar );
1434  manual = ( !bmanu.isEmpty() && bmanu == "1" );
1436 
1437  le_density ->setText( bdens );
1438  le_viscosity->setText( bvisc );
1439  le_vbar ->setText( svbar );
1440  le_solution ->setText( solution_rec.solutionDesc );
1441 qDebug() << "updSolu: reread manual" << manual << bmanu;
1442 }
1443 
1444 // Query whether user wants to retain already-applied noise
1446 {
1447  QString msg = tr(
1448  "Noise has previously been applied to this triple.<br/>"
1449  "Do you want to retain the previous noise selection?<br/>"
1450  "<ul><li><b>Yes</b> to retain the applied noise selection;</li>"
1451  "<li><b>No </b> to apply a new noise selection.</li></ul>" );
1452 
1453  QMessageBox msgBox( this );
1454  msgBox.setWindowTitle( tr( "Noise Already Applied" ) );
1455  msgBox.setTextFormat ( Qt::RichText );
1456  msgBox.setText ( msg );
1457  msgBox.addButton ( QMessageBox::No );
1458  msgBox.addButton ( QMessageBox::Yes );
1459  msgBox.setDefaultButton( QMessageBox::Yes );
1460 
1461  bool retain = ( msgBox.exec() == QMessageBox::Yes );
1462 
1463  return retain;
1464 }
1465 
1466 // Back out applied noise in preparation for possible reselection of noise
1468 {
1469  int noif = noiflags[ index ];
1470 
1471  // Add noise back into data
1472  ri_noise = ( ( noif & 1 ) != 0 ) ? rinoises[ index ] : US_Noise();
1473  ti_noise = ( ( noif & 2 ) != 0 ) ? tinoises[ index ] : US_Noise();
1474  ri_noise.apply_to_data( dataList[ index ], false );
1475  ti_noise.apply_to_data( dataList[ index ], false );
1476 }
1477 
1478 // Copy report files to the database
1479 void US_AnalysisBase2::reportFilesToDB( QStringList& files )
1480 {
1481  US_Passwd pw;
1482  US_DB2 db( pw.getPasswd() );
1483  US_DB2* dbP = &db;
1484  QStringList query;
1485  US_DataIO::EditedData* edata = &dataList[ lw_triples->currentRow() ];
1486  QString tripdesc = edata->description;
1487  QString pfdir = QString( files[ 0 ] ).section( "/", 0, -2 );
1488 
1489  // Get the ID of the EditedData DB record associated with the report
1490  query << "get_editID" << edata->editGUID;
1491  db.query( query );
1492  db.next();
1493  int idEdit = db.value( 0 ).toString().toInt();
1494 
1495  // Set the runID for the report
1496  US_Report freport;
1497  freport.runID = runID;
1498 
1499  // Write all report records to the database
1500  int st = freport.saveFileDocuments( pfdir, files, dbP,
1501  idEdit, tripdesc );
1502 
1503  if ( st != US_DB2::OK )
1504  {
1505  qDebug() << "*ERROR* saveFileDocuments, status" << st;
1506  }
1507 }
1508 
1509 // Write a general dataset information HTML report file
1510 bool US_AnalysisBase2::write_dset_report( QString& dsfname )
1511 {
1512  QFile f_rep( dsfname );
1513 
1514  bool is_ok = f_rep.open( QIODevice::WriteOnly | QIODevice::Truncate );
1515 
1516  if ( ! is_ok )
1517  return is_ok;
1518 
1519  QTextStream ts( &f_rep );
1520 
1521  int index = lw_triples->currentRow();
1522  US_DataIO::EditedData* edata = &dataList[ index ];
1523 
1524  QString title = "US_Analysis_Base";
1525  QString head1 = tr( "General Data Set Information" );
1526 
1527  ts << html_header( title, head1, edata );
1528  ts << run_details();
1529  ts << hydrodynamics();
1530  ts << scan_info();
1531  ts << indent( 2 ) + "</body>\n</html>\n";
1532 
1533  f_rep.close();
1534  return is_ok;
1535 }
1536 
1537 // Update report files list, including adding PNG for each SVGZ
1538 void US_AnalysisBase2::update_filelist( QStringList& flist,
1539  const QString fname )
1540 {
1541  flist << fname;
1542 
1543  if ( fname.contains( ".svg" ) )
1544  flist << QString( fname ).section( ".", 0, -2 ) + ".png";
1545 }
1546