UltraScan III
us_buoyancy.cpp
Go to the documentation of this file.
1 
3 #include <QApplication>
4 #include <QDomDocument>
5 
6 #include "us_buoyancy.h"
7 #include "us_license_t.h"
8 #include "us_license.h"
9 #include "us_settings.h"
10 #include "us_gui_settings.h"
11 #include "us_investigator.h"
12 #include "us_run_details2.h"
13 #include "us_math2.h"
14 #include "us_util.h"
15 #include "us_load_auc.h"
16 #include "us_passwd.h"
17 #include "us_db2.h"
18 #include "us_constants.h"
19 #include "us_simparms.h"
20 #include "us_constants.h"
21 
22 #ifndef DbgLv
23 #define DbgLv(a) if(dbg_level>=a)qDebug()
24 #endif
25 
27 // the class US_FitMeniscus.
28 
29 int main( int argc, char* argv[] )
30 {
31  QApplication application( argc, argv );
32 
33  #include "main1.inc"
34 
35  // License is OK. Start up.
36 
37  US_Buoyancy w;
38  w.show();
39  return application.exec();
40 }
41 
42 // Constructor
44 {
45  // initialize gradient forming material to 65% Nycodenz (weight/vol):
46 
47  bottom = 0.0;
48  bottom_calc = 0.0;
49 
50  total_speeds = 0;
51  v_line = NULL;
53  current_scan = 1;
54  current_rpm = 0.0;
55  tmp_dpoint.name = "";
57  tmp_dpoint.dataset = "";
59  tmp_dpoint.peakDensity = 0.0;
60  tmp_dpoint.peakVbar = 0.0;
61  tmp_dpoint.temperature = 0.0;
62  tmp_dpoint.bufferDensity = 0.998234;
63  tmp_dpoint.meniscus = 0.0;
64  tmp_dpoint.bottom = 0.0;
65  tmp_dpoint.speed = 0.0;
66  tmp_dpoint.gradientMW = 821.0;
67  tmp_dpoint.gradientVbar = 0.4831;
68  tmp_dpoint.gradientC0 = 1.2294;
69 
70  setWindowTitle( tr( "Buoyancy Equilibrium Data Analysis" ) );
71  setPalette( US_GuiSettings::frameColor() );
72 
73  QVBoxLayout* top = new QVBoxLayout( this );
74  top->setSpacing ( 2 );
75  top->setContentsMargins ( 2, 2, 2, 2 );
76 
77  // Put the Run Info across the entire window
78  QHBoxLayout* runInfo = new QHBoxLayout();
79  QLabel* lb_info = us_label( tr( "Dataset Info:" ), -1 );
80  runInfo->addWidget( lb_info );
81 
82  le_info = us_lineedit( "", 1, true );
83  runInfo->addWidget( le_info );
84 
85  top->addLayout( runInfo );
86 
87  QHBoxLayout* main = new QHBoxLayout();
88  QVBoxLayout* left = new QVBoxLayout;
89 
90  // Start of Grid Layout
91  QGridLayout* specs = new QGridLayout;
92  int s_row = 0;
93 
94  // Row 1
95  // Investigator
96 
97  QPushButton* pb_investigator = us_pushbutton( tr( "Select Investigator" ) );
98  connect( pb_investigator, SIGNAL( clicked() ), SLOT( sel_investigator() ) );
99  specs->addWidget( pb_investigator, s_row, 0 );
100 
101  if ( US_Settings::us_inv_level() < 1 )
102  pb_investigator->setEnabled( false );
103 
104  int id = US_Settings::us_inv_ID();
105  QString number = ( id > 0 ) ?
106  QString::number( US_Settings::us_inv_ID() ) + ": "
107  : "";
108  le_investigator = us_lineedit( number + US_Settings::us_inv_name(), 1, true );
109  specs->addWidget( le_investigator, s_row++, 1, 1, 3 );
110 
111  // Row 1A
113  specs->addLayout( disk_controls, s_row++, 0, 1, 4 );
114 
115  // Row 2
116  QPushButton* pb_load = us_pushbutton( tr( "Load Data" ) );
117  connect( pb_load, SIGNAL( clicked() ), SLOT( load() ) );
118  specs->addWidget( pb_load, s_row, 0, 1, 2 );
119 
120  pb_details = us_pushbutton( tr( "Run Details" ), false );
121  connect( pb_details, SIGNAL( clicked() ), SLOT( details() ) );
122  specs->addWidget( pb_details, s_row++, 2, 1, 2 );
123 
124  // Row 3
125  QLabel* lb_triple = us_label( tr( "Cell / Channel / Wavelength:" ), -1 );
126  specs->addWidget( lb_triple, s_row, 0, 1, 2 );
127 
129  connect( cb_triple, SIGNAL( currentIndexChanged( int ) ),
130  SLOT ( new_triple ( int ) ) );
131  specs->addWidget( cb_triple, s_row++, 2, 1, 2 );
132 
133  lbl_rpms = us_label( tr( "Speed Step (RPM) of triple:" ), -1 );
134  cb_rpms = us_comboBox();
135  specs->addWidget( lbl_rpms, s_row, 0, 1, 2 );
136  specs->addWidget( cb_rpms, s_row++, 2, 1, 2 );
137 
138  // Scans
139  QLabel* lbl_scan = us_label( tr( "Scan Focus:" ), -1 );
140  lbl_scan->setAlignment( Qt::AlignVCenter | Qt::AlignRight );
141  specs->addWidget( lbl_scan, s_row, 0, 1, 2 );
142 
143  ct_selectScan = us_counter ( 3, 0.0, 0.0 ); // Update range upon load
144  ct_selectScan->setStep( 1 );
145  ct_selectScan->setValue ( current_scan );
146  specs->addWidget( ct_selectScan, s_row++, 2, 1, 2 );
147  connect( ct_selectScan, SIGNAL( valueChanged( double ) ),
148  SLOT ( plot_scan( double ) ) );
149 
150  QButtonGroup* bg_points = new QButtonGroup( this );
151 
152  QGridLayout* box1 = us_radiobutton( tr( "Select meniscus" ), rb_meniscus );
153  QGridLayout* box2 = us_radiobutton( tr( "Select peak position" ), rb_datapoint );
154 
155  rb_meniscus->setChecked( true );
156  rb_datapoint->setChecked( false );
157  rb_meniscus->setEnabled( false );
158  rb_datapoint->setEnabled( false );
159  bg_points->addButton( rb_meniscus );
160  bg_points->addButton( rb_datapoint );
161  specs->addLayout( box1, s_row, 0, 1, 2 );
162  specs->addLayout( box2, s_row++, 2, 1, 2 );
163 
164  QLabel* lbl_meniscus = us_label( tr( "Meniscus Position (cm):" ), -1 );
165  specs->addWidget( lbl_meniscus, s_row, 0, 1, 2 );
166  le_meniscus = us_lineedit( "0.0" );
167  specs->addWidget( le_meniscus, s_row++, 2, 1, 2 );
168  connect (le_meniscus, SIGNAL( editingFinished (void)), this,
169  SLOT (update_meniscus(void)));
170 
171  QLabel* lbl_stretch = us_label( tr( "Rotor Stretch (cm):" ), -1 );
172  specs->addWidget( lbl_stretch, s_row, 0, 1, 2 );
173  le_stretch = us_lineedit( "0.0" );
174  specs->addWidget( le_stretch, s_row++, 2, 1, 2 );
175 
176  QLabel* lbl_bottom = us_label( tr( "Centerpiece Bottom (cm):" ), -1 );
177  specs->addWidget( lbl_bottom, s_row, 0, 1, 2 );
178  le_bottom = us_lineedit( QString::number(bottom) );
179  specs->addWidget( le_bottom, s_row++, 2, 1, 2 );
180  connect (le_bottom, SIGNAL( editingFinished (void)), this,
181  SLOT (update_bottom(void)));
182 
183  QLabel* lbl_bottom_calc = us_label( tr( "Speed-corrected Bottom (cm):" ), -1 );
184  specs->addWidget( lbl_bottom_calc, s_row, 0, 1, 2 );
185  le_bottom_calc = us_lineedit( QString::number( bottom_calc ) );
186  specs->addWidget( le_bottom_calc, s_row++, 2, 1, 2 );
187  connect (le_bottom_calc, SIGNAL( editingFinished (void)), this,
188  SLOT (update_bottom_calc(void)));
189 
190  // Solution info:
191  QLabel* lbl_dens_0 = us_label( tr( "Loading Density (g/ml):" ), -1 );
192  specs->addWidget( lbl_dens_0, s_row, 0, 1, 2 );
193  le_dens_0 = us_lineedit( QString::number(tmp_dpoint.gradientC0) );
194  specs->addWidget( le_dens_0, s_row++, 2, 1, 2 );
195  connect (le_dens_0, SIGNAL( editingFinished (void)), this,
196  SLOT (update_dens_0(void)));
197 
198  QLabel* lbl_buffer_density = us_label( tr( "Buffer Density (g/ml):" ), -1 );
199  specs->addWidget( lbl_buffer_density, s_row, 0, 1, 2 );
201  specs->addWidget( le_buffer_density, s_row++, 2, 1, 2 );
202  connect (le_buffer_density, SIGNAL( editingFinished (void)), this,
203  SLOT ( update_bufferDensity( void ) ));
204 
205  QLabel* lbl_vbar = us_label( tr( "Gradient Mat. vbar (ml/g):" ), -1 );
206  specs->addWidget( lbl_vbar, s_row, 0, 1, 2 );
207  le_vbar = us_lineedit( QString::number( tmp_dpoint.gradientVbar ) );
208  specs->addWidget( le_vbar, s_row++, 2, 1, 2 );
209  connect (le_vbar, SIGNAL( editingFinished (void)), this,
210  SLOT (update_vbar(void)));
211 
212  QLabel* lbl_MW = us_label( tr( "Gradient Mat. MW (g/mol):" ), -1 );
213  specs->addWidget( lbl_MW, s_row, 0, 1, 2 );
214  le_MW = us_lineedit( QString::number( tmp_dpoint.gradientMW ) );
215  specs->addWidget( le_MW, s_row++, 2, 1, 2 );
216  connect (le_MW, SIGNAL( editingFinished (void)), this,
217  SLOT (update_MW(void)));
218 
219  QLabel* lbl_temperature = us_label( tr( "Temperature (°C):" ), -1 );
220  specs->addWidget( lbl_temperature, s_row, 0, 1, 2 );
221  le_temperature = us_lineedit( QString::number( tmp_dpoint.temperature ) );
222  specs->addWidget( le_temperature, s_row++, 2, 1, 2 );
223 
224  QLabel* lbl_peakName = us_label( tr( "Peak name/label:" ), -1 );
225  specs->addWidget( lbl_peakName, s_row, 0, 1, 2 );
227  specs->addWidget( le_peakName, s_row++, 2, 1, 2 );
228  connect (le_peakName, SIGNAL( editingFinished (void)), this,
229  SLOT (update_peakName(void)));
230 
231  QLabel* lbl_peakPosition = us_label( tr( "Peak Position (cm):" ), -1 );
232  specs->addWidget( lbl_peakPosition, s_row, 0, 1, 2 );
233  le_peakPosition = us_lineedit( QString::number( tmp_dpoint.peakPosition ) );
234  specs->addWidget( le_peakPosition, s_row++, 2, 1, 2 );
235 
236  QLabel* lbl_peakDensity = us_label( tr( "Peak Density (g/ml):" ), -1 );
237  specs->addWidget( lbl_peakDensity, s_row, 0, 1, 2 );
238  le_peakDensity = us_lineedit( QString::number( tmp_dpoint.peakDensity ) );
239  specs->addWidget( le_peakDensity, s_row++, 2, 1, 2 );
240 
241  QLabel* lbl_peakVbar = us_label( tr( "Peak vbar (ml/g):" ), -1 );
242  specs->addWidget( lbl_peakVbar, s_row, 0, 1, 2 );
243  le_peakVbar = us_lineedit( QString::number( tmp_dpoint.peakVbar ) );
244  specs->addWidget( le_peakVbar, s_row++, 2, 1, 2 );
245 
246  // Button rows
247  QBoxLayout* buttons = new QHBoxLayout;
248 
249  pb_save = us_pushbutton( tr( "Save Datapoint" ), false );
250  connect( pb_save, SIGNAL( clicked() ), SLOT( save() ) );
251  specs->addWidget( pb_save, s_row, 0, 1, 2 );
252 
253  pb_write = us_pushbutton( tr( "Write Report" ), false );
254  connect( pb_write, SIGNAL( clicked() ), SLOT( write() ) );
255  specs->addWidget( pb_write, s_row++, 2, 1, 2 );
256 
257  QPushButton* pb_reset = us_pushbutton( tr( "Reset" ) );
258  connect( pb_reset, SIGNAL( clicked() ), SLOT( reset() ) );
259  buttons->addWidget( pb_reset );
260 
261  QPushButton* pb_help = us_pushbutton( tr( "Help" ) );
262  connect( pb_help, SIGNAL( clicked() ), SLOT( help() ) );
263  buttons->addWidget( pb_help );
264 
265  QPushButton* pb_accept = us_pushbutton( tr( "Close" ) );
266  connect( pb_accept, SIGNAL( clicked() ), SLOT( close() ) );
267  buttons->addWidget( pb_accept );
268 
269  // Plot layout on right side of window
270  plot = new US_Plot( data_plot,
271  tr( "Absorbance Data" ),
272  tr( "Radius (in cm)" ), tr( "Absorbance" ) );
273 
274  data_plot->setMinimumSize( 600, 400 );
275 
276  data_plot->enableAxis( QwtPlot::xBottom, true );
277  data_plot->enableAxis( QwtPlot::yLeft , true );
278 
279  pick = new US_PlotPicker( data_plot );
280  // Set rubber band to display for Control+Left Mouse Button
281  pick->setRubberBand ( QwtPicker::VLineRubberBand );
282  pick->setMousePattern( QwtEventPattern::MouseSelect1,
283  Qt::LeftButton, Qt::ControlModifier );
284 
285  left->addLayout( specs );
286  left->addStretch();
287  left->addLayout( buttons );
288 
289  main->addLayout( left );
290  main->addLayout( plot );
291  main->setStretchFactor( plot, 3 );
292  top ->addLayout( main );
293 
294  reset();
295 }
296 
297 // Select a new triple
298 void US_Buoyancy::new_triple( int index )
299 {
300  current_triple = index;
301  data = allData[ index ];
302  le_info->setText( runID + ": " + allData[index].description );
303  tmp_dpoint.description = allData[index].description;
306 }
307 
309 {
310  QString str;
311 
313  str.setNum( current_stretch );
314  le_stretch->setText( str );
315 
316  if ( meniscus[current_triple] != 0 )
317  {
319  str.setNum( tmp_dpoint.meniscus );
320  le_meniscus->setText( str );
321  }
322  else
323  {
324  le_meniscus->setText( "0.0" );
325  rb_meniscus ->setChecked( true );
326  rb_meniscus ->setEnabled( false );
327  rb_datapoint->setEnabled( false );
328  }
329  str.setNum( simparams[current_triple].bottom_position );
330  le_bottom->setText( str );
332  str.setNum( tmp_dpoint.bottom );
333  le_bottom_calc->setText( str );
334  str.setNum( tmp_dpoint.temperature );
335  le_temperature->setText( str );
336  calc_points();
337 }
338 
339 // Load an AUC data set
341 {
342 
343  QString str;
344  if (tmp_dpoint.peakPosition != 0.0)
345  {
346  double omega_s, C, C0, r2, k1, k2, k3, k4;
347  omega_s = pow( current_rpm * M_PI/30.0, 2.0 );
348  C0 = tmp_dpoint.gradientC0 - tmp_dpoint.bufferDensity; //subtract buffer density from nycodenz density
349  r2 = pow( tmp_dpoint.bottom, 2.0 ) - pow( tmp_dpoint.meniscus, 2.0);
350  k1 = tmp_dpoint.gradientMW * omega_s/( 2.0 * R * (tmp_dpoint.temperature + 273.15) );
352  k2 = exp( k1 * ( k4 ) * (pow( tmp_dpoint.peakPosition, 2.0 ) - pow( tmp_dpoint.meniscus, 2.0 ) ) );
353  k3 = exp( k1 * ( k4 ) * r2);
354  C = k1 * k4 * C0 *r2 * k2/( k3 - 1.0 ) + tmp_dpoint.bufferDensity;
355  str.setNum( C );
356  le_peakDensity->setText( str );
357  str.setNum( 1.0/C );
358  le_peakVbar->setText( str );
359  str.setNum( tmp_dpoint.peakPosition );
360  le_peakPosition->setText( str );
361  pb_save->setEnabled( true );
362  }
363  else
364  {
365  le_peakDensity->setText( "0" );
366  le_peakVbar->setText( "0" );
367  le_peakPosition->setText( "0" );
368  pb_save->setEnabled( false );
369  }
370 }
371 
372 // Load an AUC data set
373 void US_Buoyancy::load( void )
374 {
375  bool isLocal = ! disk_controls->db();
376  reset();
377 
378  US_LoadAUC* dialog =
379  new US_LoadAUC( isLocal, allData, triples, workingDir );
380 
381  connect( dialog, SIGNAL( changed ( bool ) ),
382  this, SLOT( update_disk_db( bool ) ) );
383 
384  if ( dialog->exec() == QDialog::Rejected ) return;
385 
386  runID = workingDir.section( "/", -1, -1 );
387  cb_triple->clear();
388  delete dialog;
389  if ( triples.size() == 0 )
390  {
391  QMessageBox::warning( this,
392  tr( "No Files Found" ),
393  tr( "There were no files of the form *.auc\n"
394  "found in the specified directory." ) );
395  return;
396  }
397 
398  cb_triple->addItems( triples );
399  connect( cb_triple, SIGNAL( currentIndexChanged( int ) ),
400  SLOT ( new_triple ( int ) ) );
401  current_triple = 0;
402 
403  le_info->setText( runID + ": " + allData[0].description );
404  tmp_dpoint.description = allData[0].description;
406 
407 
408  data = allData[ 0 ];
409  dataType = QString( QChar( data.type[ 0 ] ) )
410  + QString( QChar( data.type[ 1 ] ) );
411 
412  simparams.resize(triples.size());
413  meniscus.resize(triples.size());
414 
415  for (int ii=0; ii<triples.size(); ii++)
416  {
417  meniscus[ii] = 0.0;
418  }
419  if (isLocal)
420  {
421  for ( int ii = 0; ii < triples.size(); ii++ )
422  { // Generate file names
423  QString triple = QString( triples.at( ii ) ).replace( " / ", "." );
424  QString file = runID + "." + dataType + "." + triple + ".auc";
425  files << file;
426  simparams[ii].initFromData( NULL, allData[ii], true, runID, dataType);
427  }
428  }
429  else
430  {
431  US_Passwd pw;
432  US_DB2 db( pw.getPasswd() );
433  for ( int ii = 0; ii < triples.size(); ii++ )
434  { // Generate file names
435  QString triple = QString( triples.at( ii ) ).replace( " / ", "." );
436  QString file = runID + "." + dataType + "." + triple + ".auc";
437  files << file;
438  simparams[ii].initFromData( &db, allData[ii], true, runID, dataType);
439  }
440  }
441  QString file = workingDir + "/" + runID + "." + dataType + ".xml";
442  expType = "";
443  QFile xf( file );
444 
445  if ( xf.open( QIODevice::ReadOnly | QIODevice::Text ) )
446  {
447  QXmlStreamReader xml( &xf );
448 
449  while( ! xml.atEnd() )
450  {
451  xml.readNext();
452 
453  if ( xml.isStartElement() && xml.name() == "experiment" )
454  {
455  QXmlStreamAttributes xa = xml.attributes();
456  expType = xa.value( "type" ).toString();
457  break;
458  }
459  }
460 
461  xf.close();
462  }
463 
464  if ( expType.isEmpty() && disk_controls->db() )
465  { // no experiment type yet and data read from DB: try for DB exp type
466  US_Passwd pw;
467  US_DB2 db( pw.getPasswd() );
468 
469  if ( db.lastErrno() != US_DB2::OK )
470  {
471  QMessageBox::warning( this, tr( "Connection Problem" ),
472  tr( "Could not connect to database \n" ) + db.lastError() );
473  return;
474  }
475 
476  QStringList query;
477  query << "get_experiment_info_by_runID" << runID
478  << QString::number( US_Settings::us_inv_ID() );
479 
480  db.query( query );
481  db.next();
482  expType = db.value( 8 ).toString();
483  }
484  else // insure Ulll... form, e.g., "Equilibrium"
485  {
486  expType = expType.left( 1 ).toUpper() +
487  expType.mid( 1 ).toLower();
488  }
489  expIsBuoyancy = ( expType.compare( "Buoyancy", Qt::CaseInsensitive ) == 0 );
490  if (expIsBuoyancy)
491  {
492  US_Passwd pw;
493  US_DB2 db( pw.getPasswd() );
495  pick ->disconnect();
496  connect( pick, SIGNAL( cMouseUp( const QwtDoublePoint& ) ),
497  SLOT ( mouse ( const QwtDoublePoint& ) ) );
499  connect( cb_rpms, SIGNAL( currentIndexChanged( int ) ),
500  SLOT ( new_rpmval ( int ) ) );
501  }
502  else
503  { // non-Equilibrium
504  QMessageBox::warning( this, tr( "Wrong Type of Data" ),
505  tr( "This analysis program requires data of type \"Buoyancy\".\n"
506  "Please load a different dataset with the correct type.") );
507  return;
508  }
509  // Enable pushbuttons
510  pb_details ->setEnabled( true );
511  QString str1, str2;
512 
513  if ( dataType == "FI")
514  {
515  str1 = "Fluorescence Data";
516  str2 = "Fluorescence Intensity";
517  }
518  else if ( dataType == "RI")
519  {
520  str1 = "Absorbance Data";
521  str2 = "Absorbance";
522  }
523  else if ( dataType == "RA")
524  {
525  str1 = "Absorbance Data";
526  str2 = "Absorbance";
527  }
528  else if ( dataType == "IP")
529  {
530  str1 = "Interference Data";
531  str2 = "Fringes";
532  }
533  data_plot->setTitle( str1 );
534  data_plot->setAxisTitle( QwtPlot::yLeft, str2 );
535 
536  // Temperature check
537  double dt = 0.0;
538  US_DataIO::RawData triple;
539 
540  foreach( triple, allData )
541  {
542  double temp_spread = triple.temperature_spread();
543  dt = ( temp_spread > dt ) ? temp_spread : dt;
544  }
545 
546  if ( dt > US_Settings::tempTolerance() )
547  {
548  QMessageBox::warning( this,
549  tr( "Temperature Problem" ),
550  tr( "The temperature in this run varied over the course\n"
551  "of the run to a larger extent than allowed by the\n"
552  "current threshold (" )
553  + QString::number( US_Settings::tempTolerance(), 'f', 1 )
554  + " " + DEGC + tr( ". The accuracy of experimental\n"
555  "results may be affected significantly." ) );
556  }
557  QString str;
558  str.setNum(simparams[current_triple].bottom_position);
559  le_bottom->setText( str );
560 }
561 
562 // Handle a mouse click according to the current pick step
563 void US_Buoyancy::mouse( const QwtDoublePoint& p )
564 {
565  double maximum = -1.0e99;
566  if ( rb_meniscus->isChecked() )
567  {
568  QString str;
569  str.setNum( p.x() );
570  le_meniscus->setText( str );
571  // the internally stored meniscus position is adjusted to the theoretical rest position
572  meniscus[current_triple] = p.x() - calc_stretch();
573  tmp_dpoint.meniscus = p.x();
574  rb_meniscus->setEnabled( true );
575  rb_datapoint->setEnabled( true );
576  }
577  else
578  {
579  tmp_dpoint.peakPosition = p.x();
580  pb_write->setEnabled( true );
581  calc_points();
582  }
583  // Un-zoom
584  if ( plot->btnZoom->isChecked() )
585  {
586  plot->btnZoom->setChecked( false );
587  }
588  draw_vline( p.x() );
589  data_plot->replot();
590 
591  // Remove the left line
592  if ( v_line != NULL )
593  {
594  v_line->detach();
595  delete v_line;
596  v_line = NULL;
597  }
598 
599  marker = new QwtPlotMarker;
600  QBrush brush( Qt::white );
601  QPen pen ( brush, 2.0 );
602 
603  marker->setValue( p.x(), maximum );
604  marker->setSymbol( QwtSymbol(
605  QwtSymbol::Cross,
606  brush,
607  pen,
608  QSize ( 8, 8 ) ) );
609 
610  marker->attach( data_plot );
611  data_plot->replot();
612  marker->detach();
613  delete marker;
614  marker = NULL;
615 }
616 
617 // Display run details
619 {
620  US_RunDetails2* dialog
622  dialog->exec();
623  qApp->processEvents();
624  delete dialog;
625 }
626 
627 // Select DB investigator
629 {
630  int investigator = US_Settings::us_inv_ID();
631 
632  US_Investigator* dialog = new US_Investigator( true, investigator );
633  dialog->exec();
634 
635  investigator = US_Settings::us_inv_ID();
636 
637  QString inv_text = QString::number( investigator ) + ": "
639 
640  le_investigator->setText( inv_text );
641 }
642 
643 // Reset parameters to their defaults
644 void US_Buoyancy::reset( void )
645 {
646  le_info ->setText( "" );
647 
648  ct_selectScan->disconnect();
649  ct_selectScan->setMinValue( 0 );
650  ct_selectScan->setMaxValue( 0 );
651  ct_selectScan->setValue ( 0 );
652  connect( ct_selectScan, SIGNAL( valueChanged( double ) ),
653  SLOT ( plot_scan( double ) ) );
654 
655  cb_triple->disconnect();
656 
657  data_plot->detachItems( QwtPlotItem::Rtti_PlotCurve );
658  data_plot->detachItems( QwtPlotItem::Rtti_PlotMarker );
659  v_line = NULL;
660  pick->disconnect();
661 
662  data_plot->setAxisScale( QwtPlot::xBottom, 5.7, 7.3 );
663  data_plot->setAxisScale( QwtPlot::yLeft , 0.0, 1.5 );
664  grid = us_grid( data_plot );
665  data_plot->replot();
666 
667  // Disable pushbuttons
668  pb_details ->setEnabled( false );
669  pb_write ->setEnabled( false );
670  pb_save ->setEnabled( false );
671  rb_meniscus ->setEnabled( false );
672  rb_datapoint->setEnabled( false );
673 
674  // Remove icons
675 
676  dpoint .clear();
677  allData .clear();
678  meniscus .clear();
679  data.scanData .clear();
680  trip_rpms .clear();
681  triples .clear();
682  cb_rpms ->disconnect();
683  cb_rpms ->clear();
684 }
685 
686 // Select DB investigator// Private slot to update disk/db control with dialog changes it
688 {
689  if ( isDB )
691  else
693 }
694 
695 // Plot a single scan curve
696 void US_Buoyancy::plot_scan( double scan_number )
697 {
698  // current scan is global
699  current_scan = (int) scan_number;
700  int rsize = data.pointCount();
701  int ssize = data.scanCount();
702  int count = 0;
703  QVector< double > rvec( rsize );
704  QVector< double > vvec( rsize );
705  double* r = rvec.data();
706  double* v = vvec.data();
707 
708  data_plot->detachItems( QwtPlotItem::Rtti_PlotCurve );
709  v_line = NULL;
710 
711  double maxR = -1.0e99;
712  double minR = 1.0e99;
713  double maxV = -1.0e99;
714  double minV = 1.0e99;
715  int maxscan = 0;
716  QString srpm = cb_rpms->currentText();
717  current_rpm = srpm.toDouble();
718 
719  // Plot only the currently selected scan(s)
720  //
721  for ( int ii = 0; ii < ssize; ii++ )
722  {
723  US_DataIO::Scan* s = &data.scanData[ ii ];
724 
725  QString arpm = QString::number( s->rpm );
726 
727  //how many scans are included in the current set of speeds? Increment maxscan...
728  if ( arpm == srpm )
729  {
730  maxscan++;
731  }
732  else
733  {
734  continue;
735  }
736  count = 0;
737 
738  for ( int jj = 0; jj < rsize; jj++ )
739  {
740  r[ count ] = data.xvalues[ jj ];
741  v[ count ] = s->rvalues[ jj ];
742 
743  maxR = max( maxR, r[ count ] );
744  minR = min( minR, r[ count ] );
745  maxV = max( maxV, v[ count ] );
746  minV = min( minV, v[ count ] );
747 
748  count++;
749  }
750 
751  QString title = tr( "Raw Data at " )
752  + QString::number( s->seconds ) + tr( " seconds" )
753  + " #" + QString::number( ii );
754 
755  QwtPlotCurve* c = us_curve( data_plot, title );
756  c->setData( r, v, count );
757  if (ii == current_scan - 1 )
758  { // set the temperature to the currently highlighted scan:
760  c->setPen( QPen( Qt::red ) );
761  }
762 
763  // Reset the scan curves within the new limits
764  double padR = ( maxR - minR ) / 30.0;
765  double padV = ( maxV - minV ) / 30.0;
766 
767  data_plot->setAxisScale( QwtPlot::yLeft , minV - padV, maxV + padV );
768  data_plot->setAxisScale( QwtPlot::xBottom, minR - padR, maxR + padR );
769 
770  }
771  ct_selectScan->setMinValue( 1 );
772  ct_selectScan->setMaxValue( maxscan );
773 
774  data_plot->replot();
775  update_fields();
776 }
777 
778 // Draw a vertical pick line
779 void US_Buoyancy::draw_vline( double radius )
780 {
781  double r[ 2 ];
782 
783  r[ 0 ] = radius;
784  r[ 1 ] = radius;
785 
786  QwtScaleDiv* y_axis = data_plot->axisScaleDiv( QwtPlot::yLeft );
787 
788  double padding = ( y_axis->upperBound() - y_axis->lowerBound() ) / 30.0;
789 
790  double v[ 2 ];
791  v [ 0 ] = y_axis->upperBound() - padding;
792  v [ 1 ] = y_axis->lowerBound() + padding;
793 
794  v_line = us_curve( data_plot, "V-Line" );
795  v_line->setData( r, v, 2 );
796 
797  QPen pen = QPen( QBrush( Qt::white ), 2.0 );
798  v_line->setPen( pen );
799 
800  data_plot->replot();
801 }
802 
803 void US_Buoyancy::save( void )
804 {
805  tmp_dpoint.name = le_peakName->text();
806 // tmp_dpoint.description = ;
807 // tmp_dpoint.dataset = "";
808  tmp_dpoint.triple = cb_triple->currentText();
810  tmp_dpoint.centerpiece = simparams[current_triple].bottom_position;
811  tmp_dpoint.peakPosition = le_peakPosition->text().toDouble();
812  tmp_dpoint.peakDensity = le_peakDensity->text().toDouble();
813  tmp_dpoint.peakVbar = le_peakVbar->text().toDouble();
814 // tmp_dpoint.temperature = 0.0;
815  tmp_dpoint.bufferDensity = le_buffer_density->text().toDouble();
816  tmp_dpoint.meniscus = le_meniscus->text().toDouble();
817  tmp_dpoint.bottom = le_bottom_calc->text().toDouble();
818  tmp_dpoint.speed = cb_rpms->currentText().toDouble();
819  tmp_dpoint.gradientMW = le_MW->text().toDouble();
820  tmp_dpoint.gradientVbar = le_vbar->text().toDouble();
821  tmp_dpoint.gradientC0 = le_dens_0->text().toDouble();
822  dpoint.append( tmp_dpoint );
823 }
824 
825 void US_Buoyancy::write( void )
826 {
827  QString str, str2;
828  te = new US_Editor( US_Editor::LOAD, false, "results/*.rpt*", 0, 0 );
829  te->e->setFontFamily("Arial");
830  te->e->setFontPointSize( 13 );
831  te->e->append("UltraScan Buoyant Density Equilibrium Analysis Report:\n");
832  te->e->setFontPointSize( 11 );
833  for (int i=0; i<dpoint.size(); i++)
834  {
835  te->e->append("Peak " + str.setNum( i+1 ) + " (" + dpoint[i].name +
836  " from experiment \"" + dpoint[i].dataset + "\"):" );
837  te->e->append( "Sample location:\t" + dpoint[i].triple );
838  te->e->append( "Sample description:\t" + dpoint[i].description );
839  te->e->append( "Rotor speed:\t" + str.setNum( dpoint[i].speed ) + " rpm, (Rotor stretch: "
840  + str2.setNum( dpoint[i].stretch) + " cm)" );
841  te->e->append( "Peak position:\t" + str.setNum( dpoint[i].peakPosition ) + " cm");
842  te->e->append( "Peak density:\t" + str.setNum( dpoint[i].peakDensity ) + " g/ml");
843  te->e->append( "Peak vbar:\t\t" + str.setNum( dpoint[i].peakVbar ) + " ml/g");
844  te->e->append( "Buffer density:\t" + str.setNum( dpoint[i].bufferDensity ) + " g/ml");
845  te->e->append( "Meniscus position:\t" + str.setNum( dpoint[i].meniscus ) + " cm");
846  te->e->append( "Bottom of cell:\t" + str.setNum( dpoint[i].bottom ) +
847  " cm (Centerpiece bottom at rest: " + str2.setNum( dpoint[i].centerpiece ) + " cm)" );
848  te->e->append( "Temperature:\t" + str.setNum( dpoint[i].temperature ) + " °C");
849  te->e->append( "Gradient-forming\nmaterial details:");
850  te->e->append( "Molecular weight:\t" + str.setNum( dpoint[i].gradientMW ) + " g/mol" );
851  te->e->append( "Loading density:\t" + str.setNum( dpoint[i].gradientC0 ) + " g/mol" );
852  te->e->append( "vbar:\t\t" + str.setNum( dpoint[i].gradientVbar ) + " ml/g" );
853  te->e->append("\n");
854  }
855  te->setMinimumHeight( 400 );
856  te->setMinimumWidth( 600 );
857  te->show();
858 }
859 
860 // Select a new speed within a triple
861 void US_Buoyancy::new_rpmval( int index )
862 {
863  QString srpm = cb_rpms->itemText( index ), str;
864  qDebug() << "rpmval: " << srpm;
865  current_rpm = srpm.toDouble();
867  str.setNum( calc_stretch() );
868  le_stretch->setText( str );
869  if ( meniscus[current_triple] != 0 )
870  {
871  str.setNum( meniscus[current_triple] + current_stretch );
872  le_meniscus->setText( str );
873  }
875 }
876 
878 {
879  bottom = (double) le_bottom->text().toDouble();
880 }
881 
883 {
884  bottom_calc = (double) le_bottom_calc->text().toDouble();
885 }
886 
888 {
889  tmp_dpoint.gradientC0 = (double) le_dens_0->text().toDouble();
890 }
891 
893 {
894  tmp_dpoint.gradientVbar = (double) le_vbar->text().toDouble();
895 }
896 
898 {
899  tmp_dpoint.gradientMW = (double) le_MW->text().toDouble();
900 }
901 
903 {
904  tmp_dpoint.bufferDensity = (double) le_buffer_density->text().toDouble();
905 }
906 
908 {
909  tmp_dpoint.name = le_peakName->text();
910 }
911 
912 // this function lets the user edit the meniscus position
914 {
915  meniscus[current_triple] = (double) le_meniscus->text().toDouble() - current_stretch;
916 }
917 
919 {
920  sData.clear();
921  US_DataIO::SpeedData ssDat;
922  int ksd = 0;
923  for ( int jd = 0; jd < allData.size(); jd++ )
924  {
925  data = allData[ jd ];
926  sd_offs << ksd;
927 
928  if ( jd > 0 )
929  sd_knts << ( ksd - sd_offs[ jd - 1 ] );
930 
931  trip_rpms.clear();
932 
933  for ( int ii = 0; ii < data.scanData.size(); ii++ )
934  {
935  double drpm = data.scanData[ ii ].rpm;
936  QString arpm = QString::number( drpm );
937  if ( ! trip_rpms.contains( arpm ) )
938  {
939  trip_rpms << arpm;
940  ssDat.first_scan = ii + 1;
941  ssDat.scan_count = 1;
942  ssDat.speed = drpm;
943  ssDat.meniscus = 0.0;
944  ssDat.dataLeft = 0.0;
945  ssDat.dataRight = 0.0;
946  sData << ssDat;
947  ksd++;
948  }
949 
950  else
951  {
952  int jj = trip_rpms.indexOf( arpm );
953  ssDat = sData[ jj ];
954  ssDat.scan_count++;
955  sData[ jj ].scan_count++;
956  }
957  }
958 
959  if ( jd == 0 )
960  cb_rpms->addItems( trip_rpms );
961 
962  total_speeds += trip_rpms.size();
963  }
964 
965  sd_knts << ( ksd - sd_offs[ allData.size() - 1 ] );
966 
967  if ( allData.size() > 1 )
968  {
970  ksd = sd_knts[ current_triple ];
971  trip_rpms.clear();
972  cb_rpms ->clear();
973  for ( int ii = 0; ii < ksd; ii++ )
974  {
975  QString arpm = QString::number( sData[ ii ].speed );
976  trip_rpms << arpm;
977  }
978  cb_rpms->addItems( trip_rpms );
979  }
980 }
981 
983 {
984  return ( simparams[current_triple].rotorcoeffs[ 0 ]
985  * current_rpm + simparams[current_triple].rotorcoeffs[ 1 ]
986  * pow( current_rpm, 2.0 ) );
987 }