UltraScan III
us_convert_gui.cpp
Go to the documentation of this file.
1 #include <QApplication>
2 
3 #include "us_license_t.h"
4 #include "us_license.h"
5 #include "us_util.h"
6 #include "us_settings.h"
7 #include "us_gui_settings.h"
8 #include "us_run_details2.h"
9 #include "us_plot.h"
10 #include "us_math2.h"
11 #include "us_convert_gui.h"
12 #include "us_convertio.h"
13 #include "us_experiment_gui.h"
14 #include "us_select_triples.h"
15 #include "us_solution_gui.h"
16 #include "us_db2.h"
17 #include "us_passwd.h"
18 #include "us_intensity.h"
19 #include "us_get_run.h"
20 #include "us_investigator.h"
21 #include "us_constants.h"
22 #include "us_time_state.h"
23 #include "us_report.h"
24 #include "us_gui_util.h"
25 #include "us_util.h"
26 #include "us_images.h"
27 
28 #ifdef WIN32
29 #include <float.h>
30 #ifndef isnan
31 #define isnan _isnan
32 #endif
33 #endif
34 
35 int main( int argc, char* argv[] )
36 {
37  QApplication application( argc, argv );
38 
39  #include "main1.inc"
40 
41  // License is OK. Start up.
42 
43  US_ConvertGui w;
44  w.show();
45  return application.exec();
46 }
47 
49 {
51 
52  // Ensure data directories are there
53  QDir dir;
54  dir.mkpath( US_Settings::workBaseDir() );
55  dir.mkpath( US_Settings::importDir() );
56  dir.mkpath( US_Settings::tmpDir() );
57  dir.mkpath( US_Settings::dataDir() );
58  dir.mkpath( US_Settings::archiveDir() );
59  dir.mkpath( US_Settings::resultDir() );
60  dir.mkpath( US_Settings::reportDir() );
61  dir.mkpath( US_Settings::etcDir() );
62 
63  setWindowTitle( tr( "Import Experimental Data (Beckman-XLA/XLI,"
64  " Aviv Fluorescence, OpenAUC Multiwavelength)" ) );
65  setPalette( US_GuiSettings::frameColor() );
66 
67  isMwl = false;
68  tmst_fnamei = QString( "" );
70 DbgLv(0) << "CGui: dbg_level" << dbg_level;
71 
72  QGridLayout* settings = new QGridLayout;
73 
74  int row = 0;
75 
76  // First row
77  QStringList DB = US_Settings::defaultDB();
78  if ( DB.isEmpty() ) DB << "Undefined";
79  QLabel* lb_DB = us_banner( tr( "Database: " ) + DB.at( 0 ) );
80  lb_DB->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
81 
82  // Investigator
83  bool isadmin = ( US_Settings::us_inv_level() > 2 );
84  QWidget* wg_investigator;
85  QPushButton* pb_investigator = us_pushbutton( tr( "Select Investigator"));
86 
87  if ( isadmin )
88  { // Admin gets investigator button
89  wg_investigator = (QWidget*)pb_investigator;
90  }
91  else
92  { // Non-admin gets only investigator label
93  QLabel* lb_investigator = us_label( tr( "Investigator:" ) );
94  wg_investigator = (QWidget*)lb_investigator;
95  pb_investigator->setVisible( false );
96  }
97 
98  le_investigator = us_lineedit( tr( "Not Selected" ), 0, true );
99 
100  // Radio buttons
103 
104  // Display status
105  QLabel* lb_status = us_label( tr( "Status:" ) );
106  le_status = us_lineedit( tr( "(no data loaded)" ), 1, true );
107  QPalette stpal;
108  stpal.setColor( QPalette::Text, Qt::white );
109  stpal.setColor( QPalette::Base, Qt::blue );
110  le_status->setPalette( stpal );
111 
112  // Display Run ID
113  QLabel* lb_runID = us_label( tr( "Run ID:" ) );
114  // Add this later, after tabs:settings->addWidget( lb_runID, row, 0 );
115  lb_runID->setVisible( false ); // for now
116 
117  le_runID = us_lineedit( "", 1, true );
118  //le_runID ->setMinimumWidth( 280 );
119  // Add this later, after tabs: settings->addWidget( le_runID, row++, 1 );
120  le_runID ->setVisible ( false ); // for now
121 
122  // Load the run
123  QLabel* lb_run = us_banner( tr( "Load the Run" ) );
124 
125  // Pushbuttons to load and reload data
126  pb_import = us_pushbutton( tr( "Import Experimental Data" ) );
127 
128  // External program to enter experiment information
129  pb_editRuninfo = us_pushbutton( tr( "Edit Run Information" ) );
130  pb_editRuninfo->setEnabled( false );
131 
132  // load US3 data ( that perhaps has been done offline )
133  pb_loadUS3 = us_pushbutton( tr( "Load US3 OpenAUC Run" ), true );
134 
135  // Run details
136  pb_details = us_pushbutton( tr( "Run Details" ), false );
137 
138  // Set the wavelength tolerance for c/c/w determination
139  QLabel* lb_tolerance = us_label( tr( "Separation Tolerance:" ) );
140  ct_tolerance = us_counter ( 2, 0.0, 100.0, 5.0 );
141  ct_tolerance->setStep( 1 );
142 
143  // Set up MWL controls
145  QFontMetrics fmet( font );
146  static QChar clambda( 955 ); // Lambda character
147 
148  lb_mwlctrl = us_banner ( tr( "Multi-Wavelength Lambda Controls" ) );
149  lb_lambstrt = us_label ( tr( "%1 Start:" ).arg( clambda ) );
150  lb_lambstop = us_label ( tr( "%1 End:" ).arg( clambda ) );
151  lb_lambplot = us_label ( tr( "Plot %1:" ).arg( clambda ) );
155  pb_lambprev = us_pushbutton( "previous", true, -2 );
156  pb_lambnext = us_pushbutton( "next", true, -2 );
159 
160  mwl_connect( true );
161 
162  QLabel* lb_runinfo = us_banner( tr( "Run Information" ) );
163 
164  // Change Run ID
165  QLabel* lb_runID2 = us_label( tr( "Run ID:" ) );
166  le_runID2 = us_lineedit( "", 1 );
167  //le_runID2 ->setMinimumWidth( 225 );
168 
169  // Directory
170  QLabel* lb_dir = us_label( tr( "Directory:" ) );
171  le_dir = us_lineedit( "", 1, true );
172 
173  // Description
174  lb_description = us_label( tr( "Description:" ), 0 );
175  //lb_description ->setMaximumWidth( 175 );
176  le_description = us_lineedit( "", 1 );
177 
178  // Cell / Channel / Wavelength
179  QGridLayout* ccw = new QGridLayout();
180 
182  tr( "Cell / Channel / Wavelength" ), -1 );
184  lw_triple->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
185  lw_triple->setMaximumWidth ( 150 );
186  QLabel* lb_ccwinfo = us_label(
187  tr( "Enter Associated Triple (c/c/w) Info:" ) );
188 
189  // Set up centerpiece drop-down
190  cb_centerpiece = new US_SelectBox( this );
191  centerpieceInfo();
192  cb_centerpiece -> load();
193 
194  // External program to enter solution information
195  pb_solution = us_pushbutton( tr( "Manage Solutions" ), false );
196  pb_applyAll = us_pushbutton( tr( "Apply to All" ), false );
197  // Defining data subsets
198  pb_define = us_pushbutton( tr( "Define Subsets" ), false );
199  pb_process = us_pushbutton( tr( "Process Subsets" ), false );
200  // Choosing reference channel
201  pb_reference = us_pushbutton( tr( "Define Reference Scans" ), false );
202  pb_cancelref = us_pushbutton( tr( "Undo Reference Scans" ), false );
203  // Define intensity profile
204  pb_intensity = us_pushbutton( tr( "Show Intensity Profile" ), false );
205  // Drop Triples or Channel or Cell/Channel
206  pb_dropTrips = us_pushbutton( tr( "Drop Selected Triples" ), false );
207  pb_dropCelch = us_pushbutton( tr( "Drop Selected Data" ), false );
208  pb_dropChan = us_pushbutton( tr( "Drop All Channel 'A's" ), false );
209  // Document solutio
210  QLabel* lb_solution = us_label( tr( "Solution:" ) );
211  le_solutionDesc = us_lineedit( "", 1, true );
212  // Scan Controls
213  lb_scan = us_banner( tr( "Scan Controls" ) );
214  // Scan focus from
215  lb_from = us_label( tr( "Scan Focus from:" ), 0 );
216  lb_from->setAlignment( Qt::AlignVCenter | Qt::AlignRight );
217  ct_from = us_counter ( 3, 0.0, 0.0 ); // Update range upon load
218  ct_from->setStep( 1 );
219  // Scan focus to
220  lb_to = us_label( tr( "Scan Focus to:" ), 0 );
221  lb_to->setAlignment( Qt::AlignVCenter | Qt::AlignRight );
222  ct_to = us_counter ( 3, 0.0, 0.0 ); // Update range upon load
223  ct_to->setStep( 1 );
224 
225  // Exclude and Include pushbuttons
226  pb_exclude = us_pushbutton( tr( "Exclude Scan(s)" ), false );
227  pb_include = us_pushbutton( tr( "Include All" ), false );
228  pb_include ->setEnabled( false );
229  // Standard pushbuttons
230  QPushButton* pb_reset = us_pushbutton( tr( "Reset" ) );
231  QPushButton* pb_help = us_pushbutton( tr( "Help" ) );
232  pb_saveUS3 = us_pushbutton( tr( "Save" ) );
233  QPushButton* pb_close = us_pushbutton( tr( "Close" ) );
234 
235  // Add widgets to layouts
236  settings ->addWidget( lb_DB, row++, 0, 1, 4 );
237  settings ->addWidget( wg_investigator, row, 0, 1, 2 );
238  settings ->addWidget( le_investigator, row++, 2, 1, 2 );
239  settings ->addLayout( disk_controls, row++, 0, 1, 4 );
240  settings ->addWidget( lb_run, row++, 0, 1, 4 );
241  settings ->addWidget( pb_import, row, 0, 1, 2 );
242  settings ->addWidget( pb_editRuninfo, row++, 2, 1, 2 );
243  settings ->addWidget( pb_loadUS3, row, 0, 1, 2 );
244  settings ->addWidget( pb_details, row++, 2, 1, 2 );
245  settings ->addWidget( lb_tolerance, row, 0, 1, 2 );
246  settings ->addWidget( ct_tolerance, row++, 2, 1, 2 );
247  settings ->addWidget( lb_mwlctrl, row++, 0, 1, 4 );
248  settings ->addWidget( lb_lambstrt, row, 0, 1, 1 );
249  settings ->addWidget( cb_lambstrt, row, 1, 1, 1 );
250  settings ->addWidget( lb_lambstop, row, 2, 1, 1 );
251  settings ->addWidget( cb_lambstop, row++, 3, 1, 1 );
252  settings ->addWidget( lb_lambplot, row, 0, 1, 1 );
253  settings ->addWidget( cb_lambplot, row, 1, 1, 1 );
254  settings ->addWidget( pb_lambprev, row, 2, 1, 1 );
255  settings ->addWidget( pb_lambnext, row++, 3, 1, 1 );
256 
257  ccw ->addWidget( lb_runinfo, row++, 0, 1, 12 );
258  ccw ->addWidget( lb_runID2, row, 0, 1, 3 );
259  ccw ->addWidget( le_runID2, row++, 3, 1, 9 );
260  ccw ->addWidget( lb_dir, row, 0, 1, 3 );
261  ccw ->addWidget( le_dir, row++, 3, 1, 9 );
262  ccw ->addWidget( lb_triple, row++, 0, 1, 12 );
263  ccw ->addWidget( lb_description, row, 0, 1, 3 );
264  ccw ->addWidget( le_description, row++, 3, 1, 9 );
265  ccw ->addWidget( lw_triple, row, 0, 7, 4 );
266  ccw ->addWidget( lb_ccwinfo, row++, 4, 1, 8 );
267  ccw ->addWidget( cb_centerpiece, row++, 4, 1, 8 );
268  ccw ->addWidget( pb_solution, row, 4, 1, 4 );
269  ccw ->addWidget( pb_applyAll, row++, 8, 1, 4 );
270  ccw ->addWidget( pb_define, row, 4, 1, 4 );
271  ccw ->addWidget( pb_process, row++, 8, 1, 4 );
272  ccw ->addWidget( pb_reference, row, 4, 1, 4 );
273  ccw ->addWidget( pb_cancelref, row++, 8, 1, 4 );
274  ccw ->addWidget( pb_intensity, row, 4, 1, 4 );
275  ccw ->addWidget( pb_dropTrips, row++, 8, 1, 4 );
276  ccw ->addWidget( pb_dropCelch, row, 4, 1, 4 );
277  ccw ->addWidget( pb_dropChan, row++, 8, 1, 4 );
278  ccw ->addWidget( lb_solution, row, 0, 1, 3 );
279  ccw ->addWidget( le_solutionDesc, row++, 3, 1, 9 );
280  ccw ->addWidget( lb_status, row, 0, 1, 2 );
281  ccw ->addWidget( le_status, row++, 2, 1, 10 );
282 
283  settings ->addLayout( ccw, row++, 0, 1, 4 );
284 
285  settings ->addWidget( pb_reset, row, 0, 1, 1 );
286  settings ->addWidget( pb_help, row, 1, 1, 1 );
287  settings ->addWidget( pb_saveUS3, row, 2, 1, 1 );
288  settings ->addWidget( pb_close, row++, 3, 1, 1 );
289 
290  // Plot layout for the right side of window
291  QBoxLayout* plot = new US_Plot( data_plot,
292  tr( "Absorbance Data" ),
293  tr( "Radius (in cm)" ),
294  tr( "Absorbance" ) );
295 
296  data_plot->setMinimumSize( 500, 300 );
297 
298  data_plot->enableAxis( QwtPlot::xBottom, true );
299  data_plot->enableAxis( QwtPlot::yLeft , true );
300 
301  data_plot->setAxisScale( QwtPlot::xBottom, 5.7, 7.3 );
302  data_plot->setAxisScale( QwtPlot::yLeft , 0.0, 1.5 );
303 
304  picker = new US_PlotPicker( data_plot );
305  picker ->setRubberBand ( QwtPicker::VLineRubberBand );
306  picker->setMousePattern ( QwtEventPattern::MouseSelect1,
307  Qt::LeftButton, Qt::ControlModifier );
308 
309  QGridLayout* todo = new QGridLayout();
310 
311  // Instructions ( missing to do items )
312  QLabel* lb_todoinfo = us_banner( tr( "Instructions ( to do list )" ), 0 );
314  lw_todoinfo->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
315  lw_todoinfo->setMaximumHeight ( 90 );
316  lw_todoinfo->setSelectionMode( QAbstractItemView::NoSelection );
317 
318  // Scan controls:
319  todo->addWidget( lb_scan, row++, 0, 1, 4 );
320  todo->addWidget( lb_from, row, 0, 1, 2 );
321  todo->addWidget( ct_from, row++, 2, 1, 2 );
322  todo->addWidget( lb_to, row, 0, 1, 2 );
323  todo->addWidget( ct_to, row++, 2, 1, 2 );
324  todo->addWidget( pb_exclude, row, 0, 1, 2 );
325  todo->addWidget( pb_include, row++, 2, 1, 2 );
326  todo->addWidget( lb_todoinfo, row++, 0, 1, 4 );
327  todo->addWidget( lw_todoinfo, row++, 0, 1, 4 );
328 
329  // Connect signals and slots
330  if ( isadmin )
331  connect( pb_investigator, SIGNAL( clicked() ),
332  SLOT( sel_investigator() ) );
333  connect( disk_controls, SIGNAL( changed ( bool ) ),
334  SLOT ( source_changed( bool ) ) );
335  connect( pb_import, SIGNAL( clicked() ),
336  SLOT( import() ) );
337  connect( pb_editRuninfo, SIGNAL( clicked() ),
338  SLOT( editRuninfo() ) );
339  connect( pb_loadUS3, SIGNAL( clicked() ),
340  SLOT( loadUS3() ) );
341  connect( pb_details, SIGNAL( clicked() ),
342  SLOT( runDetails() ) );
343  connect( ct_tolerance, SIGNAL( valueChanged ( double ) ),
344  SLOT ( toleranceValueChanged( double ) ) );
345  connect( le_description, SIGNAL( textEdited( QString ) ),
346  SLOT ( changeDescription() ) );
347  connect( lw_triple, SIGNAL( itemSelectionChanged() ),
348  SLOT ( changeTriple() ) );
349  connect( cb_centerpiece, SIGNAL( activated ( int ) ),
350  SLOT ( getCenterpieceIndex( int ) ) );
351  connect( pb_solution, SIGNAL( clicked() ),
352  SLOT( getSolutionInfo() ) );
353  connect( pb_applyAll, SIGNAL( clicked() ),
354  SLOT( tripleApplyAll() ) );
355  connect( pb_define, SIGNAL( clicked() ),
356  SLOT( define_subsets() ) );
357  connect( pb_process, SIGNAL( clicked() ),
358  SLOT( process_subsets() ) );
359  connect( pb_reference, SIGNAL( clicked() ),
360  SLOT( define_reference() ) );
361  connect( pb_cancelref, SIGNAL( clicked() ),
362  SLOT( cancel_reference() ) );
363  connect( pb_intensity, SIGNAL( clicked() ),
364  SLOT( show_intensity() ) );
365  connect( pb_dropTrips, SIGNAL( clicked() ),
366  SLOT( drop_reference() ) );
367  connect( pb_dropCelch, SIGNAL( clicked() ),
368  SLOT( drop_cellchan() ) );
369  connect( pb_dropChan, SIGNAL( clicked() ),
370  SLOT( drop_channel() ) );
371  connect( pb_exclude, SIGNAL( clicked() ),
372  SLOT( exclude_scans() ) );
373  connect( pb_include, SIGNAL( clicked() ),
374  SLOT( include() ) );
375  connect( pb_reset, SIGNAL( clicked() ),
376  SLOT( resetAll() ) );
377  connect( pb_help, SIGNAL( clicked() ),
378  SLOT( help() ) );
379  connect( pb_saveUS3, SIGNAL( clicked() ),
380  SLOT( saveUS3() ) );
381  connect( pb_close, SIGNAL( clicked() ),
382  SLOT( close() ) );
383 
384  // Now let's assemble the page
385 
386  QVBoxLayout* left = new QVBoxLayout;
387 
388  left->addLayout( settings );
389 
390  QVBoxLayout* right = new QVBoxLayout;
391 
392  right->addLayout( plot );
393  right->addLayout( todo );
394 
395  QHBoxLayout* main = new QHBoxLayout( this );
396  main->setSpacing ( 2 );
397  main->setContentsMargins ( 2, 2, 2, 2 );
398 
399  main->addLayout( left );
400  main->addLayout( right );
401  main->setStretchFactor( left, 3 );
402  main->setStretchFactor( right, 5 );
403 
404 DbgLv(1) << "CGui: GUI setup complete";
405  reset();
406 DbgLv(1) << "CGui: reset complete";
407 }
408 
410 {
411  lw_triple ->clear();
412 
413  le_dir ->setText( "" );
414 
415  le_description ->setText( "" );
416  le_runID ->setText( "" );
417  le_runID2 ->setText( "" );
418  le_solutionDesc ->setText( "" );
419 
420  pb_import ->setEnabled( true );
421  pb_loadUS3 ->setEnabled( true );
422  pb_exclude ->setEnabled( false );
423  pb_include ->setEnabled( false );
424  pb_details ->setEnabled( false );
425  pb_intensity ->setEnabled( false );
426  pb_cancelref ->setEnabled( false );
427  pb_dropTrips ->setEnabled( false );
428  pb_dropCelch ->setEnabled( false );
429  pb_dropChan ->setEnabled( false );
430  pb_solution ->setEnabled( false );
431  pb_editRuninfo->setEnabled( false );
432  pb_applyAll ->setEnabled( false );
433  pb_saveUS3 ->setEnabled( false );
434 
435  ct_tolerance ->setEnabled( true );
436 
437  cb_centerpiece->setEnabled( false );
438 
439  ct_from ->disconnect();
440  ct_from ->setMinValue( 0 );
441  ct_from ->setMaxValue( 0 );
442  ct_from ->setValue ( 0 );
443 
444  ct_to ->disconnect();
445  ct_to ->setMinValue( 0 );
446  ct_to ->setMaxValue( 0 );
447  ct_to ->setValue ( 0 );
448 
449  // Clear any data structures
450  legacyData .clear();
451  allExcludes .clear();
452  all_tripinfo.clear();
453  all_chaninfo.clear();
454  all_triples .clear();
455  all_channels.clear();
456  out_tripinfo.clear();
457  out_chaninfo.clear();
458  out_triples .clear();
459  out_channels.clear();
460  allData .clear();
461  outData .clear();
462  ExpData .clear();
463  if ( isMwl )
464  mwl_data.clear();
465  show_plot_progress = true;
466 
467  // Erase the todo list
468  lw_todoinfo->clear();
469  lw_todoinfo->addItem( "Load or import some AUC data" );
470 
471  data_plot ->detachItems();
472  picker ->disconnect();
473  data_plot ->setAxisScale( QwtPlot::xBottom, 5.7, 7.3 );
474  data_plot ->setAxisScale( QwtPlot::yLeft , 0.0, 1.5 );
475  grid = us_grid( data_plot );
476  data_plot ->replot();
477 
478  pb_define ->setEnabled( false );
479  pb_process ->setEnabled( false );
480  step = NONE;
481 
482  enableRunIDControl( true );
483 
484  toleranceChanged = false;
486  isPseudo = false;
487  isMwl = false;
488 
489  pb_reference ->setEnabled( false );
490  referenceDefined = false;
491 DbgLv(1) << "CGui: (1)referDef=" << referenceDefined;
492 
493  // Display investigator
495 
496  QString number = ( ExpData.invID > 0 )
497  ? QString::number( ExpData.invID ) + ": "
498  : "";
499 
500  le_investigator->setText( number + US_Settings::us_inv_name() );
501  show_mwl_control( false );
502 }
503 
505 {
506  QApplication::restoreOverrideCursor();
507  QApplication::restoreOverrideCursor();
508 
509  if ( allData.size() > 0 )
510  { // Output warning when resetting (but only if we have data)
511  int status = QMessageBox::information( this,
512  tr( "New Data Warning" ),
513  tr( "This will erase all data currently on the screen, and "
514  "reset the program to its starting condition. No hard-drive "
515  "data or database information will be affected. Proceed? " ),
516  tr( "&OK" ), tr( "&Cancel" ),
517  0, 0, 1 );
518 
519  if ( status != 0 ) return;
520  }
521 
522  reset();
523 
524  le_status->setText( tr( "(no data loaded)" ) );
525  subsets.clear();
526  reference_start = 0;
527  reference_end = 0;
528 
529  connectTolerance( false );
530  ct_tolerance ->setMinValue( 0.0 );
531  ct_tolerance ->setMaxValue( 100.0 );
532  ct_tolerance ->setValue ( 5.0 );
533  ct_tolerance ->setStep( 1 );
534  connectTolerance( true );
535  scanTolerance = 5.0;
536  runID = "";
537  data_plot->setTitle( tr( "Absorbance Data" ) );
538 }
539 
540 // Function to select the current investigator
542 {
543  US_Investigator* inv_dialog = new US_Investigator( true, ExpData.invID );
544 
545  connect( inv_dialog,
546  SIGNAL( investigator_accepted( int ) ),
547  SLOT ( assign_investigator ( int ) ) );
548 
549  inv_dialog->exec();
550 }
551 
552 // Function to assign the selected investigator as current
554 {
555  ExpData.invID = invID;
556 
557  QString number = ( invID > 0 )
558  ? QString::number( invID ) + ": "
559  : "";
560 
561  le_investigator->setText( number + US_Settings::us_inv_name() );
562 
563 }
564 
565 // Function to change the data source (disk/db)
567 {
568  QStringList DB = US_Settings::defaultDB();
569 
570  if ( DB.size() < 5 )
571  {
572  QMessageBox::warning( this,
573  tr( "Attention" ),
574  tr( "There is no default database set." ) );
575  }
576 
577  // Did we switch from disk to db?
578  if ( disk_controls->db() && ! save_diskDB )
579  {
580  // Make sure these are explicitly chosen
581  ExpData.operatorID = 0;
582  ExpData.rotorID = 0;
584  }
585 
587 
588  // Reinvestigate whether to enable the buttons
589  enableControls();
590 }
591 
593 {
595 
596  ( db ) ? disk_controls->set_db() : disk_controls->set_disk();
597 }
598 
599 // User changed the dataset separation tolerance
601 {
602  toleranceChanged = true;
603  scanTolerance = ct_tolerance->value();
604  reimport();
605 }
606 
607 // User pressed the import data button
609 {
610  int impType = getImports();
611 
612  if ( impType == 1 )
613  {
614  importMWL();
615  return;
616  }
617 
618  else if ( impType == 2 )
619  {
620  importAUC();
621  return;
622  }
623 
624 DbgLv(1) << "CGui:IMP: IN";
625  bool success = false;
626  le_status->setText( tr( "Importing experimental data ..." ) );
627 
628  success = read(); // Read the legacy data
629 
630  if ( ! success ) return;
631 
632  // Define default tolerances before converting
633  scanTolerance = ( runType == "WA" ) ? 0.1 : 5.0;
634  connectTolerance( false );
635  ct_tolerance->setValue( scanTolerance );
636  connectTolerance( true );
637 
638  // Figure out all the triple combinations and convert data
639  success = convert();
640 
641  if ( ! success ) return;
642 
643  // Initialize export data pointers vector
644  success = init_output_data();
645 
646  if ( ! success ) return;
647 
648  setTripleInfo();
649 
650  checkTemperature(); // Check to see if temperature varied too much
651 
652  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
653 
654  // Initialize exclude list
655 DbgLv(1) << "CGui:IMP: init_excludes CALL";
656  init_excludes();
657 
658  plot_current();
659 
660  QApplication::restoreOverrideCursor();
661 
662  connect( ct_from, SIGNAL( valueChanged ( double ) ),
663  SLOT ( focus_from ( double ) ) );
664 
665  connect( ct_to , SIGNAL( valueChanged ( double ) ),
666  SLOT ( focus_to ( double ) ) );
667 
669 
670  // Ok to enable some buttons now
671 DbgLv(1) << "CGui:IMP: enableControls CALL";
672  enableControls();
673 
674  if ( runType == "RI" )
675  {
676  referenceDefined = false;
677  pb_reference->setEnabled( true );
678 DbgLv(1) << "CGui: (2)referDef=" << referenceDefined;
679  }
680 DbgLv(1) << "CGui: import: RTN";
681  le_status->setText( tr( "Legacy data has been imported." ) );
682 }
683 
684 // User pressed the reimport data button
685 // Legacy data is already supposed to be present
687 {
688  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
689  if ( toleranceChanged )
690  {
691  // If the tolerance has changed, we need to reconvert the data
692  toleranceChanged = false;
693  bool success = false;
694 
695  all_tripinfo.clear();
696 
697  le_solutionDesc ->setText( "" );
698 
699  // Figure out all the triple combinations and convert data
700  success = convert();
701 
702  if ( success )
703  success = init_output_data();
704 
705  if ( ! success )
706  {
707  QApplication::restoreOverrideCursor();
708  return;
709  }
710 
711  setTripleInfo();
712  }
713 
714  // Initialize exclude list
715  init_excludes();
716 
717  // In this case the runType is not changing
719 
720  pb_include->setEnabled( false );
721  pb_exclude->setEnabled( false );
722  plot_current();
723  QApplication::restoreOverrideCursor();
724 
725  connect( ct_from, SIGNAL( valueChanged ( double ) ),
726  SLOT ( focus_from ( double ) ) );
727 
728  connect( ct_to , SIGNAL( valueChanged ( double ) ),
729  SLOT ( focus_to ( double ) ) );
730 
731  // Ok to enable some buttons now
732  enableControls();
733 
734  if ( runType == "RI" )
735  {
736  referenceDefined = false;
737  pb_reference->setEnabled( true );
738 DbgLv(1) << "CGui: (3)referDef=" << referenceDefined;
739  }
740 }
741 
742 // Import sub-directory contains MWL data
744 {
745 DbgLv(1) << "CGui:iM: IN";
746  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
747 
748  // Read the data
749  le_status->setText( tr( "Importing MWL data ..." ) );
750  qApp->processEvents();
751 DbgLv(1) << "CGui:iM: import_data";
753 
754  if ( !isMwl && le_status->text().contains( tr( "duplicate" ) ) )
755  { // If import problem was duplicate wavelengths, report it.
756  QMessageBox::warning( this,
757  tr( "Duplicate Wavelengths" ),
758  tr( "Duplicate wavelengths were encountered in the import"
759  " of the Multi-WaveLength data.\n\n"
760  "All duplicate triples were skipped." ) );
761  isMwl = true;
762  }
763 
764  if ( !isMwl )
765  { // Return immediately if there were MWL import problems
766  qApp->processEvents();
767  QApplication::restoreOverrideCursor();
768  QApplication::restoreOverrideCursor();
769  le_status->setText( tr( "MWL import error (no data loaded)" ) );
770  qApp->processEvents();
771  return;
772  }
773 
774 DbgLv(1) << "CGui:iM: RTN: import_data";
775  isMwl = true;
776  runType = "RI";
778 DbgLv(1) << "CGui:iM: runID runType" << runID << runType;
779  QApplication::restoreOverrideCursor();
780 
781  // if runType has changed, let's clear out xml data too
782 // if ( oldRunType != runType ) ExpData.clear();
783  le_runID2->setText( runID );
784  le_runID ->setText( runID );
785  le_dir ->setText( currentDir );
786  ExpData.runID = runID;
787 
788  // Define default tolerances before converting
789  connectTolerance( false );
790  scanTolerance = ( runType == "WA" ) ? 0.1 : 5.0;
791  ct_tolerance->setValue( scanTolerance );
792  connectTolerance( true );
793 
794 DbgLv(1) << "CGui:iM: show_mwl_control";
795  show_mwl_control( true );
796 DbgLv(1) << "CGui:iM: RTN:show_mwl_control";
797  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
798 
799  // Set initial lambda range; build the output data
800  le_status->setText( tr( "Duplicating wavelengths ..." ) );
801  qApp->processEvents();
802  slambda = mwl_data.countOf( "slambda" );
803  elambda = mwl_data.countOf( "elambda" );
804 DbgLv(1) << "CGui:iM: set_lambd sl el" << slambda << elambda;
805  mwl_data.set_lambdas ( slambda, elambda );
806 
807  le_status->setText( tr( "Building raw data AUCs ..." ) );
808  qApp->processEvents();
809 DbgLv(1) << "CGui:iM: buildraw";
811 DbgLv(1) << "CGui:iM: init_out";
812  if ( ! init_output_data() )
813  return;
814 
815  le_status->setText( tr( "Building Lambda list ..." ) );
816  qApp->processEvents();
817 
818  // Set up MWL data object after import
819 DbgLv(1) << "CGui:iM: mwlsetup";
820  mwl_setup();
821 
822  // Point to any existing time state file
823  QDir ddir( currentDir );
824  QStringList tmsfs = ddir.entryList( QStringList( "*.time_state.*" ),
825  QDir::Files, QDir::Name );
826  QString defs_fnamei;
827  QString tmst_dname = currentDir;
828  if ( tmst_dname.right( 1 ) != "/" )
829  tmst_dname += "/";
830 
831  if ( tmsfs.count() == 2 )
832  { // Looks like we have a TMST and corresponding Defs XML
833  tmst_fnamei = tmsfs[ 0 ];
834  defs_fnamei = tmsfs[ 1 ];
835 
836  if ( tmst_fnamei.contains( ".tmst" ) &&
837  defs_fnamei.contains( ".xml" ) )
838  { // Have both files, so save full path to TMST
839  tmst_fnamei = tmst_dname + tmst_fnamei;
840  }
841 
842  else if ( tmsfs[ 0 ].contains( ".xml" ) &&
843  tmsfs[ 1 ].contains( ".tmst" ) )
844  { // Have both files (in opposite order), so save full path to TMST
845  tmst_fnamei = tmst_dname + tmsfs[ 1 ];
846  }
847 
848  else
849  { // Do not have both files, so clear TMST file path
850  tmst_fnamei.clear();
851  }
852  }
853 
854  else // If file does not exist, clear name
855  {
856  tmst_fnamei.clear();
857  }
858 
859 // le_status->setText( tr( "MWL Import IS COMPLETE." ) );
860  qApp->processEvents();
861  QApplication::restoreOverrideCursor();
862 DbgLv(1) << "CGui:iM: DONE";
863 }
864 
865 // Import simulation data in AUC form
867 {
868  QString importDir = currentDir;
869  QDir readDir( importDir );
870 
871  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
872  le_status->setText( tr( "Loading AUC simulation data ..." ) );
873  QStringList nameFilters = QStringList( "*.auc" );
874  QStringList files = readDir.entryList( nameFilters,
875  QDir::Files | QDir::Readable, QDir::Name );
876  allData .clear();
877  all_tripinfo.clear();
878 
879  for ( int trx = 0; trx < files.size(); trx++ )
880  {
881  QString fname = files[ trx ];
882  QString fpath = importDir + "/" + fname;
883  US_DataIO::RawData rdata;
884  US_Convert::TripleInfo tripinfo;
885 
886  US_DataIO::readRawData( fpath, rdata );
887 
888  allData << rdata;
889 
890  QString triple = QString::number( rdata.cell ) + " / "
891  + QString( rdata.channel ) + " / "
892  + QString::number( qRound( rdata.scanData[ 0 ].wavelength ) );
893  tripinfo.tripleID = trx + 1;
894  tripinfo.tripleDesc = triple;
895  tripinfo.description = rdata.description;
896  tripinfo.channelID = trx + 1;
897  tripinfo.excluded = false;
898 
899  all_tripinfo << tripinfo;
900  }
901  qApp->processEvents();
902  QApplication::restoreOverrideCursor();
903 
904  QString fname = files[ 0 ];
905  runType = QString( fname ).section( ".", -5, -5 );
906  runID = QString( fname ).section( ".", 0, -6 );
907  le_runID2->setText( runID );
908  le_runID ->setText( runID );
909  scanTolerance = 5.0;
910 
911  if ( ! init_output_data() )
912  return;
913 
914  setTripleInfo();
915  le_description -> setText( allData[ 0 ].description );
916  init_excludes();
917  plot_current();
919  enableControls();
920 
921  // Point to any existing time state file
922  QDir ddir( currentDir );
923  QStringList tmsfs = ddir.entryList( QStringList( "*.time_state.*" ),
924  QDir::Files, QDir::Name );
925  QString defs_fnamei;
926  QString tmst_dname = currentDir;
927  if ( tmst_dname.right( 1 ) != "/" )
928  tmst_dname += "/";
929 DbgLv(1) << "rTS: tmst_dname" << tmst_dname << "tmsfs count" << tmsfs.count();
930 
931  if ( tmsfs.count() == 2 )
932  { // Looks like we have a TMST and corresponding Defs XML
933  tmst_fnamei = tmsfs[ 0 ];
934  defs_fnamei = tmsfs[ 1 ];
935 DbgLv(1) << "rTS: tmsfs" << tmst_fnamei << defs_fnamei;
936 
937  if ( tmst_fnamei.contains( ".tmst" ) &&
938  defs_fnamei.contains( ".xml" ) )
939  { // Have both files, so save full path to TMST
940  tmst_fnamei = tmst_dname + tmst_fnamei;
941  }
942 
943  else if ( tmsfs[ 0 ].contains( ".xml" ) &&
944  tmsfs[ 1 ].contains( ".tmst" ) )
945  { // Have both files (in opposite order), so save full path to TMST
946  tmst_fnamei = tmst_dname + tmsfs[ 1 ];
947  }
948 
949  else
950  { // Do not have both files, so clear TMST file path
951  tmst_fnamei.clear();
952  }
953 DbgLv(1) << "rTS: tmst,defs fnamei" << tmst_fnamei << defs_fnamei;
954  }
955 
956  else // If file does not exist, clear name
957  {
958 DbgLv(1) << "rTS: NON_EXIST:" << tmst_fnamei;
959  tmst_fnamei.clear();
960  }
961 
962  le_status->setText( tr( "AUC simulation data import IS COMPLETE." ) );
963 }
964 
965 // Enable the common dialog controls when there is data
967 {
968  if ( allData.size() == 0 )
969  reset();
970 
971  else
972  {
973 DbgLv(1) << "CGui: enabCtl: have-data" << allData.size() << all_tripinfo.size();
974  // Ok to enable some buttons now
975  pb_details ->setEnabled( true );
976  pb_solution ->setEnabled( true );
977  cb_centerpiece ->setEnabled( true );
978  pb_editRuninfo ->setEnabled( true );
979 
980  // Ok to drop scan if not the only one
981  int currentScanCount = 0;
982 
983  for ( int i = 0; i < all_tripinfo.size(); i++ )
984  if ( ! all_tripinfo[ i ].excluded ) currentScanCount++;
985 
986  bool drops = ( currentScanCount > 1 );
987  pb_dropTrips ->setEnabled( drops );
988  pb_dropCelch ->setEnabled( drops && isMwl );
989  pb_dropChan ->setEnabled( drops && isMwl );
990 
991  if ( runType == "RI" )
992  pb_reference->setEnabled( ! referenceDefined );
993 
994  if ( subsets.size() < 1 )
995  {
996  // Allow user to define subsets, if he hasn't already
997  pb_define ->setEnabled( true );
998  }
999 
1000  // Disable load buttons if there is data
1001  pb_import ->setEnabled( false );
1002  pb_loadUS3->setEnabled( false );
1003 
1004  // Most triples are ccw
1005  lb_triple ->setText( tr( "Cell / Channel / Wavelength" ) );
1006  connectTolerance( false );
1007  ct_tolerance->setNumButtons ( 2 );
1008  ct_tolerance->setRange ( 0.0, 100.0 );
1009  ct_tolerance->setStep ( 1.0 );
1010  ct_tolerance->setValue ( scanTolerance );
1011 
1012  // Default tolerances are different for wavelength data
1013  if ( runType == "WA" )
1014  {
1015  // First of all, wavelength triples are ccr.
1016  lb_triple ->setText( tr( "Cell / Channel / Radius" ) );
1017  ct_tolerance->setNumButtons ( 3 );
1018  ct_tolerance->setRange ( 0.0, 10.0 );
1019  ct_tolerance->setStep ( 0.001 );
1020  ct_tolerance->setValue ( scanTolerance );
1021  }
1022 
1023  connectTolerance( true );
1024 
1025  // Let's calculate if we're eligible to copy this triple info to all
1026  // or to save it
1027  // We have to check against GUID's, because solutions won't have
1028  // solutionID's yet if they are created as needed offline
1029  QRegExp rx( "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" );
1030 
1031  pb_applyAll -> setEnabled( false );
1032 // if ( all_tripinfo.size() > 1 &&
1033 // rx.exactMatch( all_tripinfo[ tripListx ].solution.solutionGUID ) )
1034  if ( out_chaninfo.size() > 1 &&
1035  rx.exactMatch( out_chaninfo[ tripListx ].solution.solutionGUID ) )
1036  {
1037  pb_applyAll -> setEnabled( true );
1038  }
1039 
1041 
1042  enableSaveBtn();
1043 DbgLv(1) << "CGui: enabCtl: enabSvBtn complete";
1044  }
1045 }
1046 
1047 // Enable or disable the runID control
1049 {
1050  if ( setEnable )
1051  {
1052  us_setReadOnly( le_runID2, false );
1053  connect( le_runID2, SIGNAL( textEdited( QString ) ),
1054  SLOT ( runIDChanged( ) ) );
1055  }
1056 
1057  else
1058  {
1059  le_runID2->disconnect();
1060  us_setReadOnly( le_runID2, true );
1061  }
1062 
1063 }
1064 
1065 // Reset the boundaries on the scan controls
1067 {
1068 DbgLv(1) << "CGui:enabScContr: isMwl" << isMwl;
1069 // if ( isMwl ) return;
1070  triple_index();
1071 DbgLv(1) << "CGui:enabScContr: trx dax" << tripListx << tripDatax;
1072 
1073  ct_from->disconnect();
1074  ct_from->setMinValue( 0.0 );
1075  ct_from->setMaxValue( outData[ tripDatax ]->scanData.size()
1076  - allExcludes[ tripDatax ].size() );
1077  ct_from->setValue ( 0 );
1078 
1079  ct_to ->disconnect();
1080  ct_to ->setMinValue( 0.0 );
1081  ct_to ->setMaxValue( outData[ tripDatax ]->scanData.size()
1082  - allExcludes[ tripDatax ].size() );
1083  ct_to ->setValue ( 0 );
1084 
1085  connect( ct_from, SIGNAL( valueChanged ( double ) ),
1086  SLOT ( focus_from ( double ) ) );
1087 
1088  connect( ct_to , SIGNAL( valueChanged ( double ) ),
1089  SLOT ( focus_to ( double ) ) );
1090 
1091 }
1092 
1093 // Enable the "save" button, if appropriate
1094 // Let's use the same logic to populate the todo list too
1096 {
1097  lw_todoinfo->clear();
1098  int count = 0;
1099  bool completed = true;
1100 DbgLv(1) << " enabCtl: tLx infsz" << tripListx << out_chaninfo.count();
1102 
1103  if ( allData.size() == 0 )
1104  {
1105  count++;
1106  lw_todoinfo->addItem( QString::number( count )
1107  + tr( ": Load or import some AUC data" ) );
1108  completed = false;
1109  }
1110 
1111  // Do we have any triples?
1112  if ( all_tripinfo.size() == 0 )
1113  {
1114  count++;
1115  lw_todoinfo->addItem( QString::number( count )
1116  + tr( ": Load or import some AUC data" ) );
1117  completed = false;
1118  }
1119 
1120  // Is the run info defined?
1121  QRegExp rx( "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" );
1122 
1123  // Not checking operator on disk -- defined as "Local"
1124  if ( ( ExpData.rotorID == 0 ) ||
1125  ( ExpData.calibrationID == 0 ) ||
1126  ( ExpData.labID == 0 ) ||
1127  ( ExpData.instrumentID == 0 ) ||
1128  ( ExpData.label.isEmpty() ) ||
1129  ( ! rx.exactMatch( ExpData.project.projectGUID ) ) )
1130  {
1131  if ( ! referenceDefined )
1132  {
1133  count++;
1134  lw_todoinfo->addItem( QString::number( count )
1135  + tr( ": Modify run ID (optional)" ) );
1136  }
1137  count++;
1138  lw_todoinfo->addItem( QString::number( count )
1139  + tr( ": Edit run information" ) );
1140  completed = false;
1141  }
1142 
1143  // Have we filled out all the c/c/w info?
1144  // Check GUIDs, because solutionID's may not be present yet.
1145  foreach ( US_Convert::TripleInfo tripinfo, out_chaninfo )
1146  {
1147  if ( ! rx.exactMatch( tripinfo.solution.solutionGUID ) )
1148  {
1149  count++;
1150  lw_todoinfo->addItem( QString::number( count ) +
1151  tr( ": Select solution for triple " ) +
1152  tripinfo.tripleDesc );
1153  completed = false;
1154  }
1155  }
1156 
1157  foreach ( US_Convert::TripleInfo tripinfo, out_chaninfo )
1158  {
1159  if ( tripinfo.centerpiece == 0 )
1160  {
1161  count++;
1162  lw_todoinfo->addItem( QString::number( count ) +
1163  tr( ": Select centerpiece for triple " ) +
1164  tripinfo.tripleDesc );
1165  completed = false;
1166  }
1167  }
1168 
1169  if ( disk_controls->db() )
1170  {
1171  // Verify connectivity
1172  US_Passwd pw;
1173  QString masterPW = pw.getPasswd();
1174  US_DB2 db( masterPW );
1175 
1176  if ( db.lastErrno() != US_DB2::OK )
1177  {
1178  count++;
1179  lw_todoinfo->addItem( QString::number( count ) +
1180  tr( ": Verify database connectivity" ) );
1181  completed = false;
1182  }
1183 
1184  // Information is there, but we need to see if the runID exists in the
1185  // DB. If we didn't load it from there, then we shouldn't be able to sync
1186  int recStatus = ExpData.checkRunID( &db );
1187 
1188  // if a record is found but saveStatus==BOTH,
1189  // then we are editing that record
1190  if ( ( recStatus == US_DB2::OK ) && ( saveStatus != BOTH ) ) // ||
1191  // ( ! ExpData.syncOK ) )
1192  {
1193  count++;
1194  lw_todoinfo->addItem( QString::number( count ) +
1195  tr( ": Select a different runID" ) );
1196  completed = false;
1197  }
1198 
1199  // Not checking operator on disk -- defined as "Local"
1200  if ( ExpData.operatorID == 0 )
1201  {
1202  count++;
1203  lw_todoinfo->addItem( QString::number( count )
1204  + tr( ": Select operator in run information" ) );
1205  completed = false;
1206  }
1207 
1208  }
1209 
1210  // This can go on the todo list, but should not prevent user from saving
1211  if ( ( runType == "RI" ) && ( ! referenceDefined ) )
1212  {
1213  count++;
1214  lw_todoinfo->addItem( QString::number( count ) +
1215  tr( ": Define reference scans" ) );
1216 
1217  if ( count == 1 )
1218  pb_reference->setEnabled( true );
1219  }
1220 
1221  // If we made it here, user can save
1222  pb_saveUS3 ->setEnabled( completed );
1223 }
1224 
1225 // Process when the user changes the runID
1227 {
1228  // See if we need to update the runID
1229  QRegExp rx( "^[A-Za-z0-9_-]{1,80}$" );
1230  QString new_runID = le_runID2->text();
1231 
1232  if ( rx.indexIn( new_runID ) >= 0 )
1233  {
1234  runID = new_runID;
1235  if ( runID.length() > 50 )
1236  {
1237  QMessageBox::warning( this,
1238  tr( "RunID Name Too Long" ),
1239  tr( "The runID name may be at most\n"
1240  "50 characters in length." ) );
1241  runID = runID.left( 50 );
1242  }
1243  plot_titles();
1244  }
1245 
1246  // If the runID has changed, a number of other things need to change too,
1247  // for instance GUID's.
1248  if ( referenceDefined )
1249  cancel_reference();
1250  ExpData.clear();
1251  foreach( US_Convert::TripleInfo tripinfo, all_tripinfo )
1252  tripinfo.clear();
1253  le_runID2->setText( runID );
1254  le_runID ->setText( runID );
1255 
1257 
1258  // Set the directory too
1259  QDir resultDir( US_Settings::resultDir() );
1260  currentDir = resultDir.absolutePath() + "/" + runID + "/";
1261  le_dir ->setText( currentDir );
1262 }
1263 
1264 // Function to generate a new guid for experiment, and associate with DB
1266 {
1267 DbgLv(1) << "CGui: edRuninfo: IN";
1268  if ( saveStatus == NOT_SAVED )
1269  {
1270  // Create a new GUID for the experiment as a whole
1272 
1273  }
1274 
1275  getExpInfo( );
1276 DbgLv(1) << "CGui: edRuninfo: getExpInfo complete";
1277 }
1278 
1279 // Function to load US3 data
1281 {
1282  // Open a dialog to get the RunID from DB or Disk
1283  US_GetRun dialog( runID, disk_controls->db() );
1284 
1285  connect( &dialog, SIGNAL( dkdb_changed ( bool ) ),
1286  this, SLOT ( update_disk_db( bool ) ) );
1287 
1288  if ( dialog.exec() == QDialog::Rejected )
1289  return;
1290 
1291  if ( runID == QString( "" ) )
1292  return;
1293 
1294  // Restore area beneath dialog
1295  qApp->processEvents();
1296 
1297 DbgLv(1) << "CGui: ldUS3: IN";
1298  // Load the data
1299  if ( disk_controls->db() )
1300  loadUS3DB();
1301 
1302  else
1303  loadUS3Disk();
1304 
1305  checkTemperature(); // Check to see if temperature varied too much
1306 DbgLv(1) << "CGui: ldUS3: RTN";
1307 
1308 }
1309 
1310 // Load AUC data from disk
1312 {
1313  // Construct the full path to the run directory
1314  QString dir = US_Settings::resultDir() + "/" + runID;
1315 
1316  dir.replace( "\\", "/" ); // WIN32 issue
1317  if ( dir.right( 1 ) != "/" ) dir += "/"; // Ensure trailing /
1318 
1319  // Load data from disk
1320  loadUS3Disk( dir );
1321 }
1322 
1323 // Load AUC data from a specified directory on local disk
1324 void US_ConvertGui::loadUS3Disk( QString dir )
1325 {
1326  resetAll();
1327  le_status->setText( tr( "Loading data from local disk ..." ) );
1328  qApp->processEvents();
1329 
1330  // Check the runID
1331  QStringList components = dir.split( "/", QString::SkipEmptyParts );
1332  QString new_runID = components.last();
1333 
1334  QRegExp rx( "^[A-Za-z0-9_-]{1,80}$" );
1335  if ( rx.indexIn( new_runID ) < 0 )
1336  {
1337  QMessageBox::warning( this,
1338  tr( "Bad runID Name" ),
1339  tr( "The runID name may consist only of alphanumeric\n"
1340  "characters, the underscore, and the hyphen." ) );
1341  return;
1342  }
1343 
1344  // Set the runID and directory
1345  runID = new_runID;
1346  le_runID ->setText( runID );
1347  le_runID2->setText( runID );
1348  le_dir ->setText( dir );
1349  currentDir = QString( dir );
1350 
1351  // Reload the AUC data
1352  le_status->setText( tr( "Loading data from Disk (raw data) ..." ) );
1353  qApp->processEvents();
1354 DbgLv(1) << "CGui: ldUS3Dk: call read";
1355  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
1356  int status = US_Convert::readUS3Disk( dir, allData, all_tripinfo, runType );
1357  QApplication::restoreOverrideCursor();
1358 
1359  if ( status == US_Convert::NODATA )
1360  {
1361  QMessageBox::warning( this,
1362  tr( "No Files Found" ),
1363  tr( "There were no files of the form *.auc\n"
1364  "found in the specified directory." ) );
1365  return;
1366  }
1367 
1368  if ( status == US_Convert::NOAUC )
1369  {
1370  QMessageBox::warning( this,
1371  tr( "UltraScan Error" ),
1372  tr( "Could not read data file.\n" ) );
1373  return;
1374  }
1375 
1376  // Now try to read the xml file
1377 DbgLv(1) << "CGui: ldUS3Dk: call rdExp sz(trinfo)" << all_tripinfo.count();
1378  le_status->setText( tr( "Loading data from Disk (experiment) ..." ) );
1379  qApp->processEvents();
1380  ExpData.clear();
1381  status = ExpData.readFromDisk( all_tripinfo, runType, runID, dir );
1382 
1383  if ( status == US_Convert::CANTOPEN )
1384  {
1385  QString readFile = runID + "."
1386  + runType + ".xml";
1387  QMessageBox::information( this,
1388  tr( "Error" ),
1389  tr( "US3 run data ok, but unable to assocate run with DB.\n " ) +
1390  tr( "Cannot open read file: " ) + dir + readFile );
1391  }
1392 
1393  else if ( status == US_Convert::BADXML )
1394  {
1395  QString readFile = runID + "."
1396  + runType + ".xml";
1397  QMessageBox::information( this,
1398  tr( "Error" ),
1399  tr( "US3 run data ok, but there is an error in association with DB.\n"
1400  "Improper XML in read file: " ) + dir + readFile );
1401  }
1402 
1403  else if ( status != US_Convert::OK )
1404  {
1405  QMessageBox::information( this,
1406  tr( "Error" ),
1407  tr( "Unknown error: " ) + status );
1408  }
1409 
1410  // Now that we have the experiment, let's read the rest of the
1411  // solution and project information
1412  le_status->setText( tr( "Loading data from Disk (project) ..." ) );
1413  qApp->processEvents();
1414 DbgLv(1) << "CGui: ldUS3Dk: call prj-rDk";
1416 
1417  // Error reporting
1418  if ( status == US_DB2::NO_PROJECT )
1419  {
1420  QMessageBox::information( this,
1421  tr( "Attention" ),
1422  tr( "The project was not found.\n"
1423  "Please select an existing project and try again.\n" ) );
1424  }
1425 
1426  else if ( status != US_DB2::OK )
1427  {
1428  QMessageBox::information( this,
1429  tr( "Disk Read Problem" ),
1430  tr( "Could not read data from the disk.\n"
1431  "Disk status: " ) + QString::number( status ) );
1432  }
1433 
1434  // and clear it out
1435  if ( status != US_DB2::OK )
1436  ExpData.project.clear();
1437 
1438  le_status->setText( tr( "Project and experiment are loaded." ) );
1439  qApp->processEvents();
1440  QString psolGUID = "";
1441 DbgLv(1) << "CGui: SOLCHK:loop";
1442 
1443  // Now the solutions
1444  for ( int ii = 0; ii < all_tripinfo.size(); ii++ )
1445  {
1446  QString csolGUID = all_tripinfo[ ii ].solution.solutionGUID;
1447 
1448  if ( csolGUID == psolGUID )
1449  {
1450  all_tripinfo[ ii ].solution = all_tripinfo[ ii - 1 ].solution;
1451  status = US_DB2::OK;
1452  continue;
1453  }
1454  else
1455  {
1456  if ( csolGUID.isEmpty() )
1457  {
1458 DbgLv(1) << "SOLCHK: ii csolGUID EMPTY" << ii << csolGUID;
1459  if ( ii > 0 )
1460  {
1461  csolGUID = psolGUID;
1462  all_tripinfo[ ii ].solution.solutionGUID = csolGUID;
1463  }
1464  }
1465  status = all_tripinfo[ ii ].solution.readFromDisk( csolGUID );
1466  psolGUID = csolGUID;
1467  }
1468 
1469  // Error reporting
1470  if ( status == US_DB2::NO_SOLUTION )
1471  {
1472  QMessageBox::information( this,
1473  tr( "Attention" ),
1474  tr( "A solution this run refers to was not found,"
1475  " or could not be read.\n"
1476  "Please select an existing solution and try again.\n" ) );
1477 DbgLv(1) << "SOLERR: ii psolGUID csolGUI" << ii << psolGUID << csolGUID;
1478  }
1479 
1480  else if ( status == US_DB2::NO_BUFFER )
1481  {
1482  QMessageBox::information( this,
1483  tr( "Attention" ),
1484  tr( "The buffer this solution refers to was not found.\n"
1485  "Please restore and try again.\n" ) );
1486  }
1487 
1488  else if ( status == US_DB2::NO_ANALYTE )
1489  {
1490  QMessageBox::information( this,
1491  tr( "Attention" ),
1492  tr( "One of the analytes this solution refers to was not found.\n"
1493  "Please restore and try again.\n" ) );
1494  }
1495 
1496  else if ( status != US_DB2::OK )
1497  {
1498  QMessageBox::information( this,
1499  tr( "Disk Read Problem" ),
1500  tr( "Could not read data from the disk.\n"
1501  "Disk status: " ) + QString::number( status ) );
1502  }
1503 
1504  // Just clear it out
1505  if ( status != US_DB2::OK )
1506  all_tripinfo[ ii ].solution.clear();
1507  }
1508 DbgLv(1) << "CGui: SOLCHK:loop-END";
1509 
1510  le_status->setText( tr( "Solutions are now loaded." ) );
1511  qApp->processEvents();
1512 
1513  // Now read the RI Profile, if it exists
1514  if ( runType == "RI" )
1515  {
1516  referenceDefined = false;
1517  pb_reference->setEnabled( true );
1518 DbgLv(1) << "CGui: (4)referDef=" << referenceDefined;
1519 
1520 DbgLv(1) << "CGui: call rdRIDk";
1521  status = ExpData.readRIDisk( runID, dir );
1522 
1523  if ( status == US_Convert::CANTOPEN )
1524  {
1525  QString readFile = runID + "."
1526  + "RIProfile.xml";
1527  QMessageBox::information( this,
1528  tr( "Error" ),
1529  tr( "US3 run data ok, but unable to read intensity profile.\n " ) +
1530  tr( "Cannot open read file: " ) + dir + readFile );
1531  }
1532 
1533  else if ( status == US_Convert::BADXML )
1534  {
1535  QString readFile = runID + "."
1536  + "RIProfile.xml";
1537  QMessageBox::information( this,
1538  tr( "Error" ),
1539  tr( "US3 run data ok, but unable to read intensity profile.\n " ) +
1540  tr( "Improper XML in read file: " ) + dir + readFile );
1541  }
1542 
1543  else if ( status != US_Convert::OK )
1544  {
1545  QMessageBox::information( this,
1546  tr( "Error" ),
1547  tr( "Unknown error: " ) + status );
1548  }
1549 
1550  else
1551  {
1552  // Enable intensity plot
1553  pb_intensity->setEnabled( true );
1554 
1555  referenceDefined = true;
1556  isPseudo = true;
1557 DbgLv(1) << "CGui: (5)referDef=" << referenceDefined;
1558  pb_reference->setEnabled( false );
1559  pb_cancelref->setEnabled( true );
1560  }
1561 
1562  }
1563 
1564  if ( allData.size() == 0 ) return;
1565 
1566  le_status->setText( tr( "%1 data triples are NOW LOADED." )
1567  .arg( allData.size() ) );
1568  qApp->processEvents();
1569 
1570  // Initialize export data pointers vector
1571  if ( ! init_output_data() )
1572  return;
1573 
1574 DbgLv(1) << "CGui: ldUS3Dk: fromIOD: sz(trinfo)" << all_tripinfo.count();
1575 
1576  // Copy solution and centerpiece info to channel vectors
1577  int cCenterpiece = all_tripinfo[ 0 ].centerpiece;
1578  US_Solution cSolution = all_tripinfo[ 0 ].solution;
1579  int idax = 0;
1580 
1581  for ( int ii = 0; ii < all_chaninfo.size(); ii++ )
1582  {
1583  if ( idax != out_chandatx[ ii ] )
1584  {
1585  idax = out_chandatx[ ii ];
1586  cCenterpiece = all_tripinfo[ idax ].centerpiece;
1587  cSolution = all_tripinfo[ idax ].solution;
1588  }
1589 
1590  all_chaninfo[ ii ].centerpiece = cCenterpiece;
1591  all_chaninfo[ ii ].solution = cSolution;
1592 DbgLv(1) << "CGui: chan trip" << ii << idax
1593  << "centp sol" << cCenterpiece << cSolution.solutionGUID;
1594  }
1595 
1596  if ( isMwl )
1597  { // If need be, load MWL data object
1599 
1600  mwl_setup();
1601  }
1602 
1603  // Update triple information on screen
1604 DbgLv(1) << "CGui: call setTripleInfo";
1605  setTripleInfo();
1606 DbgLv(1) << "CGui: call init_excludes";
1607  init_excludes();
1608 
1609 DbgLv(1) << "CGui: setDesc trLx" << tripListx << out_chaninfo.size();
1610  le_solutionDesc->setText( all_tripinfo[ 0 ].solution.solutionDesc );
1611 
1612  // Restore description
1613  le_description->setText( allData[ 0 ].description );
1614  saveDescription = QString( allData[ 0 ].description );
1615 
1616  // Reset maximum scan control values
1617 DbgLv(1) << "CGui: call enableScanControls";
1619 
1620  // The centerpiece combo box
1621  cb_centerpiece->setLogicalIndex( all_tripinfo[ 0 ].centerpiece );
1622 
1623  // Redo plot
1624 DbgLv(1) << "CGui: call plot_current";
1625  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
1626  plot_current();
1627  QApplication::restoreOverrideCursor();
1628 
1629  connect( ct_from, SIGNAL( valueChanged ( double ) ),
1630  SLOT ( focus_from ( double ) ) );
1631 
1632  connect( ct_to , SIGNAL( valueChanged ( double ) ),
1633  SLOT ( focus_to ( double ) ) );
1634 
1635  // Ok to enable some buttons now
1636  enableControls();
1637  if ( ! disk_controls->db() )
1638  pb_saveUS3 ->setEnabled( true );
1639 
1640  pb_details ->setEnabled( true );
1641  pb_solution ->setEnabled( true );
1642  cb_centerpiece ->setEnabled( true );
1643  pb_editRuninfo ->setEnabled( true );
1644 
1645  // some things one can't do from here
1646  ct_tolerance ->setEnabled( false );
1647 
1648  enableRunIDControl( false );
1649 
1650  if ( runType == "RA" && subsets.size() < 1 )
1651  {
1652  // Allow user to define subsets, if he hasn't already
1653  pb_define ->setEnabled( true );
1654  }
1655 
1656  saveStatus = ( ExpData.expID == 0 ) ? HD_ONLY : BOTH;
1657  //pb_editRuninfo ->setEnabled ( saveStatus == HD_ONLY );
1658 
1659  // Point to any existing time state file
1660  QDir ddir( currentDir );
1661  QStringList tmsfs = ddir.entryList( QStringList( "*.time_state.*" ),
1662  QDir::Files, QDir::Name );
1663  QString defs_fnamei;
1664  QString tmst_dname = currentDir;
1665  if ( tmst_dname.right( 1 ) != "/" )
1666  tmst_dname += "/";
1667 DbgLv(1) << "lTS: tmst_dname" << tmst_dname << "tmsfs count" << tmsfs.count();
1668 
1669  if ( tmsfs.count() == 2 )
1670  { // Looks like we have a TMST and corresponding Defs XML
1671  tmst_fnamei = tmsfs[ 0 ];
1672  defs_fnamei = tmsfs[ 1 ];
1673 DbgLv(1) << "lTS: tmsfs" << tmst_fnamei << defs_fnamei;
1674 
1675  if ( tmst_fnamei.contains( ".tmst" ) &&
1676  defs_fnamei.contains( ".xml" ) )
1677  { // Have both files, so save full path to TMST
1678  tmst_fnamei = tmst_dname + tmst_fnamei;
1679  }
1680 
1681  else if ( tmsfs[ 0 ].contains( ".xml" ) &&
1682  tmsfs[ 1 ].contains( ".tmst" ) )
1683  { // Have both files (in opposite order), so save full path to TMST
1684  tmst_fnamei = tmst_dname + tmsfs[ 1 ];
1685  }
1686 
1687  else
1688  { // Do not have both files, so clear TMST file path
1689  tmst_fnamei.clear();
1690  }
1691 DbgLv(1) << "lTS: tmst,defs fnamei" << tmst_fnamei << defs_fnamei;
1692  }
1693 
1694  else // If file does not exist, clear name
1695  {
1696 DbgLv(1) << "lTS: NON_EXIST:" << tmst_fnamei;
1697  tmst_fnamei.clear();
1698  }
1699 
1700  // Read it in ok, so ok to sync with DB
1701  ExpData.syncOK = true;
1702 
1703  enableSaveBtn();
1704  le_status->setText( tr( "Local disk data load IS COMPLETE." ) );
1705  qApp->processEvents();
1706 DbgLv(1) << "CGui: ldUS3Dk: RTN";
1707 }
1708 
1709 // Function to load an experiment from the DB
1711 {
1712 DbgLv(1) << "CGui: ldUS3DB: IN";
1713  le_status->setText( tr( "Loading data from DB ..." ) );
1714  qApp->processEvents();
1715 
1716  // Verify connectivity
1717  US_Passwd pw;
1718  QString masterPW = pw.getPasswd();
1719  US_DB2 db( masterPW );
1720 
1721  if ( db.lastErrno() != US_DB2::OK )
1722  {
1723  QMessageBox::information( this,
1724  tr( "Error" ),
1725  tr( "Error making the DB connection.\n" ) );
1726  return;
1727  }
1728 
1729  // We have runID from a call to a load dialog; let's copy the DB info to HD
1730  QDir readDir( US_Settings::resultDir() );
1731  QString dirname = readDir.absolutePath() + "/" + runID + "/";
1732 
1733 DbgLv(1) << "CGui: ldUS3DB: call rdDBExp";
1734  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
1735  le_status->setText( tr( "Loading data from DB (Experiment) ..." ) );
1736  qApp->processEvents();
1737  QString status = US_ConvertIO::readDBExperiment( runID, dirname, &db,
1738  speedsteps );
1739  QApplication::restoreOverrideCursor();
1740 
1741  if ( status != QString( "" ) )
1742  {
1743  QMessageBox::information( this, tr( "Error" ), status + "\n" );
1744  return;
1745  }
1746 
1747  // And load it
1748 DbgLv(1) << "CGui: ldUS3DB: call ldUS3Dk";
1749  le_status->setText( tr( "Loading data from DB (Disk data) ..." ) );
1750  qApp->processEvents();
1751  loadUS3Disk( dirname );
1752 
1753  saveStatus = BOTH; // override from loadUS3Disk()
1754  ExpData.syncOK = true; // since we just read it from there
1755 
1756  enableControls();
1757 
1758  le_status->setText( tr( "%1 data triples are NOW LOADED from DB." )
1759  .arg( allData.size() ) );
1760  qApp->processEvents();
1761 
1762 DbgLv(1) << "CGui: ldUS3DB: RTN";
1763 }
1764 
1766 {
1767 DbgLv(1) << "CGui: gExpInf: IN";
1768  ExpData.runID = le_runID -> text();
1769 
1770  if ( disk_controls->db() )
1771  {
1772  // Then we're working in DB, so verify connectivity
1773  US_Passwd pw;
1774  QString masterPW = pw.getPasswd();
1775  US_DB2 db( masterPW );
1776 
1777  if ( db.lastErrno() != US_DB2::OK )
1778  {
1779  QMessageBox::information( this,
1780  tr( "Error" ),
1781  tr( "Error making the DB connection.\n" ) );
1782  return;
1783  }
1784 
1785  // Check if the run ID already exists in the DB
1786  int recStatus = ExpData.checkRunID( &db );
1787 
1788  // if saveStatus == BOTH, then we are editing the record from the database
1789  if ( ( recStatus == US_DB2::OK ) && ( saveStatus != BOTH ) )
1790  {
1791  QMessageBox::information( this,
1792  tr( "Error" ),
1793  tr( "The current runID already exists in the database.\n"
1794  "To edit that information, load it from the database\n"
1795  "to start with." ) );
1796  return;
1797  }
1798  }
1799 
1800  // OK, proceed
1801 
1802  // Calculate average temperature
1803  double sum = 0.0;
1804  double count = 0.0;
1805  for ( int i = 0; i < allData.size(); i++ )
1806  {
1807  US_DataIO::RawData raw = allData[ i ];
1808  for ( int j = 0; j < raw.scanData.size(); j++ )
1809  sum += raw.scanData[ j ].temperature;
1810 
1811  count += raw.scanData.size();
1812  }
1813 
1814  ExpData.runTemp = QString::number( sum / count );
1815 
1816  // Load information we're passing
1817  char* optSysPtr = ExpData.opticalSystem.data();
1818  strncpy( optSysPtr, allData[ 0 ].type, 2 );
1819  optSysPtr[ 2 ] = '\0';
1820 
1821  // A list of unique rpms
1822  ExpData.rpms.clear();
1823  for ( int i = 0; i < allData.size(); i++ )
1824  {
1825  US_DataIO::RawData* raw = &allData[ i ];
1826  for ( int j = 0; j < raw->scanData.size(); j++ )
1827  {
1828  if ( ! ExpData.rpms.contains( raw->scanData[ j ].rpm ) )
1829  ExpData.rpms << raw->scanData[ j ].rpm;
1830  }
1831  }
1832 
1833  // Now sort the rpm list. Use a modified bubble sort;
1834  // the list might already be almost ordered
1835  bool done = false;
1836  while ( !done )
1837  {
1838  done = true;
1839  for ( int i = 0; i < ExpData.rpms.size() - 1; i++ )
1840  {
1841  if ( ExpData.rpms[ i ] > ExpData.rpms[ i + 1 ] )
1842  {
1843  ExpData.rpms.swap( i, i + 1 );
1844  done = false;
1845  }
1846  }
1847  }
1848 
1849  int dbdisk = ( disk_controls->db() ) ? US_Disk_DB_Controls::DB
1851 
1852  US_ExperimentGui* expInfo = new US_ExperimentGui( true, // signal_wanted
1853  ExpData,
1854  dbdisk );
1855 
1856  connect( expInfo, SIGNAL( updateExpInfoSelection( US_Experiment& ) ),
1857  this , SLOT ( updateExpInfo ( US_Experiment& ) ) );
1858 
1859  connect( expInfo, SIGNAL( cancelExpInfoSelection() ),
1860  this , SLOT ( cancelExpInfo () ) );
1861 
1862  connect( expInfo, SIGNAL( use_db ( bool ) ),
1863  SLOT ( update_disk_db( bool ) ) );
1864 
1865  expInfo->exec();
1866 DbgLv(1) << "CGui: gExpInf: RTN";
1867 }
1868 
1869 // Updating after user has selected info from experiment dialog
1871 {
1872  // Update local copy
1873  ExpData = d;
1874 
1875  if ( this->saveStatus == NOT_SAVED )
1876  this->saveStatus = EDITING; // don't delete the data!
1877 
1878  enableControls();
1879 }
1880 
1882 {
1883  // Don't clear out the data, just don't save anything new
1884 
1885  enableControls();
1886 }
1887 
1889 {
1890  const int chanID = 1;
1891 
1892  triple_index();
1893  ExpData.runID = le_runID -> text();
1894 
1895  int dbdisk = ( disk_controls->db() ) ? US_Disk_DB_Controls::DB
1897 
1898  US_Solution solution = out_chaninfo[ tripListx ].solution;
1899 
1900  US_SolutionGui* solutionInfo = new US_SolutionGui(
1901  ExpData.expID,
1902  chanID, // channelID
1903  true, // signal wanted
1904  dbdisk, // data source
1905  solution );
1906 
1907  connect( solutionInfo, SIGNAL( updateSolutionGuiSelection( US_Solution ) ),
1908  this, SLOT ( updateSolutionInfo ( US_Solution ) ) );
1909 
1910  connect( solutionInfo, SIGNAL( cancelSolutionGuiSelection() ),
1911  this, SLOT ( cancelSolutionInfo () ) );
1912 
1913  connect( solutionInfo, SIGNAL( use_db ( bool ) ),
1914  SLOT ( update_disk_db( bool ) ) );
1915 
1916  solutionInfo->exec();
1917 }
1918 
1919 // Updating after user has selected info from experiment dialog
1921 {
1922  triple_index();
1923 
1924  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
1925 
1926  // Update local copy
1927  out_chaninfo[ tripListx ].solution = s;
1928  out_tripinfo[ tripDatax ].solution = s;
1929 
1930  le_solutionDesc->setText( out_chaninfo[ tripListx ].solution.solutionDesc );
1931 
1932  // For MWL, duplicate solution to all triples of the channel
1933  if ( isMwl )
1934  {
1935  int idax = out_chandatx[ tripListx ];
1936  int ldax = tripListx + 1;
1937  ldax = ldax < out_chandatx.size()
1938  ? out_chandatx[ ldax ]
1939  : out_tripinfo.size();
1940 
1941  while ( idax < ldax )
1942  {
1943  out_tripinfo[ idax++ ].solution = s;
1944 DbgLv(0) << "CGui: updSol: dax" << idax
1945  << "s.desc s.id" << s.solutionDesc << s.solutionID << s.solutionGUID;
1946  }
1947  }
1948 
1949  // Re-plot
1950  plot_current();
1951 
1952  QApplication::restoreOverrideCursor();
1953  QApplication::restoreOverrideCursor();
1954 
1955  enableControls();
1956 }
1957 
1959 {
1960  enableControls();
1961 }
1962 
1963 // Function to copy the current triple's data to all triples
1965 {
1967 
1968  // Copy selected fields only
1969  for ( int ii = 0; ii < out_tripinfo.size(); ii++ )
1970  {
1971  out_tripinfo[ ii ].centerpiece = tripinfo.centerpiece;
1972  out_tripinfo[ ii ].solution = tripinfo.solution;
1973  }
1974 
1975  for ( int ii = 0; ii < out_chaninfo.size(); ii++ )
1976  {
1977  out_chaninfo[ ii ].centerpiece = tripinfo.centerpiece;
1978  out_chaninfo[ ii ].solution = tripinfo.solution;
1979  }
1980 
1981  for ( int ii = 0; ii < all_tripinfo.size(); ii++ )
1982  {
1983  all_tripinfo[ ii ].centerpiece = tripinfo.centerpiece;
1984  all_tripinfo[ ii ].solution = tripinfo.solution;
1985  }
1986 
1987  for ( int ii = 0; ii < all_chaninfo.size(); ii++ )
1988  {
1989  all_chaninfo[ ii ].centerpiece = tripinfo.centerpiece;
1990  all_chaninfo[ ii ].solution = tripinfo.solution;
1991  }
1992 
1993  le_status->setText( tr( "The current c/c/w information has been"
1994  " copied to all." ) );
1995  qApp->processEvents();
1996 
1997  plot_current();
1998 
1999  enableControls();
2000 }
2001 
2003 {
2004  // Create data structures for US_RunDetails2
2005  QStringList tripleDescriptions;
2006  QVector< US_DataIO::RawData > currentData;
2007 
2008  if ( isMwl )
2009  { // For MWL, only pass the 1st data set of each cell/channel
2010  for ( int ii = 0; ii < out_chaninfo.size(); ii++ )
2011  {
2012  currentData << *outData[ out_chandatx[ ii ] ];
2013  QString celchn = out_chaninfo[ ii ].tripleDesc;
2014  celchn = celchn.section( " / ", 0, 1 );
2015  tripleDescriptions << celchn;
2016  }
2017  }
2018 
2019  else
2020  { // For most data, pass all (non-excluded) triples
2021  for ( int ii = 0; ii < out_tripinfo.size(); ii++ )
2022  {
2023  currentData << *outData[ ii ];
2024  tripleDescriptions << out_tripinfo[ ii ].tripleDesc;
2025  }
2026  }
2027 
2028  US_RunDetails2* dialog = new US_RunDetails2( currentData, runID, currentDir,
2029  tripleDescriptions );
2030  dialog->exec();
2031  qApp->processEvents();
2032  delete dialog;
2033 }
2034 
2036 {
2037  if ( le_description->text().size() < 1 )
2038  le_description->setText( outData[ tripDatax ]->description );
2039 
2040  else
2041  {
2042  QString chdesc = le_description->text().trimmed();
2043  outData[ tripDatax ]->description = chdesc;
2044 
2045  if ( isMwl )
2046  { // Propagate description to all triples of channel
2047  out_chaninfo[ tripListx ].description = chdesc;
2048  int trxs = out_chandatx[ tripListx ];
2049  int trxe = trxs + nlambda;
2050  for ( int trx = trxs; trx < trxe; trx++ )
2051  outData[ trx ]->description = chdesc;
2052  }
2053  }
2054 }
2055 
2057 {
2058  QString chann = lw_triple->currentItem()->text()
2059  .section( "/", 1, 1 ).simplified();
2060  pb_dropChan ->setText( tr( "Drop All Channel '%1's" ).arg( chann ) );
2061 
2062  triple_index( );
2063 DbgLv(1) << "chgTrp: trDx trLx" << tripDatax << tripListx;
2064 
2065  le_dir ->setText( currentDir );
2066  le_description ->setText( outData[ tripDatax ]->description );
2067  le_solutionDesc->setText( out_chaninfo[ tripListx ].solution.solutionDesc );
2068 
2069  // If MWL, set the cell/channel index and get the lambda range
2070  if ( isMwl )
2071  {
2072  QVector< int > wvs;
2073  nlambda = mwl_data.lambdas( wvs, tripListx );
2074  if ( slambda != wvs[ 0 ] || elambda != wvs[ nlambda - 1 ] )
2075  { // A change in lambda range requires a general reset
2076  setTripleInfo();
2077  }
2078  }
2079 
2080  // Reset maximum scan control values
2082 
2083  // The centerpiece combo box
2084  cb_centerpiece->setLogicalIndex( out_chaninfo[ tripListx ].centerpiece );
2085 
2086  // Redo plot
2087  plot_current();
2088 }
2089 
2090 // Reset triple controls after a change
2092 {
2093  // Load them into the list box
2094  int trListSave = lw_triple->currentRow();
2095  int nchans = out_channels.count();
2096  int ntrips = out_triples .count();
2097  lw_triple->disconnect();
2098  lw_triple->clear();
2099 DbgLv(1) << " sTI: nch ntr" << nchans << ntrips << "trLSv" << trListSave;
2100 
2101  if ( isMwl )
2102  { // For MWL, wavelength lists need rebuilding
2103 DbgLv(1) << " sTI: IS Mwl outchan sz" << out_channels.count();
2104  for ( int ccx = 0; ccx < nchans; ccx++ )
2105  { // Reformat the triples entries
2106  nlambda = mwl_data.lambdas( exp_lambdas, ccx );
2107  if ( nlambda < 1 )
2108  {
2109 DbgLv(1) << " sTI: ccx nl" << ccx << nlambda;
2110  break;
2111  }
2112  slambda = exp_lambdas[ 0 ];
2113  elambda = exp_lambdas[ nlambda - 1 ];
2114 DbgLv(1) << " sTI: ccx nl sl el" << ccx << nlambda << slambda << elambda;
2115  lw_triple->addItem( out_channels[ ccx ]
2116  + QString( " / %1-%2 (%3)" )
2117  .arg( slambda ).arg( elambda ).arg( nlambda ) );
2118  }
2119 
2120  // Get wavelengths for the currently selected cell/channel
2121  tripListx = qMax( 0, qMin( trListSave, ( nchans - 1 ) ) );
2123  if ( nlambda < 1 )
2124  {
2125 DbgLv(1) << " sTI: tLx nlambda" << tripListx << nlambda;
2126  return;
2127  }
2128  slambda = exp_lambdas[ 0 ];
2129  elambda = exp_lambdas[ nlambda - 1 ];
2130  int plambda = cb_lambplot->currentText().toInt();
2131  int pltx = nlambda / 2;
2132  tripDatax = out_chandatx[ tripListx ] + pltx;
2133 DbgLv(1) << " sTI: pltx" << pltx << "nlambda" << nlambda;
2134 
2135  mwl_connect( false );
2136  cb_lambplot->clear();
2137 
2138  for ( int wvx = 0; wvx < nlambda; wvx++ )
2139  { // Rebuild the plot lambda list
2140  int ilamb = exp_lambdas[ wvx ];
2141  cb_lambplot->addItem( QString::number( ilamb ) );
2142 
2143  if ( ilamb == plambda ) pltx = wvx;
2144  }
2145 
2146  // Re-do selections for lambda start,stop,plot
2147  cb_lambstrt->setCurrentIndex( all_lambdas.indexOf( slambda ) );
2148  cb_lambstop->setCurrentIndex( all_lambdas.indexOf( elambda ) );
2149  cb_lambplot->setCurrentIndex( pltx );
2150  mwl_connect( true );
2151 DbgLv(1) << " sTI: tLx tDx" << tripListx << tripDatax;
2152  }
2153 
2154  else
2155  { // For non-MWL, just re-do triples
2156 DbgLv(1) << " sTI: NOT Mwl";
2157  for ( int trx = 0; trx < ntrips; trx++ )
2158  { // Rebuild the triples list
2159  lw_triple->addItem( out_triples[ trx ] );
2160  }
2161 
2162  tripListx = qMax( 0, qMin( trListSave, ( ntrips - 1 ) ) );
2163  tripDatax = tripListx;
2164  }
2165 
2166  lw_triple->setCurrentRow( tripListx );
2167  connect( lw_triple, SIGNAL( itemSelectionChanged() ),
2168  SLOT ( changeTriple () ) );
2169 
2170  if ( ntrips > 0 )
2171  {
2172  QString chann = lw_triple->currentItem()->text()
2173  .section( "/", 1, 1 ).simplified();
2174  pb_dropChan ->setText( tr( "Drop All Channel '%1's" ).arg( chann ) );
2175  }
2176 }
2177 
2179 {
2180  // Temperature check
2181  double dt = 0.0;
2182 
2183  foreach( US_DataIO::RawData triple, allData )
2184  {
2185  double temp_spread = triple.temperature_spread();
2186  dt = ( temp_spread > dt ) ? temp_spread : dt;
2187  }
2188 
2189  if ( dt > US_Settings::tempTolerance() )
2190  {
2191  QMessageBox::warning( this,
2192  tr( "Temperature Problem" ),
2193  tr( "The temperature in this run varied over the course\n"
2194  "of the run to a larger extent than allowed by the\n"
2195  "current threshold (" )
2196  + QString::number( US_Settings::tempTolerance(), 'f', 1 )
2197  + " " + DEGC + tr( "). The accuracy of experimental\n"
2198  "results may be affected significantly." ) );
2199  }
2200 }
2201 
2203 {
2204  int cpID = cb_centerpiece->getLogicalID();
2205  out_chaninfo[ tripListx ].centerpiece = cpID;
2206 DbgLv(1) << "getCenterpieceIndex " << out_chaninfo[tripListx].centerpiece;
2207 
2208  // For MWL, duplicate centerpiece to all triples of the channel
2209  if ( isMwl )
2210  {
2211  int idax = out_chandatx[ tripListx ];
2212  int ldax = tripListx + 1;
2213  ldax = ldax < out_chandatx.size()
2214  ? out_chandatx[ ldax ]
2215  : out_tripinfo.size();
2216 
2217  while ( idax < ldax )
2218  {
2219  out_tripinfo[ idax++ ].centerpiece = cpID;
2220  }
2221  }
2222  else
2223  out_tripinfo[ tripListx ].centerpiece = cpID;
2224 
2225  enableSaveBtn();
2226 }
2227 
2228 void US_ConvertGui::focus_from( double scan )
2229 {
2230  int from = (int)scan;
2231  int to = (int)ct_to->value();
2232 
2233  if ( from > to )
2234  {
2235  ct_to->disconnect();
2236  ct_to->setValue( scan );
2237  to = from;
2238 
2239  connect( ct_to, SIGNAL( valueChanged ( double ) ),
2240  SLOT ( focus_to ( double ) ) );
2241  }
2242 
2243  focus( from, to );
2244 }
2245 
2246 void US_ConvertGui::focus_to( double scan )
2247 {
2248  int to = (int)scan;
2249  int from = (int)ct_from->value();
2250 
2251  if ( from > to )
2252  {
2253  ct_from->disconnect();
2254  ct_from->setValue( scan );
2255  from = to;
2256 
2257  connect( ct_from, SIGNAL( valueChanged ( double ) ),
2258  SLOT ( focus_from ( double ) ) );
2259  }
2260 
2261  focus( from, to );
2262 }
2263 
2264 void US_ConvertGui::focus( int from, int to )
2265 {
2266  if ( ( from == 0 && to == 0 ) || isMwl )
2267  {
2268  pb_exclude->setEnabled( false );
2269  pb_include->setEnabled( false );
2270  }
2271  else
2272  {
2273  pb_exclude->setEnabled( true );
2274  pb_include->setEnabled( true );
2275  }
2276 
2277  QList< int > focus; // We don't care if -1 is in the list
2278  for ( int i = from - 1; i <= to - 1; i++ ) focus << i;
2279 
2280  set_colors( focus );
2281 
2282 }
2283 
2284 // Function to initialize the excluded scan count
2286 {
2287  allExcludes.clear();
2289  for ( int i = 0; i < allData.size(); i++ )
2290  allExcludes << x;
2291 }
2292 
2293 // Function to exclude user-selected scans
2295 {
2297 
2298  // Scans actually start at index 0
2299  int scanStart = (int)ct_from->value() - 1;
2300  int scanEnd = (int)ct_to ->value() - 1;
2301 
2302  // Sometimes the user leaves this at 0
2303  scanStart = ( scanStart < 0 ) ? 0 : scanStart;
2304  int scanCount = scanEnd - scanStart + 1;
2305 
2306  // Find the first scan to exclude, but account for the already excluded
2307  int scanNdx = 0;
2308  while ( scanNdx < scanStart )
2309  {
2310  if ( excludes.contains( scanNdx ) )
2311  scanStart++;
2312 
2313  scanNdx++;
2314  }
2315 
2316  // Now we have the starting point, so exclude some scans
2317  int excluded = 0;
2318  while ( excluded < scanCount )
2319  {
2320  if ( ! excludes.contains( scanNdx ) )
2321  {
2322  excluded++;
2323  allExcludes[ tripDatax ] << scanNdx;
2324  }
2325 
2326  scanNdx++;
2327  }
2328 
2330 
2331  replot();
2332 }
2333 
2335 {
2336  allExcludes[ tripDatax ].excludes.clear();
2338 
2339  pb_include->setEnabled( false );
2340  pb_exclude->setEnabled( false );
2341 
2342  replot();
2343 }
2344 
2345 // User pressed the define subsets button while processing equil-abs data
2347 {
2348  subsets.clear();
2349  countSubsets = 1; // We start with one big subset
2350 
2351  pb_define ->setEnabled( false );
2352  pb_process ->setEnabled( true );
2353 
2354  connect( picker, SIGNAL( cMouseUp( const QwtDoublePoint& ) ),
2355  SLOT ( cClick ( const QwtDoublePoint& ) ) );
2356 
2357  step = SPLIT;
2358 }
2359 
2361 {
2362  if ( subsets.size() < 1 )
2363  {
2364  // Not enough clicks to work with
2365  subsets.clear();
2366  pb_process ->setEnabled( true );
2367  return;
2368  }
2369 
2370  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
2371 
2372  // Add the top and bottom boundaries
2373  subsets << 5.7
2374  << 7.3;
2375 
2376  // Let's make sure the points are in sorted order
2377  for ( int i = 0; i < subsets.size() - 1; i++ )
2378  for ( int j = i + 1; j < subsets.size(); j++ )
2379  if ( subsets[ i ] > subsets[ j ] )
2380  {
2381  double temp = subsets[ i ];
2382  subsets[ i ] = subsets[ j ];
2383  subsets[ j ] = temp;
2384  }
2385 
2386  pb_process ->setEnabled( false );
2387  picker ->disconnect();
2388 
2389 DbgLv(1) << "CGui:pSS: split CALL";
2390  // Now let's split the triple
2392 
2393  // We don't need this any more
2394  subsets.clear();
2395 
2396  // Reinitialize some things
2397  if ( ! init_output_data() )
2398  return;
2399  setTripleInfo();
2400  init_excludes();
2401  enableControls();
2402 
2403  plot_current();
2404  QApplication::restoreOverrideCursor();
2405 }
2406 
2407 // User pressed the Define reference button while analyzing intensity data
2409 {
2410  if ( isMwl )
2411  { // First insure that the full range of wavelengths are available
2412  // for defining reference scans
2413  int kdiff = 0;
2414 
2415  for ( int ccx = 0; ccx < out_channels.size(); ccx++ )
2416  { // Review the wavelength ranges for each channel
2417  QVector< int > wvs;
2418  int klamb = mwl_data.lambdas( wvs, ccx );
2419 
2420  if ( klamb != nlamb_i )
2421  { // Count of wavelengths differs from the full input range
2422  kdiff++;
2423  }
2424 
2425  else
2426  { // Test each wavelength in this channel's range
2427  for ( int jj = 0; jj < klamb; jj++ )
2428  { // Record any differences
2429  if ( wvs[ jj ] != all_lambdas[ jj ] )
2430  kdiff++;
2431  }
2432  }
2433  }
2434 
2435  if ( kdiff != 0 )
2436  { // Report dangerous differences and allow a reference define cancel
2437  int status = QMessageBox::information( this,
2438  tr( "Inconsistent Reference Wavelengths" ),
2439  tr( "Differences in wavelength ranges exist for the channels.\n"
2440  "The safest course is to always open the full range of\n"
2441  "input wavelengths for the Reference channel.\n\n"
2442  "If you are sure that Reference wavelengths will cover\n"
2443  "all other channels, you may \"Proceed\".\n\n"
2444  "Otherwise, you should \"Cancel\".\n" ),
2445  tr( "&Cancel" ), tr( "&Proceed" ) );
2446 
2447  if ( status == 0 ) return;
2448  }
2449  }
2450 
2451  connect( picker, SIGNAL( cMouseUp( const QwtDoublePoint& ) ),
2452  SLOT ( cClick ( const QwtDoublePoint& ) ) );
2453 
2454  reference_start = 0.0;
2455  reference_end = 0.0;
2456  pb_reference->setEnabled( false );
2457  pb_cancelref->setEnabled( true );
2458 
2459  step = REFERENCE;
2460 }
2461 
2462 // Select starting point of reference scan in intensity data
2463 void US_ConvertGui::start_reference( const QwtDoublePoint& p )
2464 {
2465  reference_start = p.x();
2466 
2468  data_plot->replot();
2469 }
2470 
2471 // Select end point of reference scan in intensity data
2472 void US_ConvertGui::process_reference( const QwtDoublePoint& p )
2473 {
2474  // Just in case we get a second click message right away
2475  if ( fabs( p.x() - reference_start ) < 0.005 ) return;
2476 
2477  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
2478 
2479  le_status->setText( tr( "The reference scans are being defined..." ) );
2480  qApp->processEvents();
2481  reference_end = p.x();
2483  data_plot->replot();
2484  picker ->disconnect();
2485 
2486  // Double check if min < max
2488  {
2489  double temp = reference_start;
2491  reference_end = temp;
2492  }
2493 
2494  // Calculate the averages for all triples
2495  PseudoCalcAvg();
2496 
2497  // Now that we have the averages, let's replot
2499 
2500  // Default to displaying the first non-reference triple
2501  for ( int trx = 0; trx < outData.size(); trx++ )
2502  {
2503  if ( trx != Pseudo_reference_triple )
2504  {
2505  tripListx = trx;
2506  break;
2507  }
2508  }
2509 
2510  lw_triple->setCurrentRow( tripListx );
2511  plot_current();
2512  QApplication::restoreOverrideCursor();
2513 
2514  pb_reference ->setEnabled( false );
2515  referenceDefined = true;
2516 DbgLv(1) << "CGui: (6)referDef=" << referenceDefined;
2517  enableSaveBtn();
2518  enableRunIDControl( false );
2519  le_status->setText( tr( "The reference scans have been defined." ) );
2520  qApp->processEvents();
2521 }
2522 
2523 // Process a control-click on the plot window
2524 void US_ConvertGui::cClick( const QwtDoublePoint& p )
2525 {
2526  switch ( step )
2527  {
2528  case SPLIT :
2529  if ( countSubsets < 4 )
2530  {
2531  // process equil-abs data
2532  draw_vline( p.x() );
2533  subsets << p.x();
2534  countSubsets++;
2535  }
2536 
2537  break;
2538 
2539  case REFERENCE :
2540  // process reference scan
2541  if ( reference_start == 0.0 )
2542  start_reference( p );
2543 
2544  else
2545  process_reference( p );
2546 
2547  default :
2548  break;
2549 
2550  }
2551 }
2552 
2553 // Reference calculation for pseudo-absorbance
2555 {
2556  if ( referenceDefined ) return; // Average calculation has already been done
2557 
2558  if ( isMwl )
2559  { // Do calculations for each wavelength, if MWL
2560  PseudoCalcAvgMWL();
2561  return;
2562  }
2563 
2564  US_DataIO::RawData* referenceData = outData[ tripDatax ];
2565  int ref_size = referenceData->xvalues.size();
2566 
2567  for ( int ss = 0; ss < referenceData->scanData.size(); ss++ )
2568  {
2569  US_DataIO::Scan* scan = &referenceData->scanData[ ss ];
2570 
2571  int rr = 0;
2572  int count = 0;
2573  double sum = 0.0;
2574 
2575  while ( referenceData->radius( rr ) < reference_start &&
2576  rr < ref_size )
2577  rr++;
2578 
2579  while ( referenceData->radius( rr ) < reference_end &&
2580  rr < ref_size )
2581  {
2582  sum += scan->rvalues[ rr ];
2583  count++;
2584  rr++;
2585  }
2586 
2587  if ( count > 0 )
2588  ExpData.RIProfile << sum / count;
2589 
2590  else
2591  ExpData.RIProfile << 1.0; // See the log10 function, later
2592 
2593  }
2594 
2595  // Now average around excluded values
2596  int lastGood = 0;
2597  int countBad = 0;
2598  for ( int ss = 0; ss < ExpData.RIProfile.size(); ss++ )
2599  {
2600  // In case there are adjacent excluded scans...
2601  if ( allExcludes[ tripDatax ].contains( ss ) )
2602  countBad++;
2603 
2604  // Calculate average of before and after for intervening values
2605  else if ( countBad > 0 )
2606  {
2607  double newAvg = ( ExpData.RIProfile[ lastGood ]
2608  + ExpData.RIProfile[ ss ] ) / 2.0;
2609 
2610  for ( int rr = lastGood + 1; rr < ss; rr++ )
2611  ExpData.RIProfile[ rr ] = newAvg;
2612 
2613  countBad = 0;
2614  }
2615 
2616  // Normal situation -- value is not excluded
2617  else
2618  lastGood = ss;
2619 
2620  }
2621 
2622  // Now calculate the pseudo-absorbance
2623  for ( int trx = 0; trx < outData.size(); trx++ )
2624  {
2625  US_DataIO::RawData* currentData = outData[ trx ];
2626 
2627  for ( int ss = 0; ss < currentData->scanData.size(); ss++ )
2628  {
2629  US_DataIO::Scan* scan = &currentData->scanData[ ss ];
2630 
2631  for ( int rr = 0; rr < scan->rvalues.size(); rr++ )
2632  {
2633  double rvalue = scan->rvalues[ rr ];
2634 
2635  // Protect against possible inf's and nan's, if a reading
2636  // evaluates to 0 or wherever log function is undefined or -inf
2637  if ( rvalue < 1.0 ) rvalue = 1.0;
2638 
2639  // Check for boundary condition
2640  int ndx = ( ss < ExpData.RIProfile.size() )
2641  ? ss : ExpData.RIProfile.size() - 1;
2642  scan->rvalues[ rr ] = log10( ExpData.RIProfile[ ndx ] / rvalue );
2643  }
2644  }
2645 
2646  // Let's mark pseudo-absorbance as different from RI data,
2647  // since it needs some different processing in some places
2648  isPseudo = true;
2649  }
2650 
2651  // Enable intensity plot
2652  referenceDefined = true;
2653 DbgLv(1) << "CGui: (7)referDef=" << referenceDefined;
2654  pb_intensity->setEnabled( true );
2655  pb_reference->setEnabled( false );
2656  pb_cancelref->setEnabled( true );
2657 }
2658 
2659 // Bring up a graph window showing the intensity profile
2661 {
2662  QString triple = out_triples[ 0 ];
2663  QVector< double > scan_nbrs;
2664 
2665  if ( isMwl )
2666  { // For MWL, set special triple string and build scan numbers
2667  int riscans = ExpData.RI_nscans;
2668  int riwvlns = ExpData.RI_nwvlns;
2669  triple = out_channels[ 0 ] + " / "
2670  + QString::number( ExpData.RIwvlns[ 0 ] ) + "-"
2671  + QString::number( ExpData.RIwvlns[ riwvlns - 1 ] );
2672 
2673  // Scan numbers are composite wavelength.scan
2674  double scndiv = 0.1;
2675  double scnmax = (double)riscans;
2676  double scnfra = scnmax * scndiv;
2677  while ( scnfra > 0.999 )
2678  {
2679  scndiv *= 0.1;
2680  scnfra = scnmax * scndiv;
2681  }
2682 DbgLv(1) << "CGui: show_intensity scndiv scnfra" << scndiv << scnfra;
2683 
2684  for ( int ii = 0; ii < riwvlns; ii++ )
2685  {
2686  double wvbase = (double)ExpData.RIwvlns[ ii ];
2687 
2688  for ( int jj = 0; jj < riscans; jj++ )
2689  {
2690  double scnnbr = wvbase + scndiv * (double)( jj + 1 );
2691  scan_nbrs << scnnbr;
2692  }
2693  }
2694  }
2695 
2696  else
2697  { // For non-MWL, set scan numbers vector
2698  for ( int ii = 0; ii < ExpData.RIProfile.size(); ii++ )
2699  scan_nbrs << (double)( ii + 1 );
2700  }
2701 DbgLv(1) << "CGui: show_intensity scn1 scnn" << scan_nbrs[0]
2702  << scan_nbrs[ scan_nbrs.size() - 1 ] << "isMwl" << isMwl;
2703 
2704  US_Intensity* dialog
2705  = new US_Intensity( runID, triple,
2706  ( const QVector< double > ) ExpData.RIProfile,
2707  ( const QVector< double > ) scan_nbrs );
2708  dialog->exec();
2709  qApp->processEvents();
2710 }
2711 
2712 // Un-do reference scans apply
2714 {
2715  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
2716  le_status->setText( tr( "The reference scans are being canceled..." ) );
2717  qApp->processEvents();
2718  int wvoff = 0;
2719  int rscans = ExpData.RI_nscans;
2720 
2721  // Do the inverse operation and retrieve raw intensity data
2722  for ( int ii = 0; ii < outData.size(); ii++ )
2723  {
2724  US_DataIO::RawData* currentData = outData[ ii ];
2725 
2726  if ( isMwl )
2727  { // For MWL, profile is offset by wavelength
2728  int iwavl = out_triples[ ii ].section( " / ", 2, 2 ).toInt();
2729  wvoff = ExpData.RIwvlns.indexOf( iwavl );
2730 
2731  if ( wvoff < 0 )
2732  {
2733  qDebug() << "Triple " << out_triples[ ii ]
2734  << "has NO CORRESPONDING RI PROFILE POINT!!!";
2735  wvoff = 0;
2736  QMessageBox::information( this,
2737  tr( "Error" ),
2738  tr( "Triple %1 has NO CORRESPONDING RI PROFILE POINT!!!" )
2739  .arg( out_triples[ ii ] ) );
2740  int kwavl = 99999;
2741 
2742  for ( int jj = 0; jj < ExpData.RI_nwvlns; jj++ )
2743  { // Find index of nearest wavelength
2744  int jwavl = qAbs( ExpData.RIwvlns[ jj ] - iwavl );
2745 
2746  if ( jwavl < kwavl )
2747  {
2748  kwavl = jwavl;
2749  wvoff = jj;
2750  }
2751  }
2752  }
2753  }
2754 
2755  wvoff *= rscans;
2756 
2757  for ( int jj = 0; jj < currentData->scanData.size(); jj++ )
2758  {
2759  US_DataIO::Scan* scan = &currentData->scanData[ jj ];
2760  double rppro = ExpData.RIProfile[ jj + wvoff ];
2761 
2762  for ( int kk = 0; kk < scan->rvalues.size(); kk++ )
2763  {
2764  double rvalue = scan->rvalues[ kk ];
2765 
2766  scan->rvalues[ kk ] = rppro / pow( 10, rvalue );
2767  }
2768  }
2769  }
2770 
2771  referenceDefined = false;
2772  isPseudo = false;
2773  ExpData.RIProfile.clear();
2774  reference_start = 0.0;
2775  reference_end = 0.0;
2776 DbgLv(1) << "CGui: (8)referDef=" << referenceDefined;
2777 
2778  for ( int ii = 0; ii < all_tripinfo.size(); ii++ )
2779  all_tripinfo[ ii ].excluded = false;
2780 
2781  setTripleInfo();
2782 
2783  pb_reference ->setEnabled( true );
2784  pb_cancelref ->setEnabled( false );
2785  pb_intensity ->setEnabled( false );
2786  tripListx = 0;
2787  lw_triple->setCurrentRow( tripListx );
2788 
2789  plot_current();
2790 
2791  enableSaveBtn();
2792 
2793  le_status->setText( tr( "The reference scans have been canceled." ) );
2794  QApplication::restoreOverrideCursor();
2795  qApp->processEvents();
2796 }
2797 
2798 // Drop selected triples
2800 {
2801  QStringList selected;
2802  QStringList celchns;
2803 
2804  // Prepare the list of currently selected triples
2805  selected = out_triples;
2806 
2807  // Pop up and execute a dialog to select triples to delete
2808  US_SelectTriples* seldiag = new US_SelectTriples( selected );
2809 
2810  if ( seldiag->exec() != QDialog::Accepted )
2811  { // If Accept was not clicked, make sure selection list is empty
2812  selected.clear();
2813  }
2814 
2815  int selsiz = selected.size();
2816 DbgLv(1) << "DelTrip: selected size" << selsiz;
2817 
2818  // Modify triples or cell/channels and wavelengths for specified excludes
2819  if ( selsiz > 0 )
2820  {
2821  for ( int ss = 0; ss < selsiz; ss++ )
2822  { // Mark selected triples as excluded
2823  int trx = all_triples.indexOf( selected[ ss ] );
2824 
2825  if ( trx >= 0 )
2826  {
2827  all_tripinfo[ trx ].excluded = true;
2828 DbgLv(1) << "DelTrip: EXCLUDED ss trx sel" << ss << trx << selected[ss];
2829  }
2830  }
2831 
2832  // Rebuild the output data controls
2833 DbgLv(1) << "DelTrip: bldout call";
2835 DbgLv(1) << "DelTrip: bldout RTN";
2836 
2837  if ( isMwl )
2838  { // For MWL, rebuild wavelength controls
2840  }
2841 
2842  setTripleInfo(); // Review new triple information
2843  }
2844 
2845  plot_titles(); // Output a plot of the current data
2846  plot_all();
2847 }
2848 
2849 // Drop the triples for the selected channel
2851 {
2852  QString chann = lw_triple->currentItem()->text()
2853  .section( "/", 1, 1 ).simplified();
2854  int status = QMessageBox::information( this,
2855  tr( "Drop Triples with Selected Channel" ),
2856  tr( "You have selected a list item that implies you wish to"
2857  " drop triples that have channel '%1'\n\n"
2858  "If that is what you intend, click \"Proceed\".\n\n"
2859  "Otherwise, you should \"Cancel\".\n" ).arg( chann ),
2860  tr( "&Proceed" ), tr( "&Cancel" ) );
2861 
2862  if ( status != 0 ) return;
2863 
2864  for ( int trx = 0; trx < all_triples.size(); trx++ )
2865  { // Mark matching triples as excluded
2866  QString tchan = QString( all_triples[ trx ] )
2867  .section( "/", 1, 1 ).simplified();
2868 
2869  if ( tchan == chann )
2870  {
2871  all_tripinfo[ trx ].excluded = true;
2872 DbgLv(1) << "DelChan: EXCLUDED chn trx" << chann << trx;
2873  }
2874  }
2875 
2876  build_output_data(); // Rebuild the output data controls
2877 
2878  build_lambda_ctrl(); // Rebuild lambda controls
2879 
2880  setTripleInfo(); // Review new triple information
2881 
2882  plot_titles(); // Output a plot of the current data
2883  plot_all();
2884 }
2885 
2886 // Drop the triples for the selected cell/channel
2888 {
2889  QString celchn = lw_triple->currentItem()->text()
2890  .section( "/", 0, 1 ).simplified();
2891  int status = QMessageBox::information( this,
2892  tr( "Drop Triples of Selected Cell/Channel" ),
2893  tr( "You have selected a list item that implies you wish to"
2894  " drop all triples from cell/channel \"%1\"\n\n"
2895  "If that is what you intend, click \"Proceed\".\n\n"
2896  "Otherwise, you should \"Cancel\".\n" ).arg( celchn ),
2897  tr( "&Proceed" ), tr( "&Cancel" ) );
2898 
2899  if ( status != 0 ) return;
2900 
2901  for ( int trx = 0; trx < all_triples.size(); trx++ )
2902  { // Mark matching triples as excluded
2903  QString tcelchn = QString( all_triples[ trx ] )
2904  .section( "/", 0, 1 ).simplified();
2905 
2906  if ( tcelchn == celchn )
2907  {
2908  all_tripinfo[ trx ].excluded = true;
2909 DbgLv(1) << "DelChan: EXCLUDED cc trx" << celchn << trx;
2910  }
2911  }
2912 
2913  build_output_data(); // Rebuild the output data controls
2914 
2915  build_lambda_ctrl(); // Rebuild lambda controls
2916 
2917  setTripleInfo(); // Review new triple information
2918 
2919  plot_titles(); // Output a plot of the current data
2920  plot_all();
2921 }
2922 
2923 // Function to save US3 data
2925 {
2926  // Test to see if this is multi-speed data
2927  QVector< int > speeds;
2928  int notrips = 0;
2929  int nspeeds = countSpeeds( speeds, &notrips );
2930  int nitrips = allData.count();
2931  int kotrips = nitrips * nspeeds;
2932  bool is_buoy = ExpData.expType.contains( "buoyancy", Qt::CaseInsensitive );
2933 DbgLv(1) << "SV: ExpData.expType" << ExpData.expType << "is_buoy" << is_buoy;
2934 DbgLv(1) << "SV: nspeeds,itrips,otrips" << nspeeds << nitrips << notrips;
2935 DbgLv(1) << "SV: speeds" << speeds;
2936 
2937  if ( nspeeds < 2 || notrips != kotrips || is_buoy )
2938  { // For single-speed data, save current triples
2939  if ( disk_controls->db() )
2940  saveUS3DB(); // Save AUCs to disk then DB
2941 
2942  else
2943  saveUS3Disk(); // Save AUCs to disk
2944  }
2945 
2946  else
2947  { // For multi-speed data, report and split data into speed-runIDs
2948  QMessageBox::information( this,
2949  tr( "Multi-Speed Data to be Saved" ),
2950  tr( "%1 speeds are present in the data to be saved\n"
2951  "It will be split into single-speed runs.\n"
2952  "The %2 input triples will result in\n"
2953  " %3 total output triples." )
2954  .arg( nspeeds ).arg( nitrips ).arg( notrips ) );
2955 
2956  QString runIDsave = runID; // Save run ID
2957  QString runIDbase = runIDsave + "-"; // Base new run ID
2958  QVector< US_DataIO::RawData > oriData = allData; // Save original data
2959  QVector< double > oriRIPro = ExpData.RIProfile; // Save original RI Pro
2960  int nripro = ExpData.RIProfile.count();
2961 if(nripro>(-2)) return;
2962  uchar uuid[ 16 ];
2963 // saveStatus = NOT_SAVED;
2964 
2965  for ( int spx = 0; spx < nspeeds; spx++ )
2966  {
2967  int ispeed = speeds[ spx ];
2968  runID = runIDbase + QString::number( ispeed );
2969  double speed = (double)ispeed;
2970  ExpData.runID = runID;
2971  ExpData.expGUID.clear();
2972 DbgLv(1) << "SV: runID" << runID;
2973  le_runID2->setText( runID );
2974 
2975  // Create triple datasets with scans at the current speed
2976  for ( int trx = 0; trx < nitrips; trx++ )
2977  {
2978  allData[ trx ].scanData.clear();
2979 
2980  if ( trx == 0 )
2981  ExpData.RIProfile.clear();
2982 
2983  for ( int ss = 0; ss < oriData[ trx ].scanData.count(); ss++ )
2984  {
2985  if ( oriData[ trx ].scanData[ ss ].rpm == speed )
2986  { // Save scan (+RI profile?) for scan where speed matches
2987  allData[ trx ].scanData << oriData[ trx ].scanData[ ss ];
2988 
2989  if ( trx == 0 && ss < nripro )
2990  ExpData.RIProfile << oriRIPro[ ss ];
2991  }
2992  }
2993 DbgLv(1) << "SV: trx" << trx << "scans" << allData[ trx ].scanData.count();
2994 
2995  QString fname = out_tripinfo[ trx ].tripleFilename;
2996  QString uuidst = US_Util::new_guid();
2997  US_Util::uuid_parse( uuidst, uuid );
2998  out_tripinfo[ trx ].tripleFilename
2999  = runID + "." + fname.section( ".", -5, -1 );
3000  out_tripinfo[ trx ].tripleID
3001  = trx + 1;
3002  memcpy( (unsigned char*)out_tripinfo[ trx ].tripleGUID, uuid, 16 );
3003  memcpy( (unsigned char*)allData [ trx ].rawGUID , uuid, 16 );
3004  outData[ trx ] = &allData[ trx ];
3005  }
3006 
3007  // Save the triples of the current speed-run
3008  if ( disk_controls->db() )
3009  saveUS3DB(); // Save AUCs to disk then DB
3010 
3011  else
3012  saveUS3Disk(); // Save AUCs to disk
3013  }
3014  }
3015 
3016  QMessageBox::information( this,
3017  tr( "Save is Complete" ),
3018  tr( "The save of all data and reports is complete." ) );
3019 }
3020 
3021 // Save to disk (default directory)
3023 {
3024  if ( allData[ 0 ].scanData.empty() ) return US_Convert::NODATA;
3025 
3026  QDir writeDir( US_Settings::resultDir() );
3027  QString dirname = writeDir.absolutePath() + "/" + runID + "/";
3028 
3029  if ( saveStatus == NOT_SAVED &&
3030  writeDir.exists( runID ) )
3031  {
3032  QMessageBox::information( this,
3033  tr( "Error" ),
3034  tr( "The write directory, " ) + dirname +
3035  tr( " already exists. Please change run ID to a unique value." ) );
3036  return US_Convert::DUP_RUNID;
3037  }
3038 
3039  if ( ! writeDir.exists( runID ) )
3040  {
3041  if ( ! writeDir.mkpath( dirname ) )
3042  {
3043  QMessageBox::information( this,
3044  tr( "Error" ),
3045  tr( "Cannot write to " ) + writeDir.absolutePath() );
3046  return US_Convert::CANTOPEN;
3047  }
3048  }
3049 
3050  int status;
3051 
3052  // Check to see if we have all the data to write
3053  if ( ! ExpData.syncOK )
3054  {
3055  status = QMessageBox::information( this,
3056  tr( "Warning" ),
3057  tr( "The run has not yet been associated with the database."
3058  " Click 'OK' to proceed anyway, or click 'Cancel'"
3059  " and then click on the 'Edit Run Information'"
3060  " button to enter this information first.\n" ),
3061  tr( "&OK" ), tr( "&Cancel" ),
3062  0, 0, 1 );
3063  if ( status != 0 ) return US_Convert::NOT_WRITTEN;
3064  }
3065 
3066  // Write the data
3067  le_status->setText( tr( "Saving data to disk ..." ) );
3068  qApp->processEvents();
3069  bool saveGUIDs = saveStatus != NOT_SAVED ;
3070  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
3071 
3073  runType, runID, dirname, saveGUIDs );
3074 
3075  QApplication::restoreOverrideCursor();
3076 
3077  // Now try to write the xml file
3078  status = ExpData.saveToDisk( out_tripinfo, runType, runID, dirname,
3079  speedsteps );
3080 
3081  // How many files should have been written?
3082  int fileCount = out_tripinfo.size();
3083 DbgLv(1) << "SV: fileCount" << fileCount;
3084 
3085  // Now try to communicate status
3086  if ( status == US_Convert::CANTOPEN )
3087  {
3088  QString writeFile = runID + "."
3089  + runType + ".xml";
3090  QMessageBox::information( this,
3091  tr( "Error" ),
3092  tr( "Cannot open write file: " ) + dirname + writeFile );
3093  }
3094 
3095  else if ( status == US_Convert::NOXML )
3096  {
3097  // Main xml data is missing
3098  QMessageBox::information( this,
3099  tr( "Warning" ),
3100  tr( "The run information file was not written. "
3101  "Please click on the "
3102  "'Associate Run with DB' button \n\n " ) +
3103  QString::number( fileCount ) + " " +
3104  runID + tr( " files written." ) );
3105  return( status );
3106  }
3107 
3108  else if ( status == US_Convert::PARTIAL_XML )
3109  {
3110  // xml data is missing for one or more triples
3111  QMessageBox::information( this,
3112  tr( "Warning" ),
3113  tr( "Solution information is incomplete. Please click on the "
3114  "'Manage Solutions' button for each "
3115  "cell, channel, and wavelength combination \n\n " ) +
3116  QString::number( fileCount ) + " "
3117  + runID + tr( " files written." ) );
3118  return( status );
3119  }
3120 
3121  else if ( status != US_Convert::OK )
3122  {
3123  QMessageBox::information( this,
3124  tr( "Error" ),
3125  tr( "Error: " ) + status );
3126  return( status );
3127  }
3128 
3129  // Save or delete RI intensity profile
3130  if ( runType == "RI" )
3131  {
3132  if ( referenceDefined )
3133  {
3134  status = ExpData.saveRIDisk( runID, dirname );
3135 DbgLv(1) << "SV: saveRIDisk status" << status;
3136 
3137  if ( status == US_Convert::CANTOPEN )
3138  {
3139  QString writeFile = runID + "."
3140  + "RIProfile.xml";
3141  QMessageBox::information( this,
3142  tr( "Error" ),
3143  tr( "Cannot open write file: " ) + dirname + writeFile );
3144  }
3145 
3146  else if ( status != US_Convert::OK )
3147  {
3148  QMessageBox::information( this,
3149  tr( "Error" ),
3150  tr( "Error: " ) + status );
3151  return( status );
3152 
3153  }
3154  }
3155 else
3156 DbgLv(1) << "SV: NO saveRIDisk : refDef" << referenceDefined;
3157 
3158  else
3159  {
3160  // Maybe the profile has been deleted, so let's
3161  // delete the xml file and avoid confusion later
3162  QDir d( dirname );
3163  QString filename = runID + "."
3164  + "RIProfile.xml";
3165  if ( d.exists( filename ) && ! d.remove( filename ) )
3166  qDebug() << "Unable to remove file" << filename;
3167 
3168  }
3169  }
3170 else
3171 DbgLv(1) << "SV: NO saveRIDisk : runType" << runType;
3172 
3173  // Insure that we have a TimeState record locally for this run
3174  le_status->setText( tr( "Writing Time State to disk..." ) );
3176  fileCount += 2;
3177 
3178  // Status is OK
3179  le_status->setText( tr( "%1 %2 files were written to disk." )
3180  .arg( fileCount ).arg( runID ) );
3181  qApp->processEvents();
3182 
3183  if ( saveStatus == NOT_SAVED )
3184  saveStatus = HD_ONLY;
3185 
3186  // If we are here, it's ok to sync with DB
3187  ExpData.syncOK = true;
3188 
3189  enableRunIDControl( false );
3190 
3191  if ( isMwl )
3192  { // Where triples were expanded for MWL, skip plot save
3193  return( US_Convert::OK );
3194  }
3195 
3196  // Save the main plots
3197  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
3198  le_status->setText( tr( "Saving plot and report files ..." ) );
3199  qApp->processEvents();
3200  QString dir = US_Settings::reportDir() + "/" + runID;
3201  if ( ! QDir( dir ).exists() ) // make sure the directory exists
3202  QDir().mkdir( dir );
3203  data_plot->setVisible( false );
3204  int save_tripListx = tripListx;
3205 
3206  // Make sure directory is empty
3207  QDir d( dir );
3208  QStringList rmvfilt;
3209  rmvfilt << "*.svgz" << "*.png" << "*.svg";
3210  QStringList rmvfiles = d.entryList( rmvfilt, QDir::Files, QDir::Name );
3211 
3212  for ( int ii = 0; ii < rmvfiles.size(); ii++ )
3213  if ( ! d.remove( rmvfiles[ ii ] ) )
3214  qDebug() << "Unable to remove file" << rmvfiles[ ii ];
3215 
3216  for ( int ii = 0; ii < out_tripinfo.size(); ii++ )
3217  {
3218  tripListx = ii;
3219 
3220  QString t = out_tripinfo[ ii ].tripleDesc;
3221  QStringList parts = t.split(" / ");
3222 
3223  QString cell = parts[ 0 ];
3224  QString channel = parts[ 1 ];
3225  QString wl = parts[ 2 ];
3226 
3227  QString triple = "";
3228 
3229  if ( runType == "WA" )
3230  {
3231  double r = wl.toDouble() * 1000.0;
3232  QString radius = QString::number( (int) round( r ) );
3233  triple = cell + channel + radius;
3234  }
3235 
3236  else
3237  {
3238  triple = cell + channel + wl;
3239  }
3240 
3241  QString filename = dir + "/cnvt." + triple + ".raw.svgz";
3242 
3243  // Redo current plot and write it to a file
3244  lw_triple->setCurrentRow( tripListx );
3245  plot_current();
3246  int status = US_GuiUtil::save_plot( filename, data_plot );
3247  if ( status != 0 )
3248  qDebug() << filename << "plot not saved";
3249  }
3250 
3251  // Restore original plot
3252  tripListx = save_tripListx;
3253  lw_triple->setCurrentRow( tripListx );
3254  plot_current();
3255  data_plot->setVisible( true );
3256  le_status->setText( tr( "Saving of plot files IS COMPLETE." ) );
3257  qApp->processEvents();
3258  QApplication::restoreOverrideCursor();
3259  QApplication::restoreOverrideCursor();
3260 
3261  return( US_Convert::OK );
3262 }
3263 
3264 // Save to Database
3266 {
3267  // Verify connectivity
3268  US_Passwd pw;
3269  QString masterPW = pw.getPasswd();
3270  US_DB2 db( masterPW );
3271 
3272  if ( db.lastErrno() != US_DB2::OK )
3273  {
3274  QMessageBox::information( this,
3275  tr( "Error" ),
3276  tr( "Database connectivity error" ) );
3277 
3278  return;
3279  }
3280 DbgLv(1) << "DBSv: (1)trip0tripFilename" << out_tripinfo[0].tripleFilename;
3281 DbgLv(1) << "DBSv: tripleGUID "
3282  << US_Util::uuid_unparse((uchar*)out_tripinfo[0].tripleGUID);
3283 
3284  // Ok, let's make sure they know what'll happen
3285  if ( saveStatus == BOTH )
3286  {
3287  int status = QMessageBox::information( this,
3288  tr( "Warning" ),
3289  tr( "This will overwrite the raw data currently in the " ) +
3290  tr( "database, and all existing edit profiles, models " ) +
3291  tr( "and noise data will be deleted too. Proceed? " ),
3292  tr( "&OK" ), tr( "&Cancel" ),
3293  0, 0, 1 );
3294  if ( status != 0 ) return;
3295  }
3296 
3297  else
3298  {
3299  int status = QMessageBox::information( this,
3300  tr( "Warning" ),
3301  tr( "Once this data is written to the DB you will not " ) +
3302  tr( "be able to make changes to it without erasing the " ) +
3303  tr( "edit profiles, models and noise files too. Proceed? " ),
3304  tr( "&OK" ), tr( "&Cancel" ),
3305  0, 0, 1 );
3306  if ( status != 0 ) return;
3307  }
3308 
3309  // First check some of the data with the DB
3310  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
3311  le_status->setText( tr( "Preparing Save with DB check ..." ) );
3312  qApp->processEvents();
3313 
3314  int status = US_ConvertIO::checkDiskData( ExpData, out_tripinfo, &db );
3315 
3316  // Save a flag for need to repeat the disk write later
3317  bool repeat_disk = ( status == US_DB2::NO_RAWDATA );
3318 
3319  QApplication::restoreOverrideCursor();
3320 DbgLv(1) << "DBSv: (2)trip0tripFilename" << out_tripinfo[0].tripleFilename;
3321 DbgLv(1) << "DBSv: dset tripleID " << out_tripinfo[0].tripleID;
3322 
3323  if ( status == US_DB2::NO_PERSON ) // Investigator or operator doesn't exist
3324  {
3325  QMessageBox::information( this,
3326  tr( "Error" ),
3327  tr( "This investigator or instrument operator was not found\n"
3328  "in the database.\n" ) );
3329  return;
3330  }
3331 
3332  if ( status == US_DB2::BADGUID )
3333  {
3334  QMessageBox::information( this,
3335  tr( "Error" ),
3336  tr( "Bad GUID format.\n"
3337  "Please click on Edit Run Information"
3338  " and re-select hardware.\n" ) );
3339  return;
3340  }
3341 
3342  if ( status == US_DB2::NO_ROTOR )
3343  {
3344  QMessageBox::information( this,
3345  tr( "Error" ),
3346  tr( "Don't recognize the rotor configuration.\n"
3347  "Please click on Edit Run Information"
3348  " and re-select hardware.\n") );
3349  return;
3350  }
3351 
3352  if ( status != US_DB2::OK && status != US_DB2::NO_RAWDATA )
3353  {
3354  // US_DB2::OK means we're updating; US_DB2::NO_RAWDATA means it's new
3355  QMessageBox::information( this,
3356  tr( "Error" ),
3357  db.lastError() + " (" + db.lastErrno() + ")\n" );
3358  return;
3359  }
3360 
3361  // Save updated files and prepare to transfer to DB
3362  le_status->setText( tr( "Preparing Save with Disk write ..." ) );
3363  qApp->processEvents();
3364 DbgLv(1) << "DBSv: (2)dset tripleID " << out_tripinfo[0].tripleID;
3365 
3366  status = saveUS3Disk();
3367  if ( status != US_Convert::OK )
3368  return;
3369 DbgLv(1) << "DBSv: local files saved";
3370 
3371  QString error = QString( "" );
3372 
3373  // Get the directory where the auc files are
3374  QDir resultDir( US_Settings::resultDir() );
3375  QString dir = resultDir.absolutePath() + "/" + ExpData.runID + "/";
3376 
3377  if ( ! resultDir.exists( ExpData.runID ) )
3378  {
3379  QMessageBox::information( this,
3380  tr( "Error" ),
3381  tr( "Cannot read from " ) + dir ); // aucDir.absolutePath() );
3382  return;
3383  }
3384 
3385  QStringList nameFilters = QStringList( "*.auc" );
3386 
3387  QDir readDir( dir );
3388 
3389  QStringList files = readDir.entryList( nameFilters,
3390  QDir::Files | QDir::Readable, QDir::Name );
3391 DbgLv(1) << "DBSv: files count" << files.size();
3392 
3393  if ( files.size() == 0 )
3394  {
3395  QMessageBox::warning( this,
3396  tr( "No Files Found" ),
3397  tr( "There were no files of the form *.auc\n"
3398  "found in the specified directory." ) );
3399  return;
3400  }
3401 
3402  if ( ExpData.checkRunID( &db ) == US_DB2::OK && ( saveStatus != BOTH ) )
3403  {
3404  // Then the user is trying to overwrite a runID that is already in the DB
3405  QMessageBox::warning( this,
3406  tr( "Duplicate runID" ),
3407  tr( "This runID already exists in the database. To edit that "
3408  "run information, load it from there to begin with.\n" ) );
3409  return;
3410  }
3411 
3412  // If saveStatus == BOTH already, then it came from the db to begin with
3413  // and it should be updated. Otherwise, there shouldn't be any database
3414  // records with this runID found
3415  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
3416  le_status->setText( tr( "Saving Experiment to DB ..." ) );
3417  qApp->processEvents();
3418  status = ExpData.saveToDB( ( saveStatus == BOTH ), &db, speedsteps );
3419  QApplication::restoreOverrideCursor();
3420 
3421  if ( status == US_DB2::NO_PROJECT )
3422  {
3423  QMessageBox::warning( this,
3424  tr( "Project missing" ),
3425  tr( "The project associated with this experiment could not be "
3426  "updated or added to the database.\n" ) );
3427  return;
3428  }
3429 
3430  else if ( status == US_DB2::DUPFIELD )
3431  {
3432  QMessageBox::warning( this,
3433  tr( "Duplicate runID" ),
3434  tr( "The runID already exists in the database.\n" ) );
3435  return;
3436  }
3437 
3438  else if ( status == US_DB2::ERROR )
3439  {
3440  // This is what happens in the case of RI data, and the xml is bad
3441  QMessageBox::warning( this,
3442  tr( "Bad RI XML" ),
3443  tr( "There was a problem with the xml data"
3444  " read from the database.\n" ) );
3445  }
3446 
3447  else if ( status != US_DB2::OK )
3448  {
3449  QMessageBox::warning( this,
3450  tr( "Problem saving experiment information" ),
3451  tr( "MySQL Error : " ) + db.lastError() + " ("
3452  + QString::number( status ) + ")" );
3453  return;
3454  }
3455 
3456  // If the data came from the database in the first place,
3457  // then this function erases all the edit profiles, models
3458  // and noise files in the database too. However, if one
3459  // changes most of the things here ( solution, rotor, etc. )
3460  // it would invalidate the data anyway.
3461  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
3462  le_status->setText( tr( "Writing raw data to DB ..." ) );
3463  qApp->processEvents();
3464 
3465  QString writeStatus =
3467 
3468  QApplication::restoreOverrideCursor();
3469 
3470  if ( ! writeStatus.isEmpty() )
3471  {
3472  QMessageBox::warning( this,
3473  tr( "Problem saving experiment" ),
3474  tr( "Unspecified database error: " ) + writeStatus );
3475  le_status->setText( tr( "*ERROR* Problem saving experiment." ) );
3476  return;
3477  }
3478 
3479  if ( repeat_disk )
3480  { // Last disk save did not have tripleID values, so update files
3481  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
3482  le_status->setText( tr( "Writing updated Raw records to disk..." ) );
3483 
3484  status = saveUS3Disk();
3485 
3486  QApplication::restoreOverrideCursor();
3487  qApp->processEvents();
3488 DbgLv(1) << "DBSv: REPEAT disk save for raw IDs";
3489  }
3490 
3491  // Insure that we have a TimeState record in the DB for this run
3492  le_status->setText( tr( "Writing Time State to DB..." ) );
3493  writeTimeStateDB();
3494 
3495  le_status->setText( tr( "DB data save complete. Saving reports..." ) );
3496  qApp->processEvents();
3497  saveStatus = BOTH;
3498  enableRunIDControl( false );
3499 
3500  saveReportsToDB();
3501  QApplication::restoreOverrideCursor();
3502  QApplication::restoreOverrideCursor();
3503 
3504  le_status->setText( tr( "DB data and reports save IS COMPLETE." ) );
3505  qApp->processEvents();
3506 }
3507 
3509 {
3510  if ( isMwl )
3511  return;
3512 
3513  // Verify connectivity
3514  US_Passwd pw;
3515  QString masterPW = pw.getPasswd();
3516  US_DB2 db( masterPW );
3517 
3518  if ( db.lastErrno() != US_DB2::OK )
3519  {
3520  QMessageBox::information( this,
3521  tr( "Error" ),
3522  tr( "Database connectivity error" ) );
3523 
3524  return;
3525  }
3526 
3527  // Get a list of report files produced by us_convert
3528  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
3529  QString dir = US_Settings::reportDir() + "/" + runID;
3530  QDir d( dir, "cnvt*", QDir::Name, QDir::Files | QDir::Readable );
3531  d.makeAbsolute();
3532  QStringList files = d.entryList( QDir::Files );
3533 
3534  // Add any run details files to it
3535  QDir d2( dir, "rundetail*", QDir::Name, QDir::Files | QDir::Readable );
3536  d2.makeAbsolute();
3537  files << d2.entryList( QDir::Files );
3538 
3539  // Create US_Report object
3540  QString now = QDateTime::currentDateTime().toString();
3541  US_Report myReport;
3542  myReport.reset();
3543  myReport.runID = runID;
3544  myReport.title = runID + " Report";
3545  myReport.html = "<p>Report created " + now + "</p>";
3546 
3547  // Save all us_convert report files to the DB
3548  QString errorMsg = "";
3549  foreach( QString file, files )
3550  {
3551  // Get description info for the correct triple
3552  QStringList parts = file.split( "." );
3553  QString fileTriple = US_Util::expanded_triple( parts[ 1 ], true );
3554 
3555  // Match the triple to find the correct description in memory
3556  QString description = QString( "" );
3557  for ( int ii = 0; ii < out_tripinfo.size(); ii++ )
3558  {
3559  if ( fileTriple == out_tripinfo[ ii ].tripleDesc )
3560  {
3561  description = outData[ ii ]->description;
3562  break;
3563  }
3564  }
3565 
3566  // Edit data ID is not known yet, so use 1. It goes in the report document
3567  // table itself, so we're not overwriting anything.
3568  US_Report::Status status = myReport.saveDocumentFromFile(
3569  dir, file, &db, 1, description );
3570  if ( status != US_Report::REPORT_OK )
3571  {
3572  errorMsg += file + " was not saved to report database; error code: "
3573  + QString::number( status ) + "\n";
3574  qDebug() << "US_ConvertGui.saveDocumentFromFile error: "
3575  << db.lastError() << db.lastErrno();
3576  }
3577  }
3578  QApplication::restoreOverrideCursor();
3579 
3580  if ( ! errorMsg.isEmpty() )
3581  {
3582  QMessageBox::warning( this,
3583  tr( "Problem saving reports to DB" ),
3584  errorMsg );
3585  }
3586 
3587 }
3588 
3590 {
3591  QString dir;
3592  int impType = 0;
3593 
3594  dir = QFileDialog::getExistingDirectory( this,
3595  tr( "Raw Data Directory" ),
3597  QFileDialog::DontResolveSymlinks );
3598 
3599  dir.replace( "\\", "/" );
3600 
3601  if ( dir.isEmpty() ) // If no directory chosen, return now
3602  return -1;
3603 
3604  QDir readDir( dir, "*", QDir::Name, QDir::Files | QDir::Readable );
3605  readDir.makeAbsolute();
3606  if ( dir.right( 1 ) != "/" ) dir += "/"; // Ensure trailing "/"
3607 
3608  // See if we need to fix the runID
3609  QString new_runID = dir.section( "/", -2, -2 );
3610  QRegExp rx( "[^A-Za-z0-9_-]" );
3611 
3612  int pos = 0;
3613  bool runID_changed = false;
3614  while ( ( pos = rx.indexIn( new_runID ) ) != -1 )
3615  {
3616  new_runID.replace( pos, 1, "_" ); // Replace 1 char at position pos
3617  runID_changed = true;
3618  }
3619 DbgLv(1) << "CGui:gI: dir" << dir << "new_runID" << new_runID
3620  << "rID_chgd" << runID_changed;
3621 
3622  // Let the user know if the runID name has changed
3623  if ( runID_changed )
3624  {
3625  QMessageBox::warning( this,
3626  tr( "RunID Name Changed" ),
3627  tr( "The runID name has been changed. It may consist only"
3628  "of alphanumeric \n"
3629  " characters, the underscore, and the hyphen. New runID: " )
3630  + new_runID );
3631  }
3632 
3633  // Set the runID and directory
3634  runID = new_runID;
3635  le_runID ->setText( runID );
3636  le_runID2->setText( runID );
3637  le_dir ->setText( dir );
3638  currentDir = QString( dir );
3639 
3640  // Get the list of files in the chosen directory
3641  QStringList nameFilters = QStringList( "*" );
3642  QStringList files = readDir.entryList( nameFilters,
3643  QDir::Files | QDir::Readable, QDir::Name );
3644 
3645  QString tmstFname;
3646  QString txmlFname;
3647  int nauc = 0;
3648  int nmwrs = 0;
3649  int nother = 0;
3650  int ntmst = 0;
3651  int ntxml = 0;
3652  int ntotf = files.size();
3653 DbgLv(1) << "CGui:gI: ntotf" << ntotf;
3654 
3655  for ( int jj = 0; jj < ntotf; jj++ )
3656  {
3657  QString fname = files[ jj ];
3658 
3659  if ( fname.endsWith( ".mwrs" ) )
3660  nmwrs++;
3661 
3662  else if ( fname.endsWith( ".auc" ) )
3663  nauc++;
3664 
3665  else if ( fname.endsWith( "time_state.xml" ) )
3666  {
3667  ntxml++;
3668  txmlFname = fname;
3669  }
3670  else if ( fname.endsWith( "time_state.tmst" ) )
3671  {
3672  ntmst++;
3673  tmstFname = fname;
3674  }
3675  else
3676  nother++;
3677  }
3678 DbgLv(1) << "CGui:gI: nmwrs nauc nother" << nmwrs << nauc << nother;
3679 
3680  if ( nmwrs > nother )
3681  impType = 1; // Flag import of MWL data
3682 
3683  else if ( nauc > nother )
3684  impType = 2; // Flag import of AUC data
3685 
3686  else
3687  impType = 0; // Flag import of Beckman Raw
3688 
3689 DbgLv(1) << "CGui:gI: RTN impType" << impType;
3690  return impType;
3691 }
3692 
3694 {
3695  oldRunType = runType; // let's see if the runType changes
3696 
3697  // Read the legacy data
3698 DbgLv(1) << "CGui:RD: rdLegDat CALL";
3699  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
3701  QApplication::restoreOverrideCursor();
3702 DbgLv(1) << "CGui:RD: rdLegDat RTN lDsz" << legacyData.size();
3703 
3704  if ( legacyData.size() == 0 ) return( false );
3705 
3706  // if runType has changed, let's clear out xml data too
3707  if ( oldRunType != runType ) ExpData.clear();
3708 
3709  return( true );
3710 }
3711 
3713 {
3714 DbgLv(1) << "CGui:CV: IN";
3715  // Set tolerance to stay between wl numbers
3716  double tolerance = (double)ct_tolerance->value();
3717 
3718  // Convert the data
3719  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
3721  runType, tolerance );
3722 DbgLv(1) << "CGui:CV: ndat ntrip runType" << allData.size()
3723  << all_tripinfo.size() << runType;
3724  QApplication::restoreOverrideCursor();
3725 
3726  if ( allData.size() == 0 ) return( false );
3727 
3728  le_description->setText( allData[ 0 ].description );
3729  saveDescription = QString( allData[ 0 ].description );
3730 
3731  // Now let's show the user the first one
3732  tripListx = -1;
3733  for ( int i = 0; i < all_tripinfo.size(); i++ )
3734  {
3735  if ( all_tripinfo[ i ].excluded ) continue;
3736 
3737  if ( tripListx == -1 ) tripListx = i;
3738 DbgLv(1) << "CGui:CV: i, trip" << i << all_tripinfo[i].tripleDesc;
3739  }
3740 
3741 DbgLv(1) << "CGui:CV: RTN tLx" << tripListx << "ntrip" << all_tripinfo.size();
3742  return( true );
3743 }
3744 
3746 {
3747 DbgLv(1) << "CGui: centpInfo: db" << disk_controls->db();
3748  if ( disk_controls->db() )
3749  return centerpieceInfoDB();
3750 
3751  else
3752  return centerpieceInfoDisk();
3753 }
3754 
3755 // Function to get abstractCenterpiece names from DB
3757 {
3758  // Verify connectivity
3759  US_Passwd pw;
3760  QString masterPW = pw.getPasswd();
3761  US_DB2 db( masterPW );
3762 
3763  if ( db.lastErrno() != US_DB2::OK )
3764  {
3765  QMessageBox::information( this,
3766  tr( "Error" ),
3767  tr( "Database connectivity error" ) );
3768 
3769  return( false );
3770  }
3771 
3772  QStringList q( "get_abstractCenterpiece_names" );
3773  db.query( q );
3774 
3775  QList<listInfo> options;
3776  while ( db.next() )
3777  {
3778  struct listInfo option;
3779  option.ID = db.value( 0 ).toString();
3780  option.text = db.value( 1 ).toString();
3781  options << option;
3782  }
3783 
3784  cb_centerpiece->clear();
3785  if ( options.size() > 0 )
3786  cb_centerpiece->addOptions( options );
3787 
3788 DbgLv(1) << "CGui: centpInfoDB RTN";
3789  return true;
3790 }
3791 
3792 // Function to get abstractCenterpiece names from disk
3794 {
3795  // First figure out the xml file name, and try to open it
3796  QFile f( US_Settings::appBaseDir() + "/etc/abstractCenterpieces.xml" );
3797 
3798  if ( ! f.open( QIODevice::ReadOnly ) ) return false;
3799 
3800  QList<listInfo> options;
3801  QXmlStreamReader xml( &f );
3802  while ( ! xml.atEnd() )
3803  {
3804  xml.readNext();
3805 
3806  if ( xml.isStartElement() )
3807  {
3808  if ( xml.name() == "abstractCenterpiece" )
3809  {
3810  struct listInfo option;
3811  QXmlStreamAttributes a = xml.attributes();
3812  option.ID = a.value("id").toString();
3813  option.text = a.value("name").toString();
3814  options << option;
3815  }
3816  }
3817  }
3818 
3819  bool error = xml.hasError();
3820  f.close();
3821 
3822  if ( error ) return false;
3823 
3824  cb_centerpiece->clear();
3825  if ( options.size() > 0 )
3826  {
3827  // Let's sort them so they come up like the DB
3828  for ( int i = 0; i < options.size() - 1; i++ )
3829  for ( int j = i + 1; j < options.size(); j++ )
3830  if ( options[ i ].text > options[ j ].text )
3831  options.swap( i, j );
3832 
3833  cb_centerpiece->addOptions( options );
3834  }
3835 
3836 DbgLv(1) << "CGui: centpInfoDk RTN";
3837  return true;
3838 }
3839 
3841 {
3842  triple_index();
3843 DbgLv(1) << " PlCur: tDx szoutD" << tripDatax << outData.count();
3844 
3845  US_DataIO::RawData currentData = *outData[ tripDatax ];
3846 
3847  if ( currentData.scanData.empty() ) return;
3848 
3849  plot_titles();
3850 DbgLv(1) << " PlCur: PlTit RTN";
3851 
3852  // Plot current data for cell / channel / wavelength triple
3853  plot_all();
3854 
3855  // Set the Scan spin boxes
3857 }
3858 
3860 {
3861 DbgLv(1) << " PlTit: tDx outsz otrisz" << tripDatax << outData.size()
3862  << out_tripinfo.size();
3863  char chtype[ 3 ] = { 'R', 'A', '\0' };
3864 
3865  strncpy( chtype, outData[ tripDatax ]->type, 2 );
3866  QString dataType = QString( chtype ).left( 2 );
3867  QString triple = out_tripinfo[ tripDatax ].tripleDesc;
3868  QStringList parts = triple.split(" / ");
3869 DbgLv(1) << " PlTit: triple" << triple << "parts" << parts;
3870 
3871  QString cell = parts[ 0 ];
3872  QString channel = parts[ 1 ];
3873  QString wavelen = isMwl ? cb_lambplot->currentText() : parts[ 2 ];
3874 
3875  // Plot Title and legends
3876  QString title;
3877  QString xLegend = tr( "Radius (in cm)" );
3878  QString yLegend = tr( "Absorbance" );
3879  QString ccwlong = runID + tr( "\nCell: " ) + cell
3880  + tr( " Channel: " ) + channel
3881  + tr( " Wavelength: " ) + wavelen;
3882  QString ccrlong = QString( ccwlong ).replace( "Wavelength:", "Radius:" );
3883 DbgLv(1) << " PlTit: dataType" << dataType;
3884 
3885  if ( dataType == "RA" )
3886  {
3887  title = tr( "Radial Absorbance Data\nRun ID: " ) + ccwlong;
3888  }
3889 
3890  else if ( dataType == "RI" && isPseudo )
3891  {
3892  title = tr( "Pseudo Absorbance Data\nRun ID: " ) + ccwlong;
3893  }
3894 
3895  else if ( dataType == "RI" )
3896  {
3897  title = tr( "Radial Intensity Data\nRun ID: " ) + ccwlong;
3898  yLegend = tr( "Radial Intensity at " ) + wavelen + " nm";
3899  }
3900 
3901  else if ( dataType == "IP" )
3902  {
3903  title = tr( "Interference Data\nRun ID: " ) + ccwlong;
3904  yLegend = tr( "Fringes" );
3905  }
3906 
3907  else if ( dataType == "FI" )
3908  {
3909  title = tr( "Fluorescence Intensity Data\nRun ID: " ) + ccwlong;
3910  yLegend = tr( "Fluorescence Intensity" );
3911  }
3912 
3913  else if ( dataType == "WA" )
3914  {
3915  title = tr( "Wavelength Data\nRun ID: " ) + ccrlong;
3916  xLegend = tr( "Wavelength" );
3917  yLegend = tr( "Absorbance" );
3918  }
3919 
3920  else if ( dataType == "WI" )
3921  {
3922  title = tr( "Wavelength Intensity Data\nRun ID: " ) + ccrlong;
3923  xLegend = tr( "Wavelength" );
3924  yLegend = tr( "Intensity" );
3925  }
3926 
3927  else
3928  title = tr( "File type not recognized" );
3929 
3930  data_plot->setTitle( title );
3931  data_plot->setAxisTitle( QwtPlot::yLeft, yLegend );
3932  data_plot->setAxisTitle( QwtPlot::xBottom, xLegend );
3933 
3934 }
3935 
3937 {
3938  US_DataIO::RawData* currentData = outData[ tripDatax ];
3939 
3940  data_plot->detachItems();
3941  grid = us_grid( data_plot );
3942 
3943  int size = currentData->xvalues.size();
3944 
3945  QVector< double > rvec( size );
3946  QVector< double > vvec( size );
3947 
3948  double* r = rvec.data();
3949  double* v = vvec.data();
3950 
3951  double maxR = -1.0e99;
3952  double minR = 1.0e99;
3953  double maxV = -1.0e99;
3954  double minV = 1.0e99;
3955 
3956  for ( int i = 0; i < currentData->scanData.size(); i++ )
3957  {
3958  US_Convert::Excludes currentExcludes = allExcludes[ tripDatax ];
3959  if ( currentExcludes.contains( i ) ) continue;
3960  US_DataIO::Scan* s = &currentData->scanData[ i ];
3961 
3962  for ( int j = 0; j < size; j++ )
3963  {
3964  r[ j ] = currentData->radius( j );
3965  v[ j ] = s->rvalues[ j ];
3966 
3967  if ( v[ j ] > 1.0e99 || isnan( v[ j ] ) )
3968  {
3969  // For some reason v[j] is going off the scale
3970  // Don't know why, but filter out for now
3971  qDebug() << "(r, v) = ( " << r[j] << ", " << v[j] << ")"
3972  << " (minR, maxR) = ( " << minR << ", " << maxR << ")" << endl
3973  << " (minV, maxV) = ( " << minV << ", " << maxV << ")" << endl;
3974  continue;
3975  }
3976 
3977  maxR = max( maxR, r[ j ] );
3978  minR = min( minR, r[ j ] );
3979  maxV = max( maxV, v[ j ] );
3980  minV = min( minV, v[ j ] );
3981  }
3982 
3983  QString title = tr( "Raw Data at " )
3984  + QString::number( s->seconds ) + tr( " seconds" );
3985 
3986  QwtPlotCurve* c = us_curve( data_plot, title );
3987  c->setData( r, v, size );
3988 
3989  }
3990 
3991  // Reset the scan curves within the new limits
3992  double padR = ( maxR - minR ) / 30.0;
3993  double padV = ( maxV - minV ) / 30.0;
3994 
3995  data_plot->setAxisScale( QwtPlot::yLeft , minV - padV, maxV + padV );
3996  data_plot->setAxisScale( QwtPlot::xBottom, minR - padR, maxR + padR );
3997 
3998  show_plot_progress = false;
3999  data_plot->replot();
4000 }
4001 
4003 {
4004  plot_all();
4005 }
4006 
4007 void US_ConvertGui::set_colors( const QList< int >& focus )
4008 {
4009  // Get pointers to curves
4010  QwtPlotItemList list = data_plot->itemList();
4011  QList< QwtPlotCurve* > curves;
4012 
4013  for ( int i = 0; i < list.size(); i++ )
4014  {
4015  if ( list[ i ]->title().text().contains( "Raw" ) )
4016  curves << dynamic_cast< QwtPlotCurve* >( list[ i ] );
4017  }
4018 
4019  QPen p = curves[ 0 ]->pen();
4020  QBrush b = curves[ 0 ]->brush();
4021  QColor std = US_GuiSettings::plotCurve();
4022 
4023  // Mark these scans in red
4024  for ( int i = 0; i < curves.size(); i++ )
4025  {
4026  if ( focus.contains( i ) )
4027  {
4028  p.setColor( Qt::red );
4029  }
4030  else
4031  {
4032  p.setColor( std );
4033  b.setColor( std );
4034  }
4035 
4036  curves[ i ]->setPen ( p );
4037  curves[ i ]->setBrush( b );
4038  }
4039 
4040  data_plot->replot();
4041 }
4042 
4043 void US_ConvertGui::draw_vline( double radius )
4044 {
4045  double r[ 2 ];
4046 
4047  r[ 0 ] = radius;
4048  r[ 1 ] = radius;
4049  QwtScaleDiv* y_axis = data_plot->axisScaleDiv( QwtPlot::yLeft );
4050 
4051  double padding = ( y_axis->upperBound() - y_axis->lowerBound() ) / 30.0;
4052 
4053  double v[ 2 ];
4054  v [ 0 ] = y_axis->upperBound() - padding;
4055  v [ 1 ] = y_axis->lowerBound() + padding;
4056 
4057  QwtPlotCurve* v_line = us_curve( data_plot, "V-Line" );
4058  v_line->setData( r, v, 2 );
4059 
4060  QPen pen = QPen( QBrush( Qt::white ), 2.0 );
4061  v_line->setPen( pen );
4062 
4063  data_plot->replot();
4064 }
4065 
4066 void US_ConvertGui::db_error( const QString& error )
4067 {
4068  QMessageBox::warning( this, tr( "Database Problem" ),
4069  tr( "Database returned the following error: \n" ) + error );
4070 }
4071 
4072 // User changed the Lambda Start value
4074 {
4075 DbgLv(1) << "lambdaStartChanged" << value;
4076  slambda = cb_lambstrt->itemText( value ).toInt();
4077  elambda = cb_lambstop->currentText() .toInt();
4078  tripListx = lw_triple->currentRow();
4079  int currChan = out_chaninfo[ tripListx ].channelID;
4080 DbgLv(1) << "lambdaStartChanged" << value << "sl el tLx cCh"
4081  << slambda << elambda << tripListx << currChan;
4082 
4083  for ( int trx = 0; trx < all_tripinfo.count(); trx++ )
4084  {
4085  int iwavl = all_tripinfo[ trx ]
4086  .tripleDesc.section( " / ", 2, 2 ).toInt();
4087 
4088  if ( all_tripinfo[ trx ].channelID == currChan )
4089  all_tripinfo[ trx ].excluded = ( iwavl < slambda );
4090 DbgLv(1) << "lStChg: trx iwavl chnID excl" << trx << iwavl
4091  << all_tripinfo[trx].channelID << all_tripinfo[trx].excluded;
4092  }
4093 
4095 DbgLv(1) << "lStChg: BlOutDa RTN";
4096  reset_lambdas();
4097 DbgLv(1) << "lStChg: RsLambd RTN";
4098 }
4099 
4100 // User changed the Lambda End value
4102 {
4103 DbgLv(1) << "lambdaEndChanged" << value;
4104  slambda = cb_lambstrt->currentText() .toInt();
4105  elambda = cb_lambstop->itemText( value ).toInt();
4106  tripListx = lw_triple->currentRow();
4107  int currChan = out_chaninfo[ tripListx ].channelID;
4108 DbgLv(1) << "lEnChg: val" << value << "sl el tLx cCh"
4109  << slambda << elambda << tripListx << currChan;
4110 
4111  for ( int trx = 0; trx < all_tripinfo.count(); trx++ )
4112  {
4113  int iwavl = all_tripinfo[ trx ]
4114  .tripleDesc.section( " / ", 2, 2 ).toInt();
4115 
4116  if ( all_tripinfo[ trx ].channelID == currChan && iwavl > elambda )
4117  all_tripinfo[ trx ].excluded = ( iwavl > elambda );
4118  }
4119 
4121 DbgLv(1) << "lEnChg: BlOutDa RTN";
4122  reset_lambdas();
4123 DbgLv(1) << "lEnChg: RsLambd RTN";
4124 }
4125 
4126 // User changed the Lambda Plot value
4128 {
4129  triple_index();
4130 
4131  plot_current();
4132  pb_lambprev->setEnabled( value > 0 );
4133  pb_lambnext->setEnabled( ( value + 1 ) < cb_lambplot->count() );
4134 }
4135 
4136 // User clicked the Previous Lambda Plot button
4138 {
4139  int wvx = qMax( 0, cb_lambplot->currentIndex() - 1 );
4140 
4141  cb_lambplot->setCurrentIndex( wvx );
4142 }
4143 
4144 // User clicked the Next Lambda Plot button
4146 {
4147  int wvxmax = cb_lambplot->count() - 1;
4148  int wvx = qMin( wvxmax, cb_lambplot->currentIndex() + 1 );
4149 
4150  cb_lambplot->setCurrentIndex( wvx );
4151 }
4152 
4153 // Show or hide MWL controls
4155 {
4156  lb_mwlctrl ->setVisible( show );
4157  lb_lambstrt ->setVisible( show );
4158  cb_lambstrt ->setVisible( show );
4159  lb_lambstop ->setVisible( show );
4160  cb_lambstop ->setVisible( show );
4161  lb_lambplot ->setVisible( show );
4162  cb_lambplot ->setVisible( show );
4163  pb_lambprev ->setVisible( show );
4164  pb_lambnext ->setVisible( show );
4165  pb_dropCelch->setVisible( show );
4166  pb_dropChan ->setVisible( show );
4167 
4168  pb_exclude ->setVisible( !show );
4169  pb_include ->setVisible( !show );
4170 
4171  adjustSize();
4172 }
4173 
4174 // Determine triple index (separate list,data for MWL)
4176 {
4177  tripListx = lw_triple->currentRow();
4178  tripDatax = isMwl
4179  ? out_chandatx[ tripListx ] + cb_lambplot->currentIndex()
4180  : tripListx;
4181 DbgLv(1) << " triple_index trLx trDx" << tripListx << tripDatax
4182  << " triple" << lw_triple->currentItem()->text();
4183 }
4184 
4185 // Turn MWL connections on or off
4186 void US_ConvertGui::mwl_connect( bool connect_on )
4187 {
4188  if ( connect_on )
4189  {
4190  connect( cb_lambstrt, SIGNAL( currentIndexChanged( int ) ),
4191  this, SLOT ( lambdaStartChanged ( int ) ) );
4192  connect( cb_lambstop, SIGNAL( currentIndexChanged( int ) ),
4193  this, SLOT ( lambdaEndChanged ( int ) ) );
4194  connect( cb_lambplot, SIGNAL( currentIndexChanged( int ) ),
4195  this, SLOT ( lambdaPlotChanged ( int ) ) );
4196  connect( pb_lambprev, SIGNAL( clicked ( ) ),
4197  this, SLOT ( lambdaPrevClicked ( ) ) );
4198  connect( pb_lambnext, SIGNAL( clicked ( ) ),
4199  this, SLOT ( lambdaNextClicked ( ) ) );
4200  }
4201 
4202  else
4203  {
4204  cb_lambstrt->disconnect();
4205  cb_lambstop->disconnect();
4206  cb_lambplot->disconnect();
4207  pb_lambprev->disconnect();
4208  pb_lambnext->disconnect();
4209  }
4210 }
4211 
4212 // Reset with lambda delta,range changes
4214 {
4215  if ( ! isMwl )
4216  return;
4217 
4218  int plambda = cb_lambplot->currentText().toInt();
4219  QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) );
4220 
4221 DbgLv(1) << "rsL: slambda elambda" << slambda << elambda;
4222  mwl_data.set_lambdas ( slambda, elambda, tripListx );
4223  mwl_connect( false );
4224 
4226  int plx = nlambda / 2;
4227  cb_lambplot->clear();
4228 DbgLv(1) << "rsL: nlambda" << nlambda;
4229 
4230  for ( int wvx = 0; wvx < nlambda; wvx++ )
4231  { // Add to plot-lambda list and possibly detect old selection in new list
4232  int ilamb = exp_lambdas[ wvx ];
4233  cb_lambplot->addItem( QString::number( ilamb ) );
4234 
4235  if ( ilamb == plambda ) plx = wvx;
4236  }
4237 
4238 DbgLv(1) << "rsL: plambda" << plambda << "plx" << plx;
4239  cb_lambplot->setCurrentIndex( plx );
4240 
4241  // Rebuild list of triples
4242  QStringList celchns;
4243  QString pwvln = " / " + QString::number( exp_lambdas[ 0 ] )
4244  + "-" + QString::number( exp_lambdas[ nlambda - 1 ] )
4245  + " (" + QString::number( nlambda ) + ")";
4246 
4247  int ncelchn = mwl_data.cellchannels( celchns );
4248  nlambda = mwl_data.countOf( "lambda" );
4249 DbgLv(1) << "rsL: ncc nl szcc szci" << ncelchn << nlambda << celchns.count()
4250  << all_chaninfo.count();
4251 
4252  for ( int ii = 0; ii < ncelchn; ii++ )
4253  { // Redo internal channel information description field
4254  all_chaninfo[ ii ].tripleDesc = celchns[ ii ] + pwvln;
4255  }
4256 
4257  mwl_connect( true );
4258  QApplication::restoreOverrideCursor();
4259 
4260  setTripleInfo();
4261 DbgLv(1) << "rsL: sTrInf RTN";
4262 
4263  init_excludes();
4264 DbgLv(1) << "rsL: InExcl RTN";
4265 
4266  plot_current();
4267 DbgLv(1) << "rsL: PlCurr RTN";
4268 }
4269 
4270 // Do pseudo-absorbance calculation and apply for MultiWaveLength case
4272 {
4273  QVector< double > ri_prof; // RI profile for a single wavelength
4274  ExpData.RIProfile.clear(); // Composite RI profile
4275  ExpData.RIwvlns .clear(); // RI profile wavelengths
4276 
4277  if ( referenceDefined ) return; // Average calculation is already done
4278 
4279  US_DataIO::RawData* refData = outData[ tripDatax ];
4280  int ref_size = refData->xvalues.size();
4281  int ccx = tripListx;
4282  int tripx = out_chandatx[ ccx ];
4284  ExpData.RI_nscans = refData->scanData.size();
4286 DbgLv(1) << "PseCalcAvgMWL: ccx tripx nlambda" << ccx << tripx << nlambda;
4287 
4288  // Loop to calculate reference data for each wavelength,
4289  // then apply it to all triples with that same wavelength.
4290  for ( int wvx = 0; wvx < nlambda; wvx++ )
4291  {
4292  refData = outData[ tripx ];
4293  ref_size = refData->xvalues.size();
4294  int nscan = refData->scanData.size();
4295  ri_prof.clear();
4296 
4297  // Get the reference profile for the current wavelength
4298  for ( int ss = 0; ss < nscan; ss++ )
4299  {
4300  US_DataIO::Scan* scan = &refData->scanData[ ss ];
4301 
4302  int rr = 0;
4303  int count = 0;
4304  double sum = 0.0;
4305 
4306  while ( refData->radius( rr ) < reference_start && rr < ref_size )
4307  rr++;
4308 
4309  while ( refData->radius( rr ) < reference_end &&
4310  rr < ref_size )
4311  {
4312  sum += scan->rvalues[ rr ];
4313  count++;
4314  rr++;
4315  }
4316 
4317  double rip_avg = count > 0 ? ( sum / (double)count ) : 1.0;
4318  ri_prof << rip_avg;
4319  ExpData.RIProfile << rip_avg;
4320 
4321  } // END: scan loop for reference triple
4322 
4323  int rip_size = ri_prof.size();
4324  int iwavl = exp_lambdas[ wvx ];
4325 DbgLv(1) << "PseCalcAvgMWL: wvx" << wvx << "rsiz wavl" << rip_size << iwavl;
4326  ExpData.RIwvlns << iwavl;
4327 
4328  // Now calculate the pseudo-absorbance for all cell/channel/this-lambda
4329  for ( int trx = 0; trx < outData.size(); trx++ )
4330  {
4331  int jwavl = out_triples[ trx ].section( " / ", -1, -1 ).toInt();
4332 
4333  if ( jwavl != iwavl ) continue;
4334 
4335  // Triple data has the current wavelength value
4336  US_DataIO::RawData* currentData = outData[ trx ];
4337 
4338  for ( int ss = 0; ss < currentData->scanData.size(); ss++ )
4339  {
4340  US_DataIO::Scan* scan = &currentData->scanData[ ss ];
4341  // Check for boundary condition
4342  int ndx = ( ss < rip_size ) ? ss : rip_size - 1;
4343  double ripval = ri_prof[ ndx ];
4344 
4345  for ( int rr = 0; rr < scan->rvalues.size(); rr++ )
4346  {
4347  // Protect against possible inf's and nan's, if a reading
4348  // evaluates to 0 or wherever log function is undefined or -inf
4349  double rvalue = qMax( 1.0, scan->rvalues[ rr ] );
4350 
4351  scan->rvalues[ rr ] = log10( ripval / rvalue );
4352  } // END: readings loop for a scan
4353 
4354  } // END: scan loop for a specific triple
4355 
4356  } // END: cell-channel apply loop for one wavelength
4357 
4358  tripx++;
4359 DbgLv(1) << "PseCalcAvgMWL: tripx" << tripx;
4360  } // END: WaveLength loop
4361 
4362  isPseudo = true;
4363  referenceDefined = true;
4364 DbgLv(1) << "CGui: (9)referDef=" << referenceDefined;
4365  pb_intensity->setEnabled( true );
4366  pb_reference->setEnabled( false );
4367  pb_cancelref->setEnabled( true );
4368 }
4369 
4370 // Do MWL Gui setup after import or load of MWL data
4372 {
4373  mwl_connect( false );
4374 
4375  // Propagate initial lists of Lambdas
4377  cb_lambstrt->clear();
4378  cb_lambstop->clear();
4379 
4380  for ( int ii = 0; ii < nlamb_i; ii++ )
4381  {
4382  QString clamb = QString::number( all_lambdas[ ii ] );
4383  cb_lambstrt->addItem( clamb );
4384  cb_lambstop->addItem( clamb );
4385  }
4386 
4387  cb_lambstrt->setCurrentIndex( 0 );
4388  cb_lambstop->setCurrentIndex( nlamb_i - 1 );
4390  cb_lambplot->clear();
4391 
4392  for ( int ii = 0; ii < nlambda; ii++ )
4393  {
4394  QString clamb = QString::number( exp_lambdas[ ii ] );
4395  cb_lambplot->addItem( clamb );
4396  }
4397 
4398  cb_lambplot->setCurrentIndex( nlambda / 2 );
4399 
4400  show_mwl_control( true );
4401  mwl_connect( true );
4402 
4403  setTripleInfo();
4404  le_description -> setText( allData[ 0 ].description );
4405 
4406  // Initialize exclude list
4407  init_excludes();
4408 
4409  plot_current();
4410 
4412 
4413  // Ok to enable some buttons now
4414  enableControls();
4415 
4416  int rlamb_s = all_lambdas[ 0 ];
4417  int rlamb_e = all_lambdas[ nlamb_i - 1 ];
4418  int ntriple = all_tripinfo.size();
4419  static QChar clambda( 955 ); // Lambda character
4420  QString lambmsg = tr( "MWL imported : %1 triples : %2 %3 to %4" )
4421  .arg( ntriple ).arg( clambda ).arg( rlamb_s ).arg( rlamb_e );
4422 // le_lambraw->setText( lambmsg );
4423  le_status->setText( lambmsg );
4424  qApp->processEvents();
4425  adjustSize();
4426 }
4427 
4428 // Initialize output data pointers and lists
4430 {
4431  bool success = true;
4432  bool have_trip = ( all_tripinfo.size() == allData.size() );
4433 DbgLv(1) << "CGui:IOD: have_trip" << have_trip;
4434  if ( ! have_trip )
4435  all_tripinfo.clear();
4436  outData .clear();
4437  all_chaninfo.clear();
4438  all_triples .clear();
4439  all_channels.clear();
4440  out_tripinfo.clear();
4441  out_chaninfo.clear();
4442  out_triples .clear();
4443  out_channels.clear();
4444  out_chandatx.clear();
4445 
4446  // Set up initial export-data pointers list and all/out lists
4447  for ( int trx = 0; trx < allData.size(); trx++ )
4448  {
4449  US_DataIO::RawData* edata = &allData[ trx ];
4450  US_Convert::TripleInfo tripinfo;
4451  US_Convert::TripleInfo chaninfo;
4452 
4453  outData << edata;
4454 
4455  if ( have_trip )
4456  tripinfo = all_tripinfo[ trx ];
4457 
4458  QString triple = QString::number( edata->cell ) + " / "
4459  + QString( edata->channel ) + " / "
4460  + ( ! runType.contains( "W" )
4461  ? QString::number( qRound( edata->scanData[ 0 ].wavelength ) )
4462  : tripinfo.tripleDesc.section( " / ", 2, 2 ) );
4463  QString celchn = triple.section( " / ", 0, 1 );
4464  int chanID = all_channels.indexOf( celchn ) + 1;
4465  chanID = ( chanID < 1 ) ? ( all_channels.count() + 1 ) : chanID;
4466  tripinfo.tripleID = trx + 1;
4467  tripinfo.tripleDesc = triple;
4468  tripinfo.description = edata->description;
4469  tripinfo.channelID = chanID;
4470  tripinfo.excluded = false;
4471  chaninfo = tripinfo;
4472  chaninfo.tripleDesc = celchn;
4473 DbgLv(1) << "CGui:IOD: trx" << trx << "triple" << triple;
4474 
4475  if ( have_trip )
4476  all_tripinfo[ trx ] = tripinfo;
4477  else
4478  all_tripinfo << tripinfo;
4479  out_tripinfo << tripinfo;
4480  all_triples << triple;
4481  out_triples << triple;
4482 
4483  if ( ! all_channels.contains( celchn ) || runType.contains( "W" ) )
4484  {
4485  all_channels << celchn;
4486  all_chaninfo << chaninfo;
4487  out_channels << celchn;
4488  out_chaninfo << chaninfo;
4489  out_chandatx << trx;
4490 DbgLv(1) << "CGui:IOD: ochx" << trx << "celchn cID" << celchn << chanID;
4491  }
4492  }
4493 
4494  // Save a vector of speed steps read or computed from the data scans
4495  char chtype[ 3 ] = { 'R', 'A', '\0' };
4496  strncpy( chtype, allData[ 0 ].type, 2 );
4497  QString dataType = QString( chtype ).left( 2 );
4498  int nspeed = US_SimulationParameters::readSpeedSteps( runID, dataType,
4499  speedsteps );
4500  int nspeedc = 0;
4501 DbgLv(1) << "CGui:IOD: rSS nspeed" << nspeed;
4502 
4503  if ( nspeed == 0 )
4504  {
4506  speedsteps );
4507  nspeedc = speedsteps.size();
4508  nspeed = nspeedc;
4509  }
4510 DbgLv(1) << "CGui:IOD: cSS nspeed" << speedsteps.size();
4511 
4512  // MultiWaveLength if channels and triples counts differ
4513  isMwl = ( all_chaninfo.count() != all_tripinfo.count() );
4514 DbgLv(1) << "CGui:IOD: isMwl" << isMwl << "c.count t.count"
4515  << all_chaninfo.count() << all_tripinfo.count();
4516  if ( isMwl && ( all_tripinfo.count() / all_chaninfo.count() ) < 4 )
4517  { // If less than 4 wavelengths, treat as non-MWL
4518  isMwl = false;
4521 DbgLv(1) << "CGui:IOD: isMwl" << isMwl << "c.count t.count"
4522  << all_chaninfo.count() << all_tripinfo.count() << out_chaninfo.count();
4523  }
4524 
4525  if ( isMwl )
4526  { // If MWL, update speed steps
4527 DbgLv(1) << "CGui:IOD: updSS call";
4528  QVector< SP_SPEEDPROFILE > testss = speedsteps;
4529  int nstest = mwl_data.update_speedsteps( testss );
4530  if ( nstest > 0 )
4531  {
4532  nspeed = nstest;
4533  speedsteps = testss;
4534  }
4535  else if ( nstest < 0 )
4536  {
4537  QMessageBox::critical( this,
4538  tr( "Invalid MWL Speedsteps" ),
4539  tr( "The \"set_speed\" values in MWRS files have"
4540  " resulted in too many speed steps or steps"
4541  " where speeds decrease.\n\nImport is ABORTED!!" ) );
4542  success = false;
4543  resetAll();
4544  }
4545 DbgLv(1) << "CGui:IOD: updSS nspeed nstest nspeedc"
4546  << nspeed << nstest << nspeedc << "ss0 timf omgf"
4547  << speedsteps[0].time_first << speedsteps[0].w2t_first;
4548  }
4549 
4550  else
4551  { // Else complete channel lists
4552  for ( int trx = 0; trx < all_tripinfo.count(); trx++ )
4553  {
4554  QString triple = all_tripinfo[ trx ].tripleDesc;
4555 DbgLv(1) << "CGui:IOD: trx" << trx << "triple" << triple;
4556  all_chaninfo[ trx ].tripleDesc = triple;
4557  out_chaninfo[ trx ].tripleDesc = triple;
4558  }
4559 DbgLv(1) << "CGui:IOD: nspeed" << nspeed << "sp0.rspeed sp0.avspeed"
4560  << nspeed << speedsteps[0].rotorspeed << speedsteps[0].avg_speed;
4561  }
4562 
4563  return success;
4564 DbgLv(1) << "CGui:IOD: RETURN";
4565 }
4566 
4567 // Build output data pointers and lists after new exclusions
4569 {
4570  outData .clear(); // Pointers to output data
4571  out_tripinfo.clear(); // Output triple information objects
4572  out_triples .clear(); // Output triple strings ("1 / A / 250")
4573  out_chaninfo.clear(); // Output channel information objects
4574  out_channels.clear(); // Output channel strings ("2 / B")
4575  out_chandatx.clear(); // Triple start indexes for each channel
4576  int outx = 0; // Output triple data index
4577 
4578  // Set up updated export-data pointers list and supporting output lists
4579  for ( int trx = 0; trx < allData.size(); trx++ )
4580  {
4581  US_Convert::TripleInfo* tripinfo = &all_tripinfo[ trx ];
4582 
4583  if ( tripinfo->excluded ) continue;
4584 
4585  outData << &allData[ trx ];
4586 
4587  QString triple = tripinfo->tripleDesc;
4588  QString celchn = triple.section( " / ", 0, 1 );
4589 
4590  out_tripinfo << *tripinfo;
4591  out_triples << triple;
4592 
4593  if ( ! out_channels.contains( celchn ) )
4594  {
4595  out_channels << celchn;
4596  out_chaninfo << *tripinfo;
4597  out_chandatx << outx;
4598  }
4599 
4600  outx++;
4601  }
4602 }
4603 
4604 // Turn ct_tolerance connection on or off
4605 void US_ConvertGui::connectTolerance( bool setConnect )
4606 {
4607  if ( setConnect )
4608  {
4609  connect( ct_tolerance, SIGNAL( valueChanged ( double ) ),
4610  SLOT ( toleranceValueChanged( double ) ) );
4611  }
4612  else
4613  {
4614  ct_tolerance->disconnect();
4615  }
4616 }
4617 
4618 // Function to count speeds present in all data
4619 int US_ConvertGui::countSpeeds( QVector< int >& speeds, int* pNotrips )
4620 {
4621  speeds.clear(); // Initial list of unique speeds
4622  int nspeed = 0; // Total unique speeds encountered
4623  int notrips = 0; // Count of total output triples
4624  int nitrips = allData.size(); // Count of input triples
4625  int pspeed = 0; // Speed at previous scan
4626 
4627  if ( isMwl )
4628  { // Skip the speed counting for MWL
4629  return nspeed;
4630  }
4631 
4632  for ( int trx = 0; trx < nitrips; trx++ )
4633  { // Examine the speeds within each triple
4634  US_DataIO::RawData* edata = &allData[ trx ];
4635 
4636  for ( int ss = 0; ss < edata->scanData.size(); ss++ )
4637  { // Test each scan's speed
4638  int speed = qRound( edata->scanData[ ss ].rpm );
4639 
4640  if ( ! speeds.contains( speed ) )
4641  { // New speed: add to list and bump unique-speed count
4642  speeds << speed; // Newly encountered speed
4643  nspeed++; // Count of unique speeds
4644  }
4645 
4646  if ( speed != pspeed )
4647  { // Not the same speed as previous scan: bump out-triple count
4648  pspeed = speed; // Previous speed for next iteration
4649  notrips++; // Count of output triples
4650  }
4651  }
4652 DbgLv(1) << "cS: trx nspeed notrips" << nspeed << notrips;
4653  }
4654 
4655  if ( pNotrips != NULL )
4656  *pNotrips = notrips; // Return number of output triples
4657 
4658  return nspeed; // Return number of unique speeds
4659 }
4660 
4661 // Function to write TimeState files to local disk
4663 {
4664  US_TimeState timestate;
4665  QString tmst_fbase = runID + ".time_state.tmst";
4666  QString defs_fbase = runID + ".time_state.xml";
4667  QString tmst_fdir = currentDir;
4668  if ( tmst_fdir.right( 1 ) != "/" ) tmst_fdir + "/";
4669  QString tmst_fname = tmst_fdir + tmst_fbase;
4670  QString defs_fname = tmst_fdir + defs_fbase;
4671  QString defs_fnamei = QString( tmst_fnamei ).section( ".", 0, -2 ) + ".xml";
4672  int nspeed = speedsteps.size();
4673  int ssx = 0;
4674  QVector< double > rrpms;
4675  int nmscans = isMwl ? mwl_data.raw_speeds( rrpms ) : 0;
4676 DbgLv(1) << "wTS: nspeed" << nspeed << "tmst_fname" << tmst_fname;
4677 
4678  // Determine if TimeState of right character already exists
4679  if ( ! tmst_fnamei.isEmpty() )
4680  { // An input TMST exists
4681  timestate.open_read_data( tmst_fnamei );
4682  bool constti;
4683  double timeinc;
4684  double ftime;
4685  QStringList fkeys;
4686  QStringList ffmts;
4687  int ntimes = timestate.time_range( &constti, &timeinc, &ftime );
4688  int nvalues = timestate.field_keys( &fkeys, &ffmts );
4689  timestate.close_read_data();
4690 DbgLv(1) << "wTS: TMST file exists:" << tmst_fnamei;
4691 
4692  if ( tmst_fnamei == tmst_fname && defs_fnamei == defs_fname )
4693  { // Same paths, so we are done
4694 DbgLv(1) << "wTS: existing TMST in run directory - NO UPDATE.";
4695  return ntimes;
4696  }
4697 
4698  // See if all file characteristics match what is now needed
4699  bool use_exstsf = ( ntimes >= nmscans ); // Use existing TMST file?
4700  use_exstsf = ( fkeys.contains( "RawSpeed" ) ) ? use_exstsf : false;
4701  use_exstsf = ( nvalues > 2 ) ? use_exstsf : false;
4702  if ( constti )
4703  { // Constant time increment
4704  use_exstsf = ( ntimes > nmscans ) ? use_exstsf : false;
4705  use_exstsf = ( timeinc > 0.0 ) ? use_exstsf : false;
4706  }
4707  else
4708  { // Non-constant time increment
4709  use_exstsf = ( ntimes >= nmscans ) ? use_exstsf : false;
4710  use_exstsf = ( timeinc == 0.0 ) ? use_exstsf : false;
4711  use_exstsf = ( fkeys.contains( "Time" ) ) ? use_exstsf : false;
4712  }
4713 DbgLv(1) << "wTS: use_exstsf" << use_exstsf << "ntimes nmscans nvalues"
4714  << ntimes << nmscans << nvalues;
4715 
4716  if ( use_exstsf )
4717  { // Existing files have enough: we can use them; need to copy?
4718 
4719  if ( tmst_fnamei.contains( "imports" ) )
4720  { // Existing are in */imports, so copy to current (results/run)
4721  QFile::copy( tmst_fnamei, tmst_fname );
4722  QFile::copy( defs_fnamei, defs_fname );
4723 DbgLv(1) << "wTS: COPY from IMPORTS";
4724  }
4725 
4726  else if ( tmst_fnamei.startsWith( tmst_fdir ) )
4727  { // In current directory, so only a name change (move)
4728  if ( tmst_fname != tmst_fnamei )
4729  QFile::rename( tmst_fnamei, tmst_fname );
4730  if ( defs_fname != defs_fnamei )
4731  QFile::rename( defs_fnamei, defs_fname );
4732 DbgLv(1) << "wTS: RENAME in RESULTS";
4733  }
4734 
4735  else
4736  { // They are somewhere else, so copy to current
4737  QFile::copy( tmst_fnamei, tmst_fname );
4738  QFile::copy( defs_fnamei, defs_fname );
4739 DbgLv(1) << "wTS: COPY from OTHER:" << tmst_fnamei;
4740  }
4741 
4742  // Flag destination file as the input file (in case we re-enter)
4743  tmst_fnamei = tmst_fname;
4744  return ntimes;
4745  }
4746 
4747  else if ( tmst_fnamei.startsWith( tmst_fdir ) )
4748  { // Set is in current directory but not useable as is, so delete
4749  QFile::remove( tmst_fnamei );
4750  QFile::remove( defs_fnamei );
4751  tmst_fnamei.clear();
4752 DbgLv(1) << "wTS: DELETE from RESULTS";
4753  }
4754  }
4755 else
4756 DbgLv(1) << "wTS: EMPTY: tmst_fnamei";
4757 
4758  // Create a new TMST
4759  timestate.open_write_data( tmst_fname, 0.0, 0.0 );
4760  timestate.set_key( "Time", "F4" );
4761  timestate.set_key( "RawSpeed", "I4" );
4762  timestate.set_key( "SetSpeed", "I4" );
4763  timestate.set_key( "Omega2T", "F4" );
4764  timestate.set_key( "Temperature", "F4" );
4765  timestate.set_key( "Scan", "I2" );
4766 
4767  US_DataIO::RawData* rdata = outData[ 0 ];
4768 DbgLv(1) << "wTS: nscan" << rdata->scanData.size();
4769 
4770  for ( int sc = 0; sc < rdata->scanData.size(); sc++ )
4771  {
4772  US_DataIO::Scan* scan = &rdata->scanData[ sc ];
4773  int scan_nbr = sc + 1;
4774  double sctime = scan->seconds;
4775  double raw_speed = ( sc < nmscans ) ? rrpms[ sc ] : scan->rpm;
4776  int set_speed = qRound( raw_speed / 100.0 ) * 100;
4777  if ( nspeed > 0 )
4778  {
4779  while( sctime > speedsteps[ ssx ].time_last && ssx < (nspeed - 1) )
4780  ssx++;
4781  set_speed = speedsteps[ ssx ].set_speed <= 0 ? set_speed
4782  : speedsteps[ ssx ].set_speed;
4783  }
4784 DbgLv(1) << "wTS: sc snbr" << sc << scan_nbr << "set_speed" << set_speed
4785  << "raw_speed" << raw_speed;
4786 
4787  timestate.set_value( "Time", sctime );
4788  timestate.set_value( "RawSpeed", raw_speed );
4789  timestate.set_value( "SetSpeed", set_speed );
4790  timestate.set_value( "Omega2T", scan->omega2t );
4791  timestate.set_value( "Temperature", scan->temperature );
4792  timestate.set_value( "Scan", scan_nbr );
4793 
4794  timestate.flush_record();
4795  }
4796 
4797  // Complete write of TMST and DEFS files
4798  timestate.close_write_data();
4799  timestate.write_defs();
4800  // Flag destination file as the input file (in case we re-enter)
4801  tmst_fnamei = tmst_fname;
4802 DbgLv(1) << "wTS: ntimes" << timestate.time_count();
4803 
4804  return timestate.time_count();
4805 }
4806 
4807 // Function to write TimeState files to the database
4809 {
4810  int status = 0;
4811  US_Passwd pw;
4812  US_DB2 db( pw.getPasswd() );
4813 
4814  if ( db.lastErrno() != US_DB2::OK )
4815  {
4816 DbgLv(1) << "wTSdb: connect" << db.lastErrno() << db.lastError();
4817  return -99;
4818  }
4819 DbgLv(1) << "wTSdb: connect" << db.lastErrno() << db.lastError();
4820 
4821  QString tmst_fbase = runID + ".time_state.tmst";
4822  QString tmst_fdir = ( QString( currentDir ).right( 1 ) == "/" )
4823  ? currentDir : currentDir + "/";
4824  QString tmst_fname = tmst_fdir + tmst_fbase;
4825  QString tmst_cksm = US_Util::md5sum_file( tmst_fname );
4826 DbgLv(1) << "wTSdb: fname " << tmst_fname << "cksm" << tmst_cksm;
4827 
4828  // Create a new TimeState DB record, if need be. If one already exists,
4829  // it may be updated or it may be deleted and recreated.
4830  int timestateID = US_TimeState::dbCreate( &db, ExpData.expID, tmst_fname );
4831 DbgLv(1) << "wTSdb: post-create timestateID" << timestateID;
4832 
4833  // If a TimeState DB record now exists, check for binary data in it.
4834  // If need be, upload binary TMST data
4835  if ( timestateID > 0 )
4836  { // A record has been created/updated/affirmed, so check for data blob
4837  QString cksum;
4838  status = US_TimeState::dbExamine( &db, &timestateID, NULL,
4839  NULL, NULL, &cksum, NULL );
4840 DbgLv(1) << "wTSdb: examine status" << status << "cksum-db" << cksum;
4841 
4842  if ( status == US_DB2::OK && cksum != tmst_cksm )
4843  { // No or mismatched blob in DB, so upload it
4844  status = US_TimeState::dbUpload( &db, timestateID,
4845  tmst_fname );
4846 DbgLv(1) << "wTSdb: upload status" << status;
4847  }
4848  }
4849 
4850  return status;
4851 }
4852 
4853 // Build lambda controls
4855 {
4856  if ( ! isMwl )
4857  return;
4858 
4859  // For MWL, rebuild wavelength controls
4860  int ntrip = out_tripinfo.count();
4861 DbgLv(1) << "BldLCtr: ntrip" << ntrip;
4862  int ccx = out_tripinfo[ 0 ].channelID - 1;
4863 DbgLv(1) << "BldLCtr: st ccx" << ccx;
4864  int wvx = 0;
4865  int ccxo = 0;
4866  exp_lambdas.clear();
4867 
4868  for ( int trx = 0; trx < ntrip; trx++ )
4869  { // Loop to add non-excluded wavelengths
4870  int ichan = out_tripinfo[ trx ].channelID - 1;
4871  int iwavl = out_triples [ trx ].section( " / ", 2, 2 ).toInt();
4872 DbgLv(1) << "BldLCtr: trx ichan ccx iwavl" << trx << ichan << ccx << iwavl;
4873 
4874  if ( ichan != ccx )
4875  { // If a new channel, store the previous channel's lambda list
4876  mwl_data.set_lambdas( exp_lambdas, ccxo );
4877 DbgLv(1) << "BldLCtr: trx ichan ccx ccxo iwavl nlam" << trx << ichan << ccx
4878  << ccxo << iwavl << exp_lambdas.count() << wvx;
4879  wvx = 0;
4880  exp_lambdas.clear();
4881 
4882  ccx = ichan;
4883  ccxo++;
4884  }
4885 
4886  exp_lambdas << iwavl;
4887  wvx++;
4888  }
4889 
4890  // Store the last channel's lambdas
4891  mwl_data.set_lambdas( exp_lambdas, ccxo );
4892 DbgLv(1) << "BldLCtr: ccxo nlam" << ccxo << exp_lambdas.count();
4893  mwl_connect( false );
4894 
4895  // Set controls for the currently selected cell/channel in the list
4896  tripListx = lw_triple->currentRow();
4898  slambda = exp_lambdas[ 0 ];
4899  elambda = exp_lambdas[ nlambda - 1 ];
4900 
4901 DbgLv(1) << "BldLCtr: ccx nlam" << 0 << exp_lambdas.count();
4902  cb_lambstrt->setCurrentIndex( all_lambdas.indexOf( slambda ) );
4903  cb_lambstop->setCurrentIndex( all_lambdas.indexOf( elambda ) );
4904  cb_lambplot->setCurrentIndex( nlambda / 2 );
4905  mwl_connect( true );
4906 
4907  reset_lambdas(); // Make sure internal MWL lambdas are right
4908 
4909 }